17697SMichael.Christensen@Sun.COM /* 27697SMichael.Christensen@Sun.COM * CDDL HEADER START 37697SMichael.Christensen@Sun.COM * 47697SMichael.Christensen@Sun.COM * The contents of this file are subject to the terms of the 57697SMichael.Christensen@Sun.COM * Common Development and Distribution License (the "License"). 67697SMichael.Christensen@Sun.COM * You may not use this file except in compliance with the License. 77697SMichael.Christensen@Sun.COM * 87697SMichael.Christensen@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97697SMichael.Christensen@Sun.COM * or http://www.opensolaris.org/os/licensing. 107697SMichael.Christensen@Sun.COM * See the License for the specific language governing permissions 117697SMichael.Christensen@Sun.COM * and limitations under the License. 127697SMichael.Christensen@Sun.COM * 137697SMichael.Christensen@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 147697SMichael.Christensen@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157697SMichael.Christensen@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 167697SMichael.Christensen@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 177697SMichael.Christensen@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 187697SMichael.Christensen@Sun.COM * 197697SMichael.Christensen@Sun.COM * CDDL HEADER END 207697SMichael.Christensen@Sun.COM */ 217697SMichael.Christensen@Sun.COM 227697SMichael.Christensen@Sun.COM /* 238894SMichael.Christensen@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247697SMichael.Christensen@Sun.COM * Use is subject to license terms. 257697SMichael.Christensen@Sun.COM */ 267697SMichael.Christensen@Sun.COM 277697SMichael.Christensen@Sun.COM /* 287697SMichael.Christensen@Sun.COM * Domain Services Module Common Code. 297697SMichael.Christensen@Sun.COM * 307697SMichael.Christensen@Sun.COM * This module is intended to be used by both Solaris and the VBSC 317697SMichael.Christensen@Sun.COM * module. 327697SMichael.Christensen@Sun.COM */ 337697SMichael.Christensen@Sun.COM 347697SMichael.Christensen@Sun.COM #include <sys/modctl.h> 357697SMichael.Christensen@Sun.COM #include <sys/ksynch.h> 367697SMichael.Christensen@Sun.COM #include <sys/taskq.h> 377697SMichael.Christensen@Sun.COM #include <sys/disp.h> 387697SMichael.Christensen@Sun.COM #include <sys/cmn_err.h> 397697SMichael.Christensen@Sun.COM #include <sys/note.h> 407697SMichael.Christensen@Sun.COM #include <sys/mach_descrip.h> 417697SMichael.Christensen@Sun.COM #include <sys/mdesc.h> 427697SMichael.Christensen@Sun.COM #include <sys/ldc.h> 437697SMichael.Christensen@Sun.COM #include <sys/ds.h> 447697SMichael.Christensen@Sun.COM #include <sys/ds_impl.h> 457697SMichael.Christensen@Sun.COM 467697SMichael.Christensen@Sun.COM #ifndef MIN 477697SMichael.Christensen@Sun.COM #define MIN(a, b) ((a) < (b) ? (a) : (b)) 487697SMichael.Christensen@Sun.COM #endif 497697SMichael.Christensen@Sun.COM 507697SMichael.Christensen@Sun.COM #define DS_DECODE_BUF_LEN 30 517697SMichael.Christensen@Sun.COM 527697SMichael.Christensen@Sun.COM /* 537697SMichael.Christensen@Sun.COM * All DS ports in the system 547697SMichael.Christensen@Sun.COM * 557697SMichael.Christensen@Sun.COM * The list of DS ports is read in from the MD when the DS module is 567697SMichael.Christensen@Sun.COM * initialized and is never modified. This eliminates the need for 577697SMichael.Christensen@Sun.COM * locking to access the port array itself. Access to the individual 587697SMichael.Christensen@Sun.COM * ports are synchronized at the port level. 597697SMichael.Christensen@Sun.COM */ 607697SMichael.Christensen@Sun.COM ds_port_t ds_ports[DS_MAX_PORTS]; 617697SMichael.Christensen@Sun.COM ds_portset_t ds_allports; /* all DS ports in the system */ 629535SMichael.Christensen@Sun.COM ds_portset_t ds_nullport; /* allows test against null portset */ 637697SMichael.Christensen@Sun.COM 649603SMichael.Christensen@Sun.COM /* DS SP port id */ 659603SMichael.Christensen@Sun.COM uint64_t ds_sp_port_id = DS_PORTID_INVALID; 669603SMichael.Christensen@Sun.COM 677697SMichael.Christensen@Sun.COM /* 687697SMichael.Christensen@Sun.COM * Table of registered services 697697SMichael.Christensen@Sun.COM * 707697SMichael.Christensen@Sun.COM * Locking: Accesses to the table of services are synchronized using 717697SMichael.Christensen@Sun.COM * a mutex lock. The reader lock must be held when looking up service 727697SMichael.Christensen@Sun.COM * information in the table. The writer lock must be held when any 737697SMichael.Christensen@Sun.COM * service information is being modified. 747697SMichael.Christensen@Sun.COM */ 757697SMichael.Christensen@Sun.COM ds_svcs_t ds_svcs; 767697SMichael.Christensen@Sun.COM 777697SMichael.Christensen@Sun.COM /* 787697SMichael.Christensen@Sun.COM * Flag to prevent callbacks while in the middle of DS teardown. 797697SMichael.Christensen@Sun.COM */ 807697SMichael.Christensen@Sun.COM boolean_t ds_enabled = B_FALSE; /* enable/disable taskq processing */ 817697SMichael.Christensen@Sun.COM 827697SMichael.Christensen@Sun.COM /* 837697SMichael.Christensen@Sun.COM * Retry count and delay for LDC reads and writes 847697SMichael.Christensen@Sun.COM */ 857697SMichael.Christensen@Sun.COM #ifndef DS_DEFAULT_RETRIES 867697SMichael.Christensen@Sun.COM #define DS_DEFAULT_RETRIES 10000 /* number of times to retry */ 877697SMichael.Christensen@Sun.COM #endif 887697SMichael.Christensen@Sun.COM #ifndef DS_DEFAULT_DELAY 897697SMichael.Christensen@Sun.COM #define DS_DEFAULT_DELAY 1000 /* usecs to wait between retries */ 907697SMichael.Christensen@Sun.COM #endif 917697SMichael.Christensen@Sun.COM 927697SMichael.Christensen@Sun.COM static int ds_retries = DS_DEFAULT_RETRIES; 937697SMichael.Christensen@Sun.COM static clock_t ds_delay = DS_DEFAULT_DELAY; 947697SMichael.Christensen@Sun.COM 957697SMichael.Christensen@Sun.COM /* 967697SMichael.Christensen@Sun.COM * Supported versions of the DS message protocol 977697SMichael.Christensen@Sun.COM * 987697SMichael.Christensen@Sun.COM * The version array must be sorted in order from the highest 997697SMichael.Christensen@Sun.COM * supported version to the lowest. Support for a particular 1007697SMichael.Christensen@Sun.COM * <major>.<minor> version implies all lower minor versions of 1017697SMichael.Christensen@Sun.COM * that same major version are supported as well. 1027697SMichael.Christensen@Sun.COM */ 1037697SMichael.Christensen@Sun.COM static ds_ver_t ds_vers[] = { { 1, 0 } }; 1047697SMichael.Christensen@Sun.COM 1057697SMichael.Christensen@Sun.COM #define DS_NUM_VER (sizeof (ds_vers) / sizeof (ds_vers[0])) 1067697SMichael.Christensen@Sun.COM 1077697SMichael.Christensen@Sun.COM 1087697SMichael.Christensen@Sun.COM /* incoming message handling functions */ 1097697SMichael.Christensen@Sun.COM typedef void (*ds_msg_handler_t)(ds_port_t *port, caddr_t buf, size_t len); 1107697SMichael.Christensen@Sun.COM static void ds_handle_init_req(ds_port_t *port, caddr_t buf, size_t len); 1117697SMichael.Christensen@Sun.COM static void ds_handle_init_ack(ds_port_t *port, caddr_t buf, size_t len); 1127697SMichael.Christensen@Sun.COM static void ds_handle_init_nack(ds_port_t *port, caddr_t buf, size_t len); 1137697SMichael.Christensen@Sun.COM static void ds_handle_reg_req(ds_port_t *port, caddr_t buf, size_t len); 1147697SMichael.Christensen@Sun.COM static void ds_handle_reg_ack(ds_port_t *port, caddr_t buf, size_t len); 1157697SMichael.Christensen@Sun.COM static void ds_handle_reg_nack(ds_port_t *port, caddr_t buf, size_t len); 1167697SMichael.Christensen@Sun.COM static void ds_handle_unreg_req(ds_port_t *port, caddr_t buf, size_t len); 1177697SMichael.Christensen@Sun.COM static void ds_handle_unreg_ack(ds_port_t *port, caddr_t buf, size_t len); 1187697SMichael.Christensen@Sun.COM static void ds_handle_unreg_nack(ds_port_t *port, caddr_t buf, size_t len); 1197697SMichael.Christensen@Sun.COM static void ds_handle_data(ds_port_t *port, caddr_t buf, size_t len); 1207697SMichael.Christensen@Sun.COM static void ds_handle_nack(ds_port_t *port, caddr_t buf, size_t len); 1217697SMichael.Christensen@Sun.COM 1227697SMichael.Christensen@Sun.COM /* 1237697SMichael.Christensen@Sun.COM * DS Message Handler Dispatch Table 1247697SMichael.Christensen@Sun.COM * 1257697SMichael.Christensen@Sun.COM * A table used to dispatch all incoming messages. This table 1267697SMichael.Christensen@Sun.COM * contains handlers for all the fixed message types, as well as 1277697SMichael.Christensen@Sun.COM * the the messages defined in the 1.0 version of the DS protocol. 1287697SMichael.Christensen@Sun.COM * The handlers are indexed based on the DS header msg_type values 1297697SMichael.Christensen@Sun.COM */ 1307697SMichael.Christensen@Sun.COM static const ds_msg_handler_t ds_msg_handlers[] = { 1317697SMichael.Christensen@Sun.COM ds_handle_init_req, /* DS_INIT_REQ */ 1327697SMichael.Christensen@Sun.COM ds_handle_init_ack, /* DS_INIT_ACK */ 1337697SMichael.Christensen@Sun.COM ds_handle_init_nack, /* DS_INIT_NACK */ 1347697SMichael.Christensen@Sun.COM ds_handle_reg_req, /* DS_REG_REQ */ 1357697SMichael.Christensen@Sun.COM ds_handle_reg_ack, /* DS_REG_ACK */ 1367697SMichael.Christensen@Sun.COM ds_handle_reg_nack, /* DS_REG_NACK */ 1377697SMichael.Christensen@Sun.COM ds_handle_unreg_req, /* DS_UNREG */ 1387697SMichael.Christensen@Sun.COM ds_handle_unreg_ack, /* DS_UNREG_ACK */ 1397697SMichael.Christensen@Sun.COM ds_handle_unreg_nack, /* DS_UNREG_NACK */ 1407697SMichael.Christensen@Sun.COM ds_handle_data, /* DS_DATA */ 1417697SMichael.Christensen@Sun.COM ds_handle_nack /* DS_NACK */ 1427697SMichael.Christensen@Sun.COM }; 1437697SMichael.Christensen@Sun.COM 1447697SMichael.Christensen@Sun.COM 1457697SMichael.Christensen@Sun.COM 1467697SMichael.Christensen@Sun.COM /* initialization functions */ 1477697SMichael.Christensen@Sun.COM static int ds_ldc_init(ds_port_t *port); 1487697SMichael.Christensen@Sun.COM 1497697SMichael.Christensen@Sun.COM /* event processing functions */ 1507697SMichael.Christensen@Sun.COM static uint_t ds_ldc_cb(uint64_t event, caddr_t arg); 1517697SMichael.Christensen@Sun.COM static int ds_recv_msg(ds_port_t *port, caddr_t msgp, size_t *sizep); 1527697SMichael.Christensen@Sun.COM static void ds_handle_up_event(ds_port_t *port); 1537697SMichael.Christensen@Sun.COM static void ds_handle_down_reset_events(ds_port_t *port); 1547697SMichael.Christensen@Sun.COM static void ds_handle_recv(void *arg); 1557697SMichael.Christensen@Sun.COM static void ds_dispatch_event(void *arg); 1567697SMichael.Christensen@Sun.COM 1577697SMichael.Christensen@Sun.COM /* message sending functions */ 1587697SMichael.Christensen@Sun.COM static int ds_send_msg(ds_port_t *port, caddr_t msg, size_t msglen); 1597697SMichael.Christensen@Sun.COM static int ds_send_reg_req(ds_svc_t *svc, ds_port_t *port); 1607697SMichael.Christensen@Sun.COM static void ds_send_unreg_nack(ds_port_t *port, ds_svc_hdl_t bad_hdl); 1617697SMichael.Christensen@Sun.COM static void ds_send_data_nack(ds_port_t *port, ds_svc_hdl_t bad_hdl); 1627697SMichael.Christensen@Sun.COM 1637697SMichael.Christensen@Sun.COM /* walker functions */ 1647697SMichael.Christensen@Sun.COM static int ds_svc_isfree(ds_svc_t *svc, void *arg); 1657697SMichael.Christensen@Sun.COM static int ds_svc_unregister(ds_svc_t *svc, void *arg); 1667697SMichael.Christensen@Sun.COM static int ds_svc_port_up(ds_svc_t *svc, void *arg); 1677697SMichael.Christensen@Sun.COM 1687697SMichael.Christensen@Sun.COM /* service utilities */ 1697697SMichael.Christensen@Sun.COM static void ds_reset_svc(ds_svc_t *svc, ds_port_t *port); 1707697SMichael.Christensen@Sun.COM static int ds_svc_register_onport(ds_svc_t *svc, ds_port_t *port); 171*10042SMichael.Christensen@Sun.COM static int ds_svc_register_onport_walker(ds_svc_t *svc, void *arg); 172*10042SMichael.Christensen@Sun.COM static void ds_set_port_ready(ds_port_t *port, uint16_t major, uint16_t minor); 1737697SMichael.Christensen@Sun.COM 1747697SMichael.Christensen@Sun.COM /* port utilities */ 1757697SMichael.Christensen@Sun.COM static void ds_port_reset(ds_port_t *port); 1767697SMichael.Christensen@Sun.COM static ldc_status_t ds_update_ldc_state(ds_port_t *port); 1777697SMichael.Christensen@Sun.COM 1787697SMichael.Christensen@Sun.COM /* misc utilities */ 1797697SMichael.Christensen@Sun.COM static void min_max_versions(int num_versions, ds_ver_t *sup_versionsp, 1807697SMichael.Christensen@Sun.COM uint16_t *min_major, uint16_t *max_major); 1817697SMichael.Christensen@Sun.COM 1827697SMichael.Christensen@Sun.COM /* debug */ 1837697SMichael.Christensen@Sun.COM static char *decode_ldc_events(uint64_t event, char *buf); 1847697SMichael.Christensen@Sun.COM 1857697SMichael.Christensen@Sun.COM /* loopback */ 1867697SMichael.Christensen@Sun.COM static void ds_loopback_register(ds_svc_hdl_t hdl); 1877697SMichael.Christensen@Sun.COM static void ds_loopback_unregister(ds_svc_hdl_t hdl); 1887697SMichael.Christensen@Sun.COM static void ds_loopback_send(ds_svc_hdl_t hdl, void *buf, size_t buflen); 1898172SMichael.Christensen@Sun.COM static int ds_loopback_set_svc(ds_svc_t *svc, ds_capability_t *cap, 1908172SMichael.Christensen@Sun.COM ds_svc_hdl_t *lb_hdlp); 1917697SMichael.Christensen@Sun.COM 1927697SMichael.Christensen@Sun.COM /* client handling */ 1937697SMichael.Christensen@Sun.COM static int i_ds_hdl_lookup(char *service, uint_t is_client, ds_svc_hdl_t *hdlp, 1947697SMichael.Christensen@Sun.COM uint_t maxhdls); 1957697SMichael.Christensen@Sun.COM static ds_svc_t *ds_find_clnt_svc_by_hdl_port(ds_svc_hdl_t hdl, 1967697SMichael.Christensen@Sun.COM ds_port_t *port); 1977697SMichael.Christensen@Sun.COM static ds_svc_t *ds_find_svc_by_id_port(char *svc_id, int is_client, 1987697SMichael.Christensen@Sun.COM ds_port_t *port); 1997697SMichael.Christensen@Sun.COM static ds_svc_t *ds_svc_clone(ds_svc_t *svc); 2007697SMichael.Christensen@Sun.COM static void ds_check_for_dup_services(ds_svc_t *svc); 2017697SMichael.Christensen@Sun.COM static void ds_delete_svc_entry(ds_svc_t *svc); 2027697SMichael.Christensen@Sun.COM 2037697SMichael.Christensen@Sun.COM char * 2047697SMichael.Christensen@Sun.COM ds_strdup(char *str) 2057697SMichael.Christensen@Sun.COM { 2067697SMichael.Christensen@Sun.COM char *newstr; 2077697SMichael.Christensen@Sun.COM 2087697SMichael.Christensen@Sun.COM newstr = DS_MALLOC(strlen(str) + 1); 2097697SMichael.Christensen@Sun.COM (void) strcpy(newstr, str); 2107697SMichael.Christensen@Sun.COM return (newstr); 2117697SMichael.Christensen@Sun.COM } 2127697SMichael.Christensen@Sun.COM 2137697SMichael.Christensen@Sun.COM void 2147697SMichael.Christensen@Sun.COM ds_common_init(void) 2157697SMichael.Christensen@Sun.COM { 2167697SMichael.Christensen@Sun.COM /* Validate version table */ 2177697SMichael.Christensen@Sun.COM ASSERT(ds_vers_isvalid(ds_vers, DS_NUM_VER) == DS_VERS_OK); 2187697SMichael.Christensen@Sun.COM 2197697SMichael.Christensen@Sun.COM /* Initialize services table */ 2207697SMichael.Christensen@Sun.COM ds_init_svcs_tbl(DS_MAXSVCS_INIT); 2217697SMichael.Christensen@Sun.COM 2227697SMichael.Christensen@Sun.COM /* enable callback processing */ 2237697SMichael.Christensen@Sun.COM ds_enabled = B_TRUE; 2247697SMichael.Christensen@Sun.COM } 2257697SMichael.Christensen@Sun.COM 2267697SMichael.Christensen@Sun.COM /* BEGIN LDC SUPPORT FUNCTIONS */ 2277697SMichael.Christensen@Sun.COM 2287697SMichael.Christensen@Sun.COM static char * 2297697SMichael.Christensen@Sun.COM decode_ldc_events(uint64_t event, char *buf) 2307697SMichael.Christensen@Sun.COM { 2317697SMichael.Christensen@Sun.COM buf[0] = 0; 2327697SMichael.Christensen@Sun.COM if (event & LDC_EVT_DOWN) (void) strcat(buf, " DOWN"); 2337697SMichael.Christensen@Sun.COM if (event & LDC_EVT_RESET) (void) strcat(buf, " RESET"); 2347697SMichael.Christensen@Sun.COM if (event & LDC_EVT_UP) (void) strcat(buf, " UP"); 2357697SMichael.Christensen@Sun.COM if (event & LDC_EVT_READ) (void) strcat(buf, " READ"); 2367697SMichael.Christensen@Sun.COM if (event & LDC_EVT_WRITE) (void) strcat(buf, " WRITE"); 2377697SMichael.Christensen@Sun.COM return (buf); 2387697SMichael.Christensen@Sun.COM } 2397697SMichael.Christensen@Sun.COM 2407697SMichael.Christensen@Sun.COM static ldc_status_t 2417697SMichael.Christensen@Sun.COM ds_update_ldc_state(ds_port_t *port) 2427697SMichael.Christensen@Sun.COM { 2437697SMichael.Christensen@Sun.COM ldc_status_t ldc_state; 2447697SMichael.Christensen@Sun.COM int rv; 2457697SMichael.Christensen@Sun.COM char ebuf[DS_EBUFSIZE]; 2467697SMichael.Christensen@Sun.COM 2477697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&port->lock)); 2487697SMichael.Christensen@Sun.COM 2497697SMichael.Christensen@Sun.COM /* 2507697SMichael.Christensen@Sun.COM * Read status and update ldc state info in port structure. 2517697SMichael.Christensen@Sun.COM */ 2527697SMichael.Christensen@Sun.COM if ((rv = ldc_status(port->ldc.hdl, &ldc_state)) != 0) { 2537697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: %s: ldc_status error: %s" DS_EOL, 2547697SMichael.Christensen@Sun.COM PORTID(port), __func__, ds_errno_to_str(rv, ebuf)); 2557697SMichael.Christensen@Sun.COM ldc_state = port->ldc.state; 2567697SMichael.Christensen@Sun.COM } else { 2577697SMichael.Christensen@Sun.COM port->ldc.state = ldc_state; 2587697SMichael.Christensen@Sun.COM } 2597697SMichael.Christensen@Sun.COM 2607697SMichael.Christensen@Sun.COM return (ldc_state); 2617697SMichael.Christensen@Sun.COM } 2627697SMichael.Christensen@Sun.COM 2637697SMichael.Christensen@Sun.COM static void 2647697SMichael.Christensen@Sun.COM ds_handle_down_reset_events(ds_port_t *port) 2657697SMichael.Christensen@Sun.COM { 2667697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: entered" DS_EOL, PORTID(port), 2677697SMichael.Christensen@Sun.COM __func__); 2687697SMichael.Christensen@Sun.COM 2697697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 2707697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 2717697SMichael.Christensen@Sun.COM 2727697SMichael.Christensen@Sun.COM ds_sys_drain_events(port); 2737697SMichael.Christensen@Sun.COM 2747697SMichael.Christensen@Sun.COM (void) ds_update_ldc_state(port); 2757697SMichael.Christensen@Sun.COM 2767697SMichael.Christensen@Sun.COM /* reset the port state */ 2777697SMichael.Christensen@Sun.COM ds_port_reset(port); 2787697SMichael.Christensen@Sun.COM 2797697SMichael.Christensen@Sun.COM /* acknowledge the reset */ 2807697SMichael.Christensen@Sun.COM (void) ldc_up(port->ldc.hdl); 2817697SMichael.Christensen@Sun.COM 2827697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 2837697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 2847697SMichael.Christensen@Sun.COM 2857697SMichael.Christensen@Sun.COM ds_handle_up_event(port); 2867697SMichael.Christensen@Sun.COM 2877697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: exit" DS_EOL, PORTID(port), __func__); 2887697SMichael.Christensen@Sun.COM } 2897697SMichael.Christensen@Sun.COM 2907697SMichael.Christensen@Sun.COM static void 2917697SMichael.Christensen@Sun.COM ds_handle_up_event(ds_port_t *port) 2927697SMichael.Christensen@Sun.COM { 2937697SMichael.Christensen@Sun.COM ldc_status_t ldc_state; 2947697SMichael.Christensen@Sun.COM 2957697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: entered" DS_EOL, PORTID(port), 2967697SMichael.Christensen@Sun.COM __func__); 2977697SMichael.Christensen@Sun.COM 2987697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 2997697SMichael.Christensen@Sun.COM 3007697SMichael.Christensen@Sun.COM ldc_state = ds_update_ldc_state(port); 3017697SMichael.Christensen@Sun.COM 3027697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 3037697SMichael.Christensen@Sun.COM 3047697SMichael.Christensen@Sun.COM if ((ldc_state == LDC_UP) && IS_DS_PORT(port)) { 3057697SMichael.Christensen@Sun.COM /* 3067697SMichael.Christensen@Sun.COM * Initiate the handshake. 3077697SMichael.Christensen@Sun.COM */ 3087697SMichael.Christensen@Sun.COM ds_send_init_req(port); 3097697SMichael.Christensen@Sun.COM } 3107697SMichael.Christensen@Sun.COM 3117697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: exit" DS_EOL, PORTID(port), __func__); 3127697SMichael.Christensen@Sun.COM } 3137697SMichael.Christensen@Sun.COM 3147697SMichael.Christensen@Sun.COM static uint_t 3157697SMichael.Christensen@Sun.COM ds_ldc_cb(uint64_t event, caddr_t arg) 3167697SMichael.Christensen@Sun.COM { 3177697SMichael.Christensen@Sun.COM ds_port_t *port = (ds_port_t *)arg; 3187697SMichael.Christensen@Sun.COM char evstring[DS_DECODE_BUF_LEN]; 3197697SMichael.Christensen@Sun.COM 3207697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: %s event (%llx) received" DS_EOL, 3217697SMichael.Christensen@Sun.COM PORTID(port), __func__, decode_ldc_events(event, evstring), 3227697SMichael.Christensen@Sun.COM (u_longlong_t)event); 3237697SMichael.Christensen@Sun.COM 3247697SMichael.Christensen@Sun.COM if (!ds_enabled) { 3257697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: callback handling is disabled" 3267697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), __func__); 3277697SMichael.Christensen@Sun.COM return (LDC_SUCCESS); 3287697SMichael.Christensen@Sun.COM } 3297697SMichael.Christensen@Sun.COM 3307697SMichael.Christensen@Sun.COM if (event & (LDC_EVT_DOWN | LDC_EVT_RESET)) { 3317697SMichael.Christensen@Sun.COM ds_handle_down_reset_events(port); 3327697SMichael.Christensen@Sun.COM goto done; 3337697SMichael.Christensen@Sun.COM } 3347697SMichael.Christensen@Sun.COM 3357697SMichael.Christensen@Sun.COM if (event & LDC_EVT_UP) { 3367697SMichael.Christensen@Sun.COM ds_handle_up_event(port); 3377697SMichael.Christensen@Sun.COM } 3387697SMichael.Christensen@Sun.COM 3397697SMichael.Christensen@Sun.COM if (event & LDC_EVT_READ) { 3407697SMichael.Christensen@Sun.COM if (port->ldc.state != LDC_UP) { 3417697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: %s: LDC READ event while " 3427697SMichael.Christensen@Sun.COM "port not up" DS_EOL, PORTID(port), __func__); 3437697SMichael.Christensen@Sun.COM goto done; 3447697SMichael.Christensen@Sun.COM } 3457697SMichael.Christensen@Sun.COM 3467697SMichael.Christensen@Sun.COM if (ds_sys_dispatch_func(ds_handle_recv, port)) { 3477697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: error initiating LDC READ " 3487697SMichael.Christensen@Sun.COM " event", PORTID(port)); 3497697SMichael.Christensen@Sun.COM } 3507697SMichael.Christensen@Sun.COM } 3517697SMichael.Christensen@Sun.COM 3527697SMichael.Christensen@Sun.COM if (event & LDC_EVT_WRITE) { 3537697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: LDC WRITE event received, " 3547697SMichael.Christensen@Sun.COM "not supported" DS_EOL, PORTID(port), __func__); 3557697SMichael.Christensen@Sun.COM } 3567697SMichael.Christensen@Sun.COM 3577697SMichael.Christensen@Sun.COM if (event & ~(LDC_EVT_UP | LDC_EVT_READ)) { 3587697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: %s: Unexpected LDC event received: " 3597697SMichael.Christensen@Sun.COM "0x%llx" DS_EOL, PORTID(port), __func__, 3607697SMichael.Christensen@Sun.COM (u_longlong_t)event); 3617697SMichael.Christensen@Sun.COM } 3627697SMichael.Christensen@Sun.COM done: 3637697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: exit" DS_EOL, PORTID(port), __func__); 3647697SMichael.Christensen@Sun.COM 3657697SMichael.Christensen@Sun.COM return (LDC_SUCCESS); 3667697SMichael.Christensen@Sun.COM } 3677697SMichael.Christensen@Sun.COM 3687697SMichael.Christensen@Sun.COM static int 3697697SMichael.Christensen@Sun.COM ds_ldc_init(ds_port_t *port) 3707697SMichael.Christensen@Sun.COM { 3717697SMichael.Christensen@Sun.COM int rv; 3727697SMichael.Christensen@Sun.COM ldc_attr_t ldc_attr; 3737697SMichael.Christensen@Sun.COM caddr_t ldc_cb_arg = (caddr_t)port; 3747697SMichael.Christensen@Sun.COM char ebuf[DS_EBUFSIZE]; 3757697SMichael.Christensen@Sun.COM 3767697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&port->lock)); 3777697SMichael.Christensen@Sun.COM 3787697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: ldc_id=%lld" DS_EOL, 3797697SMichael.Christensen@Sun.COM PORTID(port), __func__, (u_longlong_t)port->ldc.id); 3807697SMichael.Christensen@Sun.COM 3817697SMichael.Christensen@Sun.COM ldc_attr.devclass = LDC_DEV_GENERIC; 3827697SMichael.Christensen@Sun.COM ldc_attr.instance = 0; 3837697SMichael.Christensen@Sun.COM ldc_attr.mode = LDC_MODE_RELIABLE; 3847697SMichael.Christensen@Sun.COM ldc_attr.mtu = DS_STREAM_MTU; 3857697SMichael.Christensen@Sun.COM 3867697SMichael.Christensen@Sun.COM if ((rv = ldc_init(port->ldc.id, &ldc_attr, &port->ldc.hdl)) != 0) { 3877697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: %s: ldc_id: %lx, ldc_init error: %s" 3887697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), __func__, port->ldc.id, 3897697SMichael.Christensen@Sun.COM ds_errno_to_str(rv, ebuf)); 3907697SMichael.Christensen@Sun.COM return (rv); 3917697SMichael.Christensen@Sun.COM } 3927697SMichael.Christensen@Sun.COM 3937697SMichael.Christensen@Sun.COM rv = ldc_reg_callback(port->ldc.hdl, ds_ldc_cb, ldc_cb_arg); 3947697SMichael.Christensen@Sun.COM if (rv != 0) { 3957697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: %s: ldc_reg_callback error: %s" 3967697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), __func__, ds_errno_to_str(rv, ebuf)); 3977697SMichael.Christensen@Sun.COM return (rv); 3987697SMichael.Christensen@Sun.COM } 3997697SMichael.Christensen@Sun.COM 4007697SMichael.Christensen@Sun.COM ds_sys_ldc_init(port); 4017697SMichael.Christensen@Sun.COM return (0); 4027697SMichael.Christensen@Sun.COM } 4037697SMichael.Christensen@Sun.COM 4047697SMichael.Christensen@Sun.COM int 4057697SMichael.Christensen@Sun.COM ds_ldc_fini(ds_port_t *port) 4067697SMichael.Christensen@Sun.COM { 4077697SMichael.Christensen@Sun.COM int rv; 4087697SMichael.Christensen@Sun.COM char ebuf[DS_EBUFSIZE]; 4097697SMichael.Christensen@Sun.COM 4107697SMichael.Christensen@Sun.COM ASSERT(port->state >= DS_PORT_LDC_INIT); 4119916SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&port->lock)); 4127697SMichael.Christensen@Sun.COM 4137697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: ldc_id=%ld" DS_EOL, PORTID(port), 4147697SMichael.Christensen@Sun.COM __func__, port->ldc.id); 4157697SMichael.Christensen@Sun.COM 4167697SMichael.Christensen@Sun.COM if ((rv = ldc_close(port->ldc.hdl)) != 0) { 4177697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: %s: ldc_close error: %s" DS_EOL, 4187697SMichael.Christensen@Sun.COM PORTID(port), __func__, ds_errno_to_str(rv, ebuf)); 4197697SMichael.Christensen@Sun.COM return (rv); 4207697SMichael.Christensen@Sun.COM } 4217697SMichael.Christensen@Sun.COM 4227697SMichael.Christensen@Sun.COM if ((rv = ldc_unreg_callback(port->ldc.hdl)) != 0) { 4237697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: %s: ldc_unreg_callback error: %s" 4247697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), __func__, ds_errno_to_str(rv, ebuf)); 4257697SMichael.Christensen@Sun.COM return (rv); 4267697SMichael.Christensen@Sun.COM } 4277697SMichael.Christensen@Sun.COM 4287697SMichael.Christensen@Sun.COM if ((rv = ldc_fini(port->ldc.hdl)) != 0) { 4297697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: %s: ldc_fini error: %s" DS_EOL, 4307697SMichael.Christensen@Sun.COM PORTID(port), __func__, ds_errno_to_str(rv, ebuf)); 4317697SMichael.Christensen@Sun.COM return (rv); 4327697SMichael.Christensen@Sun.COM } 4337697SMichael.Christensen@Sun.COM 4349916SMichael.Christensen@Sun.COM port->ldc.id = (uint64_t)-1; 4359916SMichael.Christensen@Sun.COM port->ldc.hdl = NULL; 4369916SMichael.Christensen@Sun.COM port->ldc.state = 0; 4379916SMichael.Christensen@Sun.COM 4387697SMichael.Christensen@Sun.COM return (rv); 4397697SMichael.Christensen@Sun.COM } 4407697SMichael.Christensen@Sun.COM 4417697SMichael.Christensen@Sun.COM /* 4427697SMichael.Christensen@Sun.COM * Attempt to read a specified number of bytes from a particular LDC. 4437697SMichael.Christensen@Sun.COM * Returns zero for success or the return code from the LDC read on 4447697SMichael.Christensen@Sun.COM * failure. The actual number of bytes read from the LDC is returned 4457697SMichael.Christensen@Sun.COM * in the size parameter. 4467697SMichael.Christensen@Sun.COM */ 4477697SMichael.Christensen@Sun.COM static int 4487697SMichael.Christensen@Sun.COM ds_recv_msg(ds_port_t *port, caddr_t msgp, size_t *sizep) 4497697SMichael.Christensen@Sun.COM { 4507697SMichael.Christensen@Sun.COM int rv = 0; 4517697SMichael.Christensen@Sun.COM size_t bytes_req = *sizep; 4527697SMichael.Christensen@Sun.COM size_t bytes_left = bytes_req; 4537697SMichael.Christensen@Sun.COM size_t nbytes; 4547697SMichael.Christensen@Sun.COM int retry_count = 0; 4557697SMichael.Christensen@Sun.COM char ebuf[DS_EBUFSIZE]; 4567697SMichael.Christensen@Sun.COM 4577697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&port->rcv_lock)); 4587697SMichael.Christensen@Sun.COM 4597697SMichael.Christensen@Sun.COM *sizep = 0; 4607697SMichael.Christensen@Sun.COM 4617697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: attempting to read %ld bytes" DS_EOL, 4627697SMichael.Christensen@Sun.COM PORTID(port), bytes_req); 4637697SMichael.Christensen@Sun.COM 4647697SMichael.Christensen@Sun.COM while (bytes_left > 0) { 4657697SMichael.Christensen@Sun.COM 4667697SMichael.Christensen@Sun.COM nbytes = bytes_left; 4677697SMichael.Christensen@Sun.COM 4689916SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 4699916SMichael.Christensen@Sun.COM if (port->ldc.state == LDC_UP) { 4709916SMichael.Christensen@Sun.COM rv = ldc_read(port->ldc.hdl, msgp, &nbytes); 4719916SMichael.Christensen@Sun.COM } else 4729916SMichael.Christensen@Sun.COM rv = ENXIO; 4739916SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 4749916SMichael.Christensen@Sun.COM if (rv != 0) { 4757697SMichael.Christensen@Sun.COM if (rv == ECONNRESET) { 4767697SMichael.Christensen@Sun.COM break; 4777697SMichael.Christensen@Sun.COM } else if (rv != EAGAIN) { 4787697SMichael.Christensen@Sun.COM cmn_err(CE_NOTE, "ds@%lx: %s: %s" DS_EOL, 4797697SMichael.Christensen@Sun.COM PORTID(port), __func__, 4807697SMichael.Christensen@Sun.COM ds_errno_to_str(rv, ebuf)); 4817697SMichael.Christensen@Sun.COM break; 4827697SMichael.Christensen@Sun.COM } 4837697SMichael.Christensen@Sun.COM } else { 4847697SMichael.Christensen@Sun.COM if (nbytes != 0) { 4857697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: " 4867697SMichael.Christensen@Sun.COM "read %ld bytes, %d retries" DS_EOL, 4877697SMichael.Christensen@Sun.COM PORTID(port), nbytes, retry_count); 4887697SMichael.Christensen@Sun.COM 4897697SMichael.Christensen@Sun.COM *sizep += nbytes; 4907697SMichael.Christensen@Sun.COM msgp += nbytes; 4917697SMichael.Christensen@Sun.COM bytes_left -= nbytes; 4927697SMichael.Christensen@Sun.COM 4937697SMichael.Christensen@Sun.COM /* reset counter on a successful read */ 4947697SMichael.Christensen@Sun.COM retry_count = 0; 4957697SMichael.Christensen@Sun.COM continue; 4967697SMichael.Christensen@Sun.COM } 4977697SMichael.Christensen@Sun.COM 4987697SMichael.Christensen@Sun.COM /* 4997697SMichael.Christensen@Sun.COM * No data was read. Check if this is the 5007697SMichael.Christensen@Sun.COM * first attempt. If so, just return since 5017697SMichael.Christensen@Sun.COM * nothing has been read yet. 5027697SMichael.Christensen@Sun.COM */ 5037697SMichael.Christensen@Sun.COM if (bytes_left == bytes_req) { 5047697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: read zero bytes, " 5057697SMichael.Christensen@Sun.COM " no data available" DS_EOL, PORTID(port)); 5067697SMichael.Christensen@Sun.COM break; 5077697SMichael.Christensen@Sun.COM } 5087697SMichael.Christensen@Sun.COM } 5097697SMichael.Christensen@Sun.COM 5107697SMichael.Christensen@Sun.COM /* 5117697SMichael.Christensen@Sun.COM * A retry is necessary because the read returned 5127697SMichael.Christensen@Sun.COM * EAGAIN, or a zero length read occurred after 5137697SMichael.Christensen@Sun.COM * reading a partial message. 5147697SMichael.Christensen@Sun.COM */ 5157697SMichael.Christensen@Sun.COM if (retry_count++ >= ds_retries) { 5167697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: timed out waiting for " 5177697SMichael.Christensen@Sun.COM "message" DS_EOL, PORTID(port)); 5187697SMichael.Christensen@Sun.COM break; 5197697SMichael.Christensen@Sun.COM } 5207697SMichael.Christensen@Sun.COM 5217697SMichael.Christensen@Sun.COM drv_usecwait(ds_delay); 5227697SMichael.Christensen@Sun.COM } 5237697SMichael.Christensen@Sun.COM 5247697SMichael.Christensen@Sun.COM return (rv); 5257697SMichael.Christensen@Sun.COM } 5267697SMichael.Christensen@Sun.COM 5277697SMichael.Christensen@Sun.COM static void 5287697SMichael.Christensen@Sun.COM ds_handle_recv(void *arg) 5297697SMichael.Christensen@Sun.COM { 5307697SMichael.Christensen@Sun.COM ds_port_t *port = (ds_port_t *)arg; 5317697SMichael.Christensen@Sun.COM char *hbuf; 5327697SMichael.Christensen@Sun.COM size_t msglen; 5337697SMichael.Christensen@Sun.COM size_t read_size; 5347697SMichael.Christensen@Sun.COM boolean_t hasdata; 5357697SMichael.Christensen@Sun.COM ds_hdr_t hdr; 5367697SMichael.Christensen@Sun.COM uint8_t *msg; 5377697SMichael.Christensen@Sun.COM char *currp; 5387697SMichael.Christensen@Sun.COM int rv; 5397697SMichael.Christensen@Sun.COM ds_event_t *devent; 5407697SMichael.Christensen@Sun.COM 5417697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s..." DS_EOL, PORTID(port), __func__); 5427697SMichael.Christensen@Sun.COM 5437697SMichael.Christensen@Sun.COM /* 5447697SMichael.Christensen@Sun.COM * Read messages from the channel until there are none 5457697SMichael.Christensen@Sun.COM * pending. Valid messages are dispatched to be handled 5467697SMichael.Christensen@Sun.COM * by a separate thread while any malformed messages are 5477697SMichael.Christensen@Sun.COM * dropped. 5487697SMichael.Christensen@Sun.COM */ 5497697SMichael.Christensen@Sun.COM 5507697SMichael.Christensen@Sun.COM mutex_enter(&port->rcv_lock); 5517697SMichael.Christensen@Sun.COM 5529916SMichael.Christensen@Sun.COM for (;;) { 5539916SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 5549916SMichael.Christensen@Sun.COM if (port->ldc.state == LDC_UP) { 5559916SMichael.Christensen@Sun.COM rv = ldc_chkq(port->ldc.hdl, &hasdata); 5569916SMichael.Christensen@Sun.COM } else 5579916SMichael.Christensen@Sun.COM rv = ENXIO; 5589916SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 5599916SMichael.Christensen@Sun.COM if (rv != 0 || !hasdata) 5609916SMichael.Christensen@Sun.COM break; 5617697SMichael.Christensen@Sun.COM 5627697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "ds@%lx: %s: reading next message" DS_EOL, 5637697SMichael.Christensen@Sun.COM PORTID(port), __func__); 5647697SMichael.Christensen@Sun.COM 5657697SMichael.Christensen@Sun.COM /* 5667697SMichael.Christensen@Sun.COM * Read in the next message. 5677697SMichael.Christensen@Sun.COM */ 5687697SMichael.Christensen@Sun.COM hbuf = (char *)&hdr; 5697697SMichael.Christensen@Sun.COM bzero(hbuf, DS_HDR_SZ); 5707697SMichael.Christensen@Sun.COM read_size = DS_HDR_SZ; 5717697SMichael.Christensen@Sun.COM currp = hbuf; 5727697SMichael.Christensen@Sun.COM 5737697SMichael.Christensen@Sun.COM /* read in the message header */ 5747697SMichael.Christensen@Sun.COM if ((rv = ds_recv_msg(port, currp, &read_size)) != 0) { 5757697SMichael.Christensen@Sun.COM break; 5767697SMichael.Christensen@Sun.COM } 5777697SMichael.Christensen@Sun.COM 5787697SMichael.Christensen@Sun.COM if (read_size < DS_HDR_SZ) { 5797697SMichael.Christensen@Sun.COM /* 5807697SMichael.Christensen@Sun.COM * A zero length read is a valid signal that 5817697SMichael.Christensen@Sun.COM * there is no data left on the channel. 5827697SMichael.Christensen@Sun.COM */ 5837697SMichael.Christensen@Sun.COM if (read_size != 0) { 5847697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: invalid message " 5857697SMichael.Christensen@Sun.COM "length, received %ld bytes, expected %ld" 5867697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), read_size, DS_HDR_SZ); 5877697SMichael.Christensen@Sun.COM } 5887697SMichael.Christensen@Sun.COM continue; 5897697SMichael.Christensen@Sun.COM } 5907697SMichael.Christensen@Sun.COM 5917697SMichael.Christensen@Sun.COM /* get payload size and allocate a buffer */ 5927697SMichael.Christensen@Sun.COM read_size = ((ds_hdr_t *)hbuf)->payload_len; 5937697SMichael.Christensen@Sun.COM msglen = DS_HDR_SZ + read_size; 5947697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 5957697SMichael.Christensen@Sun.COM if (!msg) { 5967697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "Memory allocation failed attempting " 5977697SMichael.Christensen@Sun.COM " to allocate %d bytes." DS_EOL, (int)msglen); 5987697SMichael.Christensen@Sun.COM continue; 5997697SMichael.Christensen@Sun.COM } 6007697SMichael.Christensen@Sun.COM 6017697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "ds@%lx: %s: message payload len %d" DS_EOL, 6027697SMichael.Christensen@Sun.COM PORTID(port), __func__, (int)read_size); 6037697SMichael.Christensen@Sun.COM 6047697SMichael.Christensen@Sun.COM /* move message header into buffer */ 6057697SMichael.Christensen@Sun.COM (void) memcpy(msg, hbuf, DS_HDR_SZ); 6067697SMichael.Christensen@Sun.COM currp = (char *)(msg) + DS_HDR_SZ; 6077697SMichael.Christensen@Sun.COM 6087697SMichael.Christensen@Sun.COM /* read in the message body */ 6097697SMichael.Christensen@Sun.COM if ((rv = ds_recv_msg(port, currp, &read_size)) != 0) { 6107697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 6117697SMichael.Christensen@Sun.COM break; 6127697SMichael.Christensen@Sun.COM } 6137697SMichael.Christensen@Sun.COM 6147697SMichael.Christensen@Sun.COM /* validate the size of the message */ 6157697SMichael.Christensen@Sun.COM if ((DS_HDR_SZ + read_size) != msglen) { 6167697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: %s: invalid message length, " 6177697SMichael.Christensen@Sun.COM "received %ld bytes, expected %ld" DS_EOL, 6187697SMichael.Christensen@Sun.COM PORTID(port), __func__, (DS_HDR_SZ + read_size), 6197697SMichael.Christensen@Sun.COM msglen); 6207697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 6217697SMichael.Christensen@Sun.COM continue; 6227697SMichael.Christensen@Sun.COM } 6237697SMichael.Christensen@Sun.COM 6247697SMichael.Christensen@Sun.COM DS_DUMP_MSG(DS_DBG_FLAG_LDC, msg, msglen); 6257697SMichael.Christensen@Sun.COM 6267697SMichael.Christensen@Sun.COM /* 6277697SMichael.Christensen@Sun.COM * Send the message for processing, and store it 6287697SMichael.Christensen@Sun.COM * in the log. The memory is deallocated only when 6297697SMichael.Christensen@Sun.COM * the message is removed from the log. 6307697SMichael.Christensen@Sun.COM */ 6317697SMichael.Christensen@Sun.COM 6327697SMichael.Christensen@Sun.COM devent = DS_MALLOC(sizeof (ds_event_t)); 6337697SMichael.Christensen@Sun.COM devent->port = port; 6347697SMichael.Christensen@Sun.COM devent->buf = (char *)msg; 6357697SMichael.Christensen@Sun.COM devent->buflen = msglen; 6367697SMichael.Christensen@Sun.COM 6377697SMichael.Christensen@Sun.COM /* log the message */ 6387697SMichael.Christensen@Sun.COM (void) ds_log_add_msg(DS_LOG_IN(port->id), msg, msglen); 6397697SMichael.Christensen@Sun.COM 6407697SMichael.Christensen@Sun.COM if (ds_sys_dispatch_func(ds_dispatch_event, devent)) { 6417697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: error initiating " 6427697SMichael.Christensen@Sun.COM "event handler", PORTID(port)); 6437697SMichael.Christensen@Sun.COM DS_FREE(devent, sizeof (ds_event_t)); 6447697SMichael.Christensen@Sun.COM } 6457697SMichael.Christensen@Sun.COM } 6467697SMichael.Christensen@Sun.COM 6477697SMichael.Christensen@Sun.COM mutex_exit(&port->rcv_lock); 6487697SMichael.Christensen@Sun.COM 6497697SMichael.Christensen@Sun.COM /* handle connection reset errors returned from ds_recv_msg */ 6507697SMichael.Christensen@Sun.COM if (rv == ECONNRESET) { 6517697SMichael.Christensen@Sun.COM ds_handle_down_reset_events(port); 6527697SMichael.Christensen@Sun.COM } 6537697SMichael.Christensen@Sun.COM 6547697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s done" DS_EOL, PORTID(port), __func__); 6557697SMichael.Christensen@Sun.COM } 6567697SMichael.Christensen@Sun.COM 6577697SMichael.Christensen@Sun.COM static void 6587697SMichael.Christensen@Sun.COM ds_dispatch_event(void *arg) 6597697SMichael.Christensen@Sun.COM { 6607697SMichael.Christensen@Sun.COM ds_event_t *event = (ds_event_t *)arg; 6617697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 6627697SMichael.Christensen@Sun.COM ds_port_t *port; 6637697SMichael.Christensen@Sun.COM 6647697SMichael.Christensen@Sun.COM port = event->port; 6657697SMichael.Christensen@Sun.COM 6667697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)event->buf; 6677697SMichael.Christensen@Sun.COM 6687697SMichael.Christensen@Sun.COM if (DS_MSG_TYPE_VALID(hdr->msg_type)) { 6697697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "ds@%lx: dispatch_event: msg_type=%d" DS_EOL, 6707697SMichael.Christensen@Sun.COM PORTID(port), hdr->msg_type); 6717697SMichael.Christensen@Sun.COM 6727697SMichael.Christensen@Sun.COM (*ds_msg_handlers[hdr->msg_type])(port, event->buf, 6737697SMichael.Christensen@Sun.COM event->buflen); 6747697SMichael.Christensen@Sun.COM } else { 6757697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: dispatch_event: invalid msg " 6767697SMichael.Christensen@Sun.COM "type (%d)" DS_EOL, PORTID(port), hdr->msg_type); 6777697SMichael.Christensen@Sun.COM } 6787697SMichael.Christensen@Sun.COM 6797697SMichael.Christensen@Sun.COM DS_FREE(event->buf, event->buflen); 6807697SMichael.Christensen@Sun.COM DS_FREE(event, sizeof (ds_event_t)); 6817697SMichael.Christensen@Sun.COM } 6827697SMichael.Christensen@Sun.COM 6837697SMichael.Christensen@Sun.COM int 6847697SMichael.Christensen@Sun.COM ds_send_msg(ds_port_t *port, caddr_t msg, size_t msglen) 6857697SMichael.Christensen@Sun.COM { 6867697SMichael.Christensen@Sun.COM int rv; 6877697SMichael.Christensen@Sun.COM caddr_t currp = msg; 6887697SMichael.Christensen@Sun.COM size_t amt_left = msglen; 6897697SMichael.Christensen@Sun.COM int loopcnt = 0; 6907697SMichael.Christensen@Sun.COM 6917697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%lx: %s msglen: %ld" DS_EOL, PORTID(port), 6927697SMichael.Christensen@Sun.COM __func__, msglen); 6937697SMichael.Christensen@Sun.COM DS_DUMP_MSG(DS_DBG_FLAG_LDC, msg, msglen); 6947697SMichael.Christensen@Sun.COM 695*10042SMichael.Christensen@Sun.COM (void) ds_log_add_msg(DS_LOG_OUT(port->id), (uint8_t *)msg, msglen); 696*10042SMichael.Christensen@Sun.COM 6977697SMichael.Christensen@Sun.COM /* 6987697SMichael.Christensen@Sun.COM * Ensure that no other messages can be sent on this port by holding 6997697SMichael.Christensen@Sun.COM * the tx_lock mutex in case the write doesn't get sent with one write. 7007697SMichael.Christensen@Sun.COM * This guarantees that the message doesn't become fragmented. 7017697SMichael.Christensen@Sun.COM */ 7027697SMichael.Christensen@Sun.COM mutex_enter(&port->tx_lock); 7037697SMichael.Christensen@Sun.COM 7047697SMichael.Christensen@Sun.COM do { 7059916SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 7069916SMichael.Christensen@Sun.COM if (port->ldc.state == LDC_UP) { 7079916SMichael.Christensen@Sun.COM rv = ldc_write(port->ldc.hdl, currp, &msglen); 7089916SMichael.Christensen@Sun.COM } else 7099916SMichael.Christensen@Sun.COM rv = ENXIO; 7109916SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 7119916SMichael.Christensen@Sun.COM if (rv != 0) { 7127697SMichael.Christensen@Sun.COM if (rv == ECONNRESET) { 7137697SMichael.Christensen@Sun.COM mutex_exit(&port->tx_lock); 7147697SMichael.Christensen@Sun.COM ds_handle_down_reset_events(port); 7157697SMichael.Christensen@Sun.COM return (rv); 7167697SMichael.Christensen@Sun.COM } else if ((rv == EWOULDBLOCK) && 7177697SMichael.Christensen@Sun.COM (loopcnt++ < ds_retries)) { 7187697SMichael.Christensen@Sun.COM drv_usecwait(ds_delay); 7197697SMichael.Christensen@Sun.COM } else { 720*10042SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: send_msg: " 721*10042SMichael.Christensen@Sun.COM "ldc_write failed (%d), %d bytes " 722*10042SMichael.Christensen@Sun.COM "remaining" DS_EOL, PORTID(port), rv, 723*10042SMichael.Christensen@Sun.COM (int)amt_left); 7247697SMichael.Christensen@Sun.COM goto error; 7257697SMichael.Christensen@Sun.COM } 7267697SMichael.Christensen@Sun.COM } else { 7277697SMichael.Christensen@Sun.COM amt_left -= msglen; 7287697SMichael.Christensen@Sun.COM currp += msglen; 7297697SMichael.Christensen@Sun.COM msglen = amt_left; 7307697SMichael.Christensen@Sun.COM loopcnt = 0; 7317697SMichael.Christensen@Sun.COM } 7327697SMichael.Christensen@Sun.COM } while (amt_left > 0); 7337697SMichael.Christensen@Sun.COM error: 7347697SMichael.Christensen@Sun.COM mutex_exit(&port->tx_lock); 7357697SMichael.Christensen@Sun.COM 7367697SMichael.Christensen@Sun.COM return (rv); 7377697SMichael.Christensen@Sun.COM } 7387697SMichael.Christensen@Sun.COM 7397697SMichael.Christensen@Sun.COM /* END LDC SUPPORT FUNCTIONS */ 7407697SMichael.Christensen@Sun.COM 7417697SMichael.Christensen@Sun.COM 7427697SMichael.Christensen@Sun.COM /* BEGIN DS PROTOCOL SUPPORT FUNCTIONS */ 7437697SMichael.Christensen@Sun.COM 7447697SMichael.Christensen@Sun.COM static void 7457697SMichael.Christensen@Sun.COM ds_handle_init_req(ds_port_t *port, caddr_t buf, size_t len) 7467697SMichael.Christensen@Sun.COM { 7477697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 7487697SMichael.Christensen@Sun.COM ds_init_ack_t *ack; 7497697SMichael.Christensen@Sun.COM ds_init_nack_t *nack; 7507697SMichael.Christensen@Sun.COM char *msg; 7517697SMichael.Christensen@Sun.COM size_t msglen; 7527697SMichael.Christensen@Sun.COM ds_init_req_t *req; 7537697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_init_req_t); 7547697SMichael.Christensen@Sun.COM uint16_t new_major; 7557697SMichael.Christensen@Sun.COM uint16_t new_minor; 7567697SMichael.Christensen@Sun.COM boolean_t match; 7577697SMichael.Christensen@Sun.COM 7587697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 7597697SMichael.Christensen@Sun.COM if (len != explen) { 7607697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <init_req: invalid message " 7617697SMichael.Christensen@Sun.COM "length (%ld), expected %ld" DS_EOL, PORTID(port), len, 7627697SMichael.Christensen@Sun.COM explen); 7637697SMichael.Christensen@Sun.COM return; 7647697SMichael.Christensen@Sun.COM } 7657697SMichael.Christensen@Sun.COM 7667697SMichael.Christensen@Sun.COM req = (ds_init_req_t *)(buf + DS_HDR_SZ); 7677697SMichael.Christensen@Sun.COM 7687697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <init_req: ver=%d.%d" DS_EOL, 7697697SMichael.Christensen@Sun.COM PORTID(port), req->major_vers, req->minor_vers); 7707697SMichael.Christensen@Sun.COM 7717697SMichael.Christensen@Sun.COM match = negotiate_version(DS_NUM_VER, &ds_vers[0], 7727697SMichael.Christensen@Sun.COM req->major_vers, &new_major, &new_minor); 7737697SMichael.Christensen@Sun.COM 7747697SMichael.Christensen@Sun.COM /* 7757697SMichael.Christensen@Sun.COM * Check version info. ACK only if the major numbers exactly 7767697SMichael.Christensen@Sun.COM * match. The service entity can retry with a new minor 7777697SMichael.Christensen@Sun.COM * based on the response sent as part of the NACK. 7787697SMichael.Christensen@Sun.COM */ 7797697SMichael.Christensen@Sun.COM if (match) { 7807697SMichael.Christensen@Sun.COM msglen = DS_MSG_LEN(ds_init_ack_t); 7817697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 7827697SMichael.Christensen@Sun.COM 7837697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 7847697SMichael.Christensen@Sun.COM hdr->msg_type = DS_INIT_ACK; 7857697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_init_ack_t); 7867697SMichael.Christensen@Sun.COM 7877697SMichael.Christensen@Sun.COM ack = (ds_init_ack_t *)(msg + DS_HDR_SZ); 7887697SMichael.Christensen@Sun.COM ack->minor_vers = MIN(new_minor, req->minor_vers); 7897697SMichael.Christensen@Sun.COM 7907697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: init_ack>: minor=0x%04X" DS_EOL, 7917697SMichael.Christensen@Sun.COM PORTID(port), MIN(new_minor, req->minor_vers)); 7927697SMichael.Christensen@Sun.COM } else { 7937697SMichael.Christensen@Sun.COM msglen = DS_MSG_LEN(ds_init_nack_t); 7947697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 7957697SMichael.Christensen@Sun.COM 7967697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 7977697SMichael.Christensen@Sun.COM hdr->msg_type = DS_INIT_NACK; 7987697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_init_nack_t); 7997697SMichael.Christensen@Sun.COM 8007697SMichael.Christensen@Sun.COM nack = (ds_init_nack_t *)(msg + DS_HDR_SZ); 8017697SMichael.Christensen@Sun.COM nack->major_vers = new_major; 8027697SMichael.Christensen@Sun.COM 8037697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: init_nack>: major=0x%04X" DS_EOL, 8047697SMichael.Christensen@Sun.COM PORTID(port), new_major); 8057697SMichael.Christensen@Sun.COM } 8067697SMichael.Christensen@Sun.COM 8077697SMichael.Christensen@Sun.COM /* 8087697SMichael.Christensen@Sun.COM * Send the response 8097697SMichael.Christensen@Sun.COM */ 8107697SMichael.Christensen@Sun.COM (void) ds_send_msg(port, msg, msglen); 8117697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 812*10042SMichael.Christensen@Sun.COM 813*10042SMichael.Christensen@Sun.COM if (match) { 814*10042SMichael.Christensen@Sun.COM ds_set_port_ready(port, req->major_vers, ack->minor_vers); 815*10042SMichael.Christensen@Sun.COM } 8167697SMichael.Christensen@Sun.COM } 8177697SMichael.Christensen@Sun.COM 8187697SMichael.Christensen@Sun.COM static void 8197697SMichael.Christensen@Sun.COM ds_handle_init_ack(ds_port_t *port, caddr_t buf, size_t len) 8207697SMichael.Christensen@Sun.COM { 8217697SMichael.Christensen@Sun.COM ds_init_ack_t *ack; 8227697SMichael.Christensen@Sun.COM ds_ver_t *ver; 823*10042SMichael.Christensen@Sun.COM uint16_t major; 824*10042SMichael.Christensen@Sun.COM uint16_t minor; 8257697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_init_ack_t); 8267697SMichael.Christensen@Sun.COM 8277697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 8287697SMichael.Christensen@Sun.COM if (len != explen) { 8297697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <init_ack: invalid message " 8307697SMichael.Christensen@Sun.COM "length (%ld), expected %ld" DS_EOL, PORTID(port), len, 8317697SMichael.Christensen@Sun.COM explen); 8327697SMichael.Christensen@Sun.COM return; 8337697SMichael.Christensen@Sun.COM } 8347697SMichael.Christensen@Sun.COM 8357697SMichael.Christensen@Sun.COM ack = (ds_init_ack_t *)(buf + DS_HDR_SZ); 8367697SMichael.Christensen@Sun.COM 8377697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 8387697SMichael.Christensen@Sun.COM 839*10042SMichael.Christensen@Sun.COM if (port->state == DS_PORT_READY) { 840*10042SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <init_ack: port ready" DS_EOL, 841*10042SMichael.Christensen@Sun.COM PORTID(port)); 842*10042SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 843*10042SMichael.Christensen@Sun.COM return; 844*10042SMichael.Christensen@Sun.COM } 845*10042SMichael.Christensen@Sun.COM 8467697SMichael.Christensen@Sun.COM if (port->state != DS_PORT_INIT_REQ) { 8477697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <init_ack: invalid state: %d" 8487697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), port->state); 8497697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 8507697SMichael.Christensen@Sun.COM return; 8517697SMichael.Christensen@Sun.COM } 8527697SMichael.Christensen@Sun.COM 8537697SMichael.Christensen@Sun.COM ver = &(ds_vers[port->ver_idx]); 854*10042SMichael.Christensen@Sun.COM major = ver->major; 855*10042SMichael.Christensen@Sun.COM minor = MIN(ver->minor, ack->minor_vers); 856*10042SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 8577697SMichael.Christensen@Sun.COM 8587697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <init_ack: port ready v%d.%d" DS_EOL, 859*10042SMichael.Christensen@Sun.COM PORTID(port), major, minor); 860*10042SMichael.Christensen@Sun.COM 861*10042SMichael.Christensen@Sun.COM ds_set_port_ready(port, major, minor); 8627697SMichael.Christensen@Sun.COM } 8637697SMichael.Christensen@Sun.COM 8647697SMichael.Christensen@Sun.COM static void 8657697SMichael.Christensen@Sun.COM ds_handle_init_nack(ds_port_t *port, caddr_t buf, size_t len) 8667697SMichael.Christensen@Sun.COM { 8677697SMichael.Christensen@Sun.COM int idx; 8687697SMichael.Christensen@Sun.COM ds_init_nack_t *nack; 8697697SMichael.Christensen@Sun.COM ds_ver_t *ver; 8707697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_init_nack_t); 8717697SMichael.Christensen@Sun.COM 8727697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 8737697SMichael.Christensen@Sun.COM if (len != explen) { 8747697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_WARN, "ds@%lx: <init_nack: invalid message " 8757697SMichael.Christensen@Sun.COM "length (%ld), expected %ld" DS_EOL, PORTID(port), len, 8767697SMichael.Christensen@Sun.COM explen); 8777697SMichael.Christensen@Sun.COM return; 8787697SMichael.Christensen@Sun.COM } 8797697SMichael.Christensen@Sun.COM 8807697SMichael.Christensen@Sun.COM nack = (ds_init_nack_t *)(buf + DS_HDR_SZ); 8817697SMichael.Christensen@Sun.COM 8827697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 8837697SMichael.Christensen@Sun.COM 8847697SMichael.Christensen@Sun.COM if (port->state != DS_PORT_INIT_REQ) { 8857697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <init_nack: invalid state: %d" 8867697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), port->state); 8877697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 8887697SMichael.Christensen@Sun.COM return; 8897697SMichael.Christensen@Sun.COM } 8907697SMichael.Christensen@Sun.COM 8917697SMichael.Christensen@Sun.COM ver = &(ds_vers[port->ver_idx]); 8927697SMichael.Christensen@Sun.COM 8937697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <init_nack: req=v%d.%d, nack=v%d.x" 8947697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), ver->major, ver->minor, nack->major_vers); 8957697SMichael.Christensen@Sun.COM 8967697SMichael.Christensen@Sun.COM if (nack->major_vers == 0) { 8977697SMichael.Christensen@Sun.COM /* no supported protocol version */ 8987697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_WARN, "ds@%lx: <init_nack: DS not supported" 8997697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port)); 9007697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 9017697SMichael.Christensen@Sun.COM return; 9027697SMichael.Christensen@Sun.COM } 9037697SMichael.Christensen@Sun.COM 9047697SMichael.Christensen@Sun.COM /* 9057697SMichael.Christensen@Sun.COM * Walk the version list, looking for a major version 9067697SMichael.Christensen@Sun.COM * that is as close to the requested major version as 9077697SMichael.Christensen@Sun.COM * possible. 9087697SMichael.Christensen@Sun.COM */ 9097697SMichael.Christensen@Sun.COM for (idx = port->ver_idx; idx < DS_NUM_VER; idx++) { 9107697SMichael.Christensen@Sun.COM if (ds_vers[idx].major <= nack->major_vers) { 9117697SMichael.Christensen@Sun.COM /* found a version to try */ 9127697SMichael.Christensen@Sun.COM goto done; 9137697SMichael.Christensen@Sun.COM } 9147697SMichael.Christensen@Sun.COM } 9157697SMichael.Christensen@Sun.COM 9167697SMichael.Christensen@Sun.COM if (idx == DS_NUM_VER) { 9177697SMichael.Christensen@Sun.COM /* no supported version */ 9187697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_WARN, "ds@%lx: <init_nack: DS v%d.x not " 9197697SMichael.Christensen@Sun.COM "supported" DS_EOL, PORTID(port), nack->major_vers); 9207697SMichael.Christensen@Sun.COM 9217697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 9227697SMichael.Christensen@Sun.COM return; 9237697SMichael.Christensen@Sun.COM } 9247697SMichael.Christensen@Sun.COM 9257697SMichael.Christensen@Sun.COM done: 9267697SMichael.Christensen@Sun.COM /* start the handshake again */ 9277697SMichael.Christensen@Sun.COM port->ver_idx = idx; 9287697SMichael.Christensen@Sun.COM port->state = DS_PORT_LDC_INIT; 9297697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 9307697SMichael.Christensen@Sun.COM 9317697SMichael.Christensen@Sun.COM ds_send_init_req(port); 9327697SMichael.Christensen@Sun.COM 9337697SMichael.Christensen@Sun.COM } 9347697SMichael.Christensen@Sun.COM 9357697SMichael.Christensen@Sun.COM static ds_svc_t * 9367697SMichael.Christensen@Sun.COM ds_find_svc_by_id_port(char *svc_id, int is_client, ds_port_t *port) 9377697SMichael.Christensen@Sun.COM { 9387697SMichael.Christensen@Sun.COM int idx; 9397697SMichael.Christensen@Sun.COM ds_svc_t *svc, *found_svc = 0; 9407697SMichael.Christensen@Sun.COM uint32_t flag_match = is_client ? DSSF_ISCLIENT : 0; 9417697SMichael.Christensen@Sun.COM 9427697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 9437697SMichael.Christensen@Sun.COM 9447697SMichael.Christensen@Sun.COM /* walk every table entry */ 9457697SMichael.Christensen@Sun.COM for (idx = 0; idx < ds_svcs.maxsvcs; idx++) { 9467697SMichael.Christensen@Sun.COM svc = ds_svcs.tbl[idx]; 9477697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) 9487697SMichael.Christensen@Sun.COM continue; 9497697SMichael.Christensen@Sun.COM if (strcmp(svc->cap.svc_id, svc_id) != 0) 9507697SMichael.Christensen@Sun.COM continue; 9517697SMichael.Christensen@Sun.COM if ((svc->flags & DSSF_ISCLIENT) != flag_match) 9527697SMichael.Christensen@Sun.COM continue; 9537697SMichael.Christensen@Sun.COM if (port != NULL && svc->port == port) { 9547697SMichael.Christensen@Sun.COM return (svc); 9557697SMichael.Christensen@Sun.COM } else if (svc->state == DS_SVC_INACTIVE) { 9567697SMichael.Christensen@Sun.COM found_svc = svc; 9577697SMichael.Christensen@Sun.COM } else if (!found_svc) { 9587697SMichael.Christensen@Sun.COM found_svc = svc; 9597697SMichael.Christensen@Sun.COM } 9607697SMichael.Christensen@Sun.COM } 9617697SMichael.Christensen@Sun.COM 9627697SMichael.Christensen@Sun.COM return (found_svc); 9637697SMichael.Christensen@Sun.COM } 9647697SMichael.Christensen@Sun.COM 9657697SMichael.Christensen@Sun.COM static void 9667697SMichael.Christensen@Sun.COM ds_handle_reg_req(ds_port_t *port, caddr_t buf, size_t len) 9677697SMichael.Christensen@Sun.COM { 9687697SMichael.Christensen@Sun.COM ds_reg_req_t *req; 9697697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 9707697SMichael.Christensen@Sun.COM ds_reg_ack_t *ack; 9717697SMichael.Christensen@Sun.COM ds_reg_nack_t *nack; 9727697SMichael.Christensen@Sun.COM char *msg; 9737697SMichael.Christensen@Sun.COM size_t msglen; 9747697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_reg_req_t); 9757697SMichael.Christensen@Sun.COM ds_svc_t *svc = NULL; 9767697SMichael.Christensen@Sun.COM ds_ver_t version; 9777697SMichael.Christensen@Sun.COM uint16_t new_major; 9787697SMichael.Christensen@Sun.COM uint16_t new_minor; 9797697SMichael.Christensen@Sun.COM boolean_t match; 9807697SMichael.Christensen@Sun.COM 9817697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 9827697SMichael.Christensen@Sun.COM if (len < explen) { 9837697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <reg_req: invalid message " 9847697SMichael.Christensen@Sun.COM "length (%ld), expected at least %ld" DS_EOL, 9857697SMichael.Christensen@Sun.COM PORTID(port), len, explen); 9867697SMichael.Christensen@Sun.COM return; 9877697SMichael.Christensen@Sun.COM } 9887697SMichael.Christensen@Sun.COM 9897697SMichael.Christensen@Sun.COM req = (ds_reg_req_t *)(buf + DS_HDR_SZ); 9907697SMichael.Christensen@Sun.COM 9917697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_req: '%s' ver=%d.%d, hdl=0x%llx" 9927697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), req->svc_id, req->major_vers, req->minor_vers, 9937697SMichael.Christensen@Sun.COM (u_longlong_t)req->svc_handle); 9947697SMichael.Christensen@Sun.COM 9957697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 9967697SMichael.Christensen@Sun.COM svc = ds_find_svc_by_id_port(req->svc_id, 9977697SMichael.Christensen@Sun.COM DS_HDL_ISCLIENT(req->svc_handle) == 0, port); 9987697SMichael.Christensen@Sun.COM if (svc == NULL) { 9997697SMichael.Christensen@Sun.COM 10007697SMichael.Christensen@Sun.COM do_reg_nack: 10017697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 10027697SMichael.Christensen@Sun.COM 10037697SMichael.Christensen@Sun.COM msglen = DS_MSG_LEN(ds_reg_nack_t); 10047697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 10057697SMichael.Christensen@Sun.COM 10067697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 10077697SMichael.Christensen@Sun.COM hdr->msg_type = DS_REG_NACK; 10087697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_reg_nack_t); 10097697SMichael.Christensen@Sun.COM 10107697SMichael.Christensen@Sun.COM nack = (ds_reg_nack_t *)(msg + DS_HDR_SZ); 10117697SMichael.Christensen@Sun.COM nack->svc_handle = req->svc_handle; 10127697SMichael.Christensen@Sun.COM nack->result = DS_REG_VER_NACK; 10137697SMichael.Christensen@Sun.COM nack->major_vers = 0; 10147697SMichael.Christensen@Sun.COM 10157697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: reg_nack>: '%s'" DS_EOL, 10167697SMichael.Christensen@Sun.COM PORTID(port), req->svc_id); 10177697SMichael.Christensen@Sun.COM /* 10187697SMichael.Christensen@Sun.COM * Send the response 10197697SMichael.Christensen@Sun.COM */ 10207697SMichael.Christensen@Sun.COM (void) ds_send_msg(port, msg, msglen); 10217697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 10227697SMichael.Christensen@Sun.COM return; 10237697SMichael.Christensen@Sun.COM } 10247697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_req: '%s' found, hdl: 0x%llx" DS_EOL, 10257697SMichael.Christensen@Sun.COM PORTID(port), req->svc_id, (u_longlong_t)svc->hdl); 10267697SMichael.Christensen@Sun.COM 10277697SMichael.Christensen@Sun.COM /* 10287697SMichael.Christensen@Sun.COM * A client sends out a reg req in order to force service providers to 10298172SMichael.Christensen@Sun.COM * initiate a reg req from their end (limitation in the protocol). We 10308172SMichael.Christensen@Sun.COM * expect the service provider to be in the inactive (DS_SVC_INACTIVE) 10318172SMichael.Christensen@Sun.COM * state. If the service provider has already sent out a reg req (the 10328172SMichael.Christensen@Sun.COM * state is DS_SVC_REG_PENDING) or has already handshaken (the 10338172SMichael.Christensen@Sun.COM * state is DS_SVC_ACTIVE), then we can simply ignore this reg 10348172SMichael.Christensen@Sun.COM * req. For any other state, we force an unregister before initiating 10358172SMichael.Christensen@Sun.COM * a reg req. 10367697SMichael.Christensen@Sun.COM */ 10377697SMichael.Christensen@Sun.COM 10387697SMichael.Christensen@Sun.COM if (DS_HDL_ISCLIENT(req->svc_handle)) { 10398172SMichael.Christensen@Sun.COM switch (svc->state) { 10408172SMichael.Christensen@Sun.COM 10418172SMichael.Christensen@Sun.COM case DS_SVC_REG_PENDING: 10428172SMichael.Christensen@Sun.COM case DS_SVC_ACTIVE: 10438172SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_req: '%s' pinging " 10448172SMichael.Christensen@Sun.COM "client, state (%x)" DS_EOL, PORTID(port), 10458172SMichael.Christensen@Sun.COM req->svc_id, svc->state); 10468172SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 10478172SMichael.Christensen@Sun.COM return; 10488172SMichael.Christensen@Sun.COM 10498172SMichael.Christensen@Sun.COM case DS_SVC_INACTIVE: 10508172SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_req: '%s' pinging " 10518172SMichael.Christensen@Sun.COM "client" DS_EOL, PORTID(port), req->svc_id); 10528172SMichael.Christensen@Sun.COM break; 10538172SMichael.Christensen@Sun.COM 10548172SMichael.Christensen@Sun.COM default: 10558172SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_req: '%s' pinging " 10568172SMichael.Christensen@Sun.COM "client forced unreg, state (%x)" DS_EOL, 10578172SMichael.Christensen@Sun.COM PORTID(port), req->svc_id, svc->state); 10587697SMichael.Christensen@Sun.COM (void) ds_svc_unregister(svc, port); 10598172SMichael.Christensen@Sun.COM break; 10607697SMichael.Christensen@Sun.COM } 10617697SMichael.Christensen@Sun.COM (void) ds_svc_port_up(svc, port); 10627697SMichael.Christensen@Sun.COM (void) ds_svc_register_onport(svc, port); 10637697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 10647697SMichael.Christensen@Sun.COM return; 10657697SMichael.Christensen@Sun.COM } 10667697SMichael.Christensen@Sun.COM 10677697SMichael.Christensen@Sun.COM /* 10687697SMichael.Christensen@Sun.COM * Only remote service providers can initiate a registration. The 10697697SMichael.Christensen@Sun.COM * local sevice from here must be a client service. 10707697SMichael.Christensen@Sun.COM */ 10717697SMichael.Christensen@Sun.COM 10727697SMichael.Christensen@Sun.COM match = negotiate_version(svc->cap.nvers, svc->cap.vers, 10737697SMichael.Christensen@Sun.COM req->major_vers, &new_major, &new_minor); 10747697SMichael.Christensen@Sun.COM 10757697SMichael.Christensen@Sun.COM /* 10767697SMichael.Christensen@Sun.COM * Check version info. ACK only if the major numbers exactly 10777697SMichael.Christensen@Sun.COM * match. The service entity can retry with a new minor 10787697SMichael.Christensen@Sun.COM * based on the response sent as part of the NACK. 10797697SMichael.Christensen@Sun.COM */ 10807697SMichael.Christensen@Sun.COM if (match) { 10817697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_req: '%s' svc%d: state: %x " 10827697SMichael.Christensen@Sun.COM "svc_portid: %d" DS_EOL, PORTID(port), req->svc_id, 10837697SMichael.Christensen@Sun.COM (int)DS_HDL2IDX(svc->hdl), svc->state, 10847697SMichael.Christensen@Sun.COM (int)(svc->port == NULL ? -1 : PORTID(svc->port))); 10857697SMichael.Christensen@Sun.COM /* 10867697SMichael.Christensen@Sun.COM * If the current local service is already in use and 10877697SMichael.Christensen@Sun.COM * it's not on this port, clone it. 10887697SMichael.Christensen@Sun.COM */ 10897697SMichael.Christensen@Sun.COM if (svc->state != DS_SVC_INACTIVE) { 10907697SMichael.Christensen@Sun.COM if (svc->port != NULL && port == svc->port) { 10917697SMichael.Christensen@Sun.COM /* 10927697SMichael.Christensen@Sun.COM * Someone probably dropped an unreg req 10937697SMichael.Christensen@Sun.COM * somewhere. Force a local unreg. 10947697SMichael.Christensen@Sun.COM */ 10957697SMichael.Christensen@Sun.COM (void) ds_svc_unregister(svc, port); 10967697SMichael.Christensen@Sun.COM } else if (!DS_HDL_ISCLIENT(svc->hdl)) { 10977697SMichael.Christensen@Sun.COM /* 10987697SMichael.Christensen@Sun.COM * Can't clone a non-client (service provider) 10997697SMichael.Christensen@Sun.COM * handle. This is because old in-kernel 11007697SMichael.Christensen@Sun.COM * service providers can't deal with multiple 11017697SMichael.Christensen@Sun.COM * handles. 11027697SMichael.Christensen@Sun.COM */ 11037697SMichael.Christensen@Sun.COM goto do_reg_nack; 11047697SMichael.Christensen@Sun.COM } else { 11057697SMichael.Christensen@Sun.COM svc = ds_svc_clone(svc); 11067697SMichael.Christensen@Sun.COM } 11077697SMichael.Christensen@Sun.COM } 11087697SMichael.Christensen@Sun.COM svc->port = port; 11097697SMichael.Christensen@Sun.COM svc->svc_hdl = req->svc_handle; 11107697SMichael.Christensen@Sun.COM svc->state = DS_SVC_ACTIVE; 11117697SMichael.Christensen@Sun.COM 11127697SMichael.Christensen@Sun.COM msglen = DS_MSG_LEN(ds_reg_ack_t); 11137697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 11147697SMichael.Christensen@Sun.COM 11157697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 11167697SMichael.Christensen@Sun.COM hdr->msg_type = DS_REG_ACK; 11177697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_reg_ack_t); 11187697SMichael.Christensen@Sun.COM 11197697SMichael.Christensen@Sun.COM ack = (ds_reg_ack_t *)(msg + DS_HDR_SZ); 11207697SMichael.Christensen@Sun.COM ack->svc_handle = req->svc_handle; 11217697SMichael.Christensen@Sun.COM ack->minor_vers = MIN(new_minor, req->minor_vers); 11227697SMichael.Christensen@Sun.COM 11237697SMichael.Christensen@Sun.COM 11247697SMichael.Christensen@Sun.COM if (svc->ops.ds_reg_cb) { 11257697SMichael.Christensen@Sun.COM /* Call the registration callback */ 11267697SMichael.Christensen@Sun.COM version.major = req->major_vers; 11277697SMichael.Christensen@Sun.COM version.minor = ack->minor_vers; 11287697SMichael.Christensen@Sun.COM (*svc->ops.ds_reg_cb)(svc->ops.cb_arg, &version, 11297697SMichael.Christensen@Sun.COM svc->hdl); 11307697SMichael.Christensen@Sun.COM } 11317697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 11327697SMichael.Christensen@Sun.COM 11337697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: reg_ack>: '%s' minor=0x%04X" 11347697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), svc->cap.svc_id, 11357697SMichael.Christensen@Sun.COM MIN(new_minor, req->minor_vers)); 11367697SMichael.Christensen@Sun.COM } else { 11377697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 11387697SMichael.Christensen@Sun.COM 11397697SMichael.Christensen@Sun.COM msglen = DS_MSG_LEN(ds_reg_nack_t); 11407697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 11417697SMichael.Christensen@Sun.COM 11427697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 11437697SMichael.Christensen@Sun.COM hdr->msg_type = DS_REG_NACK; 11447697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_reg_nack_t); 11457697SMichael.Christensen@Sun.COM 11467697SMichael.Christensen@Sun.COM nack = (ds_reg_nack_t *)(msg + DS_HDR_SZ); 11477697SMichael.Christensen@Sun.COM nack->svc_handle = req->svc_handle; 11487697SMichael.Christensen@Sun.COM nack->result = DS_REG_VER_NACK; 11497697SMichael.Christensen@Sun.COM nack->major_vers = new_major; 11507697SMichael.Christensen@Sun.COM 11517697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: reg_nack>: '%s' major=0x%04X" 11527697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), svc->cap.svc_id, new_major); 11537697SMichael.Christensen@Sun.COM } 11547697SMichael.Christensen@Sun.COM 11557697SMichael.Christensen@Sun.COM /* send message */ 11567697SMichael.Christensen@Sun.COM (void) ds_send_msg(port, msg, msglen); 11577697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 11587697SMichael.Christensen@Sun.COM } 11597697SMichael.Christensen@Sun.COM 11607697SMichael.Christensen@Sun.COM static void 11617697SMichael.Christensen@Sun.COM ds_handle_reg_ack(ds_port_t *port, caddr_t buf, size_t len) 11627697SMichael.Christensen@Sun.COM { 11637697SMichael.Christensen@Sun.COM ds_reg_ack_t *ack; 11647697SMichael.Christensen@Sun.COM ds_ver_t *ver; 11657697SMichael.Christensen@Sun.COM ds_ver_t tmpver; 11667697SMichael.Christensen@Sun.COM ds_svc_t *svc; 11677697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_reg_ack_t); 11687697SMichael.Christensen@Sun.COM 11697697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 11707697SMichael.Christensen@Sun.COM if (len != explen) { 11717697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <reg_ack: invalid message " 11727697SMichael.Christensen@Sun.COM "length (%ld), expected %ld" DS_EOL, PORTID(port), len, 11737697SMichael.Christensen@Sun.COM explen); 11747697SMichael.Christensen@Sun.COM return; 11757697SMichael.Christensen@Sun.COM } 11767697SMichael.Christensen@Sun.COM 11777697SMichael.Christensen@Sun.COM ack = (ds_reg_ack_t *)(buf + DS_HDR_SZ); 11787697SMichael.Christensen@Sun.COM 11797697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 11807697SMichael.Christensen@Sun.COM 11817697SMichael.Christensen@Sun.COM /* 11827697SMichael.Christensen@Sun.COM * This searches for service based on how we generate handles 11837697SMichael.Christensen@Sun.COM * and so only works because this is a reg ack. 11847697SMichael.Christensen@Sun.COM */ 11857697SMichael.Christensen@Sun.COM if (DS_HDL_ISCLIENT(ack->svc_handle) || 11867697SMichael.Christensen@Sun.COM (svc = ds_get_svc(ack->svc_handle)) == NULL) { 11877697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <reg_ack: invalid handle 0x%llx" 11887697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), (u_longlong_t)ack->svc_handle); 11897697SMichael.Christensen@Sun.COM goto done; 11907697SMichael.Christensen@Sun.COM } 11917697SMichael.Christensen@Sun.COM 11927697SMichael.Christensen@Sun.COM /* make sure the message makes sense */ 11937697SMichael.Christensen@Sun.COM if (svc->state != DS_SVC_REG_PENDING) { 11947697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <reg_ack: invalid state (%d)" DS_EOL, 11957697SMichael.Christensen@Sun.COM PORTID(port), svc->state); 11967697SMichael.Christensen@Sun.COM goto done; 11977697SMichael.Christensen@Sun.COM } 11987697SMichael.Christensen@Sun.COM 11997697SMichael.Christensen@Sun.COM ver = &(svc->cap.vers[svc->ver_idx]); 12007697SMichael.Christensen@Sun.COM 12017697SMichael.Christensen@Sun.COM /* major version has been agreed upon */ 12027697SMichael.Christensen@Sun.COM svc->ver.major = ver->major; 12037697SMichael.Christensen@Sun.COM 12047697SMichael.Christensen@Sun.COM if (ack->minor_vers >= ver->minor) { 12057697SMichael.Christensen@Sun.COM /* 12067697SMichael.Christensen@Sun.COM * Use the minor version specified in the 12077697SMichael.Christensen@Sun.COM * original request. 12087697SMichael.Christensen@Sun.COM */ 12097697SMichael.Christensen@Sun.COM svc->ver.minor = ver->minor; 12107697SMichael.Christensen@Sun.COM } else { 12117697SMichael.Christensen@Sun.COM /* 12127697SMichael.Christensen@Sun.COM * Use the lower minor version returned in 12137697SMichael.Christensen@Sun.COM * the ack. By defninition, all lower minor 12147697SMichael.Christensen@Sun.COM * versions must be supported. 12157697SMichael.Christensen@Sun.COM */ 12167697SMichael.Christensen@Sun.COM svc->ver.minor = ack->minor_vers; 12177697SMichael.Christensen@Sun.COM } 12187697SMichael.Christensen@Sun.COM 12197697SMichael.Christensen@Sun.COM svc->state = DS_SVC_ACTIVE; 12207697SMichael.Christensen@Sun.COM svc->port = port; 12217697SMichael.Christensen@Sun.COM 12227697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_ack: '%s' v%d.%d ready, hdl=0x%llx" 12237697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), svc->cap.svc_id, svc->ver.major, 12247697SMichael.Christensen@Sun.COM svc->ver.minor, (u_longlong_t)svc->hdl); 12257697SMichael.Christensen@Sun.COM 12267697SMichael.Christensen@Sun.COM /* notify the client that registration is complete */ 12277697SMichael.Christensen@Sun.COM if (svc->ops.ds_reg_cb) { 12287697SMichael.Christensen@Sun.COM /* 12297697SMichael.Christensen@Sun.COM * Use a temporary version structure so that 12307697SMichael.Christensen@Sun.COM * the copy in the svc structure cannot be 12317697SMichael.Christensen@Sun.COM * modified by the client. 12327697SMichael.Christensen@Sun.COM */ 12337697SMichael.Christensen@Sun.COM tmpver.major = svc->ver.major; 12347697SMichael.Christensen@Sun.COM tmpver.minor = svc->ver.minor; 12357697SMichael.Christensen@Sun.COM 12367697SMichael.Christensen@Sun.COM (*svc->ops.ds_reg_cb)(svc->ops.cb_arg, &tmpver, svc->hdl); 12377697SMichael.Christensen@Sun.COM } 12387697SMichael.Christensen@Sun.COM 12397697SMichael.Christensen@Sun.COM done: 12407697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 12417697SMichael.Christensen@Sun.COM } 12427697SMichael.Christensen@Sun.COM 12437697SMichael.Christensen@Sun.COM static void 12447697SMichael.Christensen@Sun.COM ds_try_next_port(ds_svc_t *svc, int portid) 12457697SMichael.Christensen@Sun.COM { 12467697SMichael.Christensen@Sun.COM ds_port_t *port; 12477697SMichael.Christensen@Sun.COM ds_portset_t totry; 12487697SMichael.Christensen@Sun.COM int i; 12497697SMichael.Christensen@Sun.COM 12507697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%x %s" DS_EOL, portid, __func__); 12519535SMichael.Christensen@Sun.COM 12529535SMichael.Christensen@Sun.COM /* 12539535SMichael.Christensen@Sun.COM * Get the ports that haven't been tried yet and are available to try. 12549535SMichael.Christensen@Sun.COM */ 1255*10042SMichael.Christensen@Sun.COM DS_PORTSET_DUP(totry, svc->avail); 12569535SMichael.Christensen@Sun.COM for (i = 0; i < DS_MAX_PORTS; i++) { 1257*10042SMichael.Christensen@Sun.COM if (DS_PORT_IN_SET(svc->tried, i)) 1258*10042SMichael.Christensen@Sun.COM DS_PORTSET_DEL(totry, i); 12599535SMichael.Christensen@Sun.COM } 12609535SMichael.Christensen@Sun.COM 12617697SMichael.Christensen@Sun.COM if (DS_PORTSET_ISNULL(totry)) 12627697SMichael.Christensen@Sun.COM return; 12637697SMichael.Christensen@Sun.COM 12647697SMichael.Christensen@Sun.COM for (i = 0; i < DS_MAX_PORTS; i++, portid++) { 12657697SMichael.Christensen@Sun.COM if (portid >= DS_MAX_PORTS) { 12667697SMichael.Christensen@Sun.COM portid = 0; 12677697SMichael.Christensen@Sun.COM } 12687697SMichael.Christensen@Sun.COM 12697697SMichael.Christensen@Sun.COM /* 12707697SMichael.Christensen@Sun.COM * If the port is not in the available list, 12717697SMichael.Christensen@Sun.COM * it is not a candidate for registration. 12727697SMichael.Christensen@Sun.COM */ 12737697SMichael.Christensen@Sun.COM if (!DS_PORT_IN_SET(totry, portid)) { 12747697SMichael.Christensen@Sun.COM continue; 12757697SMichael.Christensen@Sun.COM } 12767697SMichael.Christensen@Sun.COM 12777697SMichael.Christensen@Sun.COM port = &ds_ports[portid]; 12787697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%x: %s trying ldc.id: %d" DS_EOL, 12797697SMichael.Christensen@Sun.COM portid, __func__, (uint_t)(port->ldc.id)); 12807697SMichael.Christensen@Sun.COM if (ds_send_reg_req(svc, port) == 0) { 12817697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%x: %s reg msg send OK" DS_EOL, 12827697SMichael.Christensen@Sun.COM portid, __func__); 12837697SMichael.Christensen@Sun.COM /* register sent successfully */ 12847697SMichael.Christensen@Sun.COM break; 12857697SMichael.Christensen@Sun.COM } 12867697SMichael.Christensen@Sun.COM DS_DBG_LDC(CE_NOTE, "ds@%x: %s reg msg send FAIL" DS_EOL, 12877697SMichael.Christensen@Sun.COM portid, __func__); 12887697SMichael.Christensen@Sun.COM 12897697SMichael.Christensen@Sun.COM /* reset the service to try the next port */ 12907697SMichael.Christensen@Sun.COM ds_reset_svc(svc, port); 12917697SMichael.Christensen@Sun.COM } 12927697SMichael.Christensen@Sun.COM } 12937697SMichael.Christensen@Sun.COM 12947697SMichael.Christensen@Sun.COM static void 12957697SMichael.Christensen@Sun.COM ds_handle_reg_nack(ds_port_t *port, caddr_t buf, size_t len) 12967697SMichael.Christensen@Sun.COM { 12977697SMichael.Christensen@Sun.COM ds_reg_nack_t *nack; 12987697SMichael.Christensen@Sun.COM ds_svc_t *svc; 12997697SMichael.Christensen@Sun.COM int idx; 13007697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_reg_nack_t); 13017697SMichael.Christensen@Sun.COM 13027697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 13037697SMichael.Christensen@Sun.COM if (len != explen) { 13047697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <reg_nack: invalid message " 13057697SMichael.Christensen@Sun.COM "length (%ld), expected %ld" DS_EOL, PORTID(port), len, 13067697SMichael.Christensen@Sun.COM explen); 13077697SMichael.Christensen@Sun.COM return; 13087697SMichael.Christensen@Sun.COM } 13097697SMichael.Christensen@Sun.COM 13107697SMichael.Christensen@Sun.COM nack = (ds_reg_nack_t *)(buf + DS_HDR_SZ); 13117697SMichael.Christensen@Sun.COM 13127697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 13137697SMichael.Christensen@Sun.COM 13147697SMichael.Christensen@Sun.COM /* 13157697SMichael.Christensen@Sun.COM * We expect a reg_nack for a client ping. 13167697SMichael.Christensen@Sun.COM */ 13177697SMichael.Christensen@Sun.COM if (DS_HDL_ISCLIENT(nack->svc_handle)) { 13187697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_nack: ping hdl: 0x%llx" 13197697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), (u_longlong_t)nack->svc_handle); 13207697SMichael.Christensen@Sun.COM goto done; 13217697SMichael.Christensen@Sun.COM } 13227697SMichael.Christensen@Sun.COM 13237697SMichael.Christensen@Sun.COM /* 13247697SMichael.Christensen@Sun.COM * This searches for service based on how we generate handles 13257697SMichael.Christensen@Sun.COM * and so only works because this is a reg nack. 13267697SMichael.Christensen@Sun.COM */ 13277697SMichael.Christensen@Sun.COM if ((svc = ds_get_svc(nack->svc_handle)) == NULL) { 13287697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <reg_nack: invalid handle 0x%llx" 13297697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), (u_longlong_t)nack->svc_handle); 13307697SMichael.Christensen@Sun.COM goto done; 13317697SMichael.Christensen@Sun.COM } 13327697SMichael.Christensen@Sun.COM 13337697SMichael.Christensen@Sun.COM /* make sure the message makes sense */ 13347697SMichael.Christensen@Sun.COM if (svc->state != DS_SVC_REG_PENDING) { 1335*10042SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_nack: '%s' handle: 0x%llx " 1336*10042SMichael.Christensen@Sun.COM "invalid state (%d)" DS_EOL, PORTID(port), svc->cap.svc_id, 1337*10042SMichael.Christensen@Sun.COM (u_longlong_t)nack->svc_handle, svc->state); 13387697SMichael.Christensen@Sun.COM goto done; 13397697SMichael.Christensen@Sun.COM } 13407697SMichael.Christensen@Sun.COM 13417697SMichael.Christensen@Sun.COM if (nack->result == DS_REG_DUP) { 13427697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <reg_nack: duplicate registration " 13437697SMichael.Christensen@Sun.COM " for %s" DS_EOL, PORTID(port), svc->cap.svc_id); 13447697SMichael.Christensen@Sun.COM ds_reset_svc(svc, port); 13457697SMichael.Christensen@Sun.COM goto done; 13467697SMichael.Christensen@Sun.COM } 13477697SMichael.Christensen@Sun.COM 13487697SMichael.Christensen@Sun.COM /* 13497697SMichael.Christensen@Sun.COM * A major version of zero indicates that the 13507697SMichael.Christensen@Sun.COM * service is not supported at all. 13517697SMichael.Christensen@Sun.COM */ 13527697SMichael.Christensen@Sun.COM if (nack->major_vers == 0) { 13537697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_nack: '%s' not supported" 13547697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), svc->cap.svc_id); 13557697SMichael.Christensen@Sun.COM ds_reset_svc(svc, port); 13567697SMichael.Christensen@Sun.COM if ((svc->flags & DSSF_ISCLIENT) == 0) 13577697SMichael.Christensen@Sun.COM ds_try_next_port(svc, PORTID(port) + 1); 13587697SMichael.Christensen@Sun.COM goto done; 13597697SMichael.Christensen@Sun.COM } 13607697SMichael.Christensen@Sun.COM 13617697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_nack: '%s' hdl=0x%llx, nack=%d.x" 13627697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), svc->cap.svc_id, 13637697SMichael.Christensen@Sun.COM (u_longlong_t)nack->svc_handle, nack->major_vers); 13647697SMichael.Christensen@Sun.COM 13657697SMichael.Christensen@Sun.COM /* 13667697SMichael.Christensen@Sun.COM * Walk the version list for the service, looking for 13677697SMichael.Christensen@Sun.COM * a major version that is as close to the requested 13687697SMichael.Christensen@Sun.COM * major version as possible. 13697697SMichael.Christensen@Sun.COM */ 13707697SMichael.Christensen@Sun.COM for (idx = svc->ver_idx; idx < svc->cap.nvers; idx++) { 13717697SMichael.Christensen@Sun.COM if (svc->cap.vers[idx].major <= nack->major_vers) { 13727697SMichael.Christensen@Sun.COM /* found a version to try */ 13737697SMichael.Christensen@Sun.COM break; 13747697SMichael.Christensen@Sun.COM } 13757697SMichael.Christensen@Sun.COM } 13767697SMichael.Christensen@Sun.COM 13777697SMichael.Christensen@Sun.COM if (idx == svc->cap.nvers) { 13787697SMichael.Christensen@Sun.COM /* no supported version */ 13797697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_nack: %s v%d.x not supported" 13807697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), svc->cap.svc_id, nack->major_vers); 13817697SMichael.Christensen@Sun.COM ds_reset_svc(svc, port); 13827697SMichael.Christensen@Sun.COM if ((svc->flags & DSSF_ISCLIENT) == 0) 13837697SMichael.Christensen@Sun.COM ds_try_next_port(svc, PORTID(port) + 1); 13847697SMichael.Christensen@Sun.COM goto done; 13857697SMichael.Christensen@Sun.COM } 13867697SMichael.Christensen@Sun.COM 13877697SMichael.Christensen@Sun.COM /* start the handshake again */ 13887697SMichael.Christensen@Sun.COM svc->state = DS_SVC_INACTIVE; 13897697SMichael.Christensen@Sun.COM svc->ver_idx = idx; 13907697SMichael.Christensen@Sun.COM 13917697SMichael.Christensen@Sun.COM (void) ds_svc_register(svc, NULL); 13927697SMichael.Christensen@Sun.COM 13937697SMichael.Christensen@Sun.COM done: 13947697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 13957697SMichael.Christensen@Sun.COM } 13967697SMichael.Christensen@Sun.COM 13977697SMichael.Christensen@Sun.COM static void 13987697SMichael.Christensen@Sun.COM ds_handle_unreg_req(ds_port_t *port, caddr_t buf, size_t len) 13997697SMichael.Christensen@Sun.COM { 14007697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 14017697SMichael.Christensen@Sun.COM ds_unreg_req_t *req; 14027697SMichael.Christensen@Sun.COM ds_unreg_ack_t *ack; 14037697SMichael.Christensen@Sun.COM ds_svc_t *svc; 14047697SMichael.Christensen@Sun.COM char *msg; 14057697SMichael.Christensen@Sun.COM size_t msglen; 14067697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_unreg_req_t); 14079916SMichael.Christensen@Sun.COM boolean_t is_up; 14087697SMichael.Christensen@Sun.COM 14097697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 14107697SMichael.Christensen@Sun.COM if (len != explen) { 14117697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <unreg_req: invalid message " 14127697SMichael.Christensen@Sun.COM "length (%ld), expected %ld" DS_EOL, PORTID(port), len, 14137697SMichael.Christensen@Sun.COM explen); 14147697SMichael.Christensen@Sun.COM return; 14157697SMichael.Christensen@Sun.COM } 14167697SMichael.Christensen@Sun.COM 14177697SMichael.Christensen@Sun.COM req = (ds_unreg_req_t *)(buf + DS_HDR_SZ); 14187697SMichael.Christensen@Sun.COM 14197697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 14207697SMichael.Christensen@Sun.COM 14217697SMichael.Christensen@Sun.COM /* lookup appropriate client or service */ 14227697SMichael.Christensen@Sun.COM if (DS_HDL_ISCLIENT(req->svc_handle) || 14237697SMichael.Christensen@Sun.COM ((svc = ds_find_clnt_svc_by_hdl_port(req->svc_handle, port)) 14247697SMichael.Christensen@Sun.COM == NULL && ((svc = ds_get_svc(req->svc_handle)) == NULL || 14257697SMichael.Christensen@Sun.COM svc->port != port))) { 14269916SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 14279916SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 14289916SMichael.Christensen@Sun.COM is_up = (port->ldc.state == LDC_UP); 14299916SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 14309916SMichael.Christensen@Sun.COM if (!is_up) 14319916SMichael.Christensen@Sun.COM return; 1432*10042SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <unreg_req: invalid handle 0x%llx" 14337697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), (u_longlong_t)req->svc_handle); 14347697SMichael.Christensen@Sun.COM ds_send_unreg_nack(port, req->svc_handle); 14357697SMichael.Christensen@Sun.COM return; 14367697SMichael.Christensen@Sun.COM } 14377697SMichael.Christensen@Sun.COM 14387697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <unreg_req: '%s' handle 0x%llx" DS_EOL, 14397697SMichael.Christensen@Sun.COM PORTID(port), svc->cap.svc_id, (u_longlong_t)req->svc_handle); 14407697SMichael.Christensen@Sun.COM 14417697SMichael.Christensen@Sun.COM (void) ds_svc_unregister(svc, svc->port); 14427697SMichael.Christensen@Sun.COM 14437697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: unreg_ack>: '%s' hdl=0x%llx" DS_EOL, 14447697SMichael.Christensen@Sun.COM PORTID(port), svc->cap.svc_id, (u_longlong_t)req->svc_handle); 14457697SMichael.Christensen@Sun.COM 14467697SMichael.Christensen@Sun.COM ds_check_for_dup_services(svc); 14477697SMichael.Christensen@Sun.COM 14487697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 14497697SMichael.Christensen@Sun.COM 14507697SMichael.Christensen@Sun.COM msglen = DS_HDR_SZ + sizeof (ds_unreg_ack_t); 14517697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 14527697SMichael.Christensen@Sun.COM 14537697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 14547697SMichael.Christensen@Sun.COM hdr->msg_type = DS_UNREG_ACK; 14557697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_unreg_ack_t); 14567697SMichael.Christensen@Sun.COM 14577697SMichael.Christensen@Sun.COM ack = (ds_unreg_ack_t *)(msg + DS_HDR_SZ); 14587697SMichael.Christensen@Sun.COM ack->svc_handle = req->svc_handle; 14597697SMichael.Christensen@Sun.COM 14607697SMichael.Christensen@Sun.COM /* send message */ 14617697SMichael.Christensen@Sun.COM (void) ds_send_msg(port, msg, msglen); 14627697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 14637697SMichael.Christensen@Sun.COM 14647697SMichael.Christensen@Sun.COM } 14657697SMichael.Christensen@Sun.COM 14667697SMichael.Christensen@Sun.COM static void 14677697SMichael.Christensen@Sun.COM ds_handle_unreg_ack(ds_port_t *port, caddr_t buf, size_t len) 14687697SMichael.Christensen@Sun.COM { 14697697SMichael.Christensen@Sun.COM ds_unreg_ack_t *ack; 14707697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_unreg_ack_t); 14717697SMichael.Christensen@Sun.COM 14727697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 14737697SMichael.Christensen@Sun.COM if (len != explen) { 14747697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <unreg_ack: invalid message " 14757697SMichael.Christensen@Sun.COM "length (%ld), expected %ld" DS_EOL, PORTID(port), len, 14767697SMichael.Christensen@Sun.COM explen); 14777697SMichael.Christensen@Sun.COM return; 14787697SMichael.Christensen@Sun.COM } 14797697SMichael.Christensen@Sun.COM 14807697SMichael.Christensen@Sun.COM ack = (ds_unreg_ack_t *)(buf + DS_HDR_SZ); 14817697SMichael.Christensen@Sun.COM 14827697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <unreg_ack: hdl=0x%llx" DS_EOL, 14837697SMichael.Christensen@Sun.COM PORTID(port), (u_longlong_t)ack->svc_handle); 14847697SMichael.Christensen@Sun.COM 14858894SMichael.Christensen@Sun.COM #ifdef DEBUG 14867697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 14877697SMichael.Christensen@Sun.COM 14887697SMichael.Christensen@Sun.COM /* 14897697SMichael.Christensen@Sun.COM * Since the unregister request was initiated locally, 14907697SMichael.Christensen@Sun.COM * the service structure has already been torn down. 14917697SMichael.Christensen@Sun.COM * Just perform a sanity check to make sure the message 14927697SMichael.Christensen@Sun.COM * is appropriate. 14937697SMichael.Christensen@Sun.COM */ 14947697SMichael.Christensen@Sun.COM if (ds_get_svc(ack->svc_handle) != NULL) { 14958894SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <unreg_ack: handle 0x%llx in use" 14967697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), (u_longlong_t)ack->svc_handle); 14977697SMichael.Christensen@Sun.COM } 14987697SMichael.Christensen@Sun.COM 14997697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 15008894SMichael.Christensen@Sun.COM #endif /* DEBUG */ 15017697SMichael.Christensen@Sun.COM } 15027697SMichael.Christensen@Sun.COM 15037697SMichael.Christensen@Sun.COM static void 15047697SMichael.Christensen@Sun.COM ds_handle_unreg_nack(ds_port_t *port, caddr_t buf, size_t len) 15057697SMichael.Christensen@Sun.COM { 15067697SMichael.Christensen@Sun.COM ds_unreg_nack_t *nack; 15077697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_unreg_nack_t); 15087697SMichael.Christensen@Sun.COM 15097697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 15107697SMichael.Christensen@Sun.COM if (len != explen) { 15117697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <unreg_nack: invalid message " 15127697SMichael.Christensen@Sun.COM "length (%ld), expected %ld" DS_EOL, PORTID(port), len, 15137697SMichael.Christensen@Sun.COM explen); 15147697SMichael.Christensen@Sun.COM return; 15157697SMichael.Christensen@Sun.COM } 15167697SMichael.Christensen@Sun.COM 15177697SMichael.Christensen@Sun.COM nack = (ds_unreg_nack_t *)(buf + DS_HDR_SZ); 15187697SMichael.Christensen@Sun.COM 15197697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <unreg_nack: hdl=0x%llx" DS_EOL, 15207697SMichael.Christensen@Sun.COM PORTID(port), (u_longlong_t)nack->svc_handle); 15217697SMichael.Christensen@Sun.COM 15228894SMichael.Christensen@Sun.COM #ifdef DEBUG 15237697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 15247697SMichael.Christensen@Sun.COM 15257697SMichael.Christensen@Sun.COM /* 15267697SMichael.Christensen@Sun.COM * Since the unregister request was initiated locally, 15277697SMichael.Christensen@Sun.COM * the service structure has already been torn down. 15287697SMichael.Christensen@Sun.COM * Just perform a sanity check to make sure the message 15297697SMichael.Christensen@Sun.COM * is appropriate. 15307697SMichael.Christensen@Sun.COM */ 15317697SMichael.Christensen@Sun.COM if (ds_get_svc(nack->svc_handle) != NULL) { 15328894SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <unreg_nack: handle 0x%llx in use" 15337697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), (u_longlong_t)nack->svc_handle); 15347697SMichael.Christensen@Sun.COM } 15357697SMichael.Christensen@Sun.COM 15367697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 15378894SMichael.Christensen@Sun.COM #endif /* DEBUG */ 15387697SMichael.Christensen@Sun.COM } 15397697SMichael.Christensen@Sun.COM 15407697SMichael.Christensen@Sun.COM static void 15417697SMichael.Christensen@Sun.COM ds_handle_data(ds_port_t *port, caddr_t buf, size_t len) 15427697SMichael.Christensen@Sun.COM { 15437697SMichael.Christensen@Sun.COM ds_data_handle_t *data; 15447697SMichael.Christensen@Sun.COM ds_svc_t *svc; 15457697SMichael.Christensen@Sun.COM char *msg; 15467697SMichael.Christensen@Sun.COM int msgsz; 15477697SMichael.Christensen@Sun.COM int hdrsz; 15487697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_data_handle_t); 15497697SMichael.Christensen@Sun.COM 15507697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 15517697SMichael.Christensen@Sun.COM if (len < explen) { 15527697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <data: invalid message length " 15537697SMichael.Christensen@Sun.COM "(%ld), expected at least %ld" DS_EOL, PORTID(port), len, 15547697SMichael.Christensen@Sun.COM explen); 15557697SMichael.Christensen@Sun.COM return; 15567697SMichael.Christensen@Sun.COM } 15577697SMichael.Christensen@Sun.COM 15587697SMichael.Christensen@Sun.COM data = (ds_data_handle_t *)(buf + DS_HDR_SZ); 15597697SMichael.Christensen@Sun.COM 15607697SMichael.Christensen@Sun.COM hdrsz = DS_HDR_SZ + sizeof (ds_data_handle_t); 15617697SMichael.Christensen@Sun.COM msgsz = len - hdrsz; 15627697SMichael.Christensen@Sun.COM 15637697SMichael.Christensen@Sun.COM /* strip off the header for the client */ 15647697SMichael.Christensen@Sun.COM msg = (msgsz) ? (buf + hdrsz) : NULL; 15657697SMichael.Christensen@Sun.COM 15667697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 15677697SMichael.Christensen@Sun.COM 15687697SMichael.Christensen@Sun.COM if ((svc = ds_find_clnt_svc_by_hdl_port(data->svc_handle, port)) 15697697SMichael.Christensen@Sun.COM == NULL) { 15707697SMichael.Christensen@Sun.COM if ((svc = ds_get_svc(data->svc_handle)) == NULL) { 15717697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 15727697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <data: invalid handle 0x%llx" 15737697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), 15747697SMichael.Christensen@Sun.COM (u_longlong_t)data->svc_handle); 15757697SMichael.Christensen@Sun.COM ds_send_data_nack(port, data->svc_handle); 15767697SMichael.Christensen@Sun.COM return; 15777697SMichael.Christensen@Sun.COM } 15787697SMichael.Christensen@Sun.COM } 15797697SMichael.Christensen@Sun.COM 15807697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 15817697SMichael.Christensen@Sun.COM 15827697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: <data: '%s' hdl=0x%llx" DS_EOL, 15837697SMichael.Christensen@Sun.COM PORTID(port), svc->cap.svc_id, (u_longlong_t)svc->hdl); 15847697SMichael.Christensen@Sun.COM DS_DUMP_MSG(DS_DBG_FLAG_PRCL, msg, msgsz); 15857697SMichael.Christensen@Sun.COM 15867697SMichael.Christensen@Sun.COM /* dispatch this message to the client */ 15877697SMichael.Christensen@Sun.COM (*svc->ops.ds_data_cb)(svc->ops.cb_arg, msg, msgsz); 15887697SMichael.Christensen@Sun.COM } 15897697SMichael.Christensen@Sun.COM 15907697SMichael.Christensen@Sun.COM static void 15917697SMichael.Christensen@Sun.COM ds_handle_nack(ds_port_t *port, caddr_t buf, size_t len) 15927697SMichael.Christensen@Sun.COM { 15937697SMichael.Christensen@Sun.COM ds_svc_t *svc; 15947697SMichael.Christensen@Sun.COM ds_data_nack_t *nack; 15957697SMichael.Christensen@Sun.COM size_t explen = DS_MSG_LEN(ds_data_nack_t); 15967697SMichael.Christensen@Sun.COM 15977697SMichael.Christensen@Sun.COM /* sanity check the incoming message */ 15987697SMichael.Christensen@Sun.COM if (len != explen) { 15997697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <data_nack: invalid message " 16007697SMichael.Christensen@Sun.COM "length (%ld), expected %ld" DS_EOL, PORTID(port), len, 16017697SMichael.Christensen@Sun.COM explen); 16027697SMichael.Christensen@Sun.COM return; 16037697SMichael.Christensen@Sun.COM } 16047697SMichael.Christensen@Sun.COM 16057697SMichael.Christensen@Sun.COM nack = (ds_data_nack_t *)(buf + DS_HDR_SZ); 16067697SMichael.Christensen@Sun.COM 16077697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: data_nack: hdl=0x%llx, result=0x%llx" 16087697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), (u_longlong_t)nack->svc_handle, 16097697SMichael.Christensen@Sun.COM (u_longlong_t)nack->result); 16107697SMichael.Christensen@Sun.COM 16117697SMichael.Christensen@Sun.COM if (nack->result == DS_INV_HDL) { 16127697SMichael.Christensen@Sun.COM 16137697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 16147697SMichael.Christensen@Sun.COM 16157697SMichael.Christensen@Sun.COM if ((svc = ds_find_clnt_svc_by_hdl_port(nack->svc_handle, 16167697SMichael.Christensen@Sun.COM port)) == NULL) { 16177697SMichael.Christensen@Sun.COM if ((svc = ds_get_svc(nack->svc_handle)) == NULL) { 16187697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 16197697SMichael.Christensen@Sun.COM return; 16207697SMichael.Christensen@Sun.COM } 16217697SMichael.Christensen@Sun.COM } 16227697SMichael.Christensen@Sun.COM 16237697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: <data_nack: handle 0x%llx reported " 16247697SMichael.Christensen@Sun.COM " as invalid" DS_EOL, PORTID(port), 16257697SMichael.Christensen@Sun.COM (u_longlong_t)nack->svc_handle); 16267697SMichael.Christensen@Sun.COM 16277697SMichael.Christensen@Sun.COM (void) ds_svc_unregister(svc, svc->port); 16287697SMichael.Christensen@Sun.COM 16297697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 16307697SMichael.Christensen@Sun.COM } 16317697SMichael.Christensen@Sun.COM } 16327697SMichael.Christensen@Sun.COM 16337697SMichael.Christensen@Sun.COM /* Initialize the port */ 16347697SMichael.Christensen@Sun.COM void 16357697SMichael.Christensen@Sun.COM ds_send_init_req(ds_port_t *port) 16367697SMichael.Christensen@Sun.COM { 16377697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 16387697SMichael.Christensen@Sun.COM ds_init_req_t *init_req; 16397697SMichael.Christensen@Sun.COM size_t msglen; 16407697SMichael.Christensen@Sun.COM ds_ver_t *vers = &ds_vers[port->ver_idx]; 16417697SMichael.Christensen@Sun.COM 16427697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 16437697SMichael.Christensen@Sun.COM if (port->state != DS_PORT_LDC_INIT) { 16447697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: init_req>: invalid state: %d" 16457697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), port->state); 16467697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 16477697SMichael.Christensen@Sun.COM return; 16487697SMichael.Christensen@Sun.COM } 16497697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 16507697SMichael.Christensen@Sun.COM 16517697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: init_req>: req=v%d.%d" DS_EOL, 16527697SMichael.Christensen@Sun.COM PORTID(port), vers->major, vers->minor); 16537697SMichael.Christensen@Sun.COM 16547697SMichael.Christensen@Sun.COM msglen = DS_HDR_SZ + sizeof (ds_init_req_t); 16557697SMichael.Christensen@Sun.COM hdr = DS_MALLOC(msglen); 16567697SMichael.Christensen@Sun.COM 16577697SMichael.Christensen@Sun.COM hdr->msg_type = DS_INIT_REQ; 16587697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_init_req_t); 16597697SMichael.Christensen@Sun.COM 16607697SMichael.Christensen@Sun.COM init_req = (ds_init_req_t *)((caddr_t)hdr + DS_HDR_SZ); 16617697SMichael.Christensen@Sun.COM init_req->major_vers = vers->major; 16627697SMichael.Christensen@Sun.COM init_req->minor_vers = vers->minor; 16637697SMichael.Christensen@Sun.COM 16647697SMichael.Christensen@Sun.COM if (ds_send_msg(port, (caddr_t)hdr, msglen) == 0) { 16657697SMichael.Christensen@Sun.COM /* 16667697SMichael.Christensen@Sun.COM * We've left the port state unlocked over the malloc/send, 16677697SMichael.Christensen@Sun.COM * make sure no one has changed the state under us before 16687697SMichael.Christensen@Sun.COM * we update the state. 16697697SMichael.Christensen@Sun.COM */ 16707697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 16717697SMichael.Christensen@Sun.COM if (port->state == DS_PORT_LDC_INIT) 16727697SMichael.Christensen@Sun.COM port->state = DS_PORT_INIT_REQ; 16737697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 16747697SMichael.Christensen@Sun.COM } 16757697SMichael.Christensen@Sun.COM DS_FREE(hdr, msglen); 16767697SMichael.Christensen@Sun.COM } 16777697SMichael.Christensen@Sun.COM 16787697SMichael.Christensen@Sun.COM static int 16797697SMichael.Christensen@Sun.COM ds_send_reg_req(ds_svc_t *svc, ds_port_t *port) 16807697SMichael.Christensen@Sun.COM { 16817697SMichael.Christensen@Sun.COM ds_ver_t *ver; 16827697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 16837697SMichael.Christensen@Sun.COM caddr_t msg; 16847697SMichael.Christensen@Sun.COM size_t msglen; 16857697SMichael.Christensen@Sun.COM ds_reg_req_t *req; 16867697SMichael.Christensen@Sun.COM size_t idlen; 16877697SMichael.Christensen@Sun.COM int rv; 16887697SMichael.Christensen@Sun.COM 16898172SMichael.Christensen@Sun.COM if ((svc->state != DS_SVC_INACTIVE) && 16908172SMichael.Christensen@Sun.COM ((svc->flags & DSSF_ISCLIENT) == 0)) { 16918172SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: reg_req>: invalid svc state (%d) " 16928172SMichael.Christensen@Sun.COM "for svc '%s'" DS_EOL, PORTID(port), svc->state, 16938172SMichael.Christensen@Sun.COM svc->cap.svc_id); 16948172SMichael.Christensen@Sun.COM return (-1); 16958172SMichael.Christensen@Sun.COM } 16967697SMichael.Christensen@Sun.COM 16977697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 16987697SMichael.Christensen@Sun.COM 16997697SMichael.Christensen@Sun.COM /* check on the LDC to Zeus */ 17007697SMichael.Christensen@Sun.COM if (port->ldc.state != LDC_UP) { 17017697SMichael.Christensen@Sun.COM /* can not send message */ 17027697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: reg_req>: channel %ld is not up" 17037697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), port->ldc.id); 17047697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 17057697SMichael.Christensen@Sun.COM return (-1); 17067697SMichael.Christensen@Sun.COM } 17077697SMichael.Christensen@Sun.COM 17087697SMichael.Christensen@Sun.COM /* make sure port is ready */ 17097697SMichael.Christensen@Sun.COM if (port->state != DS_PORT_READY) { 17107697SMichael.Christensen@Sun.COM /* can not send message */ 17117697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: reg_req>: port is not ready" 17127697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port)); 17137697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 17147697SMichael.Christensen@Sun.COM return (-1); 17157697SMichael.Christensen@Sun.COM } 17167697SMichael.Christensen@Sun.COM 17177697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 17187697SMichael.Christensen@Sun.COM 17197697SMichael.Christensen@Sun.COM /* allocate the message buffer */ 17207697SMichael.Christensen@Sun.COM idlen = strlen(svc->cap.svc_id); 17217697SMichael.Christensen@Sun.COM msglen = DS_HDR_SZ + sizeof (ds_reg_req_t) + idlen; 17227697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 17237697SMichael.Christensen@Sun.COM 17247697SMichael.Christensen@Sun.COM /* copy in the header data */ 17257697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 17267697SMichael.Christensen@Sun.COM hdr->msg_type = DS_REG_REQ; 17277697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_reg_req_t) + idlen; 17287697SMichael.Christensen@Sun.COM 17297697SMichael.Christensen@Sun.COM req = (ds_reg_req_t *)(msg + DS_HDR_SZ); 17307697SMichael.Christensen@Sun.COM req->svc_handle = svc->hdl; 17317697SMichael.Christensen@Sun.COM ver = &(svc->cap.vers[svc->ver_idx]); 17327697SMichael.Christensen@Sun.COM req->major_vers = ver->major; 17337697SMichael.Christensen@Sun.COM req->minor_vers = ver->minor; 17347697SMichael.Christensen@Sun.COM 17357697SMichael.Christensen@Sun.COM /* copy in the service id */ 17367697SMichael.Christensen@Sun.COM (void) memcpy(req->svc_id, svc->cap.svc_id, idlen + 1); 17377697SMichael.Christensen@Sun.COM 17387697SMichael.Christensen@Sun.COM /* send the message */ 17397697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: reg_req>: '%s' ver=%d.%d, hdl=0x%llx" 17407697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), svc->cap.svc_id, ver->major, ver->minor, 17417697SMichael.Christensen@Sun.COM (u_longlong_t)svc->hdl); 17427697SMichael.Christensen@Sun.COM 17437697SMichael.Christensen@Sun.COM if ((rv = ds_send_msg(port, msg, msglen)) != 0) { 17447697SMichael.Christensen@Sun.COM svc->port = port; 17457697SMichael.Christensen@Sun.COM rv = -1; 17467697SMichael.Christensen@Sun.COM } else if ((svc->flags & DSSF_ISCLIENT) == 0) { 17477697SMichael.Christensen@Sun.COM svc->state = DS_SVC_REG_PENDING; 17487697SMichael.Christensen@Sun.COM } 17497697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 17507697SMichael.Christensen@Sun.COM 17517697SMichael.Christensen@Sun.COM return (rv); 17527697SMichael.Christensen@Sun.COM } 17537697SMichael.Christensen@Sun.COM 17547697SMichael.Christensen@Sun.COM /* 17557697SMichael.Christensen@Sun.COM * Keep around in case we want this later 17567697SMichael.Christensen@Sun.COM */ 17577697SMichael.Christensen@Sun.COM int 17587697SMichael.Christensen@Sun.COM ds_send_unreg_req(ds_svc_t *svc) 17597697SMichael.Christensen@Sun.COM { 17607697SMichael.Christensen@Sun.COM caddr_t msg; 17617697SMichael.Christensen@Sun.COM size_t msglen; 17627697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 17637697SMichael.Christensen@Sun.COM ds_unreg_req_t *req; 17647697SMichael.Christensen@Sun.COM ds_port_t *port = svc->port; 17657697SMichael.Christensen@Sun.COM int rv; 17667697SMichael.Christensen@Sun.COM 17677697SMichael.Christensen@Sun.COM if (port == NULL) { 17687697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "send_unreg_req: service '%s' not " 17697697SMichael.Christensen@Sun.COM "associated with a port" DS_EOL, svc->cap.svc_id); 17707697SMichael.Christensen@Sun.COM return (-1); 17717697SMichael.Christensen@Sun.COM } 17727697SMichael.Christensen@Sun.COM 17737697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 17747697SMichael.Christensen@Sun.COM 17757697SMichael.Christensen@Sun.COM /* check on the LDC to Zeus */ 17767697SMichael.Christensen@Sun.COM if (port->ldc.state != LDC_UP) { 17777697SMichael.Christensen@Sun.COM /* can not send message */ 17787697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: unreg_req>: channel %ld is not up" 17797697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), port->ldc.id); 17807697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 17817697SMichael.Christensen@Sun.COM return (-1); 17827697SMichael.Christensen@Sun.COM } 17837697SMichael.Christensen@Sun.COM 17847697SMichael.Christensen@Sun.COM /* make sure port is ready */ 17857697SMichael.Christensen@Sun.COM if (port->state != DS_PORT_READY) { 17867697SMichael.Christensen@Sun.COM /* can not send message */ 17877697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: unreg_req>: port is not ready" DS_EOL, 17887697SMichael.Christensen@Sun.COM PORTID(port)); 17897697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 17907697SMichael.Christensen@Sun.COM return (-1); 17917697SMichael.Christensen@Sun.COM } 17927697SMichael.Christensen@Sun.COM 17937697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 17947697SMichael.Christensen@Sun.COM 17957697SMichael.Christensen@Sun.COM msglen = DS_HDR_SZ + sizeof (ds_unreg_req_t); 17967697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 17977697SMichael.Christensen@Sun.COM 17987697SMichael.Christensen@Sun.COM /* copy in the header data */ 17997697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 18007697SMichael.Christensen@Sun.COM hdr->msg_type = DS_UNREG; 18017697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_unreg_req_t); 18027697SMichael.Christensen@Sun.COM 18037697SMichael.Christensen@Sun.COM req = (ds_unreg_req_t *)(msg + DS_HDR_SZ); 18047697SMichael.Christensen@Sun.COM if (svc->flags & DSSF_ISCLIENT) { 18057697SMichael.Christensen@Sun.COM req->svc_handle = svc->svc_hdl; 18067697SMichael.Christensen@Sun.COM } else { 18077697SMichael.Christensen@Sun.COM req->svc_handle = svc->hdl; 18087697SMichael.Christensen@Sun.COM } 18097697SMichael.Christensen@Sun.COM 18107697SMichael.Christensen@Sun.COM /* send the message */ 18117697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: unreg_req>: '%s' hdl=0x%llx" DS_EOL, 18127697SMichael.Christensen@Sun.COM PORTID(port), (svc->cap.svc_id) ? svc->cap.svc_id : "NULL", 18137697SMichael.Christensen@Sun.COM (u_longlong_t)svc->hdl); 18147697SMichael.Christensen@Sun.COM 18157697SMichael.Christensen@Sun.COM if ((rv = ds_send_msg(port, msg, msglen)) != 0) { 18167697SMichael.Christensen@Sun.COM rv = -1; 18177697SMichael.Christensen@Sun.COM } 18187697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 18197697SMichael.Christensen@Sun.COM 18207697SMichael.Christensen@Sun.COM return (rv); 18217697SMichael.Christensen@Sun.COM } 18227697SMichael.Christensen@Sun.COM 18237697SMichael.Christensen@Sun.COM static void 18247697SMichael.Christensen@Sun.COM ds_send_unreg_nack(ds_port_t *port, ds_svc_hdl_t bad_hdl) 18257697SMichael.Christensen@Sun.COM { 18267697SMichael.Christensen@Sun.COM caddr_t msg; 18277697SMichael.Christensen@Sun.COM size_t msglen; 18287697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 18297697SMichael.Christensen@Sun.COM ds_unreg_nack_t *nack; 18307697SMichael.Christensen@Sun.COM 18317697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 18327697SMichael.Christensen@Sun.COM 18337697SMichael.Christensen@Sun.COM /* check on the LDC to Zeus */ 18347697SMichael.Christensen@Sun.COM if (port->ldc.state != LDC_UP) { 18357697SMichael.Christensen@Sun.COM /* can not send message */ 18367697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: unreg_nack>: channel %ld is not up" 18377697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), port->ldc.id); 18387697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 18397697SMichael.Christensen@Sun.COM return; 18407697SMichael.Christensen@Sun.COM } 18417697SMichael.Christensen@Sun.COM 18427697SMichael.Christensen@Sun.COM /* make sure port is ready */ 18437697SMichael.Christensen@Sun.COM if (port->state != DS_PORT_READY) { 18447697SMichael.Christensen@Sun.COM /* can not send message */ 18457697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: unreg_nack>: port is not ready" 18467697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port)); 18477697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 18487697SMichael.Christensen@Sun.COM return; 18497697SMichael.Christensen@Sun.COM } 18507697SMichael.Christensen@Sun.COM 18517697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 18527697SMichael.Christensen@Sun.COM 18537697SMichael.Christensen@Sun.COM msglen = DS_HDR_SZ + sizeof (ds_unreg_nack_t); 18547697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 18557697SMichael.Christensen@Sun.COM 18567697SMichael.Christensen@Sun.COM /* copy in the header data */ 18577697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 18587697SMichael.Christensen@Sun.COM hdr->msg_type = DS_UNREG_NACK; 18597697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_unreg_nack_t); 18607697SMichael.Christensen@Sun.COM 18617697SMichael.Christensen@Sun.COM nack = (ds_unreg_nack_t *)(msg + DS_HDR_SZ); 18627697SMichael.Christensen@Sun.COM nack->svc_handle = bad_hdl; 18637697SMichael.Christensen@Sun.COM 18647697SMichael.Christensen@Sun.COM /* send the message */ 18657697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: unreg_nack>: hdl=0x%llx" DS_EOL, 18667697SMichael.Christensen@Sun.COM PORTID(port), (u_longlong_t)bad_hdl); 18677697SMichael.Christensen@Sun.COM 18687697SMichael.Christensen@Sun.COM (void) ds_send_msg(port, msg, msglen); 18697697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 18707697SMichael.Christensen@Sun.COM } 18717697SMichael.Christensen@Sun.COM 18727697SMichael.Christensen@Sun.COM static void 18737697SMichael.Christensen@Sun.COM ds_send_data_nack(ds_port_t *port, ds_svc_hdl_t bad_hdl) 18747697SMichael.Christensen@Sun.COM { 18757697SMichael.Christensen@Sun.COM caddr_t msg; 18767697SMichael.Christensen@Sun.COM size_t msglen; 18777697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 18787697SMichael.Christensen@Sun.COM ds_data_nack_t *nack; 18797697SMichael.Christensen@Sun.COM 18807697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 18817697SMichael.Christensen@Sun.COM 18827697SMichael.Christensen@Sun.COM /* check on the LDC to Zeus */ 18837697SMichael.Christensen@Sun.COM if (port->ldc.state != LDC_UP) { 18847697SMichael.Christensen@Sun.COM /* can not send message */ 18857697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: data_nack>: channel %ld is not up" 18867697SMichael.Christensen@Sun.COM DS_EOL, PORTID(port), port->ldc.id); 18877697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 18887697SMichael.Christensen@Sun.COM return; 18897697SMichael.Christensen@Sun.COM } 18907697SMichael.Christensen@Sun.COM 18917697SMichael.Christensen@Sun.COM /* make sure port is ready */ 18927697SMichael.Christensen@Sun.COM if (port->state != DS_PORT_READY) { 18937697SMichael.Christensen@Sun.COM /* can not send message */ 18947697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "ds@%lx: data_nack>: port is not ready" DS_EOL, 18957697SMichael.Christensen@Sun.COM PORTID(port)); 18967697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 18977697SMichael.Christensen@Sun.COM return; 18987697SMichael.Christensen@Sun.COM } 18997697SMichael.Christensen@Sun.COM 19007697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 19017697SMichael.Christensen@Sun.COM 19027697SMichael.Christensen@Sun.COM msglen = DS_HDR_SZ + sizeof (ds_data_nack_t); 19037697SMichael.Christensen@Sun.COM msg = DS_MALLOC(msglen); 19047697SMichael.Christensen@Sun.COM 19057697SMichael.Christensen@Sun.COM /* copy in the header data */ 19067697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 19077697SMichael.Christensen@Sun.COM hdr->msg_type = DS_NACK; 19087697SMichael.Christensen@Sun.COM hdr->payload_len = sizeof (ds_data_nack_t); 19097697SMichael.Christensen@Sun.COM 19107697SMichael.Christensen@Sun.COM nack = (ds_data_nack_t *)(msg + DS_HDR_SZ); 19117697SMichael.Christensen@Sun.COM nack->svc_handle = bad_hdl; 19127697SMichael.Christensen@Sun.COM nack->result = DS_INV_HDL; 19137697SMichael.Christensen@Sun.COM 19147697SMichael.Christensen@Sun.COM /* send the message */ 19157697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: data_nack>: hdl=0x%llx" DS_EOL, 19167697SMichael.Christensen@Sun.COM PORTID(port), (u_longlong_t)bad_hdl); 19177697SMichael.Christensen@Sun.COM 19187697SMichael.Christensen@Sun.COM (void) ds_send_msg(port, msg, msglen); 19197697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 19207697SMichael.Christensen@Sun.COM } 19217697SMichael.Christensen@Sun.COM 19227697SMichael.Christensen@Sun.COM /* END DS PROTOCOL SUPPORT FUNCTIONS */ 19237697SMichael.Christensen@Sun.COM 19247697SMichael.Christensen@Sun.COM #ifdef DEBUG 19257697SMichael.Christensen@Sun.COM 19267697SMichael.Christensen@Sun.COM #define BYTESPERLINE 8 19277697SMichael.Christensen@Sun.COM #define LINEWIDTH ((BYTESPERLINE * 3) + (BYTESPERLINE + 2) + 1) 19287697SMichael.Christensen@Sun.COM #define ASCIIOFFSET ((BYTESPERLINE * 3) + 2) 19297697SMichael.Christensen@Sun.COM #define ISPRINT(c) ((c >= ' ') && (c <= '~')) 19307697SMichael.Christensen@Sun.COM 19317697SMichael.Christensen@Sun.COM /* 19327697SMichael.Christensen@Sun.COM * Output a buffer formatted with a set number of bytes on 19337697SMichael.Christensen@Sun.COM * each line. Append each line with the ASCII equivalent of 19347697SMichael.Christensen@Sun.COM * each byte if it falls within the printable ASCII range, 19357697SMichael.Christensen@Sun.COM * and '.' otherwise. 19367697SMichael.Christensen@Sun.COM */ 19377697SMichael.Christensen@Sun.COM void 19387697SMichael.Christensen@Sun.COM ds_dump_msg(void *vbuf, size_t len) 19397697SMichael.Christensen@Sun.COM { 19407697SMichael.Christensen@Sun.COM int i, j; 19417697SMichael.Christensen@Sun.COM char *curr; 19427697SMichael.Christensen@Sun.COM char *aoff; 19437697SMichael.Christensen@Sun.COM char line[LINEWIDTH]; 19447697SMichael.Christensen@Sun.COM uint8_t *buf = vbuf; 19457697SMichael.Christensen@Sun.COM 19467697SMichael.Christensen@Sun.COM if (len > 128) 19477697SMichael.Christensen@Sun.COM len = 128; 19487697SMichael.Christensen@Sun.COM 19497697SMichael.Christensen@Sun.COM /* walk the buffer one line at a time */ 19507697SMichael.Christensen@Sun.COM for (i = 0; i < len; i += BYTESPERLINE) { 19517697SMichael.Christensen@Sun.COM 19527697SMichael.Christensen@Sun.COM bzero(line, LINEWIDTH); 19537697SMichael.Christensen@Sun.COM 19547697SMichael.Christensen@Sun.COM curr = line; 19557697SMichael.Christensen@Sun.COM aoff = line + ASCIIOFFSET; 19567697SMichael.Christensen@Sun.COM 19577697SMichael.Christensen@Sun.COM /* 19587697SMichael.Christensen@Sun.COM * Walk the bytes in the current line, storing 19597697SMichael.Christensen@Sun.COM * the hex value for the byte as well as the 19607697SMichael.Christensen@Sun.COM * ASCII representation in a temporary buffer. 19617697SMichael.Christensen@Sun.COM * All ASCII values are placed at the end of 19627697SMichael.Christensen@Sun.COM * the line. 19637697SMichael.Christensen@Sun.COM */ 19647697SMichael.Christensen@Sun.COM for (j = 0; (j < BYTESPERLINE) && ((i + j) < len); j++) { 19657697SMichael.Christensen@Sun.COM (void) sprintf(curr, " %02x", buf[i + j]); 19667697SMichael.Christensen@Sun.COM *aoff = (ISPRINT(buf[i + j])) ? buf[i + j] : '.'; 19677697SMichael.Christensen@Sun.COM curr += 3; 19687697SMichael.Christensen@Sun.COM aoff++; 19697697SMichael.Christensen@Sun.COM } 19707697SMichael.Christensen@Sun.COM 19717697SMichael.Christensen@Sun.COM /* 19727697SMichael.Christensen@Sun.COM * Fill in to the start of the ASCII translation 19737697SMichael.Christensen@Sun.COM * with spaces. This will only be necessary if 19747697SMichael.Christensen@Sun.COM * this is the last line and there are not enough 19757697SMichael.Christensen@Sun.COM * bytes to fill the whole line. 19767697SMichael.Christensen@Sun.COM */ 19777697SMichael.Christensen@Sun.COM while (curr != (line + ASCIIOFFSET)) 19787697SMichael.Christensen@Sun.COM *curr++ = ' '; 19797697SMichael.Christensen@Sun.COM 19807697SMichael.Christensen@Sun.COM cmn_err(CE_NOTE, "%s" DS_EOL, line); 19817697SMichael.Christensen@Sun.COM } 19827697SMichael.Christensen@Sun.COM } 19837697SMichael.Christensen@Sun.COM #endif /* DEBUG */ 19847697SMichael.Christensen@Sun.COM 19857697SMichael.Christensen@Sun.COM 19867697SMichael.Christensen@Sun.COM /* 19877697SMichael.Christensen@Sun.COM * Walk the table of registered services, executing the specified callback 19887697SMichael.Christensen@Sun.COM * function for each service on a port. A non-zero return value from the 19897697SMichael.Christensen@Sun.COM * callback is used to terminate the walk, not to indicate an error. Returns 19907697SMichael.Christensen@Sun.COM * the index of the last service visited. 19917697SMichael.Christensen@Sun.COM */ 19927697SMichael.Christensen@Sun.COM int 19937697SMichael.Christensen@Sun.COM ds_walk_svcs(svc_cb_t svc_cb, void *arg) 19947697SMichael.Christensen@Sun.COM { 19957697SMichael.Christensen@Sun.COM int idx; 19967697SMichael.Christensen@Sun.COM ds_svc_t *svc; 19977697SMichael.Christensen@Sun.COM 19987697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 19997697SMichael.Christensen@Sun.COM 20007697SMichael.Christensen@Sun.COM /* walk every table entry */ 20017697SMichael.Christensen@Sun.COM for (idx = 0; idx < ds_svcs.maxsvcs; idx++) { 20027697SMichael.Christensen@Sun.COM svc = ds_svcs.tbl[idx]; 20037697SMichael.Christensen@Sun.COM 20047697SMichael.Christensen@Sun.COM /* execute the callback */ 20057697SMichael.Christensen@Sun.COM if ((*svc_cb)(svc, arg) != 0) 20067697SMichael.Christensen@Sun.COM break; 20077697SMichael.Christensen@Sun.COM } 20087697SMichael.Christensen@Sun.COM 20097697SMichael.Christensen@Sun.COM return (idx); 20107697SMichael.Christensen@Sun.COM } 20117697SMichael.Christensen@Sun.COM 20127697SMichael.Christensen@Sun.COM static int 20137697SMichael.Christensen@Sun.COM ds_svc_isfree(ds_svc_t *svc, void *arg) 20147697SMichael.Christensen@Sun.COM { 20157697SMichael.Christensen@Sun.COM _NOTE(ARGUNUSED(arg)) 20167697SMichael.Christensen@Sun.COM 20177697SMichael.Christensen@Sun.COM /* 20187697SMichael.Christensen@Sun.COM * Looking for a free service. This may be a NULL entry 20197697SMichael.Christensen@Sun.COM * in the table, or an unused structure that could be 20207697SMichael.Christensen@Sun.COM * reused. 20217697SMichael.Christensen@Sun.COM */ 20227697SMichael.Christensen@Sun.COM 20237697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) { 20247697SMichael.Christensen@Sun.COM /* yes, it is free */ 20257697SMichael.Christensen@Sun.COM return (1); 20267697SMichael.Christensen@Sun.COM } 20277697SMichael.Christensen@Sun.COM 20287697SMichael.Christensen@Sun.COM /* not a candidate */ 20297697SMichael.Christensen@Sun.COM return (0); 20307697SMichael.Christensen@Sun.COM } 20317697SMichael.Christensen@Sun.COM 20327697SMichael.Christensen@Sun.COM int 20337697SMichael.Christensen@Sun.COM ds_svc_ismatch(ds_svc_t *svc, void *arg) 20347697SMichael.Christensen@Sun.COM { 20357697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) { 20367697SMichael.Christensen@Sun.COM return (0); 20377697SMichael.Christensen@Sun.COM } 20387697SMichael.Christensen@Sun.COM 20397697SMichael.Christensen@Sun.COM if (strcmp(svc->cap.svc_id, arg) == 0 && 20407697SMichael.Christensen@Sun.COM (svc->flags & DSSF_ISCLIENT) == 0) { 20417697SMichael.Christensen@Sun.COM /* found a match */ 20427697SMichael.Christensen@Sun.COM return (1); 20437697SMichael.Christensen@Sun.COM } 20447697SMichael.Christensen@Sun.COM 20457697SMichael.Christensen@Sun.COM return (0); 20467697SMichael.Christensen@Sun.COM } 20477697SMichael.Christensen@Sun.COM 20487697SMichael.Christensen@Sun.COM int 20497697SMichael.Christensen@Sun.COM ds_svc_clnt_ismatch(ds_svc_t *svc, void *arg) 20507697SMichael.Christensen@Sun.COM { 20517697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) { 20527697SMichael.Christensen@Sun.COM return (0); 20537697SMichael.Christensen@Sun.COM } 20547697SMichael.Christensen@Sun.COM 20557697SMichael.Christensen@Sun.COM if (strcmp(svc->cap.svc_id, arg) == 0 && 20567697SMichael.Christensen@Sun.COM (svc->flags & DSSF_ISCLIENT) != 0) { 20577697SMichael.Christensen@Sun.COM /* found a match */ 20587697SMichael.Christensen@Sun.COM return (1); 20597697SMichael.Christensen@Sun.COM } 20607697SMichael.Christensen@Sun.COM 20617697SMichael.Christensen@Sun.COM return (0); 20627697SMichael.Christensen@Sun.COM } 20637697SMichael.Christensen@Sun.COM 20647697SMichael.Christensen@Sun.COM int 20657697SMichael.Christensen@Sun.COM ds_svc_free(ds_svc_t *svc, void *arg) 20667697SMichael.Christensen@Sun.COM { 20677697SMichael.Christensen@Sun.COM _NOTE(ARGUNUSED(arg)) 20687697SMichael.Christensen@Sun.COM 20697697SMichael.Christensen@Sun.COM if (svc == NULL) { 20707697SMichael.Christensen@Sun.COM return (0); 20717697SMichael.Christensen@Sun.COM } 20727697SMichael.Christensen@Sun.COM 20737697SMichael.Christensen@Sun.COM if (svc->cap.svc_id) { 20747697SMichael.Christensen@Sun.COM DS_FREE(svc->cap.svc_id, strlen(svc->cap.svc_id) + 1); 20757697SMichael.Christensen@Sun.COM svc->cap.svc_id = NULL; 20767697SMichael.Christensen@Sun.COM } 20777697SMichael.Christensen@Sun.COM 20787697SMichael.Christensen@Sun.COM if (svc->cap.vers) { 20797697SMichael.Christensen@Sun.COM DS_FREE(svc->cap.vers, svc->cap.nvers * sizeof (ds_ver_t)); 20807697SMichael.Christensen@Sun.COM svc->cap.vers = NULL; 20817697SMichael.Christensen@Sun.COM } 20827697SMichael.Christensen@Sun.COM 20837697SMichael.Christensen@Sun.COM DS_FREE(svc, sizeof (ds_svc_t)); 20847697SMichael.Christensen@Sun.COM 20857697SMichael.Christensen@Sun.COM return (0); 20867697SMichael.Christensen@Sun.COM } 20877697SMichael.Christensen@Sun.COM 2088*10042SMichael.Christensen@Sun.COM static void 2089*10042SMichael.Christensen@Sun.COM ds_set_svc_port_tried(char *svc_id, ds_port_t *port) 2090*10042SMichael.Christensen@Sun.COM { 2091*10042SMichael.Christensen@Sun.COM int idx; 2092*10042SMichael.Christensen@Sun.COM ds_svc_t *svc; 2093*10042SMichael.Christensen@Sun.COM 2094*10042SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 2095*10042SMichael.Christensen@Sun.COM 2096*10042SMichael.Christensen@Sun.COM /* walk every table entry */ 2097*10042SMichael.Christensen@Sun.COM for (idx = 0; idx < ds_svcs.maxsvcs; idx++) { 2098*10042SMichael.Christensen@Sun.COM svc = ds_svcs.tbl[idx]; 2099*10042SMichael.Christensen@Sun.COM if (!DS_SVC_ISFREE(svc) && (svc->flags & DSSF_ISCLIENT) != 0 && 2100*10042SMichael.Christensen@Sun.COM strcmp(svc_id, svc->cap.svc_id) == 0) 2101*10042SMichael.Christensen@Sun.COM DS_PORTSET_ADD(svc->tried, PORTID(port)); 2102*10042SMichael.Christensen@Sun.COM } 2103*10042SMichael.Christensen@Sun.COM } 2104*10042SMichael.Christensen@Sun.COM 21057697SMichael.Christensen@Sun.COM static int 21067697SMichael.Christensen@Sun.COM ds_svc_register_onport(ds_svc_t *svc, ds_port_t *port) 21077697SMichael.Christensen@Sun.COM { 21087697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 21097697SMichael.Christensen@Sun.COM 21107697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) 21117697SMichael.Christensen@Sun.COM return (0); 21127697SMichael.Christensen@Sun.COM 21137697SMichael.Christensen@Sun.COM if (!DS_PORT_IN_SET(svc->avail, PORTID(port))) 21147697SMichael.Christensen@Sun.COM return (0); 21157697SMichael.Christensen@Sun.COM 2116*10042SMichael.Christensen@Sun.COM if (DS_PORT_IN_SET(svc->tried, PORTID(port))) 2117*10042SMichael.Christensen@Sun.COM return (0); 2118*10042SMichael.Christensen@Sun.COM 2119*10042SMichael.Christensen@Sun.COM if ((svc->flags & DSSF_ISCLIENT) == 0) { 2120*10042SMichael.Christensen@Sun.COM DS_PORTSET_ADD(svc->tried, PORTID(port)); 2121*10042SMichael.Christensen@Sun.COM if (svc->state != DS_SVC_INACTIVE) 2122*10042SMichael.Christensen@Sun.COM return (0); 2123*10042SMichael.Christensen@Sun.COM } else { 2124*10042SMichael.Christensen@Sun.COM ds_set_svc_port_tried(svc->cap.svc_id, port); 2125*10042SMichael.Christensen@Sun.COM 2126*10042SMichael.Christensen@Sun.COM /* 2127*10042SMichael.Christensen@Sun.COM * Never send a client reg req to the SP. 2128*10042SMichael.Christensen@Sun.COM */ 2129*10042SMichael.Christensen@Sun.COM if (PORTID(port) == ds_sp_port_id) { 2130*10042SMichael.Christensen@Sun.COM return (0); 2131*10042SMichael.Christensen@Sun.COM } 2132*10042SMichael.Christensen@Sun.COM } 21337697SMichael.Christensen@Sun.COM 21347697SMichael.Christensen@Sun.COM if (ds_send_reg_req(svc, port) == 0) { 21357697SMichael.Christensen@Sun.COM /* register sent successfully */ 21367697SMichael.Christensen@Sun.COM return (1); 21377697SMichael.Christensen@Sun.COM } 21387697SMichael.Christensen@Sun.COM 21397697SMichael.Christensen@Sun.COM if ((svc->flags & DSSF_ISCLIENT) == 0) { 21407697SMichael.Christensen@Sun.COM /* reset the service */ 21417697SMichael.Christensen@Sun.COM ds_reset_svc(svc, port); 21427697SMichael.Christensen@Sun.COM } 21437697SMichael.Christensen@Sun.COM return (0); 21447697SMichael.Christensen@Sun.COM } 21457697SMichael.Christensen@Sun.COM 2146*10042SMichael.Christensen@Sun.COM static int 2147*10042SMichael.Christensen@Sun.COM ds_svc_register_onport_walker(ds_svc_t *svc, void *arg) 2148*10042SMichael.Christensen@Sun.COM { 2149*10042SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 2150*10042SMichael.Christensen@Sun.COM 2151*10042SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) 2152*10042SMichael.Christensen@Sun.COM return (0); 2153*10042SMichael.Christensen@Sun.COM 2154*10042SMichael.Christensen@Sun.COM (void) ds_svc_register_onport(svc, arg); 2155*10042SMichael.Christensen@Sun.COM return (0); 2156*10042SMichael.Christensen@Sun.COM } 2157*10042SMichael.Christensen@Sun.COM 21587697SMichael.Christensen@Sun.COM int 21597697SMichael.Christensen@Sun.COM ds_svc_register(ds_svc_t *svc, void *arg) 21607697SMichael.Christensen@Sun.COM { 21617697SMichael.Christensen@Sun.COM _NOTE(ARGUNUSED(arg)) 21627697SMichael.Christensen@Sun.COM ds_portset_t ports; 21637697SMichael.Christensen@Sun.COM ds_port_t *port; 21647697SMichael.Christensen@Sun.COM int idx; 21657697SMichael.Christensen@Sun.COM 21667697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 21677697SMichael.Christensen@Sun.COM 21687697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) 21697697SMichael.Christensen@Sun.COM return (0); 21707697SMichael.Christensen@Sun.COM 21719535SMichael.Christensen@Sun.COM DS_PORTSET_DUP(ports, svc->avail); 21727697SMichael.Christensen@Sun.COM if (svc->flags & DSSF_ISCLIENT) { 2173*10042SMichael.Christensen@Sun.COM for (idx = 0; idx < DS_MAX_PORTS; idx++) { 2174*10042SMichael.Christensen@Sun.COM if (DS_PORT_IN_SET(svc->tried, idx)) 2175*10042SMichael.Christensen@Sun.COM DS_PORTSET_DEL(ports, idx); 2176*10042SMichael.Christensen@Sun.COM } 21777697SMichael.Christensen@Sun.COM } else if (svc->state != DS_SVC_INACTIVE) 21787697SMichael.Christensen@Sun.COM return (0); 21797697SMichael.Christensen@Sun.COM 21807697SMichael.Christensen@Sun.COM if (DS_PORTSET_ISNULL(ports)) 21817697SMichael.Christensen@Sun.COM return (0); 21827697SMichael.Christensen@Sun.COM 21837697SMichael.Christensen@Sun.COM /* 21847697SMichael.Christensen@Sun.COM * Attempt to register the service. Start with the lowest 21857697SMichael.Christensen@Sun.COM * numbered port and continue until a registration message 21867697SMichael.Christensen@Sun.COM * is sent successfully, or there are no ports left to try. 21877697SMichael.Christensen@Sun.COM */ 21887697SMichael.Christensen@Sun.COM for (idx = 0; idx < DS_MAX_PORTS; idx++) { 21897697SMichael.Christensen@Sun.COM 21907697SMichael.Christensen@Sun.COM /* 21917697SMichael.Christensen@Sun.COM * If the port is not in the available list, 21927697SMichael.Christensen@Sun.COM * it is not a candidate for registration. 21937697SMichael.Christensen@Sun.COM */ 21947697SMichael.Christensen@Sun.COM if (!DS_PORT_IN_SET(ports, idx)) { 21957697SMichael.Christensen@Sun.COM continue; 21967697SMichael.Christensen@Sun.COM } 21977697SMichael.Christensen@Sun.COM 21987697SMichael.Christensen@Sun.COM port = &ds_ports[idx]; 21997697SMichael.Christensen@Sun.COM if (ds_svc_register_onport(svc, port)) { 22007697SMichael.Christensen@Sun.COM if ((svc->flags & DSSF_ISCLIENT) == 0) 22017697SMichael.Christensen@Sun.COM break; 22027697SMichael.Christensen@Sun.COM } 22037697SMichael.Christensen@Sun.COM } 22047697SMichael.Christensen@Sun.COM 22057697SMichael.Christensen@Sun.COM return (0); 22067697SMichael.Christensen@Sun.COM } 22077697SMichael.Christensen@Sun.COM 22087697SMichael.Christensen@Sun.COM static int 22097697SMichael.Christensen@Sun.COM ds_svc_unregister(ds_svc_t *svc, void *arg) 22107697SMichael.Christensen@Sun.COM { 22117697SMichael.Christensen@Sun.COM ds_port_t *port = (ds_port_t *)arg; 22127697SMichael.Christensen@Sun.COM ds_svc_hdl_t hdl; 22137697SMichael.Christensen@Sun.COM 22147697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 22157697SMichael.Christensen@Sun.COM 22167697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) { 22177697SMichael.Christensen@Sun.COM return (0); 22187697SMichael.Christensen@Sun.COM } 22197697SMichael.Christensen@Sun.COM 22207697SMichael.Christensen@Sun.COM /* make sure the service is using this port */ 22217697SMichael.Christensen@Sun.COM if (svc->port != port) { 22227697SMichael.Christensen@Sun.COM return (0); 22237697SMichael.Christensen@Sun.COM } 22247697SMichael.Christensen@Sun.COM 22257697SMichael.Christensen@Sun.COM if (port) { 22267697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "ds@%lx: svc_unreg: id='%s', ver=%d.%d, " 22277697SMichael.Christensen@Sun.COM " hdl=0x%09lx" DS_EOL, PORTID(port), svc->cap.svc_id, 22287697SMichael.Christensen@Sun.COM svc->ver.major, svc->ver.minor, svc->hdl); 22297697SMichael.Christensen@Sun.COM } else { 22307697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "port=NULL: svc_unreg: id='%s', ver=%d.%d, " 22317697SMichael.Christensen@Sun.COM " hdl=0x%09lx" DS_EOL, svc->cap.svc_id, svc->ver.major, 22327697SMichael.Christensen@Sun.COM svc->ver.minor, svc->hdl); 22337697SMichael.Christensen@Sun.COM } 22347697SMichael.Christensen@Sun.COM 22357697SMichael.Christensen@Sun.COM /* reset the service structure */ 22367697SMichael.Christensen@Sun.COM ds_reset_svc(svc, port); 22377697SMichael.Christensen@Sun.COM 22387697SMichael.Christensen@Sun.COM /* call the client unregister callback */ 22397697SMichael.Christensen@Sun.COM if (svc->ops.ds_unreg_cb) { 22407697SMichael.Christensen@Sun.COM (*svc->ops.ds_unreg_cb)(svc->ops.cb_arg); 22417697SMichael.Christensen@Sun.COM } 22427697SMichael.Christensen@Sun.COM 22437697SMichael.Christensen@Sun.COM /* increment the count in the handle to prevent reuse */ 22447697SMichael.Christensen@Sun.COM hdl = DS_ALLOC_HDL(DS_HDL2IDX(svc->hdl), DS_HDL2COUNT(svc->hdl)); 22457697SMichael.Christensen@Sun.COM if (DS_HDL_ISCLIENT(svc->hdl)) { 22467697SMichael.Christensen@Sun.COM DS_HDL_SET_ISCLIENT(hdl); 22477697SMichael.Christensen@Sun.COM } 22487697SMichael.Christensen@Sun.COM svc->hdl = hdl; 22497697SMichael.Christensen@Sun.COM 22507697SMichael.Christensen@Sun.COM if (svc->state != DS_SVC_UNREG_PENDING) { 22517697SMichael.Christensen@Sun.COM /* try to initiate a new registration */ 22527697SMichael.Christensen@Sun.COM (void) ds_svc_register(svc, NULL); 22537697SMichael.Christensen@Sun.COM } 22547697SMichael.Christensen@Sun.COM 22557697SMichael.Christensen@Sun.COM return (0); 22567697SMichael.Christensen@Sun.COM } 22577697SMichael.Christensen@Sun.COM 22587697SMichael.Christensen@Sun.COM static int 22597697SMichael.Christensen@Sun.COM ds_svc_port_up(ds_svc_t *svc, void *arg) 22607697SMichael.Christensen@Sun.COM { 22617697SMichael.Christensen@Sun.COM ds_port_t *port = (ds_port_t *)arg; 22627697SMichael.Christensen@Sun.COM 22637697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) { 22647697SMichael.Christensen@Sun.COM /* nothing to do */ 22657697SMichael.Christensen@Sun.COM return (0); 22667697SMichael.Christensen@Sun.COM } 22677697SMichael.Christensen@Sun.COM 22687697SMichael.Christensen@Sun.COM DS_PORTSET_ADD(svc->avail, port->id); 22697697SMichael.Christensen@Sun.COM DS_PORTSET_DEL(svc->tried, port->id); 22707697SMichael.Christensen@Sun.COM 22717697SMichael.Christensen@Sun.COM return (0); 22727697SMichael.Christensen@Sun.COM } 22737697SMichael.Christensen@Sun.COM 2274*10042SMichael.Christensen@Sun.COM static void 2275*10042SMichael.Christensen@Sun.COM ds_set_port_ready(ds_port_t *port, uint16_t major, uint16_t minor) 2276*10042SMichael.Christensen@Sun.COM { 2277*10042SMichael.Christensen@Sun.COM boolean_t was_ready; 2278*10042SMichael.Christensen@Sun.COM 2279*10042SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 2280*10042SMichael.Christensen@Sun.COM was_ready = (port->state == DS_PORT_READY); 2281*10042SMichael.Christensen@Sun.COM if (!was_ready) { 2282*10042SMichael.Christensen@Sun.COM port->state = DS_PORT_READY; 2283*10042SMichael.Christensen@Sun.COM port->ver.major = major; 2284*10042SMichael.Christensen@Sun.COM port->ver.minor = minor; 2285*10042SMichael.Christensen@Sun.COM } 2286*10042SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 2287*10042SMichael.Christensen@Sun.COM 2288*10042SMichael.Christensen@Sun.COM if (!was_ready) { 2289*10042SMichael.Christensen@Sun.COM 2290*10042SMichael.Christensen@Sun.COM /* 2291*10042SMichael.Christensen@Sun.COM * The port came up, so update all the services 2292*10042SMichael.Christensen@Sun.COM * with this information. Follow that up with an 2293*10042SMichael.Christensen@Sun.COM * attempt to register any service that is not 2294*10042SMichael.Christensen@Sun.COM * already registered. 2295*10042SMichael.Christensen@Sun.COM */ 2296*10042SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 2297*10042SMichael.Christensen@Sun.COM 2298*10042SMichael.Christensen@Sun.COM (void) ds_walk_svcs(ds_svc_port_up, port); 2299*10042SMichael.Christensen@Sun.COM (void) ds_walk_svcs(ds_svc_register_onport_walker, port); 2300*10042SMichael.Christensen@Sun.COM 2301*10042SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 2302*10042SMichael.Christensen@Sun.COM } 2303*10042SMichael.Christensen@Sun.COM } 2304*10042SMichael.Christensen@Sun.COM 23057697SMichael.Christensen@Sun.COM ds_svc_t * 23067697SMichael.Christensen@Sun.COM ds_alloc_svc(void) 23077697SMichael.Christensen@Sun.COM { 23087697SMichael.Christensen@Sun.COM int idx; 23097697SMichael.Christensen@Sun.COM uint_t newmaxsvcs; 23107697SMichael.Christensen@Sun.COM ds_svc_t **newtbl; 23117697SMichael.Christensen@Sun.COM ds_svc_t *newsvc; 23127697SMichael.Christensen@Sun.COM 23137697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 23147697SMichael.Christensen@Sun.COM 23157697SMichael.Christensen@Sun.COM idx = ds_walk_svcs(ds_svc_isfree, NULL); 23167697SMichael.Christensen@Sun.COM 23177697SMichael.Christensen@Sun.COM if (idx != ds_svcs.maxsvcs) { 23187697SMichael.Christensen@Sun.COM goto found; 23197697SMichael.Christensen@Sun.COM } 23207697SMichael.Christensen@Sun.COM 23217697SMichael.Christensen@Sun.COM /* 23227697SMichael.Christensen@Sun.COM * There was no free space in the table. Grow 23237697SMichael.Christensen@Sun.COM * the table to double its current size. 23247697SMichael.Christensen@Sun.COM */ 23257697SMichael.Christensen@Sun.COM newmaxsvcs = ds_svcs.maxsvcs * 2; 23267697SMichael.Christensen@Sun.COM newtbl = DS_MALLOC(newmaxsvcs * sizeof (ds_svc_t *)); 23277697SMichael.Christensen@Sun.COM 23287697SMichael.Christensen@Sun.COM /* copy old table data to the new table */ 23297697SMichael.Christensen@Sun.COM (void) memcpy(newtbl, ds_svcs.tbl, 23307697SMichael.Christensen@Sun.COM ds_svcs.maxsvcs * sizeof (ds_svc_t *)); 23317697SMichael.Christensen@Sun.COM 23327697SMichael.Christensen@Sun.COM /* clean up the old table */ 23337697SMichael.Christensen@Sun.COM DS_FREE(ds_svcs.tbl, ds_svcs.maxsvcs * sizeof (ds_svc_t *)); 23347697SMichael.Christensen@Sun.COM ds_svcs.tbl = newtbl; 23357697SMichael.Christensen@Sun.COM ds_svcs.maxsvcs = newmaxsvcs; 23367697SMichael.Christensen@Sun.COM 23377697SMichael.Christensen@Sun.COM /* search for a free space again */ 23387697SMichael.Christensen@Sun.COM idx = ds_walk_svcs(ds_svc_isfree, NULL); 23397697SMichael.Christensen@Sun.COM 23407697SMichael.Christensen@Sun.COM /* the table is locked so should find a free slot */ 23417697SMichael.Christensen@Sun.COM ASSERT(idx != ds_svcs.maxsvcs); 23427697SMichael.Christensen@Sun.COM 23437697SMichael.Christensen@Sun.COM found: 23447697SMichael.Christensen@Sun.COM /* allocate a new svc structure if necessary */ 23457697SMichael.Christensen@Sun.COM if ((newsvc = ds_svcs.tbl[idx]) == NULL) { 23467697SMichael.Christensen@Sun.COM /* allocate a new service */ 23477697SMichael.Christensen@Sun.COM newsvc = DS_MALLOC(sizeof (ds_svc_t)); 23487697SMichael.Christensen@Sun.COM ds_svcs.tbl[idx] = newsvc; 23497697SMichael.Christensen@Sun.COM } 23507697SMichael.Christensen@Sun.COM 23517697SMichael.Christensen@Sun.COM /* fill in the handle */ 23527697SMichael.Christensen@Sun.COM newsvc->hdl = DS_ALLOC_HDL(idx, DS_HDL2COUNT(newsvc->hdl)); 23537697SMichael.Christensen@Sun.COM newsvc->state = DS_SVC_FREE; /* Mark as free temporarily */ 23547697SMichael.Christensen@Sun.COM 23557697SMichael.Christensen@Sun.COM return (newsvc); 23567697SMichael.Christensen@Sun.COM } 23577697SMichael.Christensen@Sun.COM 23587697SMichael.Christensen@Sun.COM static void 23597697SMichael.Christensen@Sun.COM ds_reset_svc(ds_svc_t *svc, ds_port_t *port) 23607697SMichael.Christensen@Sun.COM { 23617697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 23627697SMichael.Christensen@Sun.COM 23637697SMichael.Christensen@Sun.COM if (svc->state != DS_SVC_UNREG_PENDING) 23647697SMichael.Christensen@Sun.COM svc->state = DS_SVC_INACTIVE; 23657697SMichael.Christensen@Sun.COM svc->ver_idx = 0; 23667697SMichael.Christensen@Sun.COM svc->ver.major = 0; 23677697SMichael.Christensen@Sun.COM svc->ver.minor = 0; 23687697SMichael.Christensen@Sun.COM svc->port = NULL; 23697697SMichael.Christensen@Sun.COM if (port) { 23707697SMichael.Christensen@Sun.COM DS_PORTSET_DEL(svc->avail, port->id); 23717697SMichael.Christensen@Sun.COM } 23727697SMichael.Christensen@Sun.COM } 23737697SMichael.Christensen@Sun.COM 23747697SMichael.Christensen@Sun.COM ds_svc_t * 23757697SMichael.Christensen@Sun.COM ds_get_svc(ds_svc_hdl_t hdl) 23767697SMichael.Christensen@Sun.COM { 23777697SMichael.Christensen@Sun.COM int idx; 23787697SMichael.Christensen@Sun.COM ds_svc_t *svc; 23797697SMichael.Christensen@Sun.COM 23807697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 23817697SMichael.Christensen@Sun.COM 23827697SMichael.Christensen@Sun.COM if (hdl == DS_INVALID_HDL) 23837697SMichael.Christensen@Sun.COM return (NULL); 23847697SMichael.Christensen@Sun.COM 23857697SMichael.Christensen@Sun.COM idx = DS_HDL2IDX(hdl); 23867697SMichael.Christensen@Sun.COM 23877697SMichael.Christensen@Sun.COM /* check if index is out of bounds */ 23887697SMichael.Christensen@Sun.COM if ((idx < 0) || (idx >= ds_svcs.maxsvcs)) 23897697SMichael.Christensen@Sun.COM return (NULL); 23907697SMichael.Christensen@Sun.COM 23917697SMichael.Christensen@Sun.COM svc = ds_svcs.tbl[idx]; 23927697SMichael.Christensen@Sun.COM 23937697SMichael.Christensen@Sun.COM /* check for a valid service */ 23947697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) 23957697SMichael.Christensen@Sun.COM return (NULL); 23967697SMichael.Christensen@Sun.COM 23977697SMichael.Christensen@Sun.COM /* make sure the handle is an exact match */ 23987697SMichael.Christensen@Sun.COM if (svc->hdl != hdl) 23997697SMichael.Christensen@Sun.COM return (NULL); 24007697SMichael.Christensen@Sun.COM 24017697SMichael.Christensen@Sun.COM return (svc); 24027697SMichael.Christensen@Sun.COM } 24037697SMichael.Christensen@Sun.COM 24047697SMichael.Christensen@Sun.COM static void 24057697SMichael.Christensen@Sun.COM ds_port_reset(ds_port_t *port) 24067697SMichael.Christensen@Sun.COM { 24077697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 24087697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&port->lock)); 24097697SMichael.Christensen@Sun.COM 24107697SMichael.Christensen@Sun.COM /* connection went down, mark everything inactive */ 24117697SMichael.Christensen@Sun.COM (void) ds_walk_svcs(ds_svc_unregister, port); 24127697SMichael.Christensen@Sun.COM 24137697SMichael.Christensen@Sun.COM port->ver_idx = 0; 24147697SMichael.Christensen@Sun.COM port->ver.major = 0; 24157697SMichael.Christensen@Sun.COM port->ver.minor = 0; 24167697SMichael.Christensen@Sun.COM port->state = DS_PORT_LDC_INIT; 24177697SMichael.Christensen@Sun.COM } 24187697SMichael.Christensen@Sun.COM 24197697SMichael.Christensen@Sun.COM /* 24207697SMichael.Christensen@Sun.COM * Verify that a version array is sorted as expected for the 24217697SMichael.Christensen@Sun.COM * version negotiation to work correctly. 24227697SMichael.Christensen@Sun.COM */ 24237697SMichael.Christensen@Sun.COM ds_vers_check_t 24247697SMichael.Christensen@Sun.COM ds_vers_isvalid(ds_ver_t *vers, int nvers) 24257697SMichael.Christensen@Sun.COM { 24267697SMichael.Christensen@Sun.COM uint16_t curr_major; 24277697SMichael.Christensen@Sun.COM uint16_t curr_minor; 24287697SMichael.Christensen@Sun.COM int idx; 24297697SMichael.Christensen@Sun.COM 24307697SMichael.Christensen@Sun.COM curr_major = vers[0].major; 24317697SMichael.Christensen@Sun.COM curr_minor = vers[0].minor; 24327697SMichael.Christensen@Sun.COM 24337697SMichael.Christensen@Sun.COM /* 24347697SMichael.Christensen@Sun.COM * Walk the version array, verifying correct ordering. 24357697SMichael.Christensen@Sun.COM * The array must be sorted from highest supported 24367697SMichael.Christensen@Sun.COM * version to lowest supported version. 24377697SMichael.Christensen@Sun.COM */ 24387697SMichael.Christensen@Sun.COM for (idx = 0; idx < nvers; idx++) { 24397697SMichael.Christensen@Sun.COM if (vers[idx].major > curr_major) { 24407697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "ds_vers_isvalid: version array has " 24417697SMichael.Christensen@Sun.COM " increasing major versions" DS_EOL); 24427697SMichael.Christensen@Sun.COM return (DS_VERS_INCREASING_MAJOR_ERR); 24437697SMichael.Christensen@Sun.COM } 24447697SMichael.Christensen@Sun.COM 24457697SMichael.Christensen@Sun.COM if (vers[idx].major < curr_major) { 24467697SMichael.Christensen@Sun.COM curr_major = vers[idx].major; 24477697SMichael.Christensen@Sun.COM curr_minor = vers[idx].minor; 24487697SMichael.Christensen@Sun.COM continue; 24497697SMichael.Christensen@Sun.COM } 24507697SMichael.Christensen@Sun.COM 24517697SMichael.Christensen@Sun.COM if (vers[idx].minor > curr_minor) { 24527697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "ds_vers_isvalid: version array has " 24537697SMichael.Christensen@Sun.COM " increasing minor versions" DS_EOL); 24547697SMichael.Christensen@Sun.COM return (DS_VERS_INCREASING_MINOR_ERR); 24557697SMichael.Christensen@Sun.COM } 24567697SMichael.Christensen@Sun.COM 24577697SMichael.Christensen@Sun.COM curr_minor = vers[idx].minor; 24587697SMichael.Christensen@Sun.COM } 24597697SMichael.Christensen@Sun.COM 24607697SMichael.Christensen@Sun.COM return (DS_VERS_OK); 24617697SMichael.Christensen@Sun.COM } 24627697SMichael.Christensen@Sun.COM 24637697SMichael.Christensen@Sun.COM /* 24647697SMichael.Christensen@Sun.COM * Extended user capability init. 24657697SMichael.Christensen@Sun.COM */ 24667697SMichael.Christensen@Sun.COM int 24677697SMichael.Christensen@Sun.COM ds_ucap_init(ds_capability_t *cap, ds_clnt_ops_t *ops, uint32_t flags, 24687697SMichael.Christensen@Sun.COM int instance, ds_svc_hdl_t *hdlp) 24697697SMichael.Christensen@Sun.COM { 24707697SMichael.Christensen@Sun.COM ds_vers_check_t status; 24717697SMichael.Christensen@Sun.COM ds_svc_t *svc; 24727697SMichael.Christensen@Sun.COM int rv = 0; 24737697SMichael.Christensen@Sun.COM ds_svc_hdl_t lb_hdl, hdl; 24747697SMichael.Christensen@Sun.COM int is_loopback; 24757697SMichael.Christensen@Sun.COM int is_client; 24767697SMichael.Christensen@Sun.COM 24777697SMichael.Christensen@Sun.COM /* sanity check the args */ 24787697SMichael.Christensen@Sun.COM if ((cap == NULL) || (ops == NULL)) { 24797697SMichael.Christensen@Sun.COM cmn_err(CE_NOTE, "%s: invalid arguments" DS_EOL, __func__); 24807697SMichael.Christensen@Sun.COM return (EINVAL); 24817697SMichael.Christensen@Sun.COM } 24827697SMichael.Christensen@Sun.COM 24837697SMichael.Christensen@Sun.COM /* sanity check the capability specifier */ 24847697SMichael.Christensen@Sun.COM if ((cap->svc_id == NULL) || (cap->vers == NULL) || (cap->nvers == 0)) { 24857697SMichael.Christensen@Sun.COM cmn_err(CE_NOTE, "%s: invalid capability specifier" DS_EOL, 24867697SMichael.Christensen@Sun.COM __func__); 24877697SMichael.Christensen@Sun.COM return (EINVAL); 24887697SMichael.Christensen@Sun.COM } 24897697SMichael.Christensen@Sun.COM 24907697SMichael.Christensen@Sun.COM /* sanity check the version array */ 24917697SMichael.Christensen@Sun.COM if ((status = ds_vers_isvalid(cap->vers, cap->nvers)) != DS_VERS_OK) { 24927697SMichael.Christensen@Sun.COM cmn_err(CE_NOTE, "%s: invalid capability version array " 24937697SMichael.Christensen@Sun.COM "for %s service: %s" DS_EOL, __func__, cap->svc_id, 24947697SMichael.Christensen@Sun.COM (status == DS_VERS_INCREASING_MAJOR_ERR) ? 24957697SMichael.Christensen@Sun.COM "increasing major versions" : 24967697SMichael.Christensen@Sun.COM "increasing minor versions"); 24977697SMichael.Christensen@Sun.COM return (EINVAL); 24987697SMichael.Christensen@Sun.COM } 24997697SMichael.Christensen@Sun.COM 25007697SMichael.Christensen@Sun.COM /* data and register callbacks are required */ 25017697SMichael.Christensen@Sun.COM if ((ops->ds_data_cb == NULL) || (ops->ds_reg_cb == NULL)) { 25027697SMichael.Christensen@Sun.COM cmn_err(CE_NOTE, "%s: invalid ops specifier for %s service" 25037697SMichael.Christensen@Sun.COM DS_EOL, __func__, cap->svc_id); 25047697SMichael.Christensen@Sun.COM return (EINVAL); 25057697SMichael.Christensen@Sun.COM } 25067697SMichael.Christensen@Sun.COM 25077697SMichael.Christensen@Sun.COM flags &= DSSF_USERFLAGS; 25087697SMichael.Christensen@Sun.COM is_client = flags & DSSF_ISCLIENT; 25097697SMichael.Christensen@Sun.COM 25107697SMichael.Christensen@Sun.COM DS_DBG_USR(CE_NOTE, "%s: svc_id='%s', data_cb=0x%lx, cb_arg=0x%lx" 25117697SMichael.Christensen@Sun.COM DS_EOL, __func__, cap->svc_id, PTR_TO_LONG(ops->ds_data_cb), 25127697SMichael.Christensen@Sun.COM PTR_TO_LONG(ops->cb_arg)); 25137697SMichael.Christensen@Sun.COM 25147697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 25157697SMichael.Christensen@Sun.COM 25167697SMichael.Christensen@Sun.COM /* check if the service is already registered */ 25177697SMichael.Christensen@Sun.COM if (i_ds_hdl_lookup(cap->svc_id, is_client, NULL, 1) == 1) { 25187697SMichael.Christensen@Sun.COM /* already registered */ 25197697SMichael.Christensen@Sun.COM cmn_err(CE_NOTE, "Service '%s'/%s already registered" DS_EOL, 25207697SMichael.Christensen@Sun.COM cap->svc_id, 25217697SMichael.Christensen@Sun.COM (flags & DSSF_ISCLIENT) ? "client" : "service"); 25227697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 25237697SMichael.Christensen@Sun.COM return (EALREADY); 25247697SMichael.Christensen@Sun.COM } 25257697SMichael.Christensen@Sun.COM 25267697SMichael.Christensen@Sun.COM svc = ds_alloc_svc(); 25277697SMichael.Christensen@Sun.COM if (is_client) { 25287697SMichael.Christensen@Sun.COM DS_HDL_SET_ISCLIENT(svc->hdl); 25297697SMichael.Christensen@Sun.COM } 25307697SMichael.Christensen@Sun.COM 25317697SMichael.Christensen@Sun.COM svc->state = DS_SVC_FREE; 25327697SMichael.Christensen@Sun.COM svc->svc_hdl = DS_BADHDL1; 25337697SMichael.Christensen@Sun.COM 25347697SMichael.Christensen@Sun.COM svc->flags = flags; 25357697SMichael.Christensen@Sun.COM svc->drvi = instance; 25367697SMichael.Christensen@Sun.COM svc->drv_psp = NULL; 25377697SMichael.Christensen@Sun.COM 25387697SMichael.Christensen@Sun.COM /* 25399242SMichael.Christensen@Sun.COM * Check for loopback. "pri" is a legacy service that assumes it 25409242SMichael.Christensen@Sun.COM * will never use loopback mode. 25417697SMichael.Christensen@Sun.COM */ 25429242SMichael.Christensen@Sun.COM if (strcmp(cap->svc_id, "pri") == 0) { 25439242SMichael.Christensen@Sun.COM is_loopback = 0; 25449242SMichael.Christensen@Sun.COM } else if (i_ds_hdl_lookup(cap->svc_id, is_client == 0, &lb_hdl, 1) 25459242SMichael.Christensen@Sun.COM == 1) { 25468172SMichael.Christensen@Sun.COM if ((rv = ds_loopback_set_svc(svc, cap, &lb_hdl)) != 0) { 25479242SMichael.Christensen@Sun.COM DS_DBG_USR(CE_NOTE, "%s: ds_loopback_set_svc '%s' err " 25489242SMichael.Christensen@Sun.COM " (%d)" DS_EOL, __func__, cap->svc_id, rv); 25497697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 25507697SMichael.Christensen@Sun.COM return (rv); 25517697SMichael.Christensen@Sun.COM } 25527697SMichael.Christensen@Sun.COM is_loopback = 1; 25537697SMichael.Christensen@Sun.COM } else 25547697SMichael.Christensen@Sun.COM is_loopback = 0; 25557697SMichael.Christensen@Sun.COM 25567697SMichael.Christensen@Sun.COM /* copy over all the client information */ 25577697SMichael.Christensen@Sun.COM (void) memcpy(&svc->cap, cap, sizeof (ds_capability_t)); 25587697SMichael.Christensen@Sun.COM 25597697SMichael.Christensen@Sun.COM /* make a copy of the service name */ 25607697SMichael.Christensen@Sun.COM svc->cap.svc_id = ds_strdup(cap->svc_id); 25617697SMichael.Christensen@Sun.COM 25627697SMichael.Christensen@Sun.COM /* make a copy of the version array */ 25637697SMichael.Christensen@Sun.COM svc->cap.vers = DS_MALLOC(cap->nvers * sizeof (ds_ver_t)); 25647697SMichael.Christensen@Sun.COM (void) memcpy(svc->cap.vers, cap->vers, cap->nvers * sizeof (ds_ver_t)); 25657697SMichael.Christensen@Sun.COM 25667697SMichael.Christensen@Sun.COM /* copy the client ops vector */ 25677697SMichael.Christensen@Sun.COM (void) memcpy(&svc->ops, ops, sizeof (ds_clnt_ops_t)); 25687697SMichael.Christensen@Sun.COM 25697697SMichael.Christensen@Sun.COM svc->state = DS_SVC_INACTIVE; 25707697SMichael.Christensen@Sun.COM svc->ver_idx = 0; 25717697SMichael.Christensen@Sun.COM DS_PORTSET_DUP(svc->avail, ds_allports); 25727697SMichael.Christensen@Sun.COM DS_PORTSET_SETNULL(svc->tried); 25737697SMichael.Christensen@Sun.COM 25747697SMichael.Christensen@Sun.COM ds_svcs.nsvcs++; 25757697SMichael.Christensen@Sun.COM 25767697SMichael.Christensen@Sun.COM hdl = svc->hdl; 25777697SMichael.Christensen@Sun.COM 25787697SMichael.Christensen@Sun.COM /* 25797697SMichael.Christensen@Sun.COM * kludge to allow user callback code to get handle and user args. 25807697SMichael.Christensen@Sun.COM * Make sure the callback arg points to the svc structure. 25817697SMichael.Christensen@Sun.COM */ 25827697SMichael.Christensen@Sun.COM if ((flags & DSSF_ISUSER) != 0) { 25837697SMichael.Christensen@Sun.COM ds_cbarg_set_cookie(svc); 25847697SMichael.Christensen@Sun.COM } 25857697SMichael.Christensen@Sun.COM 25867697SMichael.Christensen@Sun.COM if (is_loopback) { 25877697SMichael.Christensen@Sun.COM ds_loopback_register(hdl); 25887697SMichael.Christensen@Sun.COM ds_loopback_register(lb_hdl); 25897697SMichael.Christensen@Sun.COM } 25907697SMichael.Christensen@Sun.COM 25917697SMichael.Christensen@Sun.COM /* 25927697SMichael.Christensen@Sun.COM * If this is a client or a non-loopback service provider, send 25937697SMichael.Christensen@Sun.COM * out register requests. 25947697SMichael.Christensen@Sun.COM */ 25957697SMichael.Christensen@Sun.COM if (!is_loopback || (flags & DSSF_ISCLIENT) != 0) 25967697SMichael.Christensen@Sun.COM (void) ds_svc_register(svc, NULL); 25977697SMichael.Christensen@Sun.COM 25987697SMichael.Christensen@Sun.COM if (hdlp) { 25997697SMichael.Christensen@Sun.COM *hdlp = hdl; 26007697SMichael.Christensen@Sun.COM } 26017697SMichael.Christensen@Sun.COM 26027697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 26037697SMichael.Christensen@Sun.COM 26047697SMichael.Christensen@Sun.COM DS_DBG_USR(CE_NOTE, "%s: service '%s' assigned handle 0x%09lx" DS_EOL, 26057697SMichael.Christensen@Sun.COM __func__, svc->cap.svc_id, hdl); 26067697SMichael.Christensen@Sun.COM 26077697SMichael.Christensen@Sun.COM return (0); 26087697SMichael.Christensen@Sun.COM } 26097697SMichael.Christensen@Sun.COM 26107697SMichael.Christensen@Sun.COM /* 26117697SMichael.Christensen@Sun.COM * ds_cap_init interface for previous revision. 26127697SMichael.Christensen@Sun.COM */ 26137697SMichael.Christensen@Sun.COM int 26147697SMichael.Christensen@Sun.COM ds_cap_init(ds_capability_t *cap, ds_clnt_ops_t *ops) 26157697SMichael.Christensen@Sun.COM { 26167697SMichael.Christensen@Sun.COM return (ds_ucap_init(cap, ops, 0, DS_INVALID_INSTANCE, NULL)); 26177697SMichael.Christensen@Sun.COM } 26187697SMichael.Christensen@Sun.COM 26197697SMichael.Christensen@Sun.COM /* 26207697SMichael.Christensen@Sun.COM * Interface for ds_unreg_hdl in lds driver. 26217697SMichael.Christensen@Sun.COM */ 26227697SMichael.Christensen@Sun.COM int 26237697SMichael.Christensen@Sun.COM ds_unreg_hdl(ds_svc_hdl_t hdl) 26247697SMichael.Christensen@Sun.COM { 26257697SMichael.Christensen@Sun.COM ds_svc_t *svc; 26267697SMichael.Christensen@Sun.COM int is_loopback; 26277697SMichael.Christensen@Sun.COM ds_svc_hdl_t lb_hdl; 26287697SMichael.Christensen@Sun.COM 26297697SMichael.Christensen@Sun.COM DS_DBG_USR(CE_NOTE, "%s: hdl=0x%09lx" DS_EOL, __func__, hdl); 26307697SMichael.Christensen@Sun.COM 26317697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 26327697SMichael.Christensen@Sun.COM if ((svc = ds_get_svc(hdl)) == NULL) { 26337697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 26347697SMichael.Christensen@Sun.COM DS_DBG_USR(CE_NOTE, "%s: unknown hdl: 0x%llx" DS_EOL, __func__, 26357697SMichael.Christensen@Sun.COM (u_longlong_t)hdl); 26367697SMichael.Christensen@Sun.COM return (ENXIO); 26377697SMichael.Christensen@Sun.COM } 26387697SMichael.Christensen@Sun.COM 26397697SMichael.Christensen@Sun.COM DS_DBG_USR(CE_NOTE, "%s: svcid='%s', hdl=0x%llx" DS_EOL, __func__, 26407697SMichael.Christensen@Sun.COM svc->cap.svc_id, (u_longlong_t)svc->hdl); 26417697SMichael.Christensen@Sun.COM 26427697SMichael.Christensen@Sun.COM svc->state = DS_SVC_UNREG_PENDING; 26437697SMichael.Christensen@Sun.COM 26447697SMichael.Christensen@Sun.COM is_loopback = ((svc->flags & DSSF_LOOPBACK) != 0); 26457697SMichael.Christensen@Sun.COM lb_hdl = svc->svc_hdl; 26467697SMichael.Christensen@Sun.COM 26477697SMichael.Christensen@Sun.COM if (svc->port) { 26487697SMichael.Christensen@Sun.COM (void) ds_send_unreg_req(svc); 26497697SMichael.Christensen@Sun.COM } 26507697SMichael.Christensen@Sun.COM 26517697SMichael.Christensen@Sun.COM (void) ds_svc_unregister(svc, svc->port); 26527697SMichael.Christensen@Sun.COM 26537697SMichael.Christensen@Sun.COM ds_delete_svc_entry(svc); 26547697SMichael.Christensen@Sun.COM 26557697SMichael.Christensen@Sun.COM if (is_loopback) { 26567697SMichael.Christensen@Sun.COM ds_loopback_unregister(lb_hdl); 26577697SMichael.Christensen@Sun.COM } 26587697SMichael.Christensen@Sun.COM 26597697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 26607697SMichael.Christensen@Sun.COM 26617697SMichael.Christensen@Sun.COM return (0); 26627697SMichael.Christensen@Sun.COM } 26637697SMichael.Christensen@Sun.COM 26647697SMichael.Christensen@Sun.COM int 26657697SMichael.Christensen@Sun.COM ds_cap_fini(ds_capability_t *cap) 26667697SMichael.Christensen@Sun.COM { 26677697SMichael.Christensen@Sun.COM ds_svc_hdl_t hdl; 26687697SMichael.Christensen@Sun.COM int rv; 26697697SMichael.Christensen@Sun.COM uint_t nhdls = 0; 26707697SMichael.Christensen@Sun.COM 26717697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "%s: '%s'" DS_EOL, __func__, cap->svc_id); 26727697SMichael.Christensen@Sun.COM if ((rv = ds_hdl_lookup(cap->svc_id, 0, &hdl, 1, &nhdls)) != 0) { 26737697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "%s: ds_hdl_lookup '%s' err (%d)" DS_EOL, 26747697SMichael.Christensen@Sun.COM __func__, cap->svc_id, rv); 26757697SMichael.Christensen@Sun.COM return (rv); 26767697SMichael.Christensen@Sun.COM } 26777697SMichael.Christensen@Sun.COM 26787697SMichael.Christensen@Sun.COM if (nhdls == 0) { 26797697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "%s: no such service '%s'" DS_EOL, 26807697SMichael.Christensen@Sun.COM __func__, cap->svc_id); 26817697SMichael.Christensen@Sun.COM return (ENXIO); 26827697SMichael.Christensen@Sun.COM } 26837697SMichael.Christensen@Sun.COM 26847697SMichael.Christensen@Sun.COM if ((rv = ds_is_my_hdl(hdl, DS_INVALID_INSTANCE)) != 0) { 26857697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "%s: ds_is_my_handle err (%d)" DS_EOL, __func__, 26867697SMichael.Christensen@Sun.COM rv); 26877697SMichael.Christensen@Sun.COM return (rv); 26887697SMichael.Christensen@Sun.COM } 26897697SMichael.Christensen@Sun.COM 26907697SMichael.Christensen@Sun.COM if ((rv = ds_unreg_hdl(hdl)) != 0) { 26917697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "%s: ds_unreg_hdl err (%d)" DS_EOL, __func__, 26927697SMichael.Christensen@Sun.COM rv); 26937697SMichael.Christensen@Sun.COM return (rv); 26947697SMichael.Christensen@Sun.COM } 26957697SMichael.Christensen@Sun.COM 26967697SMichael.Christensen@Sun.COM return (0); 26977697SMichael.Christensen@Sun.COM } 26987697SMichael.Christensen@Sun.COM 26997697SMichael.Christensen@Sun.COM int 27007697SMichael.Christensen@Sun.COM ds_cap_send(ds_svc_hdl_t hdl, void *buf, size_t len) 27017697SMichael.Christensen@Sun.COM { 27027697SMichael.Christensen@Sun.COM int rv; 27037697SMichael.Christensen@Sun.COM ds_hdr_t *hdr; 27047697SMichael.Christensen@Sun.COM caddr_t msg; 27057697SMichael.Christensen@Sun.COM size_t msglen; 27067697SMichael.Christensen@Sun.COM size_t hdrlen; 27077697SMichael.Christensen@Sun.COM caddr_t payload; 27087697SMichael.Christensen@Sun.COM ds_svc_t *svc; 27097697SMichael.Christensen@Sun.COM ds_port_t *port; 27107697SMichael.Christensen@Sun.COM ds_data_handle_t *data; 27117697SMichael.Christensen@Sun.COM ds_svc_hdl_t svc_hdl; 27127697SMichael.Christensen@Sun.COM int is_client = 0; 27137697SMichael.Christensen@Sun.COM 27147697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "%s: hdl: 0x%llx, buf: %lx, len: %ld" DS_EOL, __func__, 27157697SMichael.Christensen@Sun.COM (u_longlong_t)hdl, (ulong_t)buf, len); 27167697SMichael.Christensen@Sun.COM 27177697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 27187697SMichael.Christensen@Sun.COM 27197697SMichael.Christensen@Sun.COM if ((svc = ds_get_svc(hdl)) == NULL) { 27207697SMichael.Christensen@Sun.COM cmn_err(CE_WARN, "%s: invalid handle 0x%llx" DS_EOL, __func__, 27217697SMichael.Christensen@Sun.COM (u_longlong_t)hdl); 27227697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 27237697SMichael.Christensen@Sun.COM return (ENXIO); 27247697SMichael.Christensen@Sun.COM } 27257697SMichael.Christensen@Sun.COM 27267697SMichael.Christensen@Sun.COM if (svc->state != DS_SVC_ACTIVE) { 27277697SMichael.Christensen@Sun.COM /* channel is up, but svc is not registered */ 27287697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "%s: invalid service state 0x%x" DS_EOL, 27297697SMichael.Christensen@Sun.COM __func__, svc->state); 27307697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 27317697SMichael.Christensen@Sun.COM return (ENOTCONN); 27327697SMichael.Christensen@Sun.COM } 27337697SMichael.Christensen@Sun.COM 27347697SMichael.Christensen@Sun.COM if (svc->flags & DSSF_LOOPBACK) { 27357697SMichael.Christensen@Sun.COM hdl = svc->svc_hdl; 27367697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 27377697SMichael.Christensen@Sun.COM ds_loopback_send(hdl, buf, len); 27387697SMichael.Christensen@Sun.COM return (0); 27397697SMichael.Christensen@Sun.COM } 27407697SMichael.Christensen@Sun.COM 27417697SMichael.Christensen@Sun.COM if ((port = svc->port) == NULL) { 27427697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "%s: service '%s' not associated with a port" 27437697SMichael.Christensen@Sun.COM DS_EOL, __func__, svc->cap.svc_id); 27447697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 27457697SMichael.Christensen@Sun.COM return (ECONNRESET); 27467697SMichael.Christensen@Sun.COM } 27477697SMichael.Christensen@Sun.COM 27487697SMichael.Christensen@Sun.COM if (svc->flags & DSSF_ISCLIENT) { 27497697SMichael.Christensen@Sun.COM is_client = 1; 27507697SMichael.Christensen@Sun.COM svc_hdl = svc->svc_hdl; 27517697SMichael.Christensen@Sun.COM } 27527697SMichael.Christensen@Sun.COM 27537697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 27547697SMichael.Christensen@Sun.COM 27557697SMichael.Christensen@Sun.COM /* check that the LDC channel is ready */ 27567697SMichael.Christensen@Sun.COM if (port->ldc.state != LDC_UP) { 27577697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "%s: LDC channel is not up" DS_EOL, __func__); 27587697SMichael.Christensen@Sun.COM return (ECONNRESET); 27597697SMichael.Christensen@Sun.COM } 27607697SMichael.Christensen@Sun.COM 27617697SMichael.Christensen@Sun.COM hdrlen = DS_HDR_SZ + sizeof (ds_data_handle_t); 27627697SMichael.Christensen@Sun.COM 27637697SMichael.Christensen@Sun.COM msg = DS_MALLOC(len + hdrlen); 27647697SMichael.Christensen@Sun.COM hdr = (ds_hdr_t *)msg; 27657697SMichael.Christensen@Sun.COM payload = msg + hdrlen; 27667697SMichael.Christensen@Sun.COM msglen = len + hdrlen; 27677697SMichael.Christensen@Sun.COM 27687697SMichael.Christensen@Sun.COM hdr->payload_len = len + sizeof (ds_data_handle_t); 27697697SMichael.Christensen@Sun.COM hdr->msg_type = DS_DATA; 27707697SMichael.Christensen@Sun.COM 27717697SMichael.Christensen@Sun.COM data = (ds_data_handle_t *)(msg + DS_HDR_SZ); 27727697SMichael.Christensen@Sun.COM if (is_client) { 27737697SMichael.Christensen@Sun.COM data->svc_handle = svc_hdl; 27747697SMichael.Christensen@Sun.COM } else { 27757697SMichael.Christensen@Sun.COM data->svc_handle = hdl; 27767697SMichael.Christensen@Sun.COM } 27777697SMichael.Christensen@Sun.COM 27787697SMichael.Christensen@Sun.COM if ((buf != NULL) && (len != 0)) { 27797697SMichael.Christensen@Sun.COM (void) memcpy(payload, buf, len); 27807697SMichael.Christensen@Sun.COM } 27817697SMichael.Christensen@Sun.COM 27827697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: data>: hdl=0x%llx, len=%ld, " 27837697SMichael.Christensen@Sun.COM " payload_len=%d" DS_EOL, PORTID(port), (u_longlong_t)svc->hdl, 27847697SMichael.Christensen@Sun.COM msglen, hdr->payload_len); 27857697SMichael.Christensen@Sun.COM DS_DUMP_MSG(DS_DBG_FLAG_PRCL, msg, msglen); 27867697SMichael.Christensen@Sun.COM 27877697SMichael.Christensen@Sun.COM if ((rv = ds_send_msg(port, msg, msglen)) != 0) { 27887697SMichael.Christensen@Sun.COM rv = (rv == EIO) ? ECONNRESET : rv; 27897697SMichael.Christensen@Sun.COM } 27907697SMichael.Christensen@Sun.COM DS_FREE(msg, msglen); 27917697SMichael.Christensen@Sun.COM 27927697SMichael.Christensen@Sun.COM return (rv); 27937697SMichael.Christensen@Sun.COM } 27947697SMichael.Christensen@Sun.COM 27957697SMichael.Christensen@Sun.COM void 27967697SMichael.Christensen@Sun.COM ds_port_common_init(ds_port_t *port) 27977697SMichael.Christensen@Sun.COM { 27987697SMichael.Christensen@Sun.COM int rv; 27997697SMichael.Christensen@Sun.COM 28007697SMichael.Christensen@Sun.COM if ((port->flags & DS_PORT_MUTEX_INITED) == 0) { 28017697SMichael.Christensen@Sun.COM mutex_init(&port->lock, NULL, MUTEX_DRIVER, NULL); 28027697SMichael.Christensen@Sun.COM mutex_init(&port->tx_lock, NULL, MUTEX_DRIVER, NULL); 28037697SMichael.Christensen@Sun.COM mutex_init(&port->rcv_lock, NULL, MUTEX_DRIVER, NULL); 28047697SMichael.Christensen@Sun.COM port->flags |= DS_PORT_MUTEX_INITED; 28057697SMichael.Christensen@Sun.COM } 28067697SMichael.Christensen@Sun.COM 28077697SMichael.Christensen@Sun.COM port->state = DS_PORT_INIT; 28087697SMichael.Christensen@Sun.COM DS_PORTSET_ADD(ds_allports, port->id); 28097697SMichael.Christensen@Sun.COM 28107697SMichael.Christensen@Sun.COM ds_sys_port_init(port); 28117697SMichael.Christensen@Sun.COM 28127697SMichael.Christensen@Sun.COM mutex_enter(&port->lock); 28137697SMichael.Christensen@Sun.COM rv = ds_ldc_init(port); 28147697SMichael.Christensen@Sun.COM mutex_exit(&port->lock); 28157697SMichael.Christensen@Sun.COM 28167697SMichael.Christensen@Sun.COM /* 28177697SMichael.Christensen@Sun.COM * If LDC successfully init'ed, try to kick off protocol for this port. 28187697SMichael.Christensen@Sun.COM */ 28197697SMichael.Christensen@Sun.COM if (rv == 0) { 28207697SMichael.Christensen@Sun.COM ds_handle_up_event(port); 28217697SMichael.Christensen@Sun.COM } 28227697SMichael.Christensen@Sun.COM } 28237697SMichael.Christensen@Sun.COM 28247697SMichael.Christensen@Sun.COM void 28259916SMichael.Christensen@Sun.COM ds_port_common_fini(ds_port_t *port) 28267697SMichael.Christensen@Sun.COM { 28279916SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&port->lock)); 28289916SMichael.Christensen@Sun.COM 28297697SMichael.Christensen@Sun.COM port->state = DS_PORT_FREE; 28307697SMichael.Christensen@Sun.COM 28317697SMichael.Christensen@Sun.COM DS_PORTSET_DEL(ds_allports, port->id); 28327697SMichael.Christensen@Sun.COM 28337697SMichael.Christensen@Sun.COM ds_sys_port_fini(port); 28347697SMichael.Christensen@Sun.COM } 28357697SMichael.Christensen@Sun.COM 28367697SMichael.Christensen@Sun.COM /* 28377697SMichael.Christensen@Sun.COM * Initialize table of registered service classes 28387697SMichael.Christensen@Sun.COM */ 28397697SMichael.Christensen@Sun.COM void 28407697SMichael.Christensen@Sun.COM ds_init_svcs_tbl(uint_t nentries) 28417697SMichael.Christensen@Sun.COM { 28427697SMichael.Christensen@Sun.COM int tblsz; 28437697SMichael.Christensen@Sun.COM 28447697SMichael.Christensen@Sun.COM ds_svcs.maxsvcs = nentries; 28457697SMichael.Christensen@Sun.COM 28467697SMichael.Christensen@Sun.COM tblsz = ds_svcs.maxsvcs * sizeof (ds_svc_t *); 28477697SMichael.Christensen@Sun.COM ds_svcs.tbl = (ds_svc_t **)DS_MALLOC(tblsz); 28487697SMichael.Christensen@Sun.COM 28497697SMichael.Christensen@Sun.COM ds_svcs.nsvcs = 0; 28507697SMichael.Christensen@Sun.COM } 28517697SMichael.Christensen@Sun.COM 28527697SMichael.Christensen@Sun.COM /* 28537697SMichael.Christensen@Sun.COM * Find the max and min version supported. 28547697SMichael.Christensen@Sun.COM * Hacked from zeus workspace, support.c 28557697SMichael.Christensen@Sun.COM */ 28567697SMichael.Christensen@Sun.COM static void 28577697SMichael.Christensen@Sun.COM min_max_versions(int num_versions, ds_ver_t *sup_versionsp, 28587697SMichael.Christensen@Sun.COM uint16_t *min_major, uint16_t *max_major) 28597697SMichael.Christensen@Sun.COM { 28607697SMichael.Christensen@Sun.COM int i; 28617697SMichael.Christensen@Sun.COM 28627697SMichael.Christensen@Sun.COM *min_major = sup_versionsp[0].major; 28637697SMichael.Christensen@Sun.COM *max_major = *min_major; 28647697SMichael.Christensen@Sun.COM 28657697SMichael.Christensen@Sun.COM for (i = 1; i < num_versions; i++) { 28667697SMichael.Christensen@Sun.COM if (sup_versionsp[i].major < *min_major) 28677697SMichael.Christensen@Sun.COM *min_major = sup_versionsp[i].major; 28687697SMichael.Christensen@Sun.COM 28697697SMichael.Christensen@Sun.COM if (sup_versionsp[i].major > *max_major) 28707697SMichael.Christensen@Sun.COM *max_major = sup_versionsp[i].major; 28717697SMichael.Christensen@Sun.COM } 28727697SMichael.Christensen@Sun.COM } 28737697SMichael.Christensen@Sun.COM 28747697SMichael.Christensen@Sun.COM /* 28757697SMichael.Christensen@Sun.COM * Check whether the major and minor numbers requested by the peer can be 28767697SMichael.Christensen@Sun.COM * satisfied. If the requested major is supported, true is returned, and the 28777697SMichael.Christensen@Sun.COM * agreed minor is returned in new_minor. If the requested major is not 28787697SMichael.Christensen@Sun.COM * supported, the routine returns false, and the closest major is returned in 28797697SMichael.Christensen@Sun.COM * *new_major, upon which the peer should re-negotiate. The closest major is 28807697SMichael.Christensen@Sun.COM * the just lower that the requested major number. 28817697SMichael.Christensen@Sun.COM * 28827697SMichael.Christensen@Sun.COM * Hacked from zeus workspace, support.c 28837697SMichael.Christensen@Sun.COM */ 28847697SMichael.Christensen@Sun.COM boolean_t 28857697SMichael.Christensen@Sun.COM negotiate_version(int num_versions, ds_ver_t *sup_versionsp, 28867697SMichael.Christensen@Sun.COM uint16_t req_major, uint16_t *new_majorp, uint16_t *new_minorp) 28877697SMichael.Christensen@Sun.COM { 28887697SMichael.Christensen@Sun.COM int i; 28897697SMichael.Christensen@Sun.COM uint16_t major, lower_major; 28907697SMichael.Christensen@Sun.COM uint16_t min_major = 0, max_major; 28917697SMichael.Christensen@Sun.COM boolean_t found_match = B_FALSE; 28927697SMichael.Christensen@Sun.COM 28937697SMichael.Christensen@Sun.COM min_max_versions(num_versions, sup_versionsp, &min_major, &max_major); 28947697SMichael.Christensen@Sun.COM 28957697SMichael.Christensen@Sun.COM DS_DBG(CE_NOTE, "negotiate_version: req_major = %u, min = %u, max = %u" 28967697SMichael.Christensen@Sun.COM DS_EOL, req_major, min_major, max_major); 28977697SMichael.Christensen@Sun.COM 28987697SMichael.Christensen@Sun.COM /* 28997697SMichael.Christensen@Sun.COM * If the minimum version supported is greater than 29007697SMichael.Christensen@Sun.COM * the version requested, return the lowest version 29017697SMichael.Christensen@Sun.COM * supported 29027697SMichael.Christensen@Sun.COM */ 29037697SMichael.Christensen@Sun.COM if (min_major > req_major) { 29047697SMichael.Christensen@Sun.COM *new_majorp = min_major; 29057697SMichael.Christensen@Sun.COM return (B_FALSE); 29067697SMichael.Christensen@Sun.COM } 29077697SMichael.Christensen@Sun.COM 29087697SMichael.Christensen@Sun.COM /* 29097697SMichael.Christensen@Sun.COM * If the largest version supported is lower than 29107697SMichael.Christensen@Sun.COM * the version requested, return the largest version 29117697SMichael.Christensen@Sun.COM * supported 29127697SMichael.Christensen@Sun.COM */ 29137697SMichael.Christensen@Sun.COM if (max_major < req_major) { 29147697SMichael.Christensen@Sun.COM *new_majorp = max_major; 29157697SMichael.Christensen@Sun.COM return (B_FALSE); 29167697SMichael.Christensen@Sun.COM } 29177697SMichael.Christensen@Sun.COM 29187697SMichael.Christensen@Sun.COM /* 29197697SMichael.Christensen@Sun.COM * Now we know that the requested version lies between the 29207697SMichael.Christensen@Sun.COM * min and max versions supported. Check if the requested 29217697SMichael.Christensen@Sun.COM * major can be found in supported versions. 29227697SMichael.Christensen@Sun.COM */ 29237697SMichael.Christensen@Sun.COM lower_major = min_major; 29247697SMichael.Christensen@Sun.COM for (i = 0; i < num_versions; i++) { 29257697SMichael.Christensen@Sun.COM major = sup_versionsp[i].major; 29267697SMichael.Christensen@Sun.COM if (major == req_major) { 29277697SMichael.Christensen@Sun.COM found_match = B_TRUE; 29287697SMichael.Christensen@Sun.COM *new_majorp = req_major; 29297697SMichael.Christensen@Sun.COM *new_minorp = sup_versionsp[i].minor; 29307697SMichael.Christensen@Sun.COM break; 29317697SMichael.Christensen@Sun.COM } else { 29327697SMichael.Christensen@Sun.COM if ((major < req_major) && (major > lower_major)) 29337697SMichael.Christensen@Sun.COM lower_major = major; 29347697SMichael.Christensen@Sun.COM } 29357697SMichael.Christensen@Sun.COM } 29367697SMichael.Christensen@Sun.COM 29377697SMichael.Christensen@Sun.COM /* 29387697SMichael.Christensen@Sun.COM * If no match is found, return the closest available number 29397697SMichael.Christensen@Sun.COM */ 29407697SMichael.Christensen@Sun.COM if (!found_match) 29417697SMichael.Christensen@Sun.COM *new_majorp = lower_major; 29427697SMichael.Christensen@Sun.COM 29437697SMichael.Christensen@Sun.COM return (found_match); 29447697SMichael.Christensen@Sun.COM } 29457697SMichael.Christensen@Sun.COM 29467697SMichael.Christensen@Sun.COM /* 29477697SMichael.Christensen@Sun.COM * Specific errno's that are used by ds.c and ldc.c 29487697SMichael.Christensen@Sun.COM */ 29497697SMichael.Christensen@Sun.COM static struct { 29507697SMichael.Christensen@Sun.COM int ds_errno; 29517697SMichael.Christensen@Sun.COM char *estr; 29527697SMichael.Christensen@Sun.COM } ds_errno_to_str_tab[] = { 29537697SMichael.Christensen@Sun.COM { EIO, "I/O error" }, 29547697SMichael.Christensen@Sun.COM { ENXIO, "No such device or address" }, 29557697SMichael.Christensen@Sun.COM { EAGAIN, "Resource temporarily unavailable" }, 29567697SMichael.Christensen@Sun.COM { ENOMEM, "Not enough space" }, 29577697SMichael.Christensen@Sun.COM { EACCES, "Permission denied" }, 29587697SMichael.Christensen@Sun.COM { EFAULT, "Bad address" }, 29597697SMichael.Christensen@Sun.COM { EBUSY, "Device busy" }, 29607697SMichael.Christensen@Sun.COM { EINVAL, "Invalid argument" }, 29617697SMichael.Christensen@Sun.COM { ENOSPC, "No space left on device" }, 29627697SMichael.Christensen@Sun.COM { ENOMSG, "No message of desired type" }, 29637697SMichael.Christensen@Sun.COM #ifdef ECHRNG 29647697SMichael.Christensen@Sun.COM { ECHRNG, "Channel number out of range" }, 29657697SMichael.Christensen@Sun.COM #endif 29667697SMichael.Christensen@Sun.COM { ENOTSUP, "Operation not supported" }, 29677697SMichael.Christensen@Sun.COM { EMSGSIZE, "Message too long" }, 29687697SMichael.Christensen@Sun.COM { EADDRINUSE, "Address already in use" }, 29697697SMichael.Christensen@Sun.COM { ECONNRESET, "Connection reset by peer" }, 29707697SMichael.Christensen@Sun.COM { ENOBUFS, "No buffer space available" }, 29717697SMichael.Christensen@Sun.COM { ENOTCONN, "Socket is not connected" }, 29727697SMichael.Christensen@Sun.COM { ECONNREFUSED, "Connection refused" }, 29737697SMichael.Christensen@Sun.COM { EALREADY, "Operation already in progress" }, 29747697SMichael.Christensen@Sun.COM { 0, NULL }, 29757697SMichael.Christensen@Sun.COM }; 29767697SMichael.Christensen@Sun.COM 29777697SMichael.Christensen@Sun.COM char * 29787697SMichael.Christensen@Sun.COM ds_errno_to_str(int ds_errno, char *ebuf) 29797697SMichael.Christensen@Sun.COM { 29807697SMichael.Christensen@Sun.COM int i, en; 29817697SMichael.Christensen@Sun.COM 29827697SMichael.Christensen@Sun.COM for (i = 0; (en = ds_errno_to_str_tab[i].ds_errno) != 0; i++) { 29837697SMichael.Christensen@Sun.COM if (en == ds_errno) { 29847697SMichael.Christensen@Sun.COM (void) strcpy(ebuf, ds_errno_to_str_tab[i].estr); 29857697SMichael.Christensen@Sun.COM return (ebuf); 29867697SMichael.Christensen@Sun.COM } 29877697SMichael.Christensen@Sun.COM } 29887697SMichael.Christensen@Sun.COM 29897697SMichael.Christensen@Sun.COM (void) sprintf(ebuf, "ds_errno (%d)", ds_errno); 29907697SMichael.Christensen@Sun.COM return (ebuf); 29917697SMichael.Christensen@Sun.COM } 29927697SMichael.Christensen@Sun.COM 29937697SMichael.Christensen@Sun.COM static void 29947697SMichael.Christensen@Sun.COM ds_loopback_register(ds_svc_hdl_t hdl) 29957697SMichael.Christensen@Sun.COM { 29968172SMichael.Christensen@Sun.COM ds_ver_t ds_ver; 29977697SMichael.Christensen@Sun.COM ds_svc_t *svc; 29987697SMichael.Christensen@Sun.COM 29997697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 30007697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: entered hdl: 0x%llx" DS_EOL, __func__, 30017697SMichael.Christensen@Sun.COM (u_longlong_t)hdl); 30027697SMichael.Christensen@Sun.COM if ((svc = ds_get_svc(hdl)) == NULL) { 30037697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: invalid hdl: 0x%llx" DS_EOL, __func__, 30047697SMichael.Christensen@Sun.COM (u_longlong_t)hdl); 30057697SMichael.Christensen@Sun.COM return; 30067697SMichael.Christensen@Sun.COM } 30078172SMichael.Christensen@Sun.COM 30087697SMichael.Christensen@Sun.COM svc->state = DS_SVC_ACTIVE; 30097697SMichael.Christensen@Sun.COM 30107697SMichael.Christensen@Sun.COM if (svc->ops.ds_reg_cb) { 30117697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: loopback regcb: hdl: 0x%llx" DS_EOL, 30127697SMichael.Christensen@Sun.COM __func__, (u_longlong_t)hdl); 30137697SMichael.Christensen@Sun.COM ds_ver.major = svc->ver.major; 30147697SMichael.Christensen@Sun.COM ds_ver.minor = svc->ver.minor; 30157697SMichael.Christensen@Sun.COM (*svc->ops.ds_reg_cb)(svc->ops.cb_arg, &ds_ver, hdl); 30167697SMichael.Christensen@Sun.COM } 30177697SMichael.Christensen@Sun.COM } 30187697SMichael.Christensen@Sun.COM 30197697SMichael.Christensen@Sun.COM static void 30207697SMichael.Christensen@Sun.COM ds_loopback_unregister(ds_svc_hdl_t hdl) 30217697SMichael.Christensen@Sun.COM { 30227697SMichael.Christensen@Sun.COM ds_svc_t *svc; 30237697SMichael.Christensen@Sun.COM 30247697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 30257697SMichael.Christensen@Sun.COM if ((svc = ds_get_svc(hdl)) == NULL) { 30267697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: invalid hdl: 0x%llx" DS_EOL, __func__, 30277697SMichael.Christensen@Sun.COM (u_longlong_t)hdl); 30287697SMichael.Christensen@Sun.COM return; 30297697SMichael.Christensen@Sun.COM } 30307697SMichael.Christensen@Sun.COM 30317697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: entered hdl: 0x%llx" DS_EOL, __func__, 30327697SMichael.Christensen@Sun.COM (u_longlong_t)hdl); 30337697SMichael.Christensen@Sun.COM 30347697SMichael.Christensen@Sun.COM svc->flags &= ~DSSF_LOOPBACK; 30357697SMichael.Christensen@Sun.COM svc->svc_hdl = DS_BADHDL2; 30368172SMichael.Christensen@Sun.COM svc->state = DS_SVC_INACTIVE; 30377697SMichael.Christensen@Sun.COM 30387697SMichael.Christensen@Sun.COM if (svc->ops.ds_unreg_cb) { 30397697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: loopback unregcb: hdl: 0x%llx" DS_EOL, 30407697SMichael.Christensen@Sun.COM __func__, (u_longlong_t)hdl); 30417697SMichael.Christensen@Sun.COM (*svc->ops.ds_unreg_cb)(svc->ops.cb_arg); 30427697SMichael.Christensen@Sun.COM } 30437697SMichael.Christensen@Sun.COM } 30447697SMichael.Christensen@Sun.COM 30457697SMichael.Christensen@Sun.COM static void 30467697SMichael.Christensen@Sun.COM ds_loopback_send(ds_svc_hdl_t hdl, void *buf, size_t buflen) 30477697SMichael.Christensen@Sun.COM { 30487697SMichael.Christensen@Sun.COM ds_svc_t *svc; 30497697SMichael.Christensen@Sun.COM 30507697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 30517697SMichael.Christensen@Sun.COM if ((svc = ds_get_svc(hdl)) == NULL) { 30527697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 30537697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: invalid hdl: 0x%llx" DS_EOL, __func__, 30547697SMichael.Christensen@Sun.COM (u_longlong_t)hdl); 30557697SMichael.Christensen@Sun.COM return; 30567697SMichael.Christensen@Sun.COM } 30577697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 30587697SMichael.Christensen@Sun.COM 30597697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: entered hdl: 0x%llx" DS_EOL, __func__, 30607697SMichael.Christensen@Sun.COM (u_longlong_t)hdl); 30617697SMichael.Christensen@Sun.COM 30627697SMichael.Christensen@Sun.COM if (svc->ops.ds_data_cb) { 30637697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: loopback datacb hdl: 0x%llx" DS_EOL, 30647697SMichael.Christensen@Sun.COM __func__, (u_longlong_t)hdl); 30657697SMichael.Christensen@Sun.COM (*svc->ops.ds_data_cb)(svc->ops.cb_arg, buf, buflen); 30667697SMichael.Christensen@Sun.COM } 30677697SMichael.Christensen@Sun.COM } 30687697SMichael.Christensen@Sun.COM 30697697SMichael.Christensen@Sun.COM static int 30708172SMichael.Christensen@Sun.COM ds_loopback_set_svc(ds_svc_t *svc, ds_capability_t *cap, ds_svc_hdl_t *lb_hdlp) 30717697SMichael.Christensen@Sun.COM { 30727697SMichael.Christensen@Sun.COM ds_svc_t *lb_svc; 30738172SMichael.Christensen@Sun.COM ds_svc_hdl_t lb_hdl = *lb_hdlp; 30748172SMichael.Christensen@Sun.COM int i; 30758172SMichael.Christensen@Sun.COM int match = 0; 30768172SMichael.Christensen@Sun.COM uint16_t new_major; 30778172SMichael.Christensen@Sun.COM uint16_t new_minor; 30787697SMichael.Christensen@Sun.COM 30797697SMichael.Christensen@Sun.COM if ((lb_svc = ds_get_svc(lb_hdl)) == NULL) { 30807697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: loopback: hdl: 0x%llx invalid" DS_EOL, 30817697SMichael.Christensen@Sun.COM __func__, (u_longlong_t)lb_hdl); 30827697SMichael.Christensen@Sun.COM return (ENXIO); 30837697SMichael.Christensen@Sun.COM } 30848172SMichael.Christensen@Sun.COM 30858172SMichael.Christensen@Sun.COM /* negotiate a version between loopback services, if possible */ 30868172SMichael.Christensen@Sun.COM for (i = 0; i < lb_svc->cap.nvers && match == 0; i++) { 30878172SMichael.Christensen@Sun.COM match = negotiate_version(cap->nvers, cap->vers, 30888172SMichael.Christensen@Sun.COM lb_svc->cap.vers[i].major, &new_major, &new_minor); 30898172SMichael.Christensen@Sun.COM } 30908172SMichael.Christensen@Sun.COM if (!match) { 30918172SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: loopback version negotiate failed" 30928172SMichael.Christensen@Sun.COM DS_EOL, __func__); 30938172SMichael.Christensen@Sun.COM return (ENOTSUP); 30948172SMichael.Christensen@Sun.COM } 30957697SMichael.Christensen@Sun.COM if (lb_svc->state != DS_SVC_INACTIVE) { 30968172SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: loopback active: hdl: 0x%llx" 30977697SMichael.Christensen@Sun.COM DS_EOL, __func__, (u_longlong_t)lb_hdl); 30987697SMichael.Christensen@Sun.COM if ((lb_svc->flags & DSSF_ISCLIENT) == 0) { 30997697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: loopback busy hdl: 0x%llx" 31007697SMichael.Christensen@Sun.COM DS_EOL, __func__, (u_longlong_t)lb_hdl); 31017697SMichael.Christensen@Sun.COM return (EBUSY); 31027697SMichael.Christensen@Sun.COM } 31038172SMichael.Christensen@Sun.COM svc->state = DS_SVC_INACTIVE; /* prevent alloc'ing svc */ 31047697SMichael.Christensen@Sun.COM lb_svc = ds_svc_clone(lb_svc); 31057697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: loopback clone: ohdl: 0x%llx " 31067697SMichael.Christensen@Sun.COM "nhdl: 0x%llx" DS_EOL, __func__, (u_longlong_t)lb_hdl, 31077697SMichael.Christensen@Sun.COM (u_longlong_t)lb_svc->hdl); 31088172SMichael.Christensen@Sun.COM *lb_hdlp = lb_svc->hdl; 31097697SMichael.Christensen@Sun.COM } 31107697SMichael.Christensen@Sun.COM 31117697SMichael.Christensen@Sun.COM svc->flags |= DSSF_LOOPBACK; 31127697SMichael.Christensen@Sun.COM svc->svc_hdl = lb_svc->hdl; 31137697SMichael.Christensen@Sun.COM svc->port = NULL; 31148172SMichael.Christensen@Sun.COM svc->ver.major = new_major; 31158172SMichael.Christensen@Sun.COM svc->ver.minor = new_minor; 31167697SMichael.Christensen@Sun.COM 31177697SMichael.Christensen@Sun.COM lb_svc->flags |= DSSF_LOOPBACK; 31187697SMichael.Christensen@Sun.COM lb_svc->svc_hdl = svc->hdl; 31197697SMichael.Christensen@Sun.COM lb_svc->port = NULL; 31208172SMichael.Christensen@Sun.COM lb_svc->ver.major = new_major; 31218172SMichael.Christensen@Sun.COM lb_svc->ver.minor = new_minor; 31227697SMichael.Christensen@Sun.COM 31237697SMichael.Christensen@Sun.COM DS_DBG_LOOP(CE_NOTE, "%s: setting loopback between: 0x%llx and 0x%llx" 31247697SMichael.Christensen@Sun.COM DS_EOL, __func__, (u_longlong_t)svc->hdl, 31257697SMichael.Christensen@Sun.COM (u_longlong_t)lb_svc->hdl); 31267697SMichael.Christensen@Sun.COM return (0); 31277697SMichael.Christensen@Sun.COM } 31287697SMichael.Christensen@Sun.COM 31297697SMichael.Christensen@Sun.COM static ds_svc_t * 31307697SMichael.Christensen@Sun.COM ds_find_clnt_svc_by_hdl_port(ds_svc_hdl_t hdl, ds_port_t *port) 31317697SMichael.Christensen@Sun.COM { 31327697SMichael.Christensen@Sun.COM int idx; 31337697SMichael.Christensen@Sun.COM ds_svc_t *svc; 31347697SMichael.Christensen@Sun.COM 31357697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: %s looking up clnt hdl: 0x%llx" DS_EOL, 31367697SMichael.Christensen@Sun.COM PORTID(port), __func__, (u_longlong_t)hdl); 31377697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 31387697SMichael.Christensen@Sun.COM 31397697SMichael.Christensen@Sun.COM /* walk every table entry */ 31407697SMichael.Christensen@Sun.COM for (idx = 0; idx < ds_svcs.maxsvcs; idx++) { 31417697SMichael.Christensen@Sun.COM svc = ds_svcs.tbl[idx]; 31427697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) 31437697SMichael.Christensen@Sun.COM continue; 31447697SMichael.Christensen@Sun.COM if ((svc->flags & DSSF_ISCLIENT) != 0 && 31457697SMichael.Christensen@Sun.COM svc->svc_hdl == hdl && svc->port == port) { 31467697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: %s found clnt hdl " 31477697SMichael.Christensen@Sun.COM "0x%llx: svc%d" DS_EOL, PORTID(port), __func__, 31487697SMichael.Christensen@Sun.COM (u_longlong_t)hdl, (uint_t)DS_HDL2IDX(svc->hdl)); 31497697SMichael.Christensen@Sun.COM return (svc); 31507697SMichael.Christensen@Sun.COM } 31517697SMichael.Christensen@Sun.COM } 31527697SMichael.Christensen@Sun.COM DS_DBG_PRCL(CE_NOTE, "ds@%lx: %s clnt hdl: 0x%llx not found" DS_EOL, 31537697SMichael.Christensen@Sun.COM PORTID(port), __func__, (u_longlong_t)hdl); 31547697SMichael.Christensen@Sun.COM 31557697SMichael.Christensen@Sun.COM return (NULL); 31567697SMichael.Christensen@Sun.COM } 31577697SMichael.Christensen@Sun.COM 31587697SMichael.Christensen@Sun.COM static ds_svc_t * 31597697SMichael.Christensen@Sun.COM ds_svc_clone(ds_svc_t *svc) 31607697SMichael.Christensen@Sun.COM { 31617697SMichael.Christensen@Sun.COM ds_svc_t *newsvc; 31627697SMichael.Christensen@Sun.COM ds_svc_hdl_t hdl; 31637697SMichael.Christensen@Sun.COM 31647697SMichael.Christensen@Sun.COM ASSERT(svc->flags & DSSF_ISCLIENT); 31657697SMichael.Christensen@Sun.COM 31667697SMichael.Christensen@Sun.COM newsvc = ds_alloc_svc(); 31677697SMichael.Christensen@Sun.COM 31687697SMichael.Christensen@Sun.COM /* Can only clone clients for now */ 31697697SMichael.Christensen@Sun.COM hdl = newsvc->hdl | DS_HDL_ISCLIENT_BIT; 31707697SMichael.Christensen@Sun.COM DS_DBG_USR(CE_NOTE, "%s: cloning client: old hdl: 0x%llx new hdl: " 31717697SMichael.Christensen@Sun.COM "0x%llx" DS_EOL, __func__, (u_longlong_t)svc->hdl, 31727697SMichael.Christensen@Sun.COM (u_longlong_t)hdl); 31737697SMichael.Christensen@Sun.COM (void) memcpy(newsvc, svc, sizeof (ds_svc_t)); 31747697SMichael.Christensen@Sun.COM newsvc->hdl = hdl; 31757697SMichael.Christensen@Sun.COM newsvc->flags &= ~DSSF_LOOPBACK; 31767697SMichael.Christensen@Sun.COM newsvc->port = NULL; 31777697SMichael.Christensen@Sun.COM newsvc->svc_hdl = DS_BADHDL2; 31787697SMichael.Christensen@Sun.COM newsvc->cap.svc_id = ds_strdup(svc->cap.svc_id); 31797697SMichael.Christensen@Sun.COM newsvc->cap.vers = DS_MALLOC(svc->cap.nvers * sizeof (ds_ver_t)); 31807697SMichael.Christensen@Sun.COM (void) memcpy(newsvc->cap.vers, svc->cap.vers, 31817697SMichael.Christensen@Sun.COM svc->cap.nvers * sizeof (ds_ver_t)); 31827697SMichael.Christensen@Sun.COM 31837697SMichael.Christensen@Sun.COM /* 31847697SMichael.Christensen@Sun.COM * Kludge to allow lds driver user callbacks to get access to current 31857697SMichael.Christensen@Sun.COM * svc structure. Arg could be index to svc table or some other piece 31867697SMichael.Christensen@Sun.COM * of info to get to the svc table entry. 31877697SMichael.Christensen@Sun.COM */ 31887697SMichael.Christensen@Sun.COM if (newsvc->flags & DSSF_ISUSER) { 31897697SMichael.Christensen@Sun.COM newsvc->ops.cb_arg = (ds_cb_arg_t)(newsvc); 31907697SMichael.Christensen@Sun.COM } 31917697SMichael.Christensen@Sun.COM return (newsvc); 31927697SMichael.Christensen@Sun.COM } 31937697SMichael.Christensen@Sun.COM 31947697SMichael.Christensen@Sun.COM /* 31957697SMichael.Christensen@Sun.COM * Internal handle lookup function. 31967697SMichael.Christensen@Sun.COM */ 31977697SMichael.Christensen@Sun.COM static int 31987697SMichael.Christensen@Sun.COM i_ds_hdl_lookup(char *service, uint_t is_client, ds_svc_hdl_t *hdlp, 31997697SMichael.Christensen@Sun.COM uint_t maxhdls) 32007697SMichael.Christensen@Sun.COM { 32017697SMichael.Christensen@Sun.COM int idx; 32027697SMichael.Christensen@Sun.COM int nhdls = 0; 32037697SMichael.Christensen@Sun.COM ds_svc_t *svc; 32047697SMichael.Christensen@Sun.COM uint32_t client_flag = is_client ? DSSF_ISCLIENT : 0; 32057697SMichael.Christensen@Sun.COM 32067697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 32077697SMichael.Christensen@Sun.COM 32087697SMichael.Christensen@Sun.COM for (idx = 0; idx < ds_svcs.maxsvcs && nhdls < maxhdls; idx++) { 32097697SMichael.Christensen@Sun.COM svc = ds_svcs.tbl[idx]; 32107697SMichael.Christensen@Sun.COM if (DS_SVC_ISFREE(svc)) 32117697SMichael.Christensen@Sun.COM continue; 32127697SMichael.Christensen@Sun.COM if (strcmp(svc->cap.svc_id, service) == 0 && 32137697SMichael.Christensen@Sun.COM (svc->flags & DSSF_ISCLIENT) == client_flag) { 32147697SMichael.Christensen@Sun.COM if (hdlp != NULL && nhdls < maxhdls) { 32157697SMichael.Christensen@Sun.COM hdlp[nhdls] = svc->hdl; 32167697SMichael.Christensen@Sun.COM nhdls++; 32177697SMichael.Christensen@Sun.COM } else { 32187697SMichael.Christensen@Sun.COM nhdls++; 32197697SMichael.Christensen@Sun.COM } 32207697SMichael.Christensen@Sun.COM } 32217697SMichael.Christensen@Sun.COM } 32227697SMichael.Christensen@Sun.COM return (nhdls); 32237697SMichael.Christensen@Sun.COM } 32247697SMichael.Christensen@Sun.COM 32257697SMichael.Christensen@Sun.COM /* 32267697SMichael.Christensen@Sun.COM * Interface for ds_hdl_lookup in lds driver. 32277697SMichael.Christensen@Sun.COM */ 32287697SMichael.Christensen@Sun.COM int 32297697SMichael.Christensen@Sun.COM ds_hdl_lookup(char *service, uint_t is_client, ds_svc_hdl_t *hdlp, 32307697SMichael.Christensen@Sun.COM uint_t maxhdls, uint_t *nhdlsp) 32317697SMichael.Christensen@Sun.COM { 32327697SMichael.Christensen@Sun.COM mutex_enter(&ds_svcs.lock); 32337697SMichael.Christensen@Sun.COM *nhdlsp = i_ds_hdl_lookup(service, is_client, hdlp, maxhdls); 32347697SMichael.Christensen@Sun.COM mutex_exit(&ds_svcs.lock); 32357697SMichael.Christensen@Sun.COM return (0); 32367697SMichael.Christensen@Sun.COM } 32377697SMichael.Christensen@Sun.COM 32387697SMichael.Christensen@Sun.COM /* 32397697SMichael.Christensen@Sun.COM * After an UNREG REQ, check if this is a client service with multiple 32407697SMichael.Christensen@Sun.COM * handles. If it is, then we can eliminate this entry. 32417697SMichael.Christensen@Sun.COM */ 32427697SMichael.Christensen@Sun.COM static void 32437697SMichael.Christensen@Sun.COM ds_check_for_dup_services(ds_svc_t *svc) 32447697SMichael.Christensen@Sun.COM { 32457697SMichael.Christensen@Sun.COM if ((svc->flags & DSSF_ISCLIENT) != 0 && 32467697SMichael.Christensen@Sun.COM svc->state == DS_SVC_INACTIVE && 32477697SMichael.Christensen@Sun.COM i_ds_hdl_lookup(svc->cap.svc_id, 1, NULL, 2) == 2) { 32487697SMichael.Christensen@Sun.COM ds_delete_svc_entry(svc); 32497697SMichael.Christensen@Sun.COM } 32507697SMichael.Christensen@Sun.COM } 32517697SMichael.Christensen@Sun.COM 32527697SMichael.Christensen@Sun.COM static void 32537697SMichael.Christensen@Sun.COM ds_delete_svc_entry(ds_svc_t *svc) 32547697SMichael.Christensen@Sun.COM { 32557697SMichael.Christensen@Sun.COM ds_svc_hdl_t tmp_hdl; 32567697SMichael.Christensen@Sun.COM 32577697SMichael.Christensen@Sun.COM ASSERT(MUTEX_HELD(&ds_svcs.lock)); 32587697SMichael.Christensen@Sun.COM 32597697SMichael.Christensen@Sun.COM /* 32607697SMichael.Christensen@Sun.COM * Clear out the structure, but do not deallocate the 32617697SMichael.Christensen@Sun.COM * memory. It can be reused for the next registration. 32627697SMichael.Christensen@Sun.COM */ 32637697SMichael.Christensen@Sun.COM DS_FREE(svc->cap.svc_id, strlen(svc->cap.svc_id) + 1); 32647697SMichael.Christensen@Sun.COM DS_FREE(svc->cap.vers, svc->cap.nvers * sizeof (ds_ver_t)); 32657697SMichael.Christensen@Sun.COM 32667697SMichael.Christensen@Sun.COM /* save the handle to prevent reuse */ 32677697SMichael.Christensen@Sun.COM tmp_hdl = svc->hdl; 32687697SMichael.Christensen@Sun.COM bzero((void *)svc, sizeof (ds_svc_t)); 32697697SMichael.Christensen@Sun.COM 32707697SMichael.Christensen@Sun.COM /* initialize for next use */ 32717697SMichael.Christensen@Sun.COM svc->hdl = tmp_hdl; 32727697SMichael.Christensen@Sun.COM svc->state = DS_SVC_FREE; 32737697SMichael.Christensen@Sun.COM 32747697SMichael.Christensen@Sun.COM ds_svcs.nsvcs--; 32757697SMichael.Christensen@Sun.COM } 3276