Home | History | Annotate | Download | only in io
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*
     28  * Domain Services Module Common Code.
     29  *
     30  * This module is intended to be used by both Solaris and the VBSC
     31  * module.
     32  */
     33 
     34 #include <sys/modctl.h>
     35 #include <sys/ksynch.h>
     36 #include <sys/taskq.h>
     37 #include <sys/disp.h>
     38 #include <sys/cmn_err.h>
     39 #include <sys/note.h>
     40 #include <sys/mach_descrip.h>
     41 #include <sys/mdesc.h>
     42 #include <sys/ldc.h>
     43 #include <sys/ds.h>
     44 #include <sys/ds_impl.h>
     45 
     46 #ifndef MIN
     47 #define	MIN(a, b)	((a) < (b) ? (a) : (b))
     48 #endif
     49 
     50 #define	DS_DECODE_BUF_LEN		30
     51 
     52 /*
     53  * All DS ports in the system
     54  *
     55  * The list of DS ports is read in from the MD when the DS module is
     56  * initialized and is never modified. This eliminates the need for
     57  * locking to access the port array itself. Access to the individual
     58  * ports are synchronized at the port level.
     59  */
     60 ds_port_t	ds_ports[DS_MAX_PORTS];
     61 ds_portset_t	ds_allports;	/* all DS ports in the system */
     62 ds_portset_t	ds_nullport;	/* allows test against null portset */
     63 
     64 /* DS SP port id */
     65 uint64_t ds_sp_port_id = DS_PORTID_INVALID;
     66 
     67 /*
     68  * Table of registered services
     69  *
     70  * Locking: Accesses to the table of services are synchronized using
     71  *   a mutex lock. The reader lock must be held when looking up service
     72  *   information in the table. The writer lock must be held when any
     73  *   service information is being modified.
     74  */
     75 ds_svcs_t	ds_svcs;
     76 
     77 /*
     78  * Flag to prevent callbacks while in the middle of DS teardown.
     79  */
     80 boolean_t ds_enabled = B_FALSE;	/* enable/disable taskq processing */
     81 
     82 /*
     83  * Retry count and delay for LDC reads and writes
     84  */
     85 #ifndef DS_DEFAULT_RETRIES
     86 #define	DS_DEFAULT_RETRIES	10000	/* number of times to retry */
     87 #endif
     88 #ifndef DS_DEFAULT_DELAY
     89 #define	DS_DEFAULT_DELAY	1000	/* usecs to wait between retries */
     90 #endif
     91 
     92 static int ds_retries = DS_DEFAULT_RETRIES;
     93 static clock_t ds_delay = DS_DEFAULT_DELAY;
     94 
     95 /*
     96  * Supported versions of the DS message protocol
     97  *
     98  * The version array must be sorted in order from the highest
     99  * supported version to the lowest. Support for a particular
    100  * <major>.<minor> version implies all lower minor versions of
    101  * that same major version are supported as well.
    102  */
    103 static ds_ver_t ds_vers[] = { { 1, 0 } };
    104 
    105 #define	DS_NUM_VER	(sizeof (ds_vers) / sizeof (ds_vers[0]))
    106 
    107 
    108 /* incoming message handling functions */
    109 typedef void (*ds_msg_handler_t)(ds_port_t *port, caddr_t buf, size_t len);
    110 static void ds_handle_init_req(ds_port_t *port, caddr_t buf, size_t len);
    111 static void ds_handle_init_ack(ds_port_t *port, caddr_t buf, size_t len);
    112 static void ds_handle_init_nack(ds_port_t *port, caddr_t buf, size_t len);
    113 static void ds_handle_reg_req(ds_port_t *port, caddr_t buf, size_t len);
    114 static void ds_handle_reg_ack(ds_port_t *port, caddr_t buf, size_t len);
    115 static void ds_handle_reg_nack(ds_port_t *port, caddr_t buf, size_t len);
    116 static void ds_handle_unreg_req(ds_port_t *port, caddr_t buf, size_t len);
    117 static void ds_handle_unreg_ack(ds_port_t *port, caddr_t buf, size_t len);
    118 static void ds_handle_unreg_nack(ds_port_t *port, caddr_t buf, size_t len);
    119 static void ds_handle_data(ds_port_t *port, caddr_t buf, size_t len);
    120 static void ds_handle_nack(ds_port_t *port, caddr_t buf, size_t len);
    121 
    122 /*
    123  * DS Message Handler Dispatch Table
    124  *
    125  * A table used to dispatch all incoming messages. This table
    126  * contains handlers for all the fixed message types, as well as
    127  * the the messages defined in the 1.0 version of the DS protocol.
    128  * The handlers are indexed based on the DS header msg_type values
    129  */
    130 static const ds_msg_handler_t ds_msg_handlers[] = {
    131 	ds_handle_init_req,		/* DS_INIT_REQ */
    132 	ds_handle_init_ack,		/* DS_INIT_ACK */
    133 	ds_handle_init_nack,		/* DS_INIT_NACK */
    134 	ds_handle_reg_req,		/* DS_REG_REQ */
    135 	ds_handle_reg_ack,		/* DS_REG_ACK */
    136 	ds_handle_reg_nack,		/* DS_REG_NACK */
    137 	ds_handle_unreg_req,		/* DS_UNREG */
    138 	ds_handle_unreg_ack,		/* DS_UNREG_ACK */
    139 	ds_handle_unreg_nack,		/* DS_UNREG_NACK */
    140 	ds_handle_data,			/* DS_DATA */
    141 	ds_handle_nack			/* DS_NACK */
    142 };
    143 
    144 
    145 
    146 /* initialization functions */
    147 static int ds_ldc_init(ds_port_t *port);
    148 
    149 /* event processing functions */
    150 static uint_t ds_ldc_cb(uint64_t event, caddr_t arg);
    151 static int ds_recv_msg(ds_port_t *port, caddr_t msgp, size_t *sizep);
    152 static void ds_handle_up_event(ds_port_t *port);
    153 static void ds_handle_down_reset_events(ds_port_t *port);
    154 static void ds_handle_recv(void *arg);
    155 static void ds_dispatch_event(void *arg);
    156 
    157 /* message sending functions */
    158 static int ds_send_msg(ds_port_t *port, caddr_t msg, size_t msglen);
    159 static int ds_send_reg_req(ds_svc_t *svc, ds_port_t *port);
    160 static void ds_send_unreg_nack(ds_port_t *port, ds_svc_hdl_t bad_hdl);
    161 static void ds_send_data_nack(ds_port_t *port, ds_svc_hdl_t bad_hdl);
    162 
    163 /* walker functions */
    164 static int ds_svc_isfree(ds_svc_t *svc, void *arg);
    165 static int ds_svc_unregister(ds_svc_t *svc, void *arg);
    166 static int ds_svc_port_up(ds_svc_t *svc, void *arg);
    167 
    168 /* service utilities */
    169 static void ds_reset_svc(ds_svc_t *svc, ds_port_t *port);
    170 static int ds_svc_register_onport(ds_svc_t *svc, ds_port_t *port);
    171 static int ds_svc_register_onport_walker(ds_svc_t *svc, void *arg);
    172 static void ds_set_port_ready(ds_port_t *port, uint16_t major, uint16_t minor);
    173 
    174 /* port utilities */
    175 static void ds_port_reset(ds_port_t *port);
    176 static ldc_status_t ds_update_ldc_state(ds_port_t *port);
    177 
    178 /* misc utilities */
    179 static void min_max_versions(int num_versions, ds_ver_t *sup_versionsp,
    180     uint16_t *min_major, uint16_t *max_major);
    181 
    182 /* debug */
    183 static char *decode_ldc_events(uint64_t event, char *buf);
    184 
    185 /* loopback */
    186 static void ds_loopback_register(ds_svc_hdl_t hdl);
    187 static void ds_loopback_unregister(ds_svc_hdl_t hdl);
    188 static void ds_loopback_send(ds_svc_hdl_t hdl, void *buf, size_t buflen);
    189 static int ds_loopback_set_svc(ds_svc_t *svc, ds_capability_t *cap,
    190     ds_svc_hdl_t *lb_hdlp);
    191 
    192 /* client handling */
    193 static int i_ds_hdl_lookup(char *service, uint_t is_client, ds_svc_hdl_t *hdlp,
    194     uint_t maxhdls);
    195 static ds_svc_t *ds_find_clnt_svc_by_hdl_port(ds_svc_hdl_t hdl,
    196     ds_port_t *port);
    197 static ds_svc_t *ds_find_svc_by_id_port(char *svc_id, int is_client,
    198     ds_port_t *port);
    199 static ds_svc_t *ds_svc_clone(ds_svc_t *svc);
    200 static void ds_check_for_dup_services(ds_svc_t *svc);
    201 static void ds_delete_svc_entry(ds_svc_t *svc);
    202 
    203 char *
    204 ds_strdup(char *str)
    205 {
    206 	char *newstr;
    207 
    208 	newstr = DS_MALLOC(strlen(str) + 1);
    209 	(void) strcpy(newstr, str);
    210 	return (newstr);
    211 }
    212 
    213 void
    214 ds_common_init(void)
    215 {
    216 	/* Validate version table */
    217 	ASSERT(ds_vers_isvalid(ds_vers, DS_NUM_VER) == DS_VERS_OK);
    218 
    219 	/* Initialize services table */
    220 	ds_init_svcs_tbl(DS_MAXSVCS_INIT);
    221 
    222 	/* enable callback processing */
    223 	ds_enabled = B_TRUE;
    224 }
    225 
    226 /* BEGIN LDC SUPPORT FUNCTIONS */
    227 
    228 static char *
    229 decode_ldc_events(uint64_t event, char *buf)
    230 {
    231 	buf[0] = 0;
    232 	if (event & LDC_EVT_DOWN)	(void) strcat(buf, " DOWN");
    233 	if (event & LDC_EVT_RESET)	(void) strcat(buf, " RESET");
    234 	if (event & LDC_EVT_UP)		(void) strcat(buf, " UP");
    235 	if (event & LDC_EVT_READ)	(void) strcat(buf, " READ");
    236 	if (event & LDC_EVT_WRITE)	(void) strcat(buf, " WRITE");
    237 	return (buf);
    238 }
    239 
    240 static ldc_status_t
    241 ds_update_ldc_state(ds_port_t *port)
    242 {
    243 	ldc_status_t	ldc_state;
    244 	int		rv;
    245 	char		ebuf[DS_EBUFSIZE];
    246 
    247 	ASSERT(MUTEX_HELD(&port->lock));
    248 
    249 	/*
    250 	 * Read status and update ldc state info in port structure.
    251 	 */
    252 	if ((rv = ldc_status(port->ldc.hdl, &ldc_state)) != 0) {
    253 		cmn_err(CE_WARN, "ds@%lx: %s: ldc_status error: %s" DS_EOL,
    254 		    PORTID(port), __func__, ds_errno_to_str(rv, ebuf));
    255 		ldc_state = port->ldc.state;
    256 	} else {
    257 		port->ldc.state = ldc_state;
    258 	}
    259 
    260 	return (ldc_state);
    261 }
    262 
    263 static void
    264 ds_handle_down_reset_events(ds_port_t *port)
    265 {
    266 	DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: entered" DS_EOL, PORTID(port),
    267 	    __func__);
    268 
    269 	mutex_enter(&ds_svcs.lock);
    270 	mutex_enter(&port->lock);
    271 
    272 	ds_sys_drain_events(port);
    273 
    274 	(void) ds_update_ldc_state(port);
    275 
    276 	/* reset the port state */
    277 	ds_port_reset(port);
    278 
    279 	/* acknowledge the reset */
    280 	(void) ldc_up(port->ldc.hdl);
    281 
    282 	mutex_exit(&port->lock);
    283 	mutex_exit(&ds_svcs.lock);
    284 
    285 	ds_handle_up_event(port);
    286 
    287 	DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: exit" DS_EOL, PORTID(port), __func__);
    288 }
    289 
    290 static void
    291 ds_handle_up_event(ds_port_t *port)
    292 {
    293 	ldc_status_t	ldc_state;
    294 
    295 	DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: entered" DS_EOL, PORTID(port),
    296 	    __func__);
    297 
    298 	mutex_enter(&port->lock);
    299 
    300 	ldc_state = ds_update_ldc_state(port);
    301 
    302 	mutex_exit(&port->lock);
    303 
    304 	if ((ldc_state == LDC_UP) && IS_DS_PORT(port)) {
    305 		/*
    306 		 * Initiate the handshake.
    307 		 */
    308 		ds_send_init_req(port);
    309 	}
    310 
    311 	DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: exit" DS_EOL, PORTID(port), __func__);
    312 }
    313 
    314 static uint_t
    315 ds_ldc_cb(uint64_t event, caddr_t arg)
    316 {
    317 	ds_port_t	*port = (ds_port_t *)arg;
    318 	char		evstring[DS_DECODE_BUF_LEN];
    319 
    320 	DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: %s event (%llx) received" DS_EOL,
    321 	    PORTID(port), __func__, decode_ldc_events(event, evstring),
    322 	    (u_longlong_t)event);
    323 
    324 	if (!ds_enabled) {
    325 		DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: callback handling is disabled"
    326 		    DS_EOL, PORTID(port), __func__);
    327 		return (LDC_SUCCESS);
    328 	}
    329 
    330 	if (event & (LDC_EVT_DOWN | LDC_EVT_RESET)) {
    331 		ds_handle_down_reset_events(port);
    332 		goto done;
    333 	}
    334 
    335 	if (event & LDC_EVT_UP) {
    336 		ds_handle_up_event(port);
    337 	}
    338 
    339 	if (event & LDC_EVT_READ) {
    340 		if (port->ldc.state != LDC_UP) {
    341 			cmn_err(CE_WARN, "ds@%lx: %s: LDC READ event while "
    342 			    "port not up" DS_EOL, PORTID(port), __func__);
    343 			goto done;
    344 		}
    345 
    346 		if (ds_sys_dispatch_func(ds_handle_recv, port)) {
    347 			cmn_err(CE_WARN, "ds@%lx: error initiating LDC READ "
    348 			    " event", PORTID(port));
    349 		}
    350 	}
    351 
    352 	if (event & LDC_EVT_WRITE) {
    353 		DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: LDC WRITE event received, "
    354 		    "not supported" DS_EOL, PORTID(port), __func__);
    355 	}
    356 
    357 	if (event & ~(LDC_EVT_UP | LDC_EVT_READ)) {
    358 		cmn_err(CE_WARN, "ds@%lx: %s: Unexpected LDC event received: "
    359 		    "0x%llx" DS_EOL, PORTID(port), __func__,
    360 		    (u_longlong_t)event);
    361 	}
    362 done:
    363 	DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: exit" DS_EOL, PORTID(port), __func__);
    364 
    365 	return (LDC_SUCCESS);
    366 }
    367 
    368 static int
    369 ds_ldc_init(ds_port_t *port)
    370 {
    371 	int		rv;
    372 	ldc_attr_t	ldc_attr;
    373 	caddr_t		ldc_cb_arg = (caddr_t)port;
    374 	char		ebuf[DS_EBUFSIZE];
    375 
    376 	ASSERT(MUTEX_HELD(&port->lock));
    377 
    378 	DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: ldc_id=%lld" DS_EOL,
    379 	    PORTID(port), __func__, (u_longlong_t)port->ldc.id);
    380 
    381 	ldc_attr.devclass = LDC_DEV_GENERIC;
    382 	ldc_attr.instance = 0;
    383 	ldc_attr.mode = LDC_MODE_RELIABLE;
    384 	ldc_attr.mtu = DS_STREAM_MTU;
    385 
    386 	if ((rv = ldc_init(port->ldc.id, &ldc_attr, &port->ldc.hdl)) != 0) {
    387 		cmn_err(CE_WARN, "ds@%lx: %s: ldc_id: %lx, ldc_init error: %s"
    388 		    DS_EOL, PORTID(port), __func__, port->ldc.id,
    389 		    ds_errno_to_str(rv, ebuf));
    390 		return (rv);
    391 	}
    392 
    393 	rv = ldc_reg_callback(port->ldc.hdl, ds_ldc_cb, ldc_cb_arg);
    394 	if (rv != 0) {
    395 		cmn_err(CE_WARN, "ds@%lx: %s: ldc_reg_callback error: %s"
    396 		    DS_EOL, PORTID(port), __func__, ds_errno_to_str(rv, ebuf));
    397 		return (rv);
    398 	}
    399 
    400 	ds_sys_ldc_init(port);
    401 	return (0);
    402 }
    403 
    404 int
    405 ds_ldc_fini(ds_port_t *port)
    406 {
    407 	int	rv;
    408 	char	ebuf[DS_EBUFSIZE];
    409 
    410 	ASSERT(port->state >= DS_PORT_LDC_INIT);
    411 	ASSERT(MUTEX_HELD(&port->lock));
    412 
    413 	DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: ldc_id=%ld" DS_EOL, PORTID(port),
    414 	    __func__, port->ldc.id);
    415 
    416 	if ((rv = ldc_close(port->ldc.hdl)) != 0) {
    417 		cmn_err(CE_WARN, "ds@%lx: %s: ldc_close error: %s" DS_EOL,
    418 		    PORTID(port), __func__, ds_errno_to_str(rv, ebuf));
    419 		return (rv);
    420 	}
    421 
    422 	if ((rv = ldc_unreg_callback(port->ldc.hdl)) != 0) {
    423 		cmn_err(CE_WARN, "ds@%lx: %s: ldc_unreg_callback error: %s"
    424 		    DS_EOL, PORTID(port), __func__, ds_errno_to_str(rv, ebuf));
    425 		return (rv);
    426 	}
    427 
    428 	if ((rv = ldc_fini(port->ldc.hdl)) != 0) {
    429 		cmn_err(CE_WARN, "ds@%lx: %s: ldc_fini error: %s" DS_EOL,
    430 		    PORTID(port), __func__, ds_errno_to_str(rv, ebuf));
    431 		return (rv);
    432 	}
    433 
    434 	port->ldc.id = (uint64_t)-1;
    435 	port->ldc.hdl = NULL;
    436 	port->ldc.state = 0;
    437 
    438 	return (rv);
    439 }
    440 
    441 /*
    442  * Attempt to read a specified number of bytes from a particular LDC.
    443  * Returns zero for success or the return code from the LDC read on
    444  * failure. The actual number of bytes read from the LDC is returned
    445  * in the size parameter.
    446  */
    447 static int
    448 ds_recv_msg(ds_port_t *port, caddr_t msgp, size_t *sizep)
    449 {
    450 	int	rv = 0;
    451 	size_t	bytes_req = *sizep;
    452 	size_t	bytes_left = bytes_req;
    453 	size_t	nbytes;
    454 	int	retry_count = 0;
    455 	char	ebuf[DS_EBUFSIZE];
    456 
    457 	ASSERT(MUTEX_HELD(&port->rcv_lock));
    458 
    459 	*sizep = 0;
    460 
    461 	DS_DBG_LDC(CE_NOTE, "ds@%lx: attempting to read %ld bytes" DS_EOL,
    462 	    PORTID(port), bytes_req);
    463 
    464 	while (bytes_left > 0) {
    465 
    466 		nbytes = bytes_left;
    467 
    468 		mutex_enter(&port->lock);
    469 		if (port->ldc.state == LDC_UP) {
    470 			rv = ldc_read(port->ldc.hdl, msgp, &nbytes);
    471 		} else
    472 			rv = ENXIO;
    473 		mutex_exit(&port->lock);
    474 		if (rv != 0) {
    475 			if (rv == ECONNRESET) {
    476 				break;
    477 			} else if (rv != EAGAIN) {
    478 				cmn_err(CE_NOTE, "ds@%lx: %s: %s" DS_EOL,
    479 				    PORTID(port), __func__,
    480 				    ds_errno_to_str(rv, ebuf));
    481 				break;
    482 			}
    483 		} else {
    484 			if (nbytes != 0) {
    485 				DS_DBG_LDC(CE_NOTE, "ds@%lx: "
    486 				    "read %ld bytes, %d retries" DS_EOL,
    487 				    PORTID(port), nbytes, retry_count);
    488 
    489 				*sizep += nbytes;
    490 				msgp += nbytes;
    491 				bytes_left -= nbytes;
    492 
    493 				/* reset counter on a successful read */
    494 				retry_count = 0;
    495 				continue;
    496 			}
    497 
    498 			/*
    499 			 * No data was read. Check if this is the
    500 			 * first attempt. If so, just return since
    501 			 * nothing has been read yet.
    502 			 */
    503 			if (bytes_left == bytes_req) {
    504 				DS_DBG_LDC(CE_NOTE, "ds@%lx: read zero bytes, "
    505 				    " no data available" DS_EOL, PORTID(port));
    506 				break;
    507 			}
    508 		}
    509 
    510 		/*
    511 		 * A retry is necessary because the read returned
    512 		 * EAGAIN, or a zero length read occurred after
    513 		 * reading a partial message.
    514 		 */
    515 		if (retry_count++ >= ds_retries) {
    516 			DS_DBG_LDC(CE_NOTE, "ds@%lx: timed out waiting for "
    517 			    "message" DS_EOL, PORTID(port));
    518 			break;
    519 		}
    520 
    521 		drv_usecwait(ds_delay);
    522 	}
    523 
    524 	return (rv);
    525 }
    526 
    527 static void
    528 ds_handle_recv(void *arg)
    529 {
    530 	ds_port_t	*port = (ds_port_t *)arg;
    531 	char		*hbuf;
    532 	size_t		msglen;
    533 	size_t		read_size;
    534 	boolean_t	hasdata;
    535 	ds_hdr_t	hdr;
    536 	uint8_t		*msg;
    537 	char		*currp;
    538 	int		rv;
    539 	ds_event_t	*devent;
    540 
    541 	DS_DBG_LDC(CE_NOTE, "ds@%lx: %s..." DS_EOL, PORTID(port), __func__);
    542 
    543 	/*
    544 	 * Read messages from the channel until there are none
    545 	 * pending. Valid messages are dispatched to be handled
    546 	 * by a separate thread while any malformed messages are
    547 	 * dropped.
    548 	 */
    549 
    550 	mutex_enter(&port->rcv_lock);
    551 
    552 	for (;;) {
    553 		mutex_enter(&port->lock);
    554 		if (port->ldc.state == LDC_UP) {
    555 			rv = ldc_chkq(port->ldc.hdl, &hasdata);
    556 		} else
    557 			rv = ENXIO;
    558 		mutex_exit(&port->lock);
    559 		if (rv != 0 || !hasdata)
    560 			break;
    561 
    562 		DS_DBG(CE_NOTE, "ds@%lx: %s: reading next message" DS_EOL,
    563 		    PORTID(port), __func__);
    564 
    565 		/*
    566 		 * Read in the next message.
    567 		 */
    568 		hbuf = (char *)&hdr;
    569 		bzero(hbuf, DS_HDR_SZ);
    570 		read_size = DS_HDR_SZ;
    571 		currp = hbuf;
    572 
    573 		/* read in the message header */
    574 		if ((rv = ds_recv_msg(port, currp, &read_size)) != 0) {
    575 			break;
    576 		}
    577 
    578 		if (read_size < DS_HDR_SZ) {
    579 			/*
    580 			 * A zero length read is a valid signal that
    581 			 * there is no data left on the channel.
    582 			 */
    583 			if (read_size != 0) {
    584 				cmn_err(CE_WARN, "ds@%lx: invalid message "
    585 				    "length, received %ld bytes, expected %ld"
    586 				    DS_EOL, PORTID(port), read_size, DS_HDR_SZ);
    587 			}
    588 			continue;
    589 		}
    590 
    591 		/* get payload size and allocate a buffer */
    592 		read_size = ((ds_hdr_t *)hbuf)->payload_len;
    593 		msglen = DS_HDR_SZ + read_size;
    594 		msg = DS_MALLOC(msglen);
    595 		if (!msg) {
    596 			cmn_err(CE_WARN, "Memory allocation failed attempting "
    597 			    " to allocate %d bytes." DS_EOL, (int)msglen);
    598 			continue;
    599 		}
    600 
    601 		DS_DBG(CE_NOTE, "ds@%lx: %s: message payload len %d" DS_EOL,
    602 		    PORTID(port), __func__, (int)read_size);
    603 
    604 		/* move message header into buffer */
    605 		(void) memcpy(msg, hbuf, DS_HDR_SZ);
    606 		currp = (char *)(msg) + DS_HDR_SZ;
    607 
    608 		/* read in the message body */
    609 		if ((rv = ds_recv_msg(port, currp, &read_size)) != 0) {
    610 			DS_FREE(msg, msglen);
    611 			break;
    612 		}
    613 
    614 		/* validate the size of the message */
    615 		if ((DS_HDR_SZ + read_size) != msglen) {
    616 			cmn_err(CE_WARN, "ds@%lx: %s: invalid message length, "
    617 			    "received %ld bytes, expected %ld" DS_EOL,
    618 			    PORTID(port), __func__, (DS_HDR_SZ + read_size),
    619 			    msglen);
    620 			DS_FREE(msg, msglen);
    621 			continue;
    622 		}
    623 
    624 		DS_DUMP_MSG(DS_DBG_FLAG_LDC, msg, msglen);
    625 
    626 		/*
    627 		 * Send the message for processing, and store it
    628 		 * in the log. The memory is deallocated only when
    629 		 * the message is removed from the log.
    630 		 */
    631 
    632 		devent = DS_MALLOC(sizeof (ds_event_t));
    633 		devent->port = port;
    634 		devent->buf = (char *)msg;
    635 		devent->buflen = msglen;
    636 
    637 		/* log the message */
    638 		(void) ds_log_add_msg(DS_LOG_IN(port->id), msg, msglen);
    639 
    640 		if (ds_sys_dispatch_func(ds_dispatch_event, devent)) {
    641 			cmn_err(CE_WARN, "ds@%lx: error initiating "
    642 			    "event handler", PORTID(port));
    643 			DS_FREE(devent, sizeof (ds_event_t));
    644 		}
    645 	}
    646 
    647 	mutex_exit(&port->rcv_lock);
    648 
    649 	/* handle connection reset errors returned from ds_recv_msg */
    650 	if (rv == ECONNRESET) {
    651 		ds_handle_down_reset_events(port);
    652 	}
    653 
    654 	DS_DBG_LDC(CE_NOTE, "ds@%lx: %s done" DS_EOL, PORTID(port), __func__);
    655 }
    656 
    657 static void
    658 ds_dispatch_event(void *arg)
    659 {
    660 	ds_event_t	*event = (ds_event_t *)arg;
    661 	ds_hdr_t	*hdr;
    662 	ds_port_t	*port;
    663 
    664 	port = event->port;
    665 
    666 	hdr = (ds_hdr_t *)event->buf;
    667 
    668 	if (DS_MSG_TYPE_VALID(hdr->msg_type)) {
    669 		DS_DBG(CE_NOTE, "ds@%lx: dispatch_event: msg_type=%d" DS_EOL,
    670 		    PORTID(port), hdr->msg_type);
    671 
    672 		(*ds_msg_handlers[hdr->msg_type])(port, event->buf,
    673 		    event->buflen);
    674 	} else {
    675 		cmn_err(CE_WARN, "ds@%lx: dispatch_event: invalid msg "
    676 		    "type (%d)" DS_EOL, PORTID(port), hdr->msg_type);
    677 	}
    678 
    679 	DS_FREE(event->buf, event->buflen);
    680 	DS_FREE(event, sizeof (ds_event_t));
    681 }
    682 
    683 int
    684 ds_send_msg(ds_port_t *port, caddr_t msg, size_t msglen)
    685 {
    686 	int	rv;
    687 	caddr_t	currp = msg;
    688 	size_t	amt_left = msglen;
    689 	int	loopcnt = 0;
    690 
    691 	DS_DBG_LDC(CE_NOTE, "ds@%lx: %s msglen: %ld" DS_EOL, PORTID(port),
    692 	    __func__, msglen);
    693 	DS_DUMP_MSG(DS_DBG_FLAG_LDC, msg, msglen);
    694 
    695 	(void) ds_log_add_msg(DS_LOG_OUT(port->id), (uint8_t *)msg, msglen);
    696 
    697 	/*
    698 	 * Ensure that no other messages can be sent on this port by holding
    699 	 * the tx_lock mutex in case the write doesn't get sent with one write.
    700 	 * This guarantees that the message doesn't become fragmented.
    701 	 */
    702 	mutex_enter(&port->tx_lock);
    703 
    704 	do {
    705 		mutex_enter(&port->lock);
    706 		if (port->ldc.state == LDC_UP) {
    707 			rv = ldc_write(port->ldc.hdl, currp, &msglen);
    708 		} else
    709 			rv = ENXIO;
    710 		mutex_exit(&port->lock);
    711 		if (rv != 0) {
    712 			if (rv == ECONNRESET) {
    713 				mutex_exit(&port->tx_lock);
    714 				(void) ds_sys_dispatch_func((void (*)(void *))
    715 				    ds_handle_down_reset_events, port);
    716 				return (rv);
    717 			} else if ((rv == EWOULDBLOCK) &&
    718 			    (loopcnt++ < ds_retries)) {
    719 				drv_usecwait(ds_delay);
    720 			} else {
    721 				DS_DBG_PRCL(CE_NOTE, "ds@%lx: send_msg: "
    722 				    "ldc_write failed (%d), %d bytes "
    723 				    "remaining" DS_EOL, PORTID(port), rv,
    724 				    (int)amt_left);
    725 				goto error;
    726 			}
    727 		} else {
    728 			amt_left -= msglen;
    729 			currp += msglen;
    730 			msglen = amt_left;
    731 			loopcnt = 0;
    732 		}
    733 	} while (amt_left > 0);
    734 error:
    735 	mutex_exit(&port->tx_lock);
    736 
    737 	return (rv);
    738 }
    739 
    740 /* END LDC SUPPORT FUNCTIONS */
    741 
    742 
    743 /* BEGIN DS PROTOCOL SUPPORT FUNCTIONS */
    744 
    745 static void
    746 ds_handle_init_req(ds_port_t *port, caddr_t buf, size_t len)
    747 {
    748 	ds_hdr_t	*hdr;
    749 	ds_init_ack_t	*ack;
    750 	ds_init_nack_t	*nack;
    751 	char		*msg;
    752 	size_t		msglen;
    753 	ds_init_req_t	*req;
    754 	size_t		explen = DS_MSG_LEN(ds_init_req_t);
    755 	uint16_t	new_major;
    756 	uint16_t	new_minor;
    757 	boolean_t	match;
    758 
    759 	/* sanity check the incoming message */
    760 	if (len != explen) {
    761 		cmn_err(CE_WARN, "ds@%lx: <init_req: invalid message "
    762 		    "length (%ld), expected %ld" DS_EOL, PORTID(port), len,
    763 		    explen);
    764 		return;
    765 	}
    766 
    767 	req = (ds_init_req_t *)(buf + DS_HDR_SZ);
    768 
    769 	DS_DBG_PRCL(CE_NOTE, "ds@%lx: <init_req: ver=%d.%d" DS_EOL,
    770 	    PORTID(port), req->major_vers, req->minor_vers);
    771 
    772 	match = negotiate_version(DS_NUM_VER, &ds_vers[0],
    773 	    req->major_vers, &new_major, &new_minor);
    774 
    775 	/*
    776 	 * Check version info. ACK only if the major numbers exactly
    777 	 * match. The service entity can retry with a new minor
    778 	 * based on the response sent as part of the NACK.
    779 	 */
    780 	if (match) {
    781 		msglen = DS_MSG_LEN(ds_init_ack_t);
    782 		msg = DS_MALLOC(msglen);
    783 
    784 		hdr = (ds_hdr_t *)msg;
    785 		hdr->msg_type = DS_INIT_ACK;
    786 		hdr->payload_len = sizeof (ds_init_ack_t);
    787 
    788 		ack = (ds_init_ack_t *)(msg + DS_HDR_SZ);
    789 		ack->minor_vers = MIN(new_minor, req->minor_vers);
    790 
    791 		DS_DBG_PRCL(CE_NOTE, "ds@%lx: init_ack>: minor=0x%04X" DS_EOL,
    792 		    PORTID(port), MIN(new_minor, req->minor_vers));
    793 	} else {
    794 		msglen = DS_MSG_LEN(ds_init_nack_t);
    795 		msg = DS_MALLOC(msglen);
    796 
    797 		hdr = (ds_hdr_t *)msg;
    798 		hdr->msg_type = DS_INIT_NACK;
    799 		hdr->payload_len = sizeof (ds_init_nack_t);
    800 
    801 		nack = (ds_init_nack_t *)(msg + DS_HDR_SZ);
    802 		nack->major_vers = new_major;
    803 
    804 		DS_DBG_PRCL(CE_NOTE, "ds@%lx: init_nack>: major=0x%04X" DS_EOL,
    805 		    PORTID(port), new_major);
    806 	}
    807 
    808 	/*
    809 	 * Send the response
    810 	 */
    811 	(void) ds_send_msg(port, msg, msglen);
    812 	DS_FREE(msg, msglen);
    813 
    814 	if (match) {
    815 		ds_set_port_ready(port, req->major_vers, ack->minor_vers);
    816 	}
    817 }
    818 
    819 static void
    820 ds_handle_init_ack(ds_port_t *port, caddr_t buf, size_t len)
    821 {
    822 	ds_init_ack_t	*ack;
    823 	ds_ver_t	*ver;
    824 	uint16_t	major;
    825 	uint16_t	minor;
    826 	size_t		explen = DS_MSG_LEN(ds_init_ack_t);
    827 
    828 	/* sanity check the incoming message */
    829 	if (len != explen) {
    830 		cmn_err(CE_WARN, "ds@%lx: <init_ack: invalid message "
    831 		    "length (%ld), expected %ld" DS_EOL, PORTID(port), len,
    832 		    explen);
    833 		return;
    834 	}
    835 
    836 	ack = (ds_init_ack_t *)(buf + DS_HDR_SZ);
    837 
    838 	mutex_enter(&port->lock);
    839 
    840 	if (port->state == DS_PORT_READY) {
    841 		DS_DBG_PRCL(CE_NOTE, "ds@%lx: <init_ack: port ready" DS_EOL,
    842 		    PORTID(port));
    843 		mutex_exit(&port->lock);
    844 		return;
    845 	}
    846 
    847 	if (port->state != DS_PORT_INIT_REQ) {
    848 		DS_DBG_PRCL(CE_NOTE, "ds@%lx: <init_ack: invalid state: %d"
    849 		    DS_EOL, PORTID(port), port->state);
    850 		mutex_exit(&port->lock);
    851 		return;
    852 	}
    853 
    854 	ver = &(ds_vers[port->ver_idx]);
    855 	major = ver->major;
    856 	minor = MIN(ver->minor, ack->minor_vers);
    857 	mutex_exit(&port->lock);
    858 
    859 	DS_DBG_PRCL(CE_NOTE, "ds@%lx: <init_ack: port ready v%d.%d" DS_EOL,
    860 	    PORTID(port), major, minor);
    861 
    862 	ds_set_port_ready(port, major, minor);
    863 }
    864 
    865 static void
    866 ds_handle_init_nack(ds_port_t *port, caddr_t buf, size_t len)
    867 {
    868 	int		idx;
    869 	ds_init_nack_t	*nack;
    870 	ds_ver_t	*ver;
    871 	size_t		explen = DS_MSG_LEN(ds_init_nack_t);
    872 
    873 	/* sanity check the incoming message */
    874 	if (len != explen) {
    875 		DS_DBG_PRCL(CE_WARN, "ds@%lx: <init_nack: invalid message "
    876 		    "length (%ld), expected %ld" DS_EOL, PORTID(port), len,
    877 		    explen);
    878 		return;
    879 	}
    880 
    881 	nack = (ds_init_nack_t *)(buf + DS_HDR_SZ);
    882 
    883 	mutex_enter(&port->lock);
    884 
    885 	if (port->state != DS_PORT_INIT_REQ) {
    886 		DS_DBG_PRCL(CE_NOTE, "ds@%lx: <init_nack: invalid state: %d"
    887 		    DS_EOL, PORTID(port), port->state);
    888 		mutex_exit(&port->lock);
    889 		return;
    890 	}
    891 
    892 	ver = &(ds_vers[port->ver_idx]);
    893 
    894 	DS_DBG_PRCL(CE_NOTE, "ds@%lx: <init_nack: req=v%d.%d, nack=v%d.x"
    895 	    DS_EOL, PORTID(port), ver->major, ver->minor, nack->major_vers);
    896 
    897 	if (nack->major_vers == 0) {
    898 		/* no supported protocol version */
    899 		DS_DBG_PRCL(CE_WARN, "ds@%lx: <init_nack: DS not supported"
    900 		    DS_EOL, PORTID(port));
    901 		mutex_exit(&port->lock);
    902 		return;
    903 	}
    904 
    905 	/*
    906 	 * Walk the version list, looking for a major version
    907 	 * that is as close to the requested major version as
    908 	 * possible.
    909 	 */
    910 	for (idx = port->ver_idx; idx < DS_NUM_VER; idx++) {
    911 		if (ds_vers[idx].major <= nack->major_vers) {
    912 			/* found a version to try */
    913 			goto done;
    914 		}
    915 	}
    916 
    917 	if (idx == DS_NUM_VER) {
    918 		/* no supported version */
    919 		DS_DBG_PRCL(CE_WARN, "ds@%lx: <init_nack: DS v%d.x not "
    920 		    "supported" DS_EOL, PORTID(port), nack->major_vers);
    921 
    922 		mutex_exit(&port->lock);
    923 		return;
    924 	}
    925 
    926 done:
    927 	/* start the handshake again */
    928 	port->ver_idx = idx;
    929 	port->state = DS_PORT_LDC_INIT;
    930 	mutex_exit(&port->lock);
    931 
    932 	ds_send_init_req(port);
    933 
    934 }
    935 
    936 static ds_svc_t *
    937 ds_find_svc_by_id_port(char *svc_id, int is_client, ds_port_t *port)
    938 {
    939 	int		idx;
    940 	ds_svc_t	*svc, *found_svc = 0;
    941 	uint32_t	flag_match = is_client ? DSSF_ISCLIENT : 0;
    942 
    943 	ASSERT(MUTEX_HELD(&ds_svcs.lock));
    944 
    945 	/* walk every table entry */
    946 	for (idx = 0; idx < ds_svcs.maxsvcs; idx++) {
    947 		svc = ds_svcs.tbl[idx];
    948 		if (DS_SVC_ISFREE(svc))
    949 			continue;
    950 		if (strcmp(svc->cap.svc_id, svc_id) != 0)
    951 			continue;
    952 		if ((svc->flags & DSSF_ISCLIENT) != flag_match)
    953 			continue;
    954 		if (port != NULL && svc->port == port) {
    955 			return (svc);
    956 		} else if (svc->state == DS_SVC_INACTIVE) {
    957 			found_svc = svc;
    958 		} else if (!found_svc) {
    959 			found_svc = svc;
    960 		}
    961 	}
    962 
    963 	return (found_svc);
    964 }
    965 
    966 static void
    967 ds_handle_reg_req(ds_port_t *port, caddr_t buf, size_t len)
    968 {
    969 	ds_reg_req_t	*req;
    970 	ds_hdr_t	*hdr;
    971 	ds_reg_ack_t	*ack;
    972 	ds_reg_nack_t	*nack;
    973 	char		*msg;
    974 	size_t		msglen;
    975 	size_t		explen = DS_MSG_LEN(ds_reg_req_t);
    976 	ds_svc_t	*svc = NULL;
    977 	ds_ver_t	version;
    978 	uint16_t	new_major;
    979 	uint16_t	new_minor;
    980 	boolean_t	match;
    981 
    982 	/* sanity check the incoming message */
    983 	if (len < explen) {
    984 		cmn_err(CE_WARN, "ds@%lx: <reg_req: invalid message "
    985 		    "length (%ld), expected at least %ld" DS_EOL,
    986 		    PORTID(port), len, explen);
    987 		return;
    988 	}
    989 
    990 	req = (ds_reg_req_t *)(buf + DS_HDR_SZ);
    991 
    992 	DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_req: '%s' ver=%d.%d, hdl=0x%llx"
    993 	    DS_EOL, PORTID(port), req->svc_id, req->major_vers, req->minor_vers,
    994 	    (u_longlong_t)req->svc_handle);
    995 
    996 	mutex_enter(&ds_svcs.lock);
    997 	svc = ds_find_svc_by_id_port(req->svc_id,
    998 	    DS_HDL_ISCLIENT(req->svc_handle) == 0, port);
    999 	if (svc == NULL) {
   1000 
   1001 do_reg_nack:
   1002 		mutex_exit(&ds_svcs.lock);
   1003 
   1004 		msglen = DS_MSG_LEN(ds_reg_nack_t);
   1005 		msg = DS_MALLOC(msglen);
   1006 
   1007 		hdr = (ds_hdr_t *)msg;
   1008 		hdr->msg_type = DS_REG_NACK;
   1009 		hdr->payload_len = sizeof (ds_reg_nack_t);
   1010 
   1011 		nack = (ds_reg_nack_t *)(msg + DS_HDR_SZ);
   1012 		nack->svc_handle = req->svc_handle;
   1013 		nack->result = DS_REG_VER_NACK;
   1014 		nack->major_vers = 0;
   1015 
   1016 		DS_DBG_PRCL(CE_NOTE, "ds@%lx: reg_nack>: '%s'" DS_EOL,
   1017 		    PORTID(port), req->svc_id);
   1018 		/*
   1019 		 * Send the response
   1020 		 */
   1021 		(void) ds_send_msg(port, msg, msglen);
   1022 		DS_FREE(msg, msglen);
   1023 		return;
   1024 	}
   1025 	DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_req: '%s' found, hdl: 0x%llx" DS_EOL,
   1026 	    PORTID(port), req->svc_id, (u_longlong_t)svc->hdl);
   1027 
   1028 	/*
   1029 	 * A client sends out a reg req in order to force service providers to
   1030 	 * initiate a reg req from their end (limitation in the protocol).  We
   1031 	 * expect the service provider to be in the inactive (DS_SVC_INACTIVE)
   1032 	 * state.  If the service provider has already sent out a reg req (the
   1033 	 * state is DS_SVC_REG_PENDING) or has already handshaken (the
   1034 	 * state is DS_SVC_ACTIVE), then we can simply ignore this reg
   1035 	 * req.  For any other state, we force an unregister before initiating
   1036 	 * a reg req.
   1037 	 */
   1038 
   1039 	if (DS_HDL_ISCLIENT(req->svc_handle)) {
   1040 		switch (svc->state) {
   1041 
   1042 		case DS_SVC_REG_PENDING:
   1043 		case DS_SVC_ACTIVE:
   1044 			DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_req: '%s' pinging "
   1045 			    "client, state (%x)" DS_EOL, PORTID(port),
   1046 			    req->svc_id, svc->state);
   1047 			mutex_exit(&ds_svcs.lock);
   1048 			return;
   1049 
   1050 		case DS_SVC_INACTIVE:
   1051 			DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_req: '%s' pinging "
   1052 			    "client" DS_EOL, PORTID(port), req->svc_id);
   1053 			break;
   1054 
   1055 		default:
   1056 			DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_req: '%s' pinging "
   1057 			    "client forced unreg, state (%x)" DS_EOL,
   1058 			    PORTID(port), req->svc_id, svc->state);
   1059 			(void) ds_svc_unregister(svc, port);
   1060 			break;
   1061 		}
   1062 		(void) ds_svc_port_up(svc, port);
   1063 		(void) ds_svc_register_onport(svc, port);
   1064 		mutex_exit(&ds_svcs.lock);
   1065 		return;
   1066 	}
   1067 
   1068 	/*
   1069 	 * Only remote service providers can initiate a registration.  The
   1070 	 * local sevice from here must be a client service.
   1071 	 */
   1072 
   1073 	match = negotiate_version(svc->cap.nvers, svc->cap.vers,
   1074 	    req->major_vers, &new_major, &new_minor);
   1075 
   1076 	/*
   1077 	 * Check version info. ACK only if the major numbers exactly
   1078 	 * match. The service entity can retry with a new minor
   1079 	 * based on the response sent as part of the NACK.
   1080 	 */
   1081 	if (match) {
   1082 		DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_req: '%s' svc%d: state: %x "
   1083 		    "svc_portid: %d" DS_EOL, PORTID(port), req->svc_id,
   1084 		    (int)DS_HDL2IDX(svc->hdl), svc->state,
   1085 		    (int)(svc->port == NULL ? -1 : PORTID(svc->port)));
   1086 		/*
   1087 		 * If the current local service is already in use and
   1088 		 * it's not on this port, clone it.
   1089 		 */
   1090 		if (svc->state != DS_SVC_INACTIVE) {
   1091 			if (svc->port != NULL && port == svc->port) {
   1092 				/*
   1093 				 * Someone probably dropped an unreg req
   1094 				 * somewhere.  Force a local unreg.
   1095 				 */
   1096 				(void) ds_svc_unregister(svc, port);
   1097 			} else if (!DS_HDL_ISCLIENT(svc->hdl)) {
   1098 				/*
   1099 				 * Can't clone a non-client (service provider)
   1100 				 * handle.  This is because old in-kernel
   1101 				 * service providers can't deal with multiple
   1102 				 * handles.
   1103 				 */
   1104 				goto do_reg_nack;
   1105 			} else {
   1106 				svc = ds_svc_clone(svc);
   1107 			}
   1108 		}
   1109 		svc->port = port;
   1110 		svc->svc_hdl = req->svc_handle;
   1111 		svc->state = DS_SVC_ACTIVE;
   1112 
   1113 		msglen = DS_MSG_LEN(ds_reg_ack_t);
   1114 		msg = DS_MALLOC(msglen);
   1115 
   1116 		hdr = (ds_hdr_t *)msg;
   1117 		hdr->msg_type = DS_REG_ACK;
   1118 		hdr->payload_len = sizeof (ds_reg_ack_t);
   1119 
   1120 		ack = (ds_reg_ack_t *)(msg + DS_HDR_SZ);
   1121 		ack->svc_handle = req->svc_handle;
   1122 		ack->minor_vers = MIN(new_minor, req->minor_vers);
   1123 
   1124 
   1125 		if (svc->ops.ds_reg_cb) {
   1126 			/* Call the registration callback */
   1127 			version.major = req->major_vers;
   1128 			version.minor = ack->minor_vers;
   1129 			(*svc->ops.ds_reg_cb)(svc->ops.cb_arg, &version,
   1130 			    svc->hdl);
   1131 		}
   1132 		mutex_exit(&ds_svcs.lock);
   1133 
   1134 		DS_DBG_PRCL(CE_NOTE, "ds@%lx: reg_ack>: '%s' minor=0x%04X"
   1135 		    DS_EOL, PORTID(port), svc->cap.svc_id,
   1136 		    MIN(new_minor, req->minor_vers));
   1137 	} else {
   1138 		mutex_exit(&ds_svcs.lock);
   1139 
   1140 		msglen = DS_MSG_LEN(ds_reg_nack_t);
   1141 		msg = DS_MALLOC(msglen);
   1142 
   1143 		hdr = (ds_hdr_t *)msg;
   1144 		hdr->msg_type = DS_REG_NACK;
   1145 		hdr->payload_len = sizeof (ds_reg_nack_t);
   1146 
   1147 		nack = (ds_reg_nack_t *)(msg + DS_HDR_SZ);
   1148 		nack->svc_handle = req->svc_handle;
   1149 		nack->result = DS_REG_VER_NACK;
   1150 		nack->major_vers = new_major;
   1151 
   1152 		DS_DBG_PRCL(CE_NOTE, "ds@%lx: reg_nack>: '%s' major=0x%04X"
   1153 		    DS_EOL, PORTID(port), svc->cap.svc_id, new_major);
   1154 	}
   1155 
   1156 	/* send message */
   1157 	(void) ds_send_msg(port, msg, msglen);
   1158 	DS_FREE(msg, msglen);
   1159 }
   1160 
   1161 static void
   1162 ds_handle_reg_ack(ds_port_t *port, caddr_t buf, size_t len)
   1163 {
   1164 	ds_reg_ack_t	*ack;
   1165 	ds_ver_t	*ver;
   1166 	ds_ver_t	tmpver;
   1167 	ds_svc_t	*svc;
   1168 	size_t		explen = DS_MSG_LEN(ds_reg_ack_t);
   1169 
   1170 	/* sanity check the incoming message */
   1171 	if (len != explen) {
   1172 		cmn_err(CE_WARN, "ds@%lx: <reg_ack: invalid message "
   1173 		    "length (%ld), expected %ld" DS_EOL, PORTID(port), len,
   1174 		    explen);
   1175 		return;
   1176 	}
   1177 
   1178 	ack = (ds_reg_ack_t *)(buf + DS_HDR_SZ);
   1179 
   1180 	mutex_enter(&ds_svcs.lock);
   1181 
   1182 	/*
   1183 	 * This searches for service based on how we generate handles
   1184 	 * and so only works because this is a reg ack.
   1185 	 */
   1186 	if (DS_HDL_ISCLIENT(ack->svc_handle) ||
   1187 	    (svc = ds_get_svc(ack->svc_handle)) == NULL) {
   1188 		cmn_err(CE_WARN, "ds@%lx: <reg_ack: invalid handle 0x%llx"
   1189 		    DS_EOL, PORTID(port), (u_longlong_t)ack->svc_handle);
   1190 		goto done;
   1191 	}
   1192 
   1193 	/* make sure the message makes sense */
   1194 	if (svc->state != DS_SVC_REG_PENDING) {
   1195 		cmn_err(CE_WARN, "ds@%lx: <reg_ack: invalid state (%d)" DS_EOL,
   1196 		    PORTID(port), svc->state);
   1197 		goto done;
   1198 	}
   1199 
   1200 	ver = &(svc->cap.vers[svc->ver_idx]);
   1201 
   1202 	/* major version has been agreed upon */
   1203 	svc->ver.major = ver->major;
   1204 
   1205 	if (ack->minor_vers >= ver->minor) {
   1206 		/*
   1207 		 * Use the minor version specified in the
   1208 		 * original request.
   1209 		 */
   1210 		svc->ver.minor = ver->minor;
   1211 	} else {
   1212 		/*
   1213 		 * Use the lower minor version returned in
   1214 		 * the ack. By defninition, all lower minor
   1215 		 * versions must be supported.
   1216 		 */
   1217 		svc->ver.minor = ack->minor_vers;
   1218 	}
   1219 
   1220 	svc->state = DS_SVC_ACTIVE;
   1221 	svc->port = port;
   1222 
   1223 	DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_ack: '%s' v%d.%d ready, hdl=0x%llx"
   1224 	    DS_EOL, PORTID(port), svc->cap.svc_id, svc->ver.major,
   1225 	    svc->ver.minor, (u_longlong_t)svc->hdl);
   1226 
   1227 	/* notify the client that registration is complete */
   1228 	if (svc->ops.ds_reg_cb) {
   1229 		/*
   1230 		 * Use a temporary version structure so that
   1231 		 * the copy in the svc structure cannot be
   1232 		 * modified by the client.
   1233 		 */
   1234 		tmpver.major = svc->ver.major;
   1235 		tmpver.minor = svc->ver.minor;
   1236 
   1237 		(*svc->ops.ds_reg_cb)(svc->ops.cb_arg, &tmpver, svc->hdl);
   1238 	}
   1239 
   1240 done:
   1241 	mutex_exit(&ds_svcs.lock);
   1242 }
   1243 
   1244 static void
   1245 ds_try_next_port(ds_svc_t *svc, int portid)
   1246 {
   1247 	ds_port_t *port;
   1248 	ds_portset_t totry;
   1249 	int i;
   1250 
   1251 	DS_DBG_LDC(CE_NOTE, "ds@%x %s" DS_EOL, portid, __func__);
   1252 
   1253 	/*
   1254 	 * Get the ports that haven't been tried yet and are available to try.
   1255 	 */
   1256 	DS_PORTSET_DUP(totry, svc->avail);
   1257 	for (i = 0; i < DS_MAX_PORTS; i++) {
   1258 		if (DS_PORT_IN_SET(svc->tried, i))
   1259 			DS_PORTSET_DEL(totry, i);
   1260 	}
   1261 
   1262 	if (DS_PORTSET_ISNULL(totry))
   1263 		return;
   1264 
   1265 	for (i = 0; i < DS_MAX_PORTS; i++, portid++) {
   1266 		if (portid >= DS_MAX_PORTS) {
   1267 			portid = 0;
   1268 		}
   1269 
   1270 		/*
   1271 		 * If the port is not in the available list,
   1272 		 * it is not a candidate for registration.
   1273 		 */
   1274 		if (!DS_PORT_IN_SET(totry, portid)) {
   1275 			continue;
   1276 		}
   1277 
   1278 		port = &ds_ports[portid];
   1279 		DS_DBG_LDC(CE_NOTE, "ds@%x: %s trying ldc.id: %d" DS_EOL,
   1280 		    portid, __func__, (uint_t)(port->ldc.id));
   1281 		if (ds_send_reg_req(svc, port) == 0) {
   1282 			DS_DBG_LDC(CE_NOTE, "ds@%x: %s reg msg send OK" DS_EOL,
   1283 			    portid, __func__);
   1284 			/* register sent successfully */
   1285 			break;
   1286 		}
   1287 		DS_DBG_LDC(CE_NOTE, "ds@%x: %s reg msg send FAIL" DS_EOL,
   1288 		    portid, __func__);
   1289 
   1290 		/* reset the service to try the next port */
   1291 		ds_reset_svc(svc, port);
   1292 	}
   1293 }
   1294 
   1295 static void
   1296 ds_handle_reg_nack(ds_port_t *port, caddr_t buf, size_t len)
   1297 {
   1298 	ds_reg_nack_t	*nack;
   1299 	ds_svc_t	*svc;
   1300 	int		idx;
   1301 	size_t		explen = DS_MSG_LEN(ds_reg_nack_t);
   1302 
   1303 	/* sanity check the incoming message */
   1304 	if (len != explen) {
   1305 		cmn_err(CE_WARN, "ds@%lx: <reg_nack: invalid message "
   1306 		    "length (%ld), expected %ld" DS_EOL, PORTID(port), len,
   1307 		    explen);
   1308 		return;
   1309 	}
   1310 
   1311 	nack = (ds_reg_nack_t *)(buf + DS_HDR_SZ);
   1312 
   1313 	mutex_enter(&ds_svcs.lock);
   1314 
   1315 	/*
   1316 	 * We expect a reg_nack for a client ping.
   1317 	 */
   1318 	if (DS_HDL_ISCLIENT(nack->svc_handle)) {
   1319 		DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_nack: ping hdl: 0x%llx"
   1320 		    DS_EOL, PORTID(port), (u_longlong_t)nack->svc_handle);
   1321 		goto done;
   1322 	}
   1323 
   1324 	/*
   1325 	 * This searches for service based on how we generate handles
   1326 	 * and so only works because this is a reg nack.
   1327 	 */
   1328 	if ((svc = ds_get_svc(nack->svc_handle)) == NULL) {
   1329 		cmn_err(CE_WARN, "ds@%lx: <reg_nack: invalid handle 0x%llx"
   1330 		    DS_EOL, PORTID(port), (u_longlong_t)nack->svc_handle);
   1331 		goto done;
   1332 	}
   1333 
   1334 	/* make sure the message makes sense */
   1335 	if (svc->state != DS_SVC_REG_PENDING) {
   1336 		DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_nack: '%s' handle: 0x%llx "
   1337 		    "invalid state (%d)" DS_EOL, PORTID(port), svc->cap.svc_id,
   1338 		    (u_longlong_t)nack->svc_handle, svc->state);
   1339 		goto done;
   1340 	}
   1341 
   1342 	if (nack->result == DS_REG_DUP) {
   1343 		cmn_err(CE_WARN, "ds@%lx: <reg_nack: duplicate registration "
   1344 		    " for %s" DS_EOL, PORTID(port), svc->cap.svc_id);
   1345 		ds_reset_svc(svc, port);
   1346 		goto done;
   1347 	}
   1348 
   1349 	/*
   1350 	 * A major version of zero indicates that the
   1351 	 * service is not supported at all.
   1352 	 */
   1353 	if (nack->major_vers == 0) {
   1354 		DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_nack: '%s' not supported"
   1355 		    DS_EOL, PORTID(port), svc->cap.svc_id);
   1356 		ds_reset_svc(svc, port);
   1357 		if ((svc->flags & DSSF_ISCLIENT) == 0)
   1358 			ds_try_next_port(svc, PORTID(port) + 1);
   1359 		goto done;
   1360 	}
   1361 
   1362 	DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_nack: '%s' hdl=0x%llx, nack=%d.x"
   1363 	    DS_EOL, PORTID(port), svc->cap.svc_id,
   1364 	    (u_longlong_t)nack->svc_handle, nack->major_vers);
   1365 
   1366 	/*
   1367 	 * Walk the version list for the service, looking for
   1368 	 * a major version that is as close to the requested
   1369 	 * major version as possible.
   1370 	 */
   1371 	for (idx = svc->ver_idx; idx < svc->cap.nvers; idx++) {
   1372 		if (svc->cap.vers[idx].major <= nack->major_vers) {
   1373 			/* found a version to try */
   1374 			break;
   1375 		}
   1376 	}
   1377 
   1378 	if (idx == svc->cap.nvers) {
   1379 		/* no supported version */
   1380 		DS_DBG_PRCL(CE_NOTE, "ds@%lx: <reg_nack: %s v%d.x not supported"
   1381 		    DS_EOL, PORTID(port), svc->cap.svc_id, nack->major_vers);
   1382 		ds_reset_svc(svc, port);
   1383 		if ((svc->flags & DSSF_ISCLIENT) == 0)
   1384 			ds_try_next_port(svc, PORTID(port) + 1);
   1385 		goto done;
   1386 	}
   1387 
   1388 	/* start the handshake again */
   1389 	svc->state = DS_SVC_INACTIVE;
   1390 	svc->ver_idx = idx;
   1391 
   1392 	(void) ds_svc_register(svc, NULL);
   1393 
   1394 done:
   1395 	mutex_exit(&ds_svcs.lock);
   1396 }
   1397 
   1398 static void
   1399 ds_handle_unreg_req(ds_port_t *port, caddr_t buf, size_t len)
   1400 {
   1401 	ds_hdr_t	*hdr;
   1402 	ds_unreg_req_t	*req;
   1403 	ds_unreg_ack_t	*ack;
   1404 	ds_svc_t	*svc;
   1405 	char		*msg;
   1406 	size_t		msglen;
   1407 	size_t		explen = DS_MSG_LEN(ds_unreg_req_t);
   1408 	boolean_t	is_up;
   1409 
   1410 	/* sanity check the incoming message */
   1411 	if (len != explen) {
   1412 		cmn_err(CE_WARN, "ds@%lx: <unreg_req: invalid message "
   1413 		    "length (%ld), expected %ld" DS_EOL, PORTID(port), len,
   1414 		    explen);
   1415 		return;
   1416 	}
   1417 
   1418 	req = (ds_unreg_req_t *)(buf + DS_HDR_SZ);
   1419 
   1420 	mutex_enter(&ds_svcs.lock);
   1421 
   1422 	/* lookup appropriate client or service */
   1423 	if (DS_HDL_ISCLIENT(req->svc_handle) ||
   1424 	    ((svc = ds_find_clnt_svc_by_hdl_port(req->svc_handle, port))
   1425 	    == NULL && ((svc = ds_get_svc(req->svc_handle)) == NULL ||
   1426 	    svc->port != port))) {
   1427 		mutex_exit(&ds_svcs.lock);
   1428 		mutex_enter(&port->lock);
   1429 		is_up = (port->ldc.state == LDC_UP);
   1430 		mutex_exit(&port->lock);
   1431 		if (!is_up)
   1432 			return;
   1433 		DS_DBG_PRCL(CE_NOTE, "ds@%lx: <unreg_req: invalid handle 0x%llx"
   1434 		    DS_EOL, PORTID(port), (u_longlong_t)req->svc_handle);
   1435 		ds_send_unreg_nack(port, req->svc_handle);
   1436 		return;
   1437 	}
   1438 
   1439 	DS_DBG_PRCL(CE_NOTE, "ds@%lx: <unreg_req: '%s' handle 0x%llx" DS_EOL,
   1440 	    PORTID(port), svc->cap.svc_id, (u_longlong_t)req->svc_handle);
   1441 
   1442 	(void) ds_svc_unregister(svc, svc->port);
   1443 
   1444 	DS_DBG_PRCL(CE_NOTE, "ds@%lx: unreg_ack>: '%s' hdl=0x%llx" DS_EOL,
   1445 	    PORTID(port), svc->cap.svc_id, (u_longlong_t)req->svc_handle);
   1446 
   1447 	ds_check_for_dup_services(svc);
   1448 
   1449 	mutex_exit(&ds_svcs.lock);
   1450 
   1451 	msglen = DS_HDR_SZ + sizeof (ds_unreg_ack_t);
   1452 	msg = DS_MALLOC(msglen);
   1453 
   1454 	hdr = (ds_hdr_t *)msg;
   1455 	hdr->msg_type = DS_UNREG_ACK;
   1456 	hdr->payload_len = sizeof (ds_unreg_ack_t);
   1457 
   1458 	ack = (ds_unreg_ack_t *)(msg + DS_HDR_SZ);
   1459 	ack->svc_handle = req->svc_handle;
   1460 
   1461 	/* send message */
   1462 	(void) ds_send_msg(port, msg, msglen);
   1463 	DS_FREE(msg, msglen);
   1464 
   1465 }
   1466 
   1467 static void
   1468 ds_handle_unreg_ack(ds_port_t *port, caddr_t buf, size_t len)
   1469 {
   1470 	ds_unreg_ack_t	*ack;
   1471 	size_t		explen = DS_MSG_LEN(ds_unreg_ack_t);
   1472 
   1473 	/* sanity check the incoming message */
   1474 	if (len != explen) {
   1475 		cmn_err(CE_WARN, "ds@%lx: <unreg_ack: invalid message "
   1476 		    "length (%ld), expected %ld" DS_EOL, PORTID(port), len,
   1477 		    explen);
   1478 		return;
   1479 	}
   1480 
   1481 	ack = (ds_unreg_ack_t *)(buf + DS_HDR_SZ);
   1482 
   1483 	DS_DBG_PRCL(CE_NOTE, "ds@%lx: <unreg_ack: hdl=0x%llx" DS_EOL,
   1484 	    PORTID(port), (u_longlong_t)ack->svc_handle);
   1485 
   1486 #ifdef DEBUG
   1487 	mutex_enter(&ds_svcs.lock);
   1488 
   1489 	/*
   1490 	 * Since the unregister request was initiated locally,
   1491 	 * the service structure has already been torn down.
   1492 	 * Just perform a sanity check to make sure the message
   1493 	 * is appropriate.
   1494 	 */
   1495 	if (ds_get_svc(ack->svc_handle) != NULL) {
   1496 		DS_DBG_PRCL(CE_NOTE, "ds@%lx: <unreg_ack: handle 0x%llx in use"
   1497 		    DS_EOL, PORTID(port), (u_longlong_t)ack->svc_handle);
   1498 	}
   1499 
   1500 	mutex_exit(&ds_svcs.lock);
   1501 #endif	/* DEBUG */
   1502 }
   1503 
   1504 static void
   1505 ds_handle_unreg_nack(ds_port_t *port, caddr_t buf, size_t len)
   1506 {
   1507 	ds_unreg_nack_t	*nack;
   1508 	size_t		explen = DS_MSG_LEN(ds_unreg_nack_t);
   1509 
   1510 	/* sanity check the incoming message */
   1511 	if (len != explen) {
   1512 		cmn_err(CE_WARN, "ds@%lx: <unreg_nack: invalid message "
   1513 		    "length (%ld), expected %ld" DS_EOL, PORTID(port), len,
   1514 		    explen);
   1515 		return;
   1516 	}
   1517 
   1518 	nack = (ds_unreg_nack_t *)(buf + DS_HDR_SZ);
   1519 
   1520 	DS_DBG_PRCL(CE_NOTE, "ds@%lx: <unreg_nack: hdl=0x%llx" DS_EOL,
   1521 	    PORTID(port), (u_longlong_t)nack->svc_handle);
   1522 
   1523 #ifdef DEBUG
   1524 	mutex_enter(&ds_svcs.lock);
   1525 
   1526 	/*
   1527 	 * Since the unregister request was initiated locally,
   1528 	 * the service structure has already been torn down.
   1529 	 * Just perform a sanity check to make sure the message
   1530 	 * is appropriate.
   1531 	 */
   1532 	if (ds_get_svc(nack->svc_handle) != NULL) {
   1533 		DS_DBG_PRCL(CE_NOTE, "ds@%lx: <unreg_nack: handle 0x%llx in use"
   1534 		    DS_EOL, PORTID(port), (u_longlong_t)nack->svc_handle);
   1535 	}
   1536 
   1537 	mutex_exit(&ds_svcs.lock);
   1538 #endif	/* DEBUG */
   1539 }
   1540 
   1541 static void
   1542 ds_handle_data(ds_port_t *port, caddr_t buf, size_t len)
   1543 {
   1544 	ds_data_handle_t	*data;
   1545 	ds_svc_t		*svc;
   1546 	char			*msg;
   1547 	int			msgsz;
   1548 	int			hdrsz;
   1549 	size_t			explen = DS_MSG_LEN(ds_data_handle_t);
   1550 
   1551 	/* sanity check the incoming message */
   1552 	if (len < explen) {
   1553 		cmn_err(CE_WARN, "ds@%lx: <data: invalid message length "
   1554 		    "(%ld), expected at least %ld" DS_EOL, PORTID(port), len,
   1555 		    explen);
   1556 		return;
   1557 	}
   1558 
   1559 	data = (ds_data_handle_t *)(buf + DS_HDR_SZ);
   1560 
   1561 	hdrsz = DS_HDR_SZ + sizeof (ds_data_handle_t);
   1562 	msgsz = len - hdrsz;
   1563 
   1564 	/* strip off the header for the client */
   1565 	msg = (msgsz) ? (buf + hdrsz) : NULL;
   1566 
   1567 	mutex_enter(&ds_svcs.lock);
   1568 
   1569 	if ((svc = ds_find_clnt_svc_by_hdl_port(data->svc_handle, port))
   1570 	    == NULL) {
   1571 		if ((svc = ds_get_svc(data->svc_handle)) == NULL) {
   1572 			mutex_exit(&ds_svcs.lock);
   1573 			cmn_err(CE_WARN, "ds@%lx: <data: invalid handle 0x%llx"
   1574 			    DS_EOL, PORTID(port),
   1575 			    (u_longlong_t)data->svc_handle);
   1576 			ds_send_data_nack(port, data->svc_handle);
   1577 			return;
   1578 		}
   1579 	}
   1580 
   1581 	mutex_exit(&ds_svcs.lock);
   1582 
   1583 	DS_DBG_PRCL(CE_NOTE, "ds@%lx: <data: '%s' hdl=0x%llx" DS_EOL,
   1584 	    PORTID(port), svc->cap.svc_id, (u_longlong_t)svc->hdl);
   1585 	DS_DUMP_MSG(DS_DBG_FLAG_PRCL, msg, msgsz);
   1586 
   1587 	/* dispatch this message to the client */
   1588 	(*svc->ops.ds_data_cb)(svc->ops.cb_arg, msg, msgsz);
   1589 }
   1590 
   1591 static void
   1592 ds_handle_nack(ds_port_t *port, caddr_t buf, size_t len)
   1593 {
   1594 	ds_svc_t	*svc;
   1595 	ds_data_nack_t	*nack;
   1596 	size_t		explen = DS_MSG_LEN(ds_data_nack_t);
   1597 
   1598 	/* sanity check the incoming message */
   1599 	if (len != explen) {
   1600 		cmn_err(CE_WARN, "ds@%lx: <data_nack: invalid message "
   1601 		    "length (%ld), expected %ld" DS_EOL, PORTID(port), len,
   1602 		    explen);
   1603 		return;
   1604 	}
   1605 
   1606 	nack = (ds_data_nack_t *)(buf + DS_HDR_SZ);
   1607 
   1608 	DS_DBG_PRCL(CE_NOTE, "ds@%lx: data_nack: hdl=0x%llx, result=0x%llx"
   1609 	    DS_EOL, PORTID(port), (u_longlong_t)nack->svc_handle,
   1610 	    (u_longlong_t)nack->result);
   1611 
   1612 	if (nack->result == DS_INV_HDL) {
   1613 
   1614 		mutex_enter(&ds_svcs.lock);
   1615 
   1616 		if ((svc = ds_find_clnt_svc_by_hdl_port(nack->svc_handle,
   1617 		    port)) == NULL) {
   1618 			if ((svc = ds_get_svc(nack->svc_handle)) == NULL) {
   1619 				mutex_exit(&ds_svcs.lock);
   1620 				return;
   1621 			}
   1622 		}
   1623 
   1624 		cmn_err(CE_WARN, "ds@%lx: <data_nack: handle 0x%llx reported "
   1625 		    " as invalid" DS_EOL, PORTID(port),
   1626 		    (u_longlong_t)nack->svc_handle);
   1627 
   1628 		(void) ds_svc_unregister(svc, svc->port);
   1629 
   1630 		mutex_exit(&ds_svcs.lock);
   1631 	}
   1632 }
   1633 
   1634 /* Initialize the port */
   1635 void
   1636 ds_send_init_req(ds_port_t *port)
   1637 {
   1638 	ds_hdr_t	*hdr;
   1639 	ds_init_req_t	*init_req;
   1640 	size_t		msglen;
   1641 	ds_ver_t	*vers = &ds_vers[port->ver_idx];
   1642 
   1643 	mutex_enter(&port->lock);
   1644 	if (port->state != DS_PORT_LDC_INIT) {
   1645 		DS_DBG_PRCL(CE_NOTE, "ds@%lx: init_req>: invalid state: %d"
   1646 		    DS_EOL, PORTID(port), port->state);
   1647 		mutex_exit(&port->lock);
   1648 		return;
   1649 	}
   1650 	mutex_exit(&port->lock);
   1651 
   1652 	DS_DBG_PRCL(CE_NOTE, "ds@%lx: init_req>: req=v%d.%d" DS_EOL,
   1653 	    PORTID(port), vers->major, vers->minor);
   1654 
   1655 	msglen = DS_HDR_SZ + sizeof (ds_init_req_t);
   1656 	hdr = DS_MALLOC(msglen);
   1657 
   1658 	hdr->msg_type = DS_INIT_REQ;
   1659 	hdr->payload_len = sizeof (ds_init_req_t);
   1660 
   1661 	init_req = (ds_init_req_t *)((caddr_t)hdr + DS_HDR_SZ);
   1662 	init_req->major_vers = vers->major;
   1663 	init_req->minor_vers = vers->minor;
   1664 
   1665 	if (ds_send_msg(port, (caddr_t)hdr, msglen) == 0) {
   1666 		/*
   1667 		 * We've left the port state unlocked over the malloc/send,
   1668 		 * make sure no one has changed the state under us before
   1669 		 * we update the state.
   1670 		 */
   1671 		mutex_enter(&port->lock);
   1672 		if (port->state == DS_PORT_LDC_INIT)
   1673 			port->state = DS_PORT_INIT_REQ;
   1674 		mutex_exit(&port->lock);
   1675 	}
   1676 	DS_FREE(hdr, msglen);
   1677 }
   1678 
   1679 static int
   1680 ds_send_reg_req(ds_svc_t *svc, ds_port_t *port)
   1681 {
   1682 	ds_ver_t	*ver;
   1683 	ds_hdr_t	*hdr;
   1684 	caddr_t		msg;
   1685 	size_t		msglen;
   1686 	ds_reg_req_t	*req;
   1687 	size_t		idlen;
   1688 	int		rv;
   1689 
   1690 	if ((svc->state != DS_SVC_INACTIVE) &&
   1691 	    ((svc->flags & DSSF_ISCLIENT) == 0)) {
   1692 		DS_DBG_PRCL(CE_NOTE, "ds@%lx: reg_req>: invalid svc state (%d) "
   1693 		    "for svc '%s'" DS_EOL, PORTID(port), svc->state,
   1694 		    svc->cap.svc_id);
   1695 		return (-1);
   1696 	}
   1697 
   1698 	mutex_enter(&port->lock);
   1699 
   1700 	/* check on the LDC to Zeus */
   1701 	if (port->ldc.state != LDC_UP) {
   1702 		/* can not send message */
   1703 		DS_DBG_PRCL(CE_NOTE, "ds@%lx: reg_req>: channel %ld is not up"
   1704 		    DS_EOL, PORTID(port), port->ldc.id);
   1705 		mutex_exit(&port->lock);
   1706 		return (-1);
   1707 	}
   1708 
   1709 	/* make sure port is ready */
   1710 	if (port->state != DS_PORT_READY) {
   1711 		/* can not send message */
   1712 		DS_DBG_PRCL(CE_NOTE, "ds@%lx: reg_req>: port is not ready"
   1713 		    DS_EOL, PORTID(port));
   1714 		mutex_exit(&port->lock);
   1715 		return (-1);
   1716 	}
   1717 
   1718 	mutex_exit(&port->lock);
   1719 
   1720 	/* allocate the message buffer */
   1721 	idlen = strlen(svc->cap.svc_id);
   1722 	msglen = DS_HDR_SZ + sizeof (ds_reg_req_t) + idlen;
   1723 	msg = DS_MALLOC(msglen);
   1724 
   1725 	/* copy in the header data */
   1726 	hdr = (ds_hdr_t *)msg;
   1727 	hdr->msg_type = DS_REG_REQ;
   1728 	hdr->payload_len = sizeof (ds_reg_req_t) + idlen;
   1729 
   1730 	req = (ds_reg_req_t *)(msg + DS_HDR_SZ);
   1731 	req->svc_handle = svc->hdl;
   1732 	ver = &(svc->cap.vers[svc->ver_idx]);
   1733 	req->major_vers = ver->major;
   1734 	req->minor_vers = ver->minor;
   1735 
   1736 	/* copy in the service id */
   1737 	(void) memcpy(req->svc_id, svc->cap.svc_id, idlen + 1);
   1738 
   1739 	/* send the message */
   1740 	DS_DBG_PRCL(CE_NOTE, "ds@%lx: reg_req>: '%s' ver=%d.%d, hdl=0x%llx"
   1741 	    DS_EOL, PORTID(port), svc->cap.svc_id, ver->major, ver->minor,
   1742 	    (u_longlong_t)svc->hdl);
   1743 
   1744 	if ((rv = ds_send_msg(port, msg, msglen)) != 0) {
   1745 		svc->port = port;
   1746 		rv = -1;
   1747 	} else if ((svc->flags & DSSF_ISCLIENT) == 0) {
   1748 		svc->state = DS_SVC_REG_PENDING;
   1749 	}
   1750 	DS_FREE(msg, msglen);
   1751 
   1752 	return (rv);
   1753 }
   1754 
   1755 /*
   1756  * Keep around in case we want this later
   1757  */
   1758 int
   1759 ds_send_unreg_req(ds_svc_t *svc)
   1760 {
   1761 	caddr_t		msg;
   1762 	size_t		msglen;
   1763 	ds_hdr_t	*hdr;
   1764 	ds_unreg_req_t	*req;
   1765 	ds_port_t	*port = svc->port;
   1766 	int		rv;
   1767 
   1768 	if (port == NULL) {
   1769 		DS_DBG(CE_NOTE, "send_unreg_req: service '%s' not "
   1770 		    "associated with a port" DS_EOL, svc->cap.svc_id);
   1771 		return (-1);
   1772 	}
   1773 
   1774 	mutex_enter(&port->lock);
   1775 
   1776 	/* check on the LDC to Zeus */
   1777 	if (port->ldc.state != LDC_UP) {
   1778 		/* can not send message */
   1779 		cmn_err(CE_WARN, "ds@%lx: unreg_req>: channel %ld is not up"
   1780 		    DS_EOL, PORTID(port), port->ldc.id);
   1781 		mutex_exit(&port->lock);
   1782 		return (-1);
   1783 	}
   1784 
   1785 	/* make sure port is ready */
   1786 	if (port->state != DS_PORT_READY) {
   1787 		/* can not send message */
   1788 		cmn_err(CE_WARN, "ds@%lx: unreg_req>: port is not ready" DS_EOL,
   1789 		    PORTID(port));
   1790 		mutex_exit(&port->lock);
   1791 		return (-1);
   1792 	}
   1793 
   1794 	mutex_exit(&port->lock);
   1795 
   1796 	msglen = DS_HDR_SZ + sizeof (ds_unreg_req_t);
   1797 	msg = DS_MALLOC(msglen);
   1798 
   1799 	/* copy in the header data */
   1800 	hdr = (ds_hdr_t *)msg;
   1801 	hdr->msg_type = DS_UNREG;
   1802 	hdr->payload_len = sizeof (ds_unreg_req_t);
   1803 
   1804 	req = (ds_unreg_req_t *)(msg + DS_HDR_SZ);
   1805 	if (svc->flags & DSSF_ISCLIENT) {
   1806 		req->svc_handle = svc->svc_hdl;
   1807 	} else {
   1808 		req->svc_handle = svc->hdl;
   1809 	}
   1810 
   1811 	/* send the message */
   1812 	DS_DBG_PRCL(CE_NOTE, "ds@%lx: unreg_req>: '%s' hdl=0x%llx" DS_EOL,
   1813 	    PORTID(port), (svc->cap.svc_id) ? svc->cap.svc_id : "NULL",
   1814 	    (u_longlong_t)svc->hdl);
   1815 
   1816 	if ((rv = ds_send_msg(port, msg, msglen)) != 0) {
   1817 		rv = -1;
   1818 	}
   1819 	DS_FREE(msg, msglen);
   1820 
   1821 	return (rv);
   1822 }
   1823 
   1824 static void
   1825 ds_send_unreg_nack(ds_port_t *port, ds_svc_hdl_t bad_hdl)
   1826 {
   1827 	caddr_t		msg;
   1828 	size_t		msglen;
   1829 	ds_hdr_t	*hdr;
   1830 	ds_unreg_nack_t	*nack;
   1831 
   1832 	mutex_enter(&port->lock);
   1833 
   1834 	/* check on the LDC to Zeus */
   1835 	if (port->ldc.state != LDC_UP) {
   1836 		/* can not send message */
   1837 		cmn_err(CE_WARN, "ds@%lx: unreg_nack>: channel %ld is not up"
   1838 		    DS_EOL, PORTID(port), port->ldc.id);
   1839 		mutex_exit(&port->lock);
   1840 		return;
   1841 	}
   1842 
   1843 	/* make sure port is ready */
   1844 	if (port->state != DS_PORT_READY) {
   1845 		/* can not send message */
   1846 		cmn_err(CE_WARN, "ds@%lx: unreg_nack>: port is not ready"
   1847 		    DS_EOL, PORTID(port));
   1848 		mutex_exit(&port->lock);
   1849 		return;
   1850 	}
   1851 
   1852 	mutex_exit(&port->lock);
   1853 
   1854 	msglen = DS_HDR_SZ + sizeof (ds_unreg_nack_t);
   1855 	msg = DS_MALLOC(msglen);
   1856 
   1857 	/* copy in the header data */
   1858 	hdr = (ds_hdr_t *)msg;
   1859 	hdr->msg_type = DS_UNREG_NACK;
   1860 	hdr->payload_len = sizeof (ds_unreg_nack_t);
   1861 
   1862 	nack = (ds_unreg_nack_t *)(msg + DS_HDR_SZ);
   1863 	nack->svc_handle = bad_hdl;
   1864 
   1865 	/* send the message */
   1866 	DS_DBG_PRCL(CE_NOTE, "ds@%lx: unreg_nack>: hdl=0x%llx" DS_EOL,
   1867 	    PORTID(port), (u_longlong_t)bad_hdl);
   1868 
   1869 	(void) ds_send_msg(port, msg, msglen);
   1870 	DS_FREE(msg, msglen);
   1871 }
   1872 
   1873 static void
   1874 ds_send_data_nack(ds_port_t *port, ds_svc_hdl_t bad_hdl)
   1875 {
   1876 	caddr_t		msg;
   1877 	size_t		msglen;
   1878 	ds_hdr_t	*hdr;
   1879 	ds_data_nack_t	*nack;
   1880 
   1881 	mutex_enter(&port->lock);
   1882 
   1883 	/* check on the LDC to Zeus */
   1884 	if (port->ldc.state != LDC_UP) {
   1885 		/* can not send message */
   1886 		cmn_err(CE_WARN, "ds@%lx: data_nack>: channel %ld is not up"
   1887 		    DS_EOL, PORTID(port), port->ldc.id);
   1888 		mutex_exit(&port->lock);
   1889 		return;
   1890 	}
   1891 
   1892 	/* make sure port is ready */
   1893 	if (port->state != DS_PORT_READY) {
   1894 		/* can not send message */
   1895 		cmn_err(CE_WARN, "ds@%lx: data_nack>: port is not ready" DS_EOL,
   1896 		    PORTID(port));
   1897 		mutex_exit(&port->lock);
   1898 		return;
   1899 	}
   1900 
   1901 	mutex_exit(&port->lock);
   1902 
   1903 	msglen = DS_HDR_SZ + sizeof (ds_data_nack_t);
   1904 	msg = DS_MALLOC(msglen);
   1905 
   1906 	/* copy in the header data */
   1907 	hdr = (ds_hdr_t *)msg;
   1908 	hdr->msg_type = DS_NACK;
   1909 	hdr->payload_len = sizeof (ds_data_nack_t);
   1910 
   1911 	nack = (ds_data_nack_t *)(msg + DS_HDR_SZ);
   1912 	nack->svc_handle = bad_hdl;
   1913 	nack->result = DS_INV_HDL;
   1914 
   1915 	/* send the message */
   1916 	DS_DBG_PRCL(CE_NOTE, "ds@%lx: data_nack>: hdl=0x%llx" DS_EOL,
   1917 	    PORTID(port), (u_longlong_t)bad_hdl);
   1918 
   1919 	(void) ds_send_msg(port, msg, msglen);
   1920 	DS_FREE(msg, msglen);
   1921 }
   1922 
   1923 /* END DS PROTOCOL SUPPORT FUNCTIONS */
   1924 
   1925 #ifdef DEBUG
   1926 
   1927 #define	BYTESPERLINE	8
   1928 #define	LINEWIDTH	((BYTESPERLINE * 3) + (BYTESPERLINE + 2) + 1)
   1929 #define	ASCIIOFFSET	((BYTESPERLINE * 3) + 2)
   1930 #define	ISPRINT(c)	((c >= ' ') && (c <= '~'))
   1931 
   1932 /*
   1933  * Output a buffer formatted with a set number of bytes on
   1934  * each line. Append each line with the ASCII equivalent of
   1935  * each byte if it falls within the printable ASCII range,
   1936  * and '.' otherwise.
   1937  */
   1938 void
   1939 ds_dump_msg(void *vbuf, size_t len)
   1940 {
   1941 	int	i, j;
   1942 	char	*curr;
   1943 	char	*aoff;
   1944 	char	line[LINEWIDTH];
   1945 	uint8_t	*buf = vbuf;
   1946 
   1947 	if (len > 128)
   1948 		len = 128;
   1949 
   1950 	/* walk the buffer one line at a time */
   1951 	for (i = 0; i < len; i += BYTESPERLINE) {
   1952 
   1953 		bzero(line, LINEWIDTH);
   1954 
   1955 		curr = line;
   1956 		aoff = line + ASCIIOFFSET;
   1957 
   1958 		/*
   1959 		 * Walk the bytes in the current line, storing
   1960 		 * the hex value for the byte as well as the
   1961 		 * ASCII representation in a temporary buffer.
   1962 		 * All ASCII values are placed at the end of
   1963 		 * the line.
   1964 		 */
   1965 		for (j = 0; (j < BYTESPERLINE) && ((i + j) < len); j++) {
   1966 			(void) sprintf(curr, " %02x", buf[i + j]);
   1967 			*aoff = (ISPRINT(buf[i + j])) ? buf[i + j] : '.';
   1968 			curr += 3;
   1969 			aoff++;
   1970 		}
   1971 
   1972 		/*
   1973 		 * Fill in to the start of the ASCII translation
   1974 		 * with spaces. This will only be necessary if
   1975 		 * this is the last line and there are not enough
   1976 		 * bytes to fill the whole line.
   1977 		 */
   1978 		while (curr != (line + ASCIIOFFSET))
   1979 			*curr++ = ' ';
   1980 
   1981 		cmn_err(CE_NOTE, "%s" DS_EOL, line);
   1982 	}
   1983 }
   1984 #endif /* DEBUG */
   1985 
   1986 
   1987 /*
   1988  * Walk the table of registered services, executing the specified callback
   1989  * function for each service on a port. A non-zero return value from the
   1990  * callback is used to terminate the walk, not to indicate an error. Returns
   1991  * the index of the last service visited.
   1992  */
   1993 int
   1994 ds_walk_svcs(svc_cb_t svc_cb, void *arg)
   1995 {
   1996 	int		idx;
   1997 	ds_svc_t	*svc;
   1998 
   1999 	ASSERT(MUTEX_HELD(&ds_svcs.lock));
   2000 
   2001 	/* walk every table entry */
   2002 	for (idx = 0; idx < ds_svcs.maxsvcs; idx++) {
   2003 		svc = ds_svcs.tbl[idx];
   2004 
   2005 		/* execute the callback */
   2006 		if ((*svc_cb)(svc, arg) != 0)
   2007 			break;
   2008 	}
   2009 
   2010 	return (idx);
   2011 }
   2012 
   2013 static int
   2014 ds_svc_isfree(ds_svc_t *svc, void *arg)
   2015 {
   2016 	_NOTE(ARGUNUSED(arg))
   2017 
   2018 	/*
   2019 	 * Looking for a free service. This may be a NULL entry
   2020 	 * in the table, or an unused structure that could be
   2021 	 * reused.
   2022 	 */
   2023 
   2024 	if (DS_SVC_ISFREE(svc)) {
   2025 		/* yes, it is free */
   2026 		return (1);
   2027 	}
   2028 
   2029 	/* not a candidate */
   2030 	return (0);
   2031 }
   2032 
   2033 int
   2034 ds_svc_ismatch(ds_svc_t *svc, void *arg)
   2035 {
   2036 	if (DS_SVC_ISFREE(svc)) {
   2037 		return (0);
   2038 	}
   2039 
   2040 	if (strcmp(svc->cap.svc_id, arg) == 0 &&
   2041 	    (svc->flags & DSSF_ISCLIENT) == 0) {
   2042 		/* found a match */
   2043 		return (1);
   2044 	}
   2045 
   2046 	return (0);
   2047 }
   2048 
   2049 int
   2050 ds_svc_clnt_ismatch(ds_svc_t *svc, void *arg)
   2051 {
   2052 	if (DS_SVC_ISFREE(svc)) {
   2053 		return (0);
   2054 	}
   2055 
   2056 	if (strcmp(svc->cap.svc_id, arg) == 0 &&
   2057 	    (svc->flags & DSSF_ISCLIENT) != 0) {
   2058 		/* found a match */
   2059 		return (1);
   2060 	}
   2061 
   2062 	return (0);
   2063 }
   2064 
   2065 int
   2066 ds_svc_free(ds_svc_t *svc, void *arg)
   2067 {
   2068 	_NOTE(ARGUNUSED(arg))
   2069 
   2070 	if (svc == NULL) {
   2071 		return (0);
   2072 	}
   2073 
   2074 	if (svc->cap.svc_id) {
   2075 		DS_FREE(svc->cap.svc_id, strlen(svc->cap.svc_id) + 1);
   2076 		svc->cap.svc_id = NULL;
   2077 	}
   2078 
   2079 	if (svc->cap.vers) {
   2080 		DS_FREE(svc->cap.vers, svc->cap.nvers * sizeof (ds_ver_t));
   2081 		svc->cap.vers = NULL;
   2082 	}
   2083 
   2084 	DS_FREE(svc, sizeof (ds_svc_t));
   2085 
   2086 	return (0);
   2087 }
   2088 
   2089 static void
   2090 ds_set_svc_port_tried(char *svc_id, ds_port_t *port)
   2091 {
   2092 	int		idx;
   2093 	ds_svc_t	*svc;
   2094 
   2095 	ASSERT(MUTEX_HELD(&ds_svcs.lock));
   2096 
   2097 	/* walk every table entry */
   2098 	for (idx = 0; idx < ds_svcs.maxsvcs; idx++) {
   2099 		svc = ds_svcs.tbl[idx];
   2100 		if (!DS_SVC_ISFREE(svc) && (svc->flags & DSSF_ISCLIENT) != 0 &&
   2101 		    strcmp(svc_id, svc->cap.svc_id) == 0)
   2102 			DS_PORTSET_ADD(svc->tried, PORTID(port));
   2103 	}
   2104 }
   2105 
   2106 static int
   2107 ds_svc_register_onport(ds_svc_t *svc, ds_port_t *port)
   2108 {
   2109 	ASSERT(MUTEX_HELD(&ds_svcs.lock));
   2110 
   2111 	if (DS_SVC_ISFREE(svc))
   2112 		return (0);
   2113 
   2114 	if (!DS_PORT_IN_SET(svc->avail, PORTID(port)))
   2115 		return (0);
   2116 
   2117 	if (DS_PORT_IN_SET(svc->tried, PORTID(port)))
   2118 		return (0);
   2119 
   2120 	if ((svc->flags & DSSF_ISCLIENT) == 0) {
   2121 		DS_PORTSET_ADD(svc->tried, PORTID(port));
   2122 		if (svc->state != DS_SVC_INACTIVE)
   2123 			return (0);
   2124 	} else {
   2125 		ds_set_svc_port_tried(svc->cap.svc_id, port);
   2126 
   2127 		/*
   2128 		 * Never send a client reg req to the SP.
   2129 		 */
   2130 		if (PORTID(port) == ds_sp_port_id) {
   2131 			return (0);
   2132 		}
   2133 	}
   2134 
   2135 	if (ds_send_reg_req(svc, port) == 0) {
   2136 		/* register sent successfully */
   2137 		return (1);
   2138 	}
   2139 
   2140 	if ((svc->flags & DSSF_ISCLIENT) == 0) {
   2141 		/* reset the service */
   2142 		ds_reset_svc(svc, port);
   2143 	}
   2144 	return (0);
   2145 }
   2146 
   2147 static int
   2148 ds_svc_register_onport_walker(ds_svc_t *svc, void *arg)
   2149 {
   2150 	ASSERT(MUTEX_HELD(&ds_svcs.lock));
   2151 
   2152 	if (DS_SVC_ISFREE(svc))
   2153 		return (0);
   2154 
   2155 	(void) ds_svc_register_onport(svc, arg);
   2156 	return (0);
   2157 }
   2158 
   2159 int
   2160 ds_svc_register(ds_svc_t *svc, void *arg)
   2161 {
   2162 	_NOTE(ARGUNUSED(arg))
   2163 	ds_portset_t ports;
   2164 	ds_port_t *port;
   2165 	int	idx;
   2166 
   2167 	ASSERT(MUTEX_HELD(&ds_svcs.lock));
   2168 
   2169 	if (DS_SVC_ISFREE(svc))
   2170 		return (0);
   2171 
   2172 	DS_PORTSET_DUP(ports, svc->avail);
   2173 	if (svc->flags & DSSF_ISCLIENT) {
   2174 		for (idx = 0; idx < DS_MAX_PORTS; idx++) {
   2175 			if (DS_PORT_IN_SET(svc->tried, idx))
   2176 				DS_PORTSET_DEL(ports, idx);
   2177 		}
   2178 	} else if (svc->state != DS_SVC_INACTIVE)
   2179 		return (0);
   2180 
   2181 	if (DS_PORTSET_ISNULL(ports))
   2182 		return (0);
   2183 
   2184 	/*
   2185 	 * Attempt to register the service. Start with the lowest
   2186 	 * numbered port and continue until a registration message
   2187 	 * is sent successfully, or there are no ports left to try.
   2188 	 */
   2189 	for (idx = 0; idx < DS_MAX_PORTS; idx++) {
   2190 
   2191 		/*
   2192 		 * If the port is not in the available list,
   2193 		 * it is not a candidate for registration.
   2194 		 */
   2195 		if (!DS_PORT_IN_SET(ports, idx)) {
   2196 			continue;
   2197 		}
   2198 
   2199 		port = &ds_ports[idx];
   2200 		if (ds_svc_register_onport(svc, port)) {
   2201 			if ((svc->flags & DSSF_ISCLIENT) == 0)
   2202 				break;
   2203 		}
   2204 	}
   2205 
   2206 	return (0);
   2207 }
   2208 
   2209 static int
   2210 ds_svc_unregister(ds_svc_t *svc, void *arg)
   2211 {
   2212 	ds_port_t *port = (ds_port_t *)arg;
   2213 	ds_svc_hdl_t hdl;
   2214 
   2215 	ASSERT(MUTEX_HELD(&ds_svcs.lock));
   2216 
   2217 	if (DS_SVC_ISFREE(svc)) {
   2218 		return (0);
   2219 	}
   2220 
   2221 	/* make sure the service is using this port */
   2222 	if (svc->port != port) {
   2223 		return (0);
   2224 	}
   2225 
   2226 	if (port) {
   2227 		DS_DBG(CE_NOTE, "ds@%lx: svc_unreg: id='%s', ver=%d.%d, "
   2228 		    " hdl=0x%09lx" DS_EOL, PORTID(port), svc->cap.svc_id,
   2229 		    svc->ver.major, svc->ver.minor, svc->hdl);
   2230 	} else {
   2231 		DS_DBG(CE_NOTE, "port=NULL: svc_unreg: id='%s', ver=%d.%d, "
   2232 		    " hdl=0x%09lx" DS_EOL, svc->cap.svc_id, svc->ver.major,
   2233 		    svc->ver.minor, svc->hdl);
   2234 	}
   2235 
   2236 	/* reset the service structure */
   2237 	ds_reset_svc(svc, port);
   2238 
   2239 	/* call the client unregister callback */
   2240 	if (svc->ops.ds_unreg_cb) {
   2241 		(*svc->ops.ds_unreg_cb)(svc->ops.cb_arg);
   2242 	}
   2243 
   2244 	/* increment the count in the handle to prevent reuse */
   2245 	hdl = DS_ALLOC_HDL(DS_HDL2IDX(svc->hdl), DS_HDL2COUNT(svc->hdl));
   2246 	if (DS_HDL_ISCLIENT(svc->hdl)) {
   2247 		DS_HDL_SET_ISCLIENT(hdl);
   2248 	}
   2249 	svc->hdl = hdl;
   2250 
   2251 	if (svc->state != DS_SVC_UNREG_PENDING) {
   2252 		/* try to initiate a new registration */
   2253 		(void) ds_svc_register(svc, NULL);
   2254 	}
   2255 
   2256 	return (0);
   2257 }
   2258 
   2259 static int
   2260 ds_svc_port_up(ds_svc_t *svc, void *arg)
   2261 {
   2262 	ds_port_t *port = (ds_port_t *)arg;
   2263 
   2264 	if (DS_SVC_ISFREE(svc)) {
   2265 		/* nothing to do */
   2266 		return (0);
   2267 	}
   2268 
   2269 	DS_PORTSET_ADD(svc->avail, port->id);
   2270 	DS_PORTSET_DEL(svc->tried, port->id);
   2271 
   2272 	return (0);
   2273 }
   2274 
   2275 static void
   2276 ds_set_port_ready(ds_port_t *port, uint16_t major, uint16_t minor)
   2277 {
   2278 	boolean_t was_ready;
   2279 
   2280 	mutex_enter(&port->lock);
   2281 	was_ready = (port->state == DS_PORT_READY);
   2282 	if (!was_ready) {
   2283 		port->state = DS_PORT_READY;
   2284 		port->ver.major = major;
   2285 		port->ver.minor = minor;
   2286 	}
   2287 	mutex_exit(&port->lock);
   2288 
   2289 	if (!was_ready) {
   2290 
   2291 		/*
   2292 		 * The port came up, so update all the services
   2293 		 * with this information. Follow that up with an
   2294 		 * attempt to register any service that is not
   2295 		 * already registered.
   2296 		 */
   2297 		mutex_enter(&ds_svcs.lock);
   2298 
   2299 		(void) ds_walk_svcs(ds_svc_port_up, port);
   2300 		(void) ds_walk_svcs(ds_svc_register_onport_walker, port);
   2301 
   2302 		mutex_exit(&ds_svcs.lock);
   2303 	}
   2304 }
   2305 
   2306 ds_svc_t *
   2307 ds_alloc_svc(void)
   2308 {
   2309 	int		idx;
   2310 	uint_t		newmaxsvcs;
   2311 	ds_svc_t	**newtbl;
   2312 	ds_svc_t	*newsvc;
   2313 
   2314 	ASSERT(MUTEX_HELD(&ds_svcs.lock));
   2315 
   2316 	idx = ds_walk_svcs(ds_svc_isfree, NULL);
   2317 
   2318 	if (idx != ds_svcs.maxsvcs) {
   2319 		goto found;
   2320 	}
   2321 
   2322 	/*
   2323 	 * There was no free space in the table. Grow
   2324 	 * the table to double its current size.
   2325 	 */
   2326 	newmaxsvcs = ds_svcs.maxsvcs * 2;
   2327 	newtbl = DS_MALLOC(newmaxsvcs * sizeof (ds_svc_t *));
   2328 
   2329 	/* copy old table data to the new table */
   2330 	(void) memcpy(newtbl, ds_svcs.tbl,
   2331 	    ds_svcs.maxsvcs * sizeof (ds_svc_t *));
   2332 
   2333 	/* clean up the old table */
   2334 	DS_FREE(ds_svcs.tbl, ds_svcs.maxsvcs * sizeof (ds_svc_t *));
   2335 	ds_svcs.tbl = newtbl;
   2336 	ds_svcs.maxsvcs = newmaxsvcs;
   2337 
   2338 	/* search for a free space again */
   2339 	idx = ds_walk_svcs(ds_svc_isfree, NULL);
   2340 
   2341 	/* the table is locked so should find a free slot */
   2342 	ASSERT(idx != ds_svcs.maxsvcs);
   2343 
   2344 found:
   2345 	/* allocate a new svc structure if necessary */
   2346 	if ((newsvc = ds_svcs.tbl[idx]) == NULL) {
   2347 		/* allocate a new service */
   2348 		newsvc = DS_MALLOC(sizeof (ds_svc_t));
   2349 		ds_svcs.tbl[idx] = newsvc;
   2350 	}
   2351 
   2352 	/* fill in the handle */
   2353 	newsvc->hdl = DS_ALLOC_HDL(idx, DS_HDL2COUNT(newsvc->hdl));
   2354 	newsvc->state = DS_SVC_FREE;	/* Mark as free temporarily */
   2355 
   2356 	return (newsvc);
   2357 }
   2358 
   2359 static void
   2360 ds_reset_svc(ds_svc_t *svc, ds_port_t *port)
   2361 {
   2362 	ASSERT(MUTEX_HELD(&ds_svcs.lock));
   2363 
   2364 	if (svc->state != DS_SVC_UNREG_PENDING)
   2365 		svc->state = DS_SVC_INACTIVE;
   2366 	svc->ver_idx = 0;
   2367 	svc->ver.major = 0;
   2368 	svc->ver.minor = 0;
   2369 	svc->port = NULL;
   2370 	if (port) {
   2371 		DS_PORTSET_DEL(svc->avail, port->id);
   2372 	}
   2373 }
   2374 
   2375 ds_svc_t *
   2376 ds_get_svc(ds_svc_hdl_t hdl)
   2377 {
   2378 	int		idx;
   2379 	ds_svc_t	*svc;
   2380 
   2381 	ASSERT(MUTEX_HELD(&ds_svcs.lock));
   2382 
   2383 	if (hdl == DS_INVALID_HDL)
   2384 		return (NULL);
   2385 
   2386 	idx = DS_HDL2IDX(hdl);
   2387 
   2388 	/* check if index is out of bounds */
   2389 	if ((idx < 0) || (idx >= ds_svcs.maxsvcs))
   2390 		return (NULL);
   2391 
   2392 	svc = ds_svcs.tbl[idx];
   2393 
   2394 	/* check for a valid service */
   2395 	if (DS_SVC_ISFREE(svc))
   2396 		return (NULL);
   2397 
   2398 	/* make sure the handle is an exact match */
   2399 	if (svc->hdl != hdl)
   2400 		return (NULL);
   2401 
   2402 	return (svc);
   2403 }
   2404 
   2405 static void
   2406 ds_port_reset(ds_port_t *port)
   2407 {
   2408 	ASSERT(MUTEX_HELD(&ds_svcs.lock));
   2409 	ASSERT(MUTEX_HELD(&port->lock));
   2410 
   2411 	/* connection went down, mark everything inactive */
   2412 	(void) ds_walk_svcs(ds_svc_unregister, port);
   2413 
   2414 	port->ver_idx = 0;
   2415 	port->ver.major = 0;
   2416 	port->ver.minor = 0;
   2417 	port->state = DS_PORT_LDC_INIT;
   2418 }
   2419 
   2420 /*
   2421  * Verify that a version array is sorted as expected for the
   2422  * version negotiation to work correctly.
   2423  */
   2424 ds_vers_check_t
   2425 ds_vers_isvalid(ds_ver_t *vers, int nvers)
   2426 {
   2427 	uint16_t	curr_major;
   2428 	uint16_t	curr_minor;
   2429 	int		idx;
   2430 
   2431 	curr_major = vers[0].major;
   2432 	curr_minor = vers[0].minor;
   2433 
   2434 	/*
   2435 	 * Walk the version array, verifying correct ordering.
   2436 	 * The array must be sorted from highest supported
   2437 	 * version to lowest supported version.
   2438 	 */
   2439 	for (idx = 0; idx < nvers; idx++) {
   2440 		if (vers[idx].major > curr_major) {
   2441 			DS_DBG(CE_NOTE, "ds_vers_isvalid: version array has "
   2442 			    " increasing major versions" DS_EOL);
   2443 			return (DS_VERS_INCREASING_MAJOR_ERR);
   2444 		}
   2445 
   2446 		if (vers[idx].major < curr_major) {
   2447 			curr_major = vers[idx].major;
   2448 			curr_minor = vers[idx].minor;
   2449 			continue;
   2450 		}
   2451 
   2452 		if (vers[idx].minor > curr_minor) {
   2453 			DS_DBG(CE_NOTE, "ds_vers_isvalid: version array has "
   2454 			    " increasing minor versions" DS_EOL);
   2455 			return (DS_VERS_INCREASING_MINOR_ERR);
   2456 		}
   2457 
   2458 		curr_minor = vers[idx].minor;
   2459 	}
   2460 
   2461 	return (DS_VERS_OK);
   2462 }
   2463 
   2464 /*
   2465  * Extended user capability init.
   2466  */
   2467 int
   2468 ds_ucap_init(ds_capability_t *cap, ds_clnt_ops_t *ops, uint32_t flags,
   2469     int instance, ds_svc_hdl_t *hdlp)
   2470 {
   2471 	ds_vers_check_t	status;
   2472 	ds_svc_t	*svc;
   2473 	int		rv = 0;
   2474 	ds_svc_hdl_t 	lb_hdl, hdl;
   2475 	int		is_loopback;
   2476 	int		is_client;
   2477 
   2478 	/* sanity check the args */
   2479 	if ((cap == NULL) || (ops == NULL)) {
   2480 		cmn_err(CE_NOTE, "%s: invalid arguments" DS_EOL, __func__);
   2481 		return (EINVAL);
   2482 	}
   2483 
   2484 	/* sanity check the capability specifier */
   2485 	if ((cap->svc_id == NULL) || (cap->vers == NULL) || (cap->nvers == 0)) {
   2486 		cmn_err(CE_NOTE, "%s: invalid capability specifier" DS_EOL,
   2487 		    __func__);
   2488 		return (EINVAL);
   2489 	}
   2490 
   2491 	/* sanity check the version array */
   2492 	if ((status = ds_vers_isvalid(cap->vers, cap->nvers)) != DS_VERS_OK) {
   2493 		cmn_err(CE_NOTE, "%s: invalid capability version array "
   2494 		    "for %s service: %s" DS_EOL, __func__, cap->svc_id,
   2495 		    (status == DS_VERS_INCREASING_MAJOR_ERR) ?
   2496 		    "increasing major versions" :
   2497 		    "increasing minor versions");
   2498 		return (EINVAL);
   2499 	}
   2500 
   2501 	/* data and register callbacks are required */
   2502 	if ((ops->ds_data_cb == NULL) || (ops->ds_reg_cb == NULL)) {
   2503 		cmn_err(CE_NOTE, "%s: invalid ops specifier for %s service"
   2504 		    DS_EOL, __func__, cap->svc_id);
   2505 		return (EINVAL);
   2506 	}
   2507 
   2508 	flags &= DSSF_USERFLAGS;
   2509 	is_client = flags & DSSF_ISCLIENT;
   2510 
   2511 	DS_DBG_USR(CE_NOTE, "%s: svc_id='%s', data_cb=0x%lx, cb_arg=0x%lx"
   2512 	    DS_EOL, __func__, cap->svc_id, PTR_TO_LONG(ops->ds_data_cb),
   2513 	    PTR_TO_LONG(ops->cb_arg));
   2514 
   2515 	mutex_enter(&ds_svcs.lock);
   2516 
   2517 	/* check if the service is already registered */
   2518 	if (i_ds_hdl_lookup(cap->svc_id, is_client, NULL, 1) == 1) {
   2519 		/* already registered */
   2520 		cmn_err(CE_NOTE, "Service '%s'/%s already registered" DS_EOL,
   2521 		    cap->svc_id,
   2522 		    (flags & DSSF_ISCLIENT) ? "client" : "service");
   2523 		mutex_exit(&ds_svcs.lock);
   2524 		return (EALREADY);
   2525 	}
   2526 
   2527 	svc = ds_alloc_svc();
   2528 	if (is_client) {
   2529 		DS_HDL_SET_ISCLIENT(svc->hdl);
   2530 	}
   2531 
   2532 	svc->state = DS_SVC_FREE;
   2533 	svc->svc_hdl = DS_BADHDL1;
   2534 
   2535 	svc->flags = flags;
   2536 	svc->drvi = instance;
   2537 	svc->drv_psp = NULL;
   2538 
   2539 	/*
   2540 	 * Check for loopback.  "pri" is a legacy service that assumes it
   2541 	 * will never use loopback mode.
   2542 	 */
   2543 	if (strcmp(cap->svc_id, "pri") == 0) {
   2544 		is_loopback = 0;
   2545 	} else if (i_ds_hdl_lookup(cap->svc_id, is_client == 0, &lb_hdl, 1)
   2546 	    == 1) {
   2547 		if ((rv = ds_loopback_set_svc(svc, cap, &lb_hdl)) != 0) {
   2548 			DS_DBG_USR(CE_NOTE, "%s: ds_loopback_set_svc '%s' err "
   2549 			    " (%d)" DS_EOL, __func__, cap->svc_id, rv);
   2550 			mutex_exit(&ds_svcs.lock);
   2551 			return (rv);
   2552 		}
   2553 		is_loopback = 1;
   2554 	} else
   2555 		is_loopback = 0;
   2556 
   2557 	/* copy over all the client information */
   2558 	(void) memcpy(&svc->cap, cap, sizeof (ds_capability_t));
   2559 
   2560 	/* make a copy of the service name */
   2561 	svc->cap.svc_id = ds_strdup(cap->svc_id);
   2562 
   2563 	/* make a copy of the version array */
   2564 	svc->cap.vers = DS_MALLOC(cap->nvers * sizeof (ds_ver_t));
   2565 	(void) memcpy(svc->cap.vers, cap->vers, cap->nvers * sizeof (ds_ver_t));
   2566 
   2567 	/* copy the client ops vector */
   2568 	(void) memcpy(&svc->ops, ops, sizeof (ds_clnt_ops_t));
   2569 
   2570 	svc->state = DS_SVC_INACTIVE;
   2571 	svc->ver_idx = 0;
   2572 	DS_PORTSET_DUP(svc->avail, ds_allports);
   2573 	DS_PORTSET_SETNULL(svc->tried);
   2574 
   2575 	ds_svcs.nsvcs++;
   2576 
   2577 	hdl = svc->hdl;
   2578 
   2579 	/*
   2580 	 * kludge to allow user callback code to get handle and user args.
   2581 	 * Make sure the callback arg points to the svc structure.
   2582 	 */
   2583 	if ((flags & DSSF_ISUSER) != 0) {
   2584 		ds_cbarg_set_cookie(svc);
   2585 	}
   2586 
   2587 	if (is_loopback) {
   2588 		ds_loopback_register(hdl);
   2589 		ds_loopback_register(lb_hdl);
   2590 	}
   2591 
   2592 	/*
   2593 	 * If this is a client or a non-loopback service provider, send
   2594 	 * out register requests.
   2595 	 */
   2596 	if (!is_loopback || (flags & DSSF_ISCLIENT) != 0)
   2597 		(void) ds_svc_register(svc, NULL);
   2598 
   2599 	if (hdlp) {
   2600 		*hdlp = hdl;
   2601 	}
   2602 
   2603 	mutex_exit(&ds_svcs.lock);
   2604 
   2605 	DS_DBG_USR(CE_NOTE, "%s: service '%s' assigned handle 0x%09lx" DS_EOL,
   2606 	    __func__, svc->cap.svc_id, hdl);
   2607 
   2608 	return (0);
   2609 }
   2610 
   2611 /*
   2612  * ds_cap_init interface for previous revision.
   2613  */
   2614 int
   2615 ds_cap_init(ds_capability_t *cap, ds_clnt_ops_t *ops)
   2616 {
   2617 	return (ds_ucap_init(cap, ops, 0, DS_INVALID_INSTANCE, NULL));
   2618 }
   2619 
   2620 /*
   2621  * Interface for ds_unreg_hdl in lds driver.
   2622  */
   2623 int
   2624 ds_unreg_hdl(ds_svc_hdl_t hdl)
   2625 {
   2626 	ds_svc_t	*svc;
   2627 	int		is_loopback;
   2628 	ds_svc_hdl_t	lb_hdl;
   2629 
   2630 	DS_DBG_USR(CE_NOTE, "%s: hdl=0x%09lx" DS_EOL, __func__, hdl);
   2631 
   2632 	mutex_enter(&ds_svcs.lock);
   2633 	if ((svc = ds_get_svc(hdl)) == NULL) {
   2634 		mutex_exit(&ds_svcs.lock);
   2635 		DS_DBG_USR(CE_NOTE, "%s: unknown hdl: 0x%llx" DS_EOL, __func__,
   2636 		    (u_longlong_t)hdl);
   2637 		return (ENXIO);
   2638 	}
   2639 
   2640 	DS_DBG_USR(CE_NOTE, "%s: svcid='%s', hdl=0x%llx" DS_EOL, __func__,
   2641 	    svc->cap.svc_id, (u_longlong_t)svc->hdl);
   2642 
   2643 	svc->state = DS_SVC_UNREG_PENDING;
   2644 
   2645 	is_loopback = ((svc->flags & DSSF_LOOPBACK) != 0);
   2646 	lb_hdl = svc->svc_hdl;
   2647 
   2648 	if (svc->port) {
   2649 		(void) ds_send_unreg_req(svc);
   2650 	}
   2651 
   2652 	(void) ds_svc_unregister(svc, svc->port);
   2653 
   2654 	ds_delete_svc_entry(svc);
   2655 
   2656 	if (is_loopback) {
   2657 		ds_loopback_unregister(lb_hdl);
   2658 	}
   2659 
   2660 	mutex_exit(&ds_svcs.lock);
   2661 
   2662 	return (0);
   2663 }
   2664 
   2665 int
   2666 ds_cap_fini(ds_capability_t *cap)
   2667 {
   2668 	ds_svc_hdl_t	hdl;
   2669 	int rv;
   2670 	uint_t nhdls = 0;
   2671 
   2672 	DS_DBG(CE_NOTE, "%s: '%s'" DS_EOL, __func__, cap->svc_id);
   2673 	if ((rv = ds_hdl_lookup(cap->svc_id, 0, &hdl, 1, &nhdls)) != 0) {
   2674 		DS_DBG(CE_NOTE, "%s: ds_hdl_lookup '%s' err (%d)" DS_EOL,
   2675 		    __func__, cap->svc_id, rv);
   2676 		return (rv);
   2677 	}
   2678 
   2679 	if (nhdls == 0) {
   2680 		DS_DBG(CE_NOTE, "%s: no such service '%s'" DS_EOL,
   2681 		    __func__, cap->svc_id);
   2682 		return (ENXIO);
   2683 	}
   2684 
   2685 	if ((rv = ds_is_my_hdl(hdl, DS_INVALID_INSTANCE)) != 0) {
   2686 		DS_DBG(CE_NOTE, "%s: ds_is_my_handle err (%d)" DS_EOL, __func__,
   2687 		    rv);
   2688 		return (rv);
   2689 	}
   2690 
   2691 	if ((rv = ds_unreg_hdl(hdl)) != 0) {
   2692 		DS_DBG(CE_NOTE, "%s: ds_unreg_hdl err (%d)" DS_EOL, __func__,
   2693 		    rv);
   2694 		return (rv);
   2695 	}
   2696 
   2697 	return (0);
   2698 }
   2699 
   2700 int
   2701 ds_cap_send(ds_svc_hdl_t hdl, void *buf, size_t len)
   2702 {
   2703 	int		rv;
   2704 	ds_hdr_t	*hdr;
   2705 	caddr_t		msg;
   2706 	size_t		msglen;
   2707 	size_t		hdrlen;
   2708 	caddr_t		payload;
   2709 	ds_svc_t	*svc;
   2710 	ds_port_t	*port;
   2711 	ds_data_handle_t *data;
   2712 	ds_svc_hdl_t	svc_hdl;
   2713 	int		is_client = 0;
   2714 
   2715 	DS_DBG(CE_NOTE, "%s: hdl: 0x%llx, buf: %lx, len: %ld" DS_EOL, __func__,
   2716 	    (u_longlong_t)hdl, (ulong_t)buf, len);
   2717 
   2718 	mutex_enter(&ds_svcs.lock);
   2719 
   2720 	if ((svc = ds_get_svc(hdl)) == NULL) {
   2721 		cmn_err(CE_WARN, "%s: invalid handle 0x%llx" DS_EOL, __func__,
   2722 		    (u_longlong_t)hdl);
   2723 		mutex_exit(&ds_svcs.lock);
   2724 		return (ENXIO);
   2725 	}
   2726 
   2727 	if (svc->state != DS_SVC_ACTIVE) {
   2728 		/* channel is up, but svc is not registered */
   2729 		DS_DBG(CE_NOTE, "%s: invalid service state 0x%x" DS_EOL,
   2730 		    __func__, svc->state);
   2731 		mutex_exit(&ds_svcs.lock);
   2732 		return (ENOTCONN);
   2733 	}
   2734 
   2735 	if (svc->flags & DSSF_LOOPBACK) {
   2736 		hdl = svc->svc_hdl;
   2737 		mutex_exit(&ds_svcs.lock);
   2738 		ds_loopback_send(hdl, buf, len);
   2739 		return (0);
   2740 	}
   2741 
   2742 	if ((port = svc->port) == NULL) {
   2743 		DS_DBG(CE_NOTE, "%s: service '%s' not associated with a port"
   2744 		    DS_EOL, __func__, svc->cap.svc_id);
   2745 		mutex_exit(&ds_svcs.lock);
   2746 		return (ECONNRESET);
   2747 	}
   2748 
   2749 	if (svc->flags & DSSF_ISCLIENT) {
   2750 		is_client = 1;
   2751 		svc_hdl = svc->svc_hdl;
   2752 	}
   2753 
   2754 	mutex_exit(&ds_svcs.lock);
   2755 
   2756 	/* check that the LDC channel is ready */
   2757 	if (port->ldc.state != LDC_UP) {
   2758 		DS_DBG(CE_NOTE, "%s: LDC channel is not up" DS_EOL, __func__);
   2759 		return (ECONNRESET);
   2760 	}
   2761 
   2762 	hdrlen = DS_HDR_SZ + sizeof (ds_data_handle_t);
   2763 
   2764 	msg = DS_MALLOC(len + hdrlen);
   2765 	hdr = (ds_hdr_t *)msg;
   2766 	payload = msg + hdrlen;
   2767 	msglen = len + hdrlen;
   2768 
   2769 	hdr->payload_len = len + sizeof (ds_data_handle_t);
   2770 	hdr->msg_type = DS_DATA;
   2771 
   2772 	data = (ds_data_handle_t *)(msg + DS_HDR_SZ);
   2773 	if (is_client) {
   2774 		data->svc_handle = svc_hdl;
   2775 	} else {
   2776 		data->svc_handle = hdl;
   2777 	}
   2778 
   2779 	if ((buf != NULL) && (len != 0)) {
   2780 		(void) memcpy(payload, buf, len);
   2781 	}
   2782 
   2783 	DS_DBG_PRCL(CE_NOTE, "ds@%lx: data>: hdl=0x%llx, len=%ld, "
   2784 	    " payload_len=%d" DS_EOL, PORTID(port), (u_longlong_t)svc->hdl,
   2785 	    msglen, hdr->payload_len);
   2786 	DS_DUMP_MSG(DS_DBG_FLAG_PRCL, msg, msglen);
   2787 
   2788 	if ((rv = ds_send_msg(port, msg, msglen)) != 0) {
   2789 		rv = (rv == EIO) ? ECONNRESET : rv;
   2790 	}
   2791 	DS_FREE(msg, msglen);
   2792 
   2793 	return (rv);
   2794 }
   2795 
   2796 void
   2797 ds_port_common_init(ds_port_t *port)
   2798 {
   2799 	int rv;
   2800 
   2801 	if ((port->flags & DS_PORT_MUTEX_INITED) == 0) {
   2802 		mutex_init(&port->lock, NULL, MUTEX_DRIVER, NULL);
   2803 		mutex_init(&port->tx_lock, NULL, MUTEX_DRIVER, NULL);
   2804 		mutex_init(&port->rcv_lock, NULL, MUTEX_DRIVER, NULL);
   2805 		port->flags |= DS_PORT_MUTEX_INITED;
   2806 	}
   2807 
   2808 	port->state = DS_PORT_INIT;
   2809 	DS_PORTSET_ADD(ds_allports, port->id);
   2810 
   2811 	ds_sys_port_init(port);
   2812 
   2813 	mutex_enter(&port->lock);
   2814 	rv = ds_ldc_init(port);
   2815 	mutex_exit(&port->lock);
   2816 
   2817 	/*
   2818 	 * If LDC successfully init'ed, try to kick off protocol for this port.
   2819 	 */
   2820 	if (rv == 0) {
   2821 		ds_handle_up_event(port);
   2822 	}
   2823 }
   2824 
   2825 void
   2826 ds_port_common_fini(ds_port_t *port)
   2827 {
   2828 	ASSERT(MUTEX_HELD(&port->lock));
   2829 
   2830 	port->state = DS_PORT_FREE;
   2831 
   2832 	DS_PORTSET_DEL(ds_allports, port->id);
   2833 
   2834 	ds_sys_port_fini(port);
   2835 }
   2836 
   2837 /*
   2838  * Initialize table of registered service classes
   2839  */
   2840 void
   2841 ds_init_svcs_tbl(uint_t nentries)
   2842 {
   2843 	int	tblsz;
   2844 
   2845 	ds_svcs.maxsvcs = nentries;
   2846 
   2847 	tblsz = ds_svcs.maxsvcs * sizeof (ds_svc_t *);
   2848 	ds_svcs.tbl = (ds_svc_t **)DS_MALLOC(tblsz);
   2849 
   2850 	ds_svcs.nsvcs = 0;
   2851 }
   2852 
   2853 /*
   2854  * Find the max and min version supported.
   2855  * Hacked from zeus workspace, support.c
   2856  */
   2857 static void
   2858 min_max_versions(int num_versions, ds_ver_t *sup_versionsp,
   2859     uint16_t *min_major, uint16_t *max_major)
   2860 {
   2861 	int i;
   2862 
   2863 	*min_major = sup_versionsp[0].major;
   2864 	*max_major = *min_major;
   2865 
   2866 	for (i = 1; i < num_versions; i++) {
   2867 		if (sup_versionsp[i].major < *min_major)
   2868 			*min_major = sup_versionsp[i].major;
   2869 
   2870 		if (sup_versionsp[i].major > *max_major)
   2871 			*max_major = sup_versionsp[i].major;
   2872 	}
   2873 }
   2874 
   2875 /*
   2876  * Check whether the major and minor numbers requested by the peer can be
   2877  * satisfied. If the requested major is supported, true is returned, and the
   2878  * agreed minor is returned in new_minor. If the requested major is not
   2879  * supported, the routine returns false, and the closest major is returned in
   2880  * *new_major, upon which the peer should re-negotiate. The closest major is
   2881  * the just lower that the requested major number.
   2882  *
   2883  * Hacked from zeus workspace, support.c
   2884  */
   2885 boolean_t
   2886 negotiate_version(int num_versions, ds_ver_t *sup_versionsp,
   2887     uint16_t req_major, uint16_t *new_majorp, uint16_t *new_minorp)
   2888 {
   2889 	int i;
   2890 	uint16_t major, lower_major;
   2891 	uint16_t min_major = 0, max_major;
   2892 	boolean_t found_match = B_FALSE;
   2893 
   2894 	min_max_versions(num_versions, sup_versionsp, &min_major, &max_major);
   2895 
   2896 	DS_DBG(CE_NOTE, "negotiate_version: req_major = %u, min = %u, max = %u"
   2897 	    DS_EOL, req_major, min_major, max_major);
   2898 
   2899 	/*
   2900 	 * If the minimum version supported is greater than
   2901 	 * the version requested, return the lowest version
   2902 	 * supported
   2903 	 */
   2904 	if (min_major > req_major) {
   2905 		*new_majorp = min_major;
   2906 		return (B_FALSE);
   2907 	}
   2908 
   2909 	/*
   2910 	 * If the largest version supported is lower than
   2911 	 * the version requested, return the largest version
   2912 	 * supported
   2913 	 */
   2914 	if (max_major < req_major) {
   2915 		*new_majorp = max_major;
   2916 		return (B_FALSE);
   2917 	}
   2918 
   2919 	/*
   2920 	 * Now we know that the requested version lies between the
   2921 	 * min and max versions supported. Check if the requested
   2922 	 * major can be found in supported versions.
   2923 	 */
   2924 	lower_major = min_major;
   2925 	for (i = 0; i < num_versions; i++) {
   2926 		major = sup_versionsp[i].major;
   2927 		if (major == req_major) {
   2928 			found_match = B_TRUE;
   2929 			*new_majorp = req_major;
   2930 			*new_minorp = sup_versionsp[i].minor;
   2931 			break;
   2932 		} else {
   2933 			if ((major < req_major) && (major > lower_major))
   2934 				lower_major = major;
   2935 		}
   2936 	}
   2937 
   2938 	/*
   2939 	 * If no match is found, return the closest available number
   2940 	 */
   2941 	if (!found_match)
   2942 		*new_majorp = lower_major;
   2943 
   2944 	return (found_match);
   2945 }
   2946 
   2947 /*
   2948  * Specific errno's that are used by ds.c and ldc.c
   2949  */
   2950 static struct {
   2951 	int ds_errno;
   2952 	char *estr;
   2953 } ds_errno_to_str_tab[] = {
   2954 	{ EIO,		"I/O error" },
   2955 	{ ENXIO,	"No such device or address" },
   2956 	{ EAGAIN,	"Resource temporarily unavailable" },
   2957 	{ ENOMEM,	"Not enough space" },
   2958 	{ EACCES,	"Permission denied" },
   2959 	{ EFAULT,	"Bad address" },
   2960 	{ EBUSY,	"Device busy" },
   2961 	{ EINVAL,	"Invalid argument" },
   2962 	{ ENOSPC,	"No space left on device" },
   2963 	{ ENOMSG,	"No message of desired type" },
   2964 #ifdef	ECHRNG
   2965 	{ ECHRNG,	"Channel number out of range" },
   2966 #endif
   2967 	{ ENOTSUP,	"Operation not supported" },
   2968 	{ EMSGSIZE,	"Message too long" },
   2969 	{ EADDRINUSE,	"Address already in use" },
   2970 	{ ECONNRESET,	"Connection reset by peer" },
   2971 	{ ENOBUFS,	"No buffer space available" },
   2972 	{ ENOTCONN,	"Socket is not connected" },
   2973 	{ ECONNREFUSED,	"Connection refused" },
   2974 	{ EALREADY,	"Operation already in progress" },
   2975 	{ 0,		NULL },
   2976 };
   2977 
   2978 char *
   2979 ds_errno_to_str(int ds_errno, char *ebuf)
   2980 {
   2981 	int i, en;
   2982 
   2983 	for (i = 0; (en = ds_errno_to_str_tab[i].ds_errno) != 0; i++) {
   2984 		if (en == ds_errno) {
   2985 			(void) strcpy(ebuf, ds_errno_to_str_tab[i].estr);
   2986 			return (ebuf);
   2987 		}
   2988 	}
   2989 
   2990 	(void) sprintf(ebuf, "ds_errno (%d)", ds_errno);
   2991 	return (ebuf);
   2992 }
   2993 
   2994 static void
   2995 ds_loopback_register(ds_svc_hdl_t hdl)
   2996 {
   2997 	ds_ver_t ds_ver;
   2998 	ds_svc_t *svc;
   2999 
   3000 	ASSERT(MUTEX_HELD(&ds_svcs.lock));
   3001 	DS_DBG_LOOP(CE_NOTE, "%s: entered hdl: 0x%llx" DS_EOL, __func__,
   3002 	    (u_longlong_t)hdl);
   3003 	if ((svc = ds_get_svc(hdl)) == NULL) {
   3004 		DS_DBG_LOOP(CE_NOTE, "%s: invalid hdl: 0x%llx" DS_EOL, __func__,
   3005 		    (u_longlong_t)hdl);
   3006 		return;
   3007 	}
   3008 
   3009 	svc->state = DS_SVC_ACTIVE;
   3010 
   3011 	if (svc->ops.ds_reg_cb) {
   3012 		DS_DBG_LOOP(CE_NOTE, "%s: loopback regcb: hdl: 0x%llx" DS_EOL,
   3013 		    __func__, (u_longlong_t)hdl);
   3014 		ds_ver.major = svc->ver.major;
   3015 		ds_ver.minor = svc->ver.minor;
   3016 		(*svc->ops.ds_reg_cb)(svc->ops.cb_arg, &ds_ver, hdl);
   3017 	}
   3018 }
   3019 
   3020 static void
   3021 ds_loopback_unregister(ds_svc_hdl_t hdl)
   3022 {
   3023 	ds_svc_t *svc;
   3024 
   3025 	ASSERT(MUTEX_HELD(&ds_svcs.lock));
   3026 	if ((svc = ds_get_svc(hdl)) == NULL) {
   3027 		DS_DBG_LOOP(CE_NOTE, "%s: invalid hdl: 0x%llx" DS_EOL, __func__,
   3028 		    (u_longlong_t)hdl);
   3029 		return;
   3030 	}
   3031 
   3032 	DS_DBG_LOOP(CE_NOTE, "%s: entered hdl: 0x%llx" DS_EOL, __func__,
   3033 	    (u_longlong_t)hdl);
   3034 
   3035 	svc->flags &= ~DSSF_LOOPBACK;
   3036 	svc->svc_hdl = DS_BADHDL2;
   3037 	svc->state = DS_SVC_INACTIVE;
   3038 
   3039 	if (svc->ops.ds_unreg_cb) {
   3040 		DS_DBG_LOOP(CE_NOTE, "%s: loopback unregcb: hdl: 0x%llx" DS_EOL,
   3041 		    __func__, (u_longlong_t)hdl);
   3042 		(*svc->ops.ds_unreg_cb)(svc->ops.cb_arg);
   3043 	}
   3044 }
   3045 
   3046 static void
   3047 ds_loopback_send(ds_svc_hdl_t hdl, void *buf, size_t buflen)
   3048 {
   3049 	ds_svc_t *svc;
   3050 
   3051 	mutex_enter(&ds_svcs.lock);
   3052 	if ((svc = ds_get_svc(hdl)) == NULL) {
   3053 		mutex_exit(&ds_svcs.lock);
   3054 		DS_DBG_LOOP(CE_NOTE, "%s: invalid hdl: 0x%llx" DS_EOL, __func__,
   3055 		    (u_longlong_t)hdl);
   3056 		return;
   3057 	}
   3058 	mutex_exit(&ds_svcs.lock);
   3059 
   3060 	DS_DBG_LOOP(CE_NOTE, "%s: entered hdl: 0x%llx" DS_EOL, __func__,
   3061 	    (u_longlong_t)hdl);
   3062 
   3063 	if (svc->ops.ds_data_cb) {
   3064 		DS_DBG_LOOP(CE_NOTE, "%s: loopback datacb hdl: 0x%llx" DS_EOL,
   3065 		    __func__, (u_longlong_t)hdl);
   3066 		(*svc->ops.ds_data_cb)(svc->ops.cb_arg, buf, buflen);
   3067 	}
   3068 }
   3069 
   3070 static int
   3071 ds_loopback_set_svc(ds_svc_t *svc, ds_capability_t *cap, ds_svc_hdl_t *lb_hdlp)
   3072 {
   3073 	ds_svc_t *lb_svc;
   3074 	ds_svc_hdl_t lb_hdl = *lb_hdlp;
   3075 	int i;
   3076 	int match = 0;
   3077 	uint16_t new_major;
   3078 	uint16_t new_minor;
   3079 
   3080 	if ((lb_svc = ds_get_svc(lb_hdl)) == NULL) {
   3081 		DS_DBG_LOOP(CE_NOTE, "%s: loopback: hdl: 0x%llx invalid" DS_EOL,
   3082 		    __func__, (u_longlong_t)lb_hdl);
   3083 		return (ENXIO);
   3084 	}
   3085 
   3086 	/* negotiate a version between loopback services, if possible */
   3087 	for (i = 0; i < lb_svc->cap.nvers && match == 0; i++) {
   3088 		match = negotiate_version(cap->nvers, cap->vers,
   3089 		    lb_svc->cap.vers[i].major, &new_major, &new_minor);
   3090 	}
   3091 	if (!match) {
   3092 		DS_DBG_LOOP(CE_NOTE, "%s: loopback version negotiate failed"
   3093 		    DS_EOL, __func__);
   3094 		return (ENOTSUP);
   3095 	}
   3096 	if (lb_svc->state != DS_SVC_INACTIVE) {
   3097 		DS_DBG_LOOP(CE_NOTE, "%s: loopback active: hdl: 0x%llx"
   3098 		    DS_EOL, __func__, (u_longlong_t)lb_hdl);
   3099 		if ((lb_svc->flags & DSSF_ISCLIENT) == 0) {
   3100 			DS_DBG_LOOP(CE_NOTE, "%s: loopback busy hdl: 0x%llx"
   3101 			    DS_EOL, __func__, (u_longlong_t)lb_hdl);
   3102 			return (EBUSY);
   3103 		}
   3104 		svc->state = DS_SVC_INACTIVE;	/* prevent alloc'ing svc */
   3105 		lb_svc = ds_svc_clone(lb_svc);
   3106 		DS_DBG_LOOP(CE_NOTE, "%s: loopback clone: ohdl: 0x%llx "
   3107 		    "nhdl: 0x%llx" DS_EOL, __func__, (u_longlong_t)lb_hdl,
   3108 		    (u_longlong_t)lb_svc->hdl);
   3109 		*lb_hdlp = lb_svc->hdl;
   3110 	}
   3111 
   3112 	svc->flags |= DSSF_LOOPBACK;
   3113 	svc->svc_hdl = lb_svc->hdl;
   3114 	svc->port = NULL;
   3115 	svc->ver.major = new_major;
   3116 	svc->ver.minor = new_minor;
   3117 
   3118 	lb_svc->flags |= DSSF_LOOPBACK;
   3119 	lb_svc->svc_hdl = svc->hdl;
   3120 	lb_svc->port = NULL;
   3121 	lb_svc->ver.major = new_major;
   3122 	lb_svc->ver.minor = new_minor;
   3123 
   3124 	DS_DBG_LOOP(CE_NOTE, "%s: setting loopback between: 0x%llx and 0x%llx"
   3125 	    DS_EOL, __func__, (u_longlong_t)svc->hdl,
   3126 	    (u_longlong_t)lb_svc->hdl);
   3127 	return (0);
   3128 }
   3129 
   3130 static ds_svc_t *
   3131 ds_find_clnt_svc_by_hdl_port(ds_svc_hdl_t hdl, ds_port_t *port)
   3132 {
   3133 	int		idx;
   3134 	ds_svc_t	*svc;
   3135 
   3136 	DS_DBG_PRCL(CE_NOTE, "ds@%lx: %s looking up clnt hdl: 0x%llx" DS_EOL,
   3137 	    PORTID(port), __func__, (u_longlong_t)hdl);
   3138 	ASSERT(MUTEX_HELD(&ds_svcs.lock));
   3139 
   3140 	/* walk every table entry */
   3141 	for (idx = 0; idx < ds_svcs.maxsvcs; idx++) {
   3142 		svc = ds_svcs.tbl[idx];
   3143 		if (DS_SVC_ISFREE(svc))
   3144 			continue;
   3145 		if ((svc->flags & DSSF_ISCLIENT) != 0 &&
   3146 		    svc->svc_hdl == hdl && svc->port == port) {
   3147 			DS_DBG_PRCL(CE_NOTE, "ds@%lx: %s found clnt hdl "
   3148 			    "0x%llx: svc%d" DS_EOL, PORTID(port), __func__,
   3149 			    (u_longlong_t)hdl, (uint_t)DS_HDL2IDX(svc->hdl));
   3150 			return (svc);
   3151 		}
   3152 	}
   3153 	DS_DBG_PRCL(CE_NOTE, "ds@%lx: %s clnt hdl: 0x%llx not found" DS_EOL,
   3154 	    PORTID(port), __func__, (u_longlong_t)hdl);
   3155 
   3156 	return (NULL);
   3157 }
   3158 
   3159 static ds_svc_t *
   3160 ds_svc_clone(ds_svc_t *svc)
   3161 {
   3162 	ds_svc_t *newsvc;
   3163 	ds_svc_hdl_t hdl;
   3164 
   3165 	ASSERT(svc->flags & DSSF_ISCLIENT);
   3166 
   3167 	newsvc = ds_alloc_svc();
   3168 
   3169 	/* Can only clone clients for now */
   3170 	hdl = newsvc->hdl | DS_HDL_ISCLIENT_BIT;
   3171 	DS_DBG_USR(CE_NOTE, "%s: cloning client: old hdl: 0x%llx new hdl: "
   3172 	    "0x%llx" DS_EOL, __func__, (u_longlong_t)svc->hdl,
   3173 	    (u_longlong_t)hdl);
   3174 	(void) memcpy(newsvc, svc, sizeof (ds_svc_t));
   3175 	newsvc->hdl = hdl;
   3176 	newsvc->flags &= ~DSSF_LOOPBACK;
   3177 	newsvc->port = NULL;
   3178 	newsvc->svc_hdl = DS_BADHDL2;
   3179 	newsvc->cap.svc_id = ds_strdup(svc->cap.svc_id);
   3180 	newsvc->cap.vers = DS_MALLOC(svc->cap.nvers * sizeof (ds_ver_t));
   3181 	(void) memcpy(newsvc->cap.vers, svc->cap.vers,
   3182 	    svc->cap.nvers * sizeof (ds_ver_t));
   3183 
   3184 	/*
   3185 	 * Kludge to allow lds driver user callbacks to get access to current
   3186 	 * svc structure.  Arg could be index to svc table or some other piece
   3187 	 * of info to get to the svc table entry.
   3188 	 */
   3189 	if (newsvc->flags & DSSF_ISUSER) {
   3190 		newsvc->ops.cb_arg = (ds_cb_arg_t)(newsvc);
   3191 	}
   3192 	return (newsvc);
   3193 }
   3194 
   3195 /*
   3196  * Internal handle lookup function.
   3197  */
   3198 static int
   3199 i_ds_hdl_lookup(char *service, uint_t is_client, ds_svc_hdl_t *hdlp,
   3200     uint_t maxhdls)
   3201 {
   3202 	int idx;
   3203 	int nhdls = 0;
   3204 	ds_svc_t *svc;
   3205 	uint32_t client_flag = is_client ? DSSF_ISCLIENT : 0;
   3206 
   3207 	ASSERT(MUTEX_HELD(&ds_svcs.lock));
   3208 
   3209 	for (idx = 0; idx < ds_svcs.maxsvcs && nhdls < maxhdls; idx++) {
   3210 		svc = ds_svcs.tbl[idx];
   3211 		if (DS_SVC_ISFREE(svc))
   3212 			continue;
   3213 		if (strcmp(svc->cap.svc_id, service) == 0 &&
   3214 		    (svc->flags & DSSF_ISCLIENT) == client_flag) {
   3215 			if (hdlp != NULL && nhdls < maxhdls) {
   3216 				hdlp[nhdls] = svc->hdl;
   3217 				nhdls++;
   3218 			} else {
   3219 				nhdls++;
   3220 			}
   3221 		}
   3222 	}
   3223 	return (nhdls);
   3224 }
   3225 
   3226 /*
   3227  * Interface for ds_hdl_lookup in lds driver.
   3228  */
   3229 int
   3230 ds_hdl_lookup(char *service, uint_t is_client, ds_svc_hdl_t *hdlp,
   3231     uint_t maxhdls, uint_t *nhdlsp)
   3232 {
   3233 	mutex_enter(&ds_svcs.lock);
   3234 	*nhdlsp = i_ds_hdl_lookup(service, is_client, hdlp, maxhdls);
   3235 	mutex_exit(&ds_svcs.lock);
   3236 	return (0);
   3237 }
   3238 
   3239 /*
   3240  * After an UNREG REQ, check if this is a client service with multiple
   3241  * handles.  If it is, then we can eliminate this entry.
   3242  */
   3243 static void
   3244 ds_check_for_dup_services(ds_svc_t *svc)
   3245 {
   3246 	if ((svc->flags & DSSF_ISCLIENT) != 0 &&
   3247 	    svc->state == DS_SVC_INACTIVE &&
   3248 	    i_ds_hdl_lookup(svc->cap.svc_id, 1, NULL, 2) == 2) {
   3249 		ds_delete_svc_entry(svc);
   3250 	}
   3251 }
   3252 
   3253 static void
   3254 ds_delete_svc_entry(ds_svc_t *svc)
   3255 {
   3256 	ds_svc_hdl_t tmp_hdl;
   3257 
   3258 	ASSERT(MUTEX_HELD(&ds_svcs.lock));
   3259 
   3260 	/*
   3261 	 * Clear out the structure, but do not deallocate the
   3262 	 * memory. It can be reused for the next registration.
   3263 	 */
   3264 	DS_FREE(svc->cap.svc_id, strlen(svc->cap.svc_id) + 1);
   3265 	DS_FREE(svc->cap.vers, svc->cap.nvers * sizeof (ds_ver_t));
   3266 
   3267 	/* save the handle to prevent reuse */
   3268 	tmp_hdl = svc->hdl;
   3269 	bzero((void *)svc, sizeof (ds_svc_t));
   3270 
   3271 	/* initialize for next use */
   3272 	svc->hdl = tmp_hdl;
   3273 	svc->state = DS_SVC_FREE;
   3274 
   3275 	ds_svcs.nsvcs--;
   3276 }
   3277