xref: /onnv-gate/usr/src/uts/sun4v/io/vnet_dds.c (revision 12011:2377022c7a2d)
16495Sspeer /*
26495Sspeer  * CDDL HEADER START
36495Sspeer  *
46495Sspeer  * The contents of this file are subject to the terms of the
56495Sspeer  * Common Development and Distribution License (the "License").
66495Sspeer  * You may not use this file except in compliance with the License.
76495Sspeer  *
86495Sspeer  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96495Sspeer  * or http://www.opensolaris.org/os/licensing.
106495Sspeer  * See the License for the specific language governing permissions
116495Sspeer  * and limitations under the License.
126495Sspeer  *
136495Sspeer  * When distributing Covered Code, include this CDDL HEADER in each
146495Sspeer  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156495Sspeer  * If applicable, add the following below this CDDL HEADER, with the
166495Sspeer  * fields enclosed by brackets "[]" replaced with your own identifying
176495Sspeer  * information: Portions Copyright [yyyy] [name of copyright owner]
186495Sspeer  *
196495Sspeer  * CDDL HEADER END
206495Sspeer  */
216495Sspeer 
226495Sspeer /*
23*12011SSriharsha.Basavapatna@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
246495Sspeer  * Use is subject to license terms.
256495Sspeer  */
266495Sspeer 
276495Sspeer #include <sys/modctl.h>
286495Sspeer #include <sys/prom_plat.h>
296495Sspeer #include <sys/ddi.h>
306495Sspeer #include <sys/sunddi.h>
316495Sspeer #include <sys/sunndi.h>
326495Sspeer #include <sys/ndi_impldefs.h>
336495Sspeer #include <sys/ddi_impldefs.h>
346495Sspeer #include <sys/ethernet.h>
356495Sspeer #include <sys/machsystm.h>
366495Sspeer #include <sys/hypervisor_api.h>
376495Sspeer #include <sys/mach_descrip.h>
386495Sspeer #include <sys/drctl.h>
396495Sspeer #include <sys/dr_util.h>
406495Sspeer #include <sys/mac.h>
416495Sspeer #include <sys/vnet.h>
426495Sspeer #include <sys/vnet_mailbox.h>
436495Sspeer #include <sys/vnet_common.h>
446495Sspeer #include <sys/hsvc.h>
456495Sspeer 
466495Sspeer 
476495Sspeer #define	VDDS_MAX_RANGES		6	/* 6 possible VRs */
486495Sspeer #define	VDDS_MAX_VRINTRS	8	/* limited to 8 intrs/VR */
496495Sspeer #define	VDDS_MAX_INTR_NUM	64	/* 0-63 or valid */
506495Sspeer 
516495Sspeer #define	VDDS_INO_RANGE_START(x) (x * VDDS_MAX_VRINTRS)
526495Sspeer #define	HVCOOKIE(c)	((c) & 0xFFFFFFFFF)
536495Sspeer #define	NIUCFGHDL(c)	((c) >> 32)
546495Sspeer 
556495Sspeer 
566495Sspeer /* For "ranges" property */
576495Sspeer typedef struct vdds_ranges {
586495Sspeer 	uint32_t child_hi;
596495Sspeer 	uint32_t child_lo;
606495Sspeer 	uint32_t parent_hi;
616495Sspeer 	uint32_t parent_lo;
626495Sspeer 	uint32_t size_hi;
636495Sspeer 	uint32_t size_lo;
646495Sspeer } vdds_ranges_t;
656495Sspeer 
666495Sspeer /* For "reg" property */
676495Sspeer typedef struct vdds_reg {
686495Sspeer 	uint32_t addr_hi;
696495Sspeer 	uint32_t addr_lo;
706495Sspeer 	uint32_t size_hi;
716495Sspeer 	uint32_t size_lo;
726495Sspeer } vdds_reg_t;
736495Sspeer 
746495Sspeer /* For ddi callback argument */
756495Sspeer typedef struct vdds_cb_arg {
766495Sspeer 	dev_info_t *dip;
776495Sspeer 	uint64_t cookie;
786495Sspeer 	uint64_t macaddr;
797529SSriharsha.Basavapatna@Sun.COM 	uint32_t max_frame_size;
806495Sspeer } vdds_cb_arg_t;
816495Sspeer 
826495Sspeer 
836495Sspeer /* Functions exported to other files */
846495Sspeer void vdds_mod_init(void);
856495Sspeer void vdds_mod_fini(void);
866495Sspeer int vdds_init(vnet_t *vnetp);
876495Sspeer void vdds_cleanup(vnet_t *vnetp);
886495Sspeer void vdds_process_dds_msg(vnet_t *vnetp, vio_dds_msg_t *dmsg);
897819SRaghuram.Kothakota@Sun.COM void vdds_cleanup_hybrid_res(void *arg);
909647SWentao.Yang@Sun.COM void vdds_cleanup_hio(vnet_t *vnetp);
916495Sspeer 
926495Sspeer /* Support functions to create/destory Hybrid device */
937529SSriharsha.Basavapatna@Sun.COM static dev_info_t *vdds_create_niu_node(uint64_t cookie,
947529SSriharsha.Basavapatna@Sun.COM     uint64_t macaddr, uint32_t max_frame_size);
956495Sspeer static int vdds_destroy_niu_node(dev_info_t *niu_dip, uint64_t cookie);
967529SSriharsha.Basavapatna@Sun.COM static dev_info_t *vdds_create_new_node(vdds_cb_arg_t *cba,
976495Sspeer     dev_info_t *pdip, int (*new_node_func)(dev_info_t *dip,
986495Sspeer     void *arg, uint_t flags));
996495Sspeer static int vdds_new_nexus_node(dev_info_t *dip, void *arg, uint_t flags);
1006495Sspeer static int vdds_new_niu_node(dev_info_t *dip, void *arg, uint_t flags);
1016495Sspeer static dev_info_t *vdds_find_node(uint64_t cookie, dev_info_t *sdip,
1026495Sspeer 	int (*match_func)(dev_info_t *dip, void *arg));
1036495Sspeer static int vdds_match_niu_nexus(dev_info_t *dip, void *arg);
1046495Sspeer static int vdds_match_niu_node(dev_info_t *dip, void *arg);
1056495Sspeer static int vdds_get_interrupts(uint64_t cookie, int ino_range,
1066495Sspeer     int *intrs, int *nintr);
1076495Sspeer 
1086495Sspeer /* DDS message processing related functions */
1096495Sspeer static void vdds_process_dds_msg_task(void *arg);
1106495Sspeer static int vdds_send_dds_resp_msg(vnet_t *vnetp, vio_dds_msg_t *dmsg, int ack);
1116495Sspeer static int vdds_send_dds_rel_msg(vnet_t *vnetp);
1126495Sspeer static void vdds_release_range_prop(dev_info_t *nexus_dip, uint64_t cookie);
1136495Sspeer 
1146495Sspeer /* Functions imported from other files */
1156495Sspeer extern int vnet_send_dds_msg(vnet_t *vnetp, void *dmsg);
11610309SSriharsha.Basavapatna@Sun.COM extern int vnet_hio_mac_init(vnet_t *vnetp, char *ifname);
11710309SSriharsha.Basavapatna@Sun.COM extern void vnet_hio_mac_cleanup(vnet_t *vnetp);
1186495Sspeer 
1196495Sspeer /* HV functions that are used in this file */
1206495Sspeer extern uint64_t vdds_hv_niu_vr_getinfo(uint32_t hvcookie,
1216495Sspeer     uint64_t *real_start, uint64_t *size);
1226495Sspeer extern uint64_t vdds_hv_niu_vr_get_txmap(uint32_t hvcookie, uint64_t *dma_map);
1236495Sspeer extern uint64_t vdds_hv_niu_vr_get_rxmap(uint32_t hvcookie, uint64_t *dma_map);
1246495Sspeer extern uint64_t vdds_hv_niu_vrtx_set_ino(uint32_t cookie, uint64_t vch_idx,
1256495Sspeer     uint32_t ino);
1266495Sspeer extern uint64_t vdds_hv_niu_vrrx_set_ino(uint32_t cookie, uint64_t vch_idx,
1276495Sspeer     uint32_t ino);
1286495Sspeer 
1296495Sspeer 
1306495Sspeer #ifdef DEBUG
1316495Sspeer 
132*12011SSriharsha.Basavapatna@Sun.COM #define	DEBUG_PRINTF	debug_printf
133*12011SSriharsha.Basavapatna@Sun.COM 
1346495Sspeer extern int vnet_dbglevel;
1356495Sspeer 
1366495Sspeer static void
debug_printf(const char * fname,void * arg,const char * fmt,...)1376495Sspeer debug_printf(const char *fname, void *arg,  const char *fmt, ...)
1386495Sspeer {
1396495Sspeer 	char    buf[512];
1406495Sspeer 	va_list ap;
1416495Sspeer 	char    *bufp = buf;
1426495Sspeer 	vnet_dds_info_t *vdds = arg;
1436495Sspeer 
1446495Sspeer 	if (vdds != NULL) {
1456495Sspeer 		(void) sprintf(bufp, "vnet%d: %s: ",
1466495Sspeer 		    vdds->vnetp->instance, fname);
1476495Sspeer 	} else {
1486495Sspeer 		(void) sprintf(bufp, "%s: ", fname);
1496495Sspeer 	}
1506495Sspeer 	bufp += strlen(bufp);
1516495Sspeer 	va_start(ap, fmt);
1526495Sspeer 	(void) vsprintf(bufp, fmt, ap);
1536495Sspeer 	va_end(ap);
1546495Sspeer 	cmn_err(CE_CONT, "%s\n", buf);
1556495Sspeer }
1566495Sspeer #endif
1576495Sspeer 
1586495Sspeer /*
15911304SJanie.Lu@Sun.COM  * Hypervisor N2/NIU services information:
16011304SJanie.Lu@Sun.COM  *
16111304SJanie.Lu@Sun.COM  * The list of HV versions that support NIU HybridIO. Note,
16211304SJanie.Lu@Sun.COM  * the order is higher version to a lower version, as the
16311304SJanie.Lu@Sun.COM  * registration is attempted in this order.
1646495Sspeer  */
16511304SJanie.Lu@Sun.COM static hsvc_info_t niu_hsvc[] = {
16611304SJanie.Lu@Sun.COM 	{HSVC_REV_1, NULL, HSVC_GROUP_NIU, 2, 0, "vnet_dds"},
16711304SJanie.Lu@Sun.COM 	{HSVC_REV_1, NULL, HSVC_GROUP_NIU, 1, 1, "vnet_dds"}
1686495Sspeer };
1696495Sspeer 
1707819SRaghuram.Kothakota@Sun.COM /*
17111304SJanie.Lu@Sun.COM  * Index that points to the successful HV version that
17211304SJanie.Lu@Sun.COM  * is registered.
17311304SJanie.Lu@Sun.COM  */
17411304SJanie.Lu@Sun.COM static int niu_hsvc_index = -1;
17511304SJanie.Lu@Sun.COM 
17611304SJanie.Lu@Sun.COM /*
1777819SRaghuram.Kothakota@Sun.COM  * Lock to serialize the NIU device node related operations.
1787819SRaghuram.Kothakota@Sun.COM  */
1797819SRaghuram.Kothakota@Sun.COM kmutex_t vdds_dev_lock;
1807819SRaghuram.Kothakota@Sun.COM 
1816495Sspeer boolean_t vdds_hv_hio_capable = B_FALSE;
1826495Sspeer 
1836495Sspeer /*
1846495Sspeer  * vdds_mod_init -- one time initialization.
1856495Sspeer  */
1866495Sspeer void
vdds_mod_init(void)1876495Sspeer vdds_mod_init(void)
1886495Sspeer {
18911304SJanie.Lu@Sun.COM 	int i;
1906495Sspeer 	int rv;
19111304SJanie.Lu@Sun.COM 	uint64_t minor = 0;
1926495Sspeer 
1936495Sspeer 	/*
19411304SJanie.Lu@Sun.COM 	 * Try register one by one from niu_hsvc.
1956495Sspeer 	 */
19611304SJanie.Lu@Sun.COM 	for (i = 0; i < (sizeof (niu_hsvc) / sizeof (hsvc_info_t)); i++) {
19711304SJanie.Lu@Sun.COM 		rv = hsvc_register(&niu_hsvc[i], &minor);
19811304SJanie.Lu@Sun.COM 		if (rv == 0) {
19911304SJanie.Lu@Sun.COM 			if (minor == niu_hsvc[i].hsvc_minor) {
20011304SJanie.Lu@Sun.COM 				vdds_hv_hio_capable = B_TRUE;
20111304SJanie.Lu@Sun.COM 				niu_hsvc_index = i;
20211304SJanie.Lu@Sun.COM 				break;
20311304SJanie.Lu@Sun.COM 			} else {
20411304SJanie.Lu@Sun.COM 				(void) hsvc_unregister(&niu_hsvc[i]);
20511304SJanie.Lu@Sun.COM 			}
20611304SJanie.Lu@Sun.COM 		}
2076495Sspeer 	}
2087819SRaghuram.Kothakota@Sun.COM 	mutex_init(&vdds_dev_lock, NULL, MUTEX_DRIVER, NULL);
20911304SJanie.Lu@Sun.COM 	DBG2(NULL, "HV HIO capable=%d ver(%ld.%ld)", vdds_hv_hio_capable,
21011304SJanie.Lu@Sun.COM 	    (niu_hsvc_index == -1) ? 0 : niu_hsvc[niu_hsvc_index].hsvc_major,
21111304SJanie.Lu@Sun.COM 	    minor);
2126495Sspeer }
2136495Sspeer 
2146495Sspeer /*
2156495Sspeer  * vdds_mod_fini -- one time cleanup.
2166495Sspeer  */
2176495Sspeer void
vdds_mod_fini(void)2186495Sspeer vdds_mod_fini(void)
2196495Sspeer {
22011304SJanie.Lu@Sun.COM 	if (niu_hsvc_index != -1) {
22111304SJanie.Lu@Sun.COM 		(void) hsvc_unregister(&niu_hsvc[niu_hsvc_index]);
22211304SJanie.Lu@Sun.COM 	}
2237819SRaghuram.Kothakota@Sun.COM 	mutex_destroy(&vdds_dev_lock);
2246495Sspeer }
2256495Sspeer 
2266495Sspeer /*
2276495Sspeer  * vdds_init -- vnet instance related DDS related initialization.
2286495Sspeer  */
2296495Sspeer int
vdds_init(vnet_t * vnetp)2306495Sspeer vdds_init(vnet_t *vnetp)
2316495Sspeer {
2326495Sspeer 	vnet_dds_info_t *vdds = &vnetp->vdds_info;
2336495Sspeer 	char		qname[TASKQ_NAMELEN];
2346495Sspeer 
2356495Sspeer 	vdds->vnetp = vnetp;
2366495Sspeer 	DBG1(vdds, "Initializing..");
2376495Sspeer 	(void) snprintf(qname, TASKQ_NAMELEN, "vdds_taskq%d", vnetp->instance);
2386495Sspeer 	if ((vdds->dds_taskqp = ddi_taskq_create(vnetp->dip, qname, 1,
2396495Sspeer 	    TASKQ_DEFAULTPRI, 0)) == NULL) {
2406495Sspeer 		cmn_err(CE_WARN, "!vnet%d: Unable to create DDS task queue",
2416495Sspeer 		    vnetp->instance);
2426495Sspeer 		return (ENOMEM);
2436495Sspeer 	}
2446495Sspeer 	mutex_init(&vdds->lock, NULL, MUTEX_DRIVER, NULL);
2456495Sspeer 	return (0);
2466495Sspeer }
2476495Sspeer 
2486495Sspeer /*
2496495Sspeer  * vdds_cleanup -- vnet instance related cleanup.
2506495Sspeer  */
2516495Sspeer void
vdds_cleanup(vnet_t * vnetp)2526495Sspeer vdds_cleanup(vnet_t *vnetp)
2536495Sspeer {
2546495Sspeer 	vnet_dds_info_t *vdds = &vnetp->vdds_info;
2556495Sspeer 
2566495Sspeer 	DBG1(vdds, "Cleanup...");
2576495Sspeer 	/* Cleanup/destroy any hybrid resouce that exists */
2586495Sspeer 	vdds_cleanup_hybrid_res(vnetp);
2596495Sspeer 
2606495Sspeer 	/* taskq_destroy will wait for all taskqs to complete */
2616495Sspeer 	ddi_taskq_destroy(vdds->dds_taskqp);
2626495Sspeer 	vdds->dds_taskqp = NULL;
2636495Sspeer 	mutex_destroy(&vdds->lock);
2646495Sspeer 	DBG1(vdds, "Cleanup complete");
2656495Sspeer }
2666495Sspeer 
2676495Sspeer /*
2686495Sspeer  * vdds_cleanup_hybrid_res -- Cleanup Hybrid resource.
2696495Sspeer  */
2706495Sspeer void
vdds_cleanup_hybrid_res(void * arg)2717819SRaghuram.Kothakota@Sun.COM vdds_cleanup_hybrid_res(void *arg)
2726495Sspeer {
2737819SRaghuram.Kothakota@Sun.COM 	vnet_t *vnetp = arg;
2746495Sspeer 	vnet_dds_info_t *vdds = &vnetp->vdds_info;
2756495Sspeer 
2766495Sspeer 	DBG1(vdds, "Hybrid device cleanup...");
2776495Sspeer 	mutex_enter(&vdds->lock);
2786495Sspeer 	if (vdds->task_flags == VNET_DDS_TASK_ADD_SHARE) {
2796495Sspeer 		/*
2806495Sspeer 		 * Task for ADD_SHARE is pending, simply
2816495Sspeer 		 * cleanup the flags, the task will quit without
2826495Sspeer 		 * any changes.
2836495Sspeer 		 */
2846495Sspeer 		vdds->task_flags = 0;
2856495Sspeer 		DBG2(vdds, "Task for ADD is pending, clean flags only");
2866495Sspeer 	} else if ((vdds->hio_dip != NULL) && (vdds->task_flags == 0)) {
2876495Sspeer 		/*
2886495Sspeer 		 * There is no task pending and a hybrid device
2896495Sspeer 		 * is present, so dispatch a task to release the share.
2906495Sspeer 		 */
2916495Sspeer 		vdds->task_flags = VNET_DDS_TASK_REL_SHARE;
2926495Sspeer 		(void) ddi_taskq_dispatch(vdds->dds_taskqp,
2936495Sspeer 		    vdds_process_dds_msg_task, vnetp, DDI_NOSLEEP);
2946495Sspeer 		DBG2(vdds, "Dispatched a task to destroy HIO device");
2956495Sspeer 	}
2966495Sspeer 	/*
2976495Sspeer 	 * Other possible cases include either DEL_SHARE or
2986495Sspeer 	 * REL_SHARE as pending. In that case, there is nothing
2996495Sspeer 	 * to do as a task is already pending to do the cleanup.
3006495Sspeer 	 */
3016495Sspeer 	mutex_exit(&vdds->lock);
3026495Sspeer 	DBG1(vdds, "Hybrid device cleanup complete");
3036495Sspeer }
3046495Sspeer 
3056495Sspeer /*
3069647SWentao.Yang@Sun.COM  * vdds_cleanup_hio -- An interface to cleanup the hio resources before
3079647SWentao.Yang@Sun.COM  *	resetting the vswitch port.
3089647SWentao.Yang@Sun.COM  */
3099647SWentao.Yang@Sun.COM void
vdds_cleanup_hio(vnet_t * vnetp)3109647SWentao.Yang@Sun.COM vdds_cleanup_hio(vnet_t *vnetp)
3119647SWentao.Yang@Sun.COM {
3129647SWentao.Yang@Sun.COM 	vnet_dds_info_t *vdds = &vnetp->vdds_info;
3139647SWentao.Yang@Sun.COM 
3149647SWentao.Yang@Sun.COM 	/* Wait for any pending vdds tasks to complete */
3159647SWentao.Yang@Sun.COM 	ddi_taskq_wait(vdds->dds_taskqp);
3169647SWentao.Yang@Sun.COM 	vdds_cleanup_hybrid_res(vnetp);
3179647SWentao.Yang@Sun.COM 	/* Wait for the cleanup task to complete */
3189647SWentao.Yang@Sun.COM 	ddi_taskq_wait(vdds->dds_taskqp);
3199647SWentao.Yang@Sun.COM }
3209647SWentao.Yang@Sun.COM 
3219647SWentao.Yang@Sun.COM /*
3226495Sspeer  * vdds_process_dds_msg -- Process a DDS message.
3236495Sspeer  */
3246495Sspeer void
vdds_process_dds_msg(vnet_t * vnetp,vio_dds_msg_t * dmsg)3256495Sspeer vdds_process_dds_msg(vnet_t *vnetp, vio_dds_msg_t *dmsg)
3266495Sspeer {
3276495Sspeer 	vnet_dds_info_t *vdds = &vnetp->vdds_info;
3286495Sspeer 	int rv;
3296495Sspeer 
3306495Sspeer 	DBG1(vdds, "DDS message received...");
3316495Sspeer 
3326495Sspeer 	if (dmsg->dds_class != DDS_VNET_NIU) {
3336495Sspeer 		DBG2(vdds, "Invalid class send NACK");
3346495Sspeer 		(void) vdds_send_dds_resp_msg(vnetp, dmsg, B_FALSE);
3356495Sspeer 		return;
3366495Sspeer 	}
3376495Sspeer 	mutex_enter(&vdds->lock);
3386495Sspeer 	switch (dmsg->dds_subclass) {
3396495Sspeer 	case DDS_VNET_ADD_SHARE:
3406495Sspeer 		DBG2(vdds, "DDS_VNET_ADD_SHARE message...");
3416495Sspeer 		if ((vdds->task_flags != 0) || (vdds->hio_dip != NULL)) {
3426495Sspeer 			/*
3436495Sspeer 			 * Either a task is already pending or
3446495Sspeer 			 * a hybrid device already exists.
3456495Sspeer 			 */
3466495Sspeer 			DWARN(vdds, "NACK: Already pending DDS task");
3476495Sspeer 			(void) vdds_send_dds_resp_msg(vnetp, dmsg, B_FALSE);
3486495Sspeer 			mutex_exit(&vdds->lock);
3496495Sspeer 			return;
3506495Sspeer 		}
3516495Sspeer 		vdds->task_flags = VNET_DDS_TASK_ADD_SHARE;
3526495Sspeer 		bcopy(dmsg, &vnetp->vdds_info.dmsg, sizeof (vio_dds_msg_t));
3536495Sspeer 		DBG2(vdds, "Dispatching task for ADD_SHARE");
3546495Sspeer 		rv = ddi_taskq_dispatch(vdds->dds_taskqp,
3556495Sspeer 		    vdds_process_dds_msg_task, vnetp, DDI_NOSLEEP);
3566495Sspeer 		if (rv != 0) {
3576495Sspeer 			/* Send NACK */
3586495Sspeer 			DBG2(vdds, "NACK: Failed to dispatch task");
3596495Sspeer 			(void) vdds_send_dds_resp_msg(vnetp, dmsg, B_FALSE);
3606495Sspeer 			vdds->task_flags = 0;
3616495Sspeer 		}
3626495Sspeer 		break;
3636495Sspeer 
3646495Sspeer 	case DDS_VNET_DEL_SHARE:
3656495Sspeer 		DBG2(vdds, "DDS_VNET_DEL_SHARE message...");
3666495Sspeer 		if (vdds->task_flags == VNET_DDS_TASK_ADD_SHARE) {
3676495Sspeer 			/*
3686495Sspeer 			 * ADD_SHARE task still pending, simply clear
3696495Sspeer 			 * task falgs and ACK.
3706495Sspeer 			 */
3716495Sspeer 			DBG2(vdds, "ACK:ADD_SHARE task still pending");
3726495Sspeer 			vdds->task_flags = 0;
3736495Sspeer 			(void) vdds_send_dds_resp_msg(vnetp, dmsg, B_TRUE);
3746495Sspeer 			mutex_exit(&vdds->lock);
3756495Sspeer 			return;
3766495Sspeer 		}
3776495Sspeer 		if ((vdds->task_flags == 0) && (vdds->hio_dip == NULL)) {
3786495Sspeer 			/* Send NACK */
3796495Sspeer 			DBG2(vdds, "NACK:No HIO device exists");
3806495Sspeer 			(void) vdds_send_dds_resp_msg(vnetp, dmsg, B_FALSE);
3816495Sspeer 			mutex_exit(&vdds->lock);
3826495Sspeer 			return;
3836495Sspeer 		}
3846495Sspeer 		vdds->task_flags = VNET_DDS_TASK_DEL_SHARE;
3856495Sspeer 		bcopy(dmsg, &vdds->dmsg, sizeof (vio_dds_msg_t));
3866495Sspeer 		DBG2(vdds, "Dispatching DEL_SHARE task");
3876495Sspeer 		rv = ddi_taskq_dispatch(vdds->dds_taskqp,
3886495Sspeer 		    vdds_process_dds_msg_task, vnetp, DDI_NOSLEEP);
3896495Sspeer 		if (rv != 0) {
3906495Sspeer 			/* Send NACK */
3916495Sspeer 			DBG2(vdds, "NACK: failed to dispatch task");
3926495Sspeer 			(void) vdds_send_dds_resp_msg(vnetp, dmsg, B_FALSE);
3936495Sspeer 			vdds->task_flags = 0;
3946495Sspeer 		}
3956495Sspeer 		break;
3966495Sspeer 	case DDS_VNET_REL_SHARE:
3976495Sspeer 		DBG2(vdds, "Reply for REL_SHARE reply=%d",
3986495Sspeer 		    dmsg->tag.vio_subtype);
3996495Sspeer 		break;
4006495Sspeer 	default:
4016495Sspeer 		DWARN(vdds, "Discarding Unknown DDS message");
4026495Sspeer 		break;
4036495Sspeer 	}
4046495Sspeer 	mutex_exit(&vdds->lock);
4056495Sspeer }
4066495Sspeer 
4076495Sspeer /*
4086495Sspeer  * vdds_process_dds_msg_task -- Called from a taskq to process the
4096495Sspeer  *	DDS message.
4106495Sspeer  */
4116495Sspeer static void
vdds_process_dds_msg_task(void * arg)4126495Sspeer vdds_process_dds_msg_task(void *arg)
4136495Sspeer {
4146495Sspeer 	vnet_t		*vnetp = arg;
4156495Sspeer 	vnet_dds_info_t	*vdds = &vnetp->vdds_info;
4166495Sspeer 	vio_dds_msg_t	*dmsg = &vdds->dmsg;
4176495Sspeer 	dev_info_t	*dip;
4187529SSriharsha.Basavapatna@Sun.COM 	uint32_t	max_frame_size;
4196495Sspeer 	uint64_t	hio_cookie;
4206495Sspeer 	int		rv;
4216495Sspeer 
4226495Sspeer 	DBG1(vdds, "DDS task started...");
4236495Sspeer 	mutex_enter(&vdds->lock);
4246495Sspeer 	switch (vdds->task_flags) {
4256495Sspeer 	case VNET_DDS_TASK_ADD_SHARE:
4266495Sspeer 		DBG2(vdds, "ADD_SHARE task...");
4276495Sspeer 		hio_cookie = dmsg->msg.share_msg.cookie;
4287529SSriharsha.Basavapatna@Sun.COM 		/*
4297529SSriharsha.Basavapatna@Sun.COM 		 * max-frame-size value need to be set to
4307529SSriharsha.Basavapatna@Sun.COM 		 * the full ethernet frame size. That is,
4317529SSriharsha.Basavapatna@Sun.COM 		 * header + payload + checksum.
4327529SSriharsha.Basavapatna@Sun.COM 		 */
4337529SSriharsha.Basavapatna@Sun.COM 		max_frame_size = vnetp->mtu +
4347529SSriharsha.Basavapatna@Sun.COM 		    sizeof (struct  ether_vlan_header) + ETHERFCSL;
4356495Sspeer 		dip = vdds_create_niu_node(hio_cookie,
4367529SSriharsha.Basavapatna@Sun.COM 		    dmsg->msg.share_msg.macaddr, max_frame_size);
4376495Sspeer 		if (dip == NULL) {
4386495Sspeer 			(void) vdds_send_dds_resp_msg(vnetp, dmsg, B_FALSE);
4396495Sspeer 			DERR(vdds, "Failed to create HIO node");
4406495Sspeer 		} else {
4416495Sspeer 			vdds->hio_dip = dip;
4426495Sspeer 			vdds->hio_cookie = hio_cookie;
44311119SSriharsha.Basavapatna@Sun.COM 			(void) snprintf(vdds->hio_ifname,
44411119SSriharsha.Basavapatna@Sun.COM 			    sizeof (vdds->hio_ifname), "%s%d",
44511119SSriharsha.Basavapatna@Sun.COM 			    ddi_driver_name(dip), ddi_get_instance(dip));
44610309SSriharsha.Basavapatna@Sun.COM 
44710309SSriharsha.Basavapatna@Sun.COM 			rv = vnet_hio_mac_init(vnetp, vdds->hio_ifname);
44810309SSriharsha.Basavapatna@Sun.COM 			if (rv != 0) {
44910309SSriharsha.Basavapatna@Sun.COM 				/* failed - cleanup, send failed DDS message */
45010309SSriharsha.Basavapatna@Sun.COM 				DERR(vdds, "HIO mac init failed, cleaning up");
45110309SSriharsha.Basavapatna@Sun.COM 				rv = vdds_destroy_niu_node(dip, hio_cookie);
45210309SSriharsha.Basavapatna@Sun.COM 				if (rv == 0) {
45310309SSriharsha.Basavapatna@Sun.COM 					/* use DERR to print by default */
45410309SSriharsha.Basavapatna@Sun.COM 					DERR(vdds, "Successfully destroyed"
45510309SSriharsha.Basavapatna@Sun.COM 					    " Hybrid node");
45610309SSriharsha.Basavapatna@Sun.COM 				} else {
45710309SSriharsha.Basavapatna@Sun.COM 					cmn_err(CE_WARN, "vnet%d:Failed to "
45810309SSriharsha.Basavapatna@Sun.COM 					    "destroy Hybrid node",
45910309SSriharsha.Basavapatna@Sun.COM 					    vnetp->instance);
46010309SSriharsha.Basavapatna@Sun.COM 				}
46110309SSriharsha.Basavapatna@Sun.COM 				vdds->hio_dip = NULL;
46210309SSriharsha.Basavapatna@Sun.COM 				vdds->hio_cookie = 0;
46310309SSriharsha.Basavapatna@Sun.COM 				(void) vdds_send_dds_resp_msg(vnetp,
46410309SSriharsha.Basavapatna@Sun.COM 				    dmsg, B_FALSE);
46510309SSriharsha.Basavapatna@Sun.COM 			} else {
46610309SSriharsha.Basavapatna@Sun.COM 				(void) vdds_send_dds_resp_msg(vnetp,
46710309SSriharsha.Basavapatna@Sun.COM 				    dmsg, B_TRUE);
46810309SSriharsha.Basavapatna@Sun.COM 			}
4696495Sspeer 			/* DERR used only print by default */
4706495Sspeer 			DERR(vdds, "Successfully created HIO node");
4716495Sspeer 		}
4726495Sspeer 		break;
4736495Sspeer 
4746495Sspeer 	case VNET_DDS_TASK_DEL_SHARE:
4756495Sspeer 		DBG2(vdds, "DEL_SHARE task...");
4766495Sspeer 		if (vnetp->vdds_info.hio_dip == NULL) {
4776495Sspeer 			DBG2(vdds, "NACK: No HIO device destroy");
4786495Sspeer 			(void) vdds_send_dds_resp_msg(vnetp, dmsg, B_FALSE);
4796495Sspeer 		} else {
48010309SSriharsha.Basavapatna@Sun.COM 			vnet_hio_mac_cleanup(vnetp);
4816495Sspeer 			rv = vdds_destroy_niu_node(vnetp->vdds_info.hio_dip,
4826495Sspeer 			    vdds->hio_cookie);
4836495Sspeer 			if (rv == 0) {
4846495Sspeer 				/* use DERR to print by default */
4856495Sspeer 				DERR(vdds, "Successfully destroyed"
4866495Sspeer 				    " Hybrid node");
4876495Sspeer 			} else {
4886495Sspeer 				cmn_err(CE_WARN, "vnet%d:Failed to "
4896495Sspeer 				    "destroy Hybrid node", vnetp->instance);
4906495Sspeer 			}
4916495Sspeer 			/* TODO: send ACK even for failure? */
4926495Sspeer 			DBG2(vdds, "ACK: HIO device destroyed");
4936495Sspeer 			(void) vdds_send_dds_resp_msg(vnetp, dmsg, B_TRUE);
4946495Sspeer 			vdds->hio_dip = 0;
4956495Sspeer 			vdds->hio_cookie = 0;
4966495Sspeer 		}
4976495Sspeer 		break;
4986495Sspeer 	case VNET_DDS_TASK_REL_SHARE:
4996495Sspeer 		DBG2(vdds, "REL_SHARE task...");
5006495Sspeer 		if (vnetp->vdds_info.hio_dip != NULL) {
50110309SSriharsha.Basavapatna@Sun.COM 			vnet_hio_mac_cleanup(vnetp);
5026495Sspeer 			rv = vdds_destroy_niu_node(vnetp->vdds_info.hio_dip,
5036495Sspeer 			    vdds->hio_cookie);
5046495Sspeer 			if (rv == 0) {
5056495Sspeer 				DERR(vdds, "Successfully destroyed "
5066495Sspeer 				    "Hybrid node");
5076495Sspeer 			} else {
5086495Sspeer 				cmn_err(CE_WARN, "vnet%d:Failed to "
5096495Sspeer 				    "destroy HIO node", vnetp->instance);
5106495Sspeer 			}
5116495Sspeer 			/* TODO: failure case */
5126495Sspeer 			(void) vdds_send_dds_rel_msg(vnetp);
5136495Sspeer 			vdds->hio_dip = 0;
5146495Sspeer 			vdds->hio_cookie = 0;
5156495Sspeer 		}
5166495Sspeer 		break;
5176495Sspeer 	default:
5186495Sspeer 		break;
5196495Sspeer 	}
5206495Sspeer 	vdds->task_flags = 0;
5216495Sspeer 	mutex_exit(&vdds->lock);
5226495Sspeer }
5236495Sspeer 
5246495Sspeer /*
5256495Sspeer  * vdds_send_dds_rel_msg -- Send a DDS_REL_SHARE message.
5266495Sspeer  */
5276495Sspeer static int
vdds_send_dds_rel_msg(vnet_t * vnetp)5286495Sspeer vdds_send_dds_rel_msg(vnet_t *vnetp)
5296495Sspeer {
5306495Sspeer 	vnet_dds_info_t *vdds = &vnetp->vdds_info;
5316495Sspeer 	vio_dds_msg_t	vmsg;
5326495Sspeer 	dds_share_msg_t	*smsg = &vmsg.msg.share_msg;
5336495Sspeer 	int rv;
5346495Sspeer 
5356495Sspeer 	DBG1(vdds, "Sending DDS_VNET_REL_SHARE message");
5366495Sspeer 	vmsg.tag.vio_msgtype = VIO_TYPE_CTRL;
5376495Sspeer 	vmsg.tag.vio_subtype = VIO_SUBTYPE_INFO;
5386495Sspeer 	vmsg.tag.vio_subtype_env = VIO_DDS_INFO;
5396495Sspeer 	/* vio_sid filled by the LDC module */
5406495Sspeer 	vmsg.dds_class = DDS_VNET_NIU;
5416495Sspeer 	vmsg.dds_subclass = DDS_VNET_REL_SHARE;
5426495Sspeer 	vmsg.dds_req_id = (++vdds->dds_req_id);
5436495Sspeer 	smsg->macaddr = vnet_macaddr_strtoul(vnetp->curr_macaddr);
5446495Sspeer 	smsg->cookie = vdds->hio_cookie;
5456495Sspeer 	rv = vnet_send_dds_msg(vnetp, &vmsg);
5466495Sspeer 	return (rv);
5476495Sspeer }
5486495Sspeer 
5496495Sspeer /*
5506495Sspeer  * vdds_send_dds_resp_msg -- Send a DDS response message.
5516495Sspeer  */
5526495Sspeer static int
vdds_send_dds_resp_msg(vnet_t * vnetp,vio_dds_msg_t * dmsg,int ack)5536495Sspeer vdds_send_dds_resp_msg(vnet_t *vnetp, vio_dds_msg_t *dmsg, int ack)
5546495Sspeer {
5556495Sspeer 	vnet_dds_info_t *vdds = &vnetp->vdds_info;
5566495Sspeer 	int rv;
5576495Sspeer 
5586495Sspeer 	DBG1(vdds, "Sending a response mesage=%d", ack);
5596495Sspeer 	if (ack == B_TRUE) {
5606495Sspeer 		dmsg->tag.vio_subtype = VIO_SUBTYPE_ACK;
5616495Sspeer 		dmsg->msg.share_resp_msg.status = DDS_VNET_SUCCESS;
5626495Sspeer 	} else {
5636495Sspeer 		dmsg->tag.vio_subtype = VIO_SUBTYPE_NACK;
5646495Sspeer 		dmsg->msg.share_resp_msg.status = DDS_VNET_FAIL;
5656495Sspeer 	}
5666495Sspeer 	rv = vnet_send_dds_msg(vnetp, dmsg);
5676495Sspeer 	return (rv);
5686495Sspeer }
5696495Sspeer 
5706495Sspeer /*
5716495Sspeer  * vdds_create_niu_node -- Create NIU Hybrid node. The NIU nexus
5726495Sspeer  *	node also created if it doesn't exist already.
5736495Sspeer  */
5746495Sspeer dev_info_t *
vdds_create_niu_node(uint64_t cookie,uint64_t macaddr,uint32_t max_frame_size)5757529SSriharsha.Basavapatna@Sun.COM vdds_create_niu_node(uint64_t cookie, uint64_t macaddr, uint32_t max_frame_size)
5766495Sspeer {
5776495Sspeer 	dev_info_t *nexus_dip;
5786495Sspeer 	dev_info_t *niu_dip;
5797529SSriharsha.Basavapatna@Sun.COM 	vdds_cb_arg_t cba;
5806495Sspeer 
5816495Sspeer 	DBG1(NULL, "Called");
5826495Sspeer 
5836495Sspeer 	if (vdds_hv_hio_capable == B_FALSE) {
5846495Sspeer 		return (NULL);
5856495Sspeer 	}
5867819SRaghuram.Kothakota@Sun.COM 	mutex_enter(&vdds_dev_lock);
5876495Sspeer 	/* Check if the nexus node exists already */
5886495Sspeer 	nexus_dip = vdds_find_node(cookie, ddi_root_node(),
5896495Sspeer 	    vdds_match_niu_nexus);
5906495Sspeer 	if (nexus_dip == NULL) {
5916495Sspeer 		/*
5926495Sspeer 		 * NIU nexus node not found, so create it now.
5936495Sspeer 		 */
5947529SSriharsha.Basavapatna@Sun.COM 		cba.dip = NULL;
5957529SSriharsha.Basavapatna@Sun.COM 		cba.cookie = cookie;
5967529SSriharsha.Basavapatna@Sun.COM 		cba.macaddr = macaddr;
5977529SSriharsha.Basavapatna@Sun.COM 		cba.max_frame_size = max_frame_size;
5987529SSriharsha.Basavapatna@Sun.COM 		nexus_dip = vdds_create_new_node(&cba, NULL,
5996495Sspeer 		    vdds_new_nexus_node);
6006495Sspeer 		if (nexus_dip == NULL) {
6017819SRaghuram.Kothakota@Sun.COM 			mutex_exit(&vdds_dev_lock);
6026495Sspeer 			return (NULL);
6036495Sspeer 		}
6046495Sspeer 	}
6056495Sspeer 	DBG2(NULL, "nexus_dip = 0x%p", nexus_dip);
6066495Sspeer 
6076495Sspeer 	/* Check if NIU node exists already before creating one */
6086495Sspeer 	niu_dip = vdds_find_node(cookie, nexus_dip,
6096495Sspeer 	    vdds_match_niu_node);
6106495Sspeer 	if (niu_dip == NULL) {
6117529SSriharsha.Basavapatna@Sun.COM 		cba.dip = NULL;
6127529SSriharsha.Basavapatna@Sun.COM 		cba.cookie = cookie;
6137529SSriharsha.Basavapatna@Sun.COM 		cba.macaddr = macaddr;
6147529SSriharsha.Basavapatna@Sun.COM 		cba.max_frame_size = max_frame_size;
6157529SSriharsha.Basavapatna@Sun.COM 		niu_dip = vdds_create_new_node(&cba, nexus_dip,
6166495Sspeer 		    vdds_new_niu_node);
6176495Sspeer 		/*
6187819SRaghuram.Kothakota@Sun.COM 		 * Hold the niu_dip to prevent it from
6197819SRaghuram.Kothakota@Sun.COM 		 * detaching.
6206495Sspeer 		 */
6217819SRaghuram.Kothakota@Sun.COM 		if (niu_dip != NULL) {
6227819SRaghuram.Kothakota@Sun.COM 			e_ddi_hold_devi(niu_dip);
6237819SRaghuram.Kothakota@Sun.COM 		} else {
6247819SRaghuram.Kothakota@Sun.COM 			DWARN(NULL, "niumx/network node creation failed");
6257819SRaghuram.Kothakota@Sun.COM 		}
6267819SRaghuram.Kothakota@Sun.COM 	} else {
6277819SRaghuram.Kothakota@Sun.COM 		DWARN(NULL, "niumx/network node already exists(dip=0x%p)",
6287819SRaghuram.Kothakota@Sun.COM 		    niu_dip);
6296495Sspeer 	}
6307819SRaghuram.Kothakota@Sun.COM 	/* release the hold that was done in find/create */
6317819SRaghuram.Kothakota@Sun.COM 	if ((niu_dip != NULL) && (e_ddi_branch_held(niu_dip)))
6327819SRaghuram.Kothakota@Sun.COM 		e_ddi_branch_rele(niu_dip);
6337819SRaghuram.Kothakota@Sun.COM 	if (e_ddi_branch_held(nexus_dip))
6347819SRaghuram.Kothakota@Sun.COM 		e_ddi_branch_rele(nexus_dip);
6357819SRaghuram.Kothakota@Sun.COM 	mutex_exit(&vdds_dev_lock);
6367819SRaghuram.Kothakota@Sun.COM 	DBG1(NULL, "returning niu_dip=0x%p", niu_dip);
6376495Sspeer 	return (niu_dip);
6386495Sspeer }
6396495Sspeer 
6406495Sspeer /*
6416495Sspeer  * vdds_destroy_niu_node -- Destroy the NIU node.
6426495Sspeer  */
6436495Sspeer int
vdds_destroy_niu_node(dev_info_t * niu_dip,uint64_t cookie)6446495Sspeer vdds_destroy_niu_node(dev_info_t *niu_dip, uint64_t cookie)
6456495Sspeer {
6466495Sspeer 	int rv;
6476495Sspeer 	dev_info_t *fdip = NULL;
6486495Sspeer 	dev_info_t *nexus_dip = ddi_get_parent(niu_dip);
6496495Sspeer 
6506495Sspeer 
6516495Sspeer 	DBG1(NULL, "Called");
6527819SRaghuram.Kothakota@Sun.COM 	ASSERT(nexus_dip != NULL);
6537819SRaghuram.Kothakota@Sun.COM 	mutex_enter(&vdds_dev_lock);
6547819SRaghuram.Kothakota@Sun.COM 
6557819SRaghuram.Kothakota@Sun.COM 	if (!e_ddi_branch_held(niu_dip))
6567819SRaghuram.Kothakota@Sun.COM 		e_ddi_branch_hold(niu_dip);
6577819SRaghuram.Kothakota@Sun.COM 	/*
6587819SRaghuram.Kothakota@Sun.COM 	 * As we are destroying now, release the
6597819SRaghuram.Kothakota@Sun.COM 	 * hold that was done in during the creation.
6607819SRaghuram.Kothakota@Sun.COM 	 */
6617819SRaghuram.Kothakota@Sun.COM 	ddi_release_devi(niu_dip);
6626495Sspeer 	rv = e_ddi_branch_destroy(niu_dip, &fdip, 0);
6636495Sspeer 	if (rv != 0) {
6646495Sspeer 		DERR(NULL, "Failed to destroy niumx/network node dip=0x%p",
6656495Sspeer 		    niu_dip);
6666495Sspeer 		if (fdip != NULL) {
6677819SRaghuram.Kothakota@Sun.COM 			ddi_release_devi(fdip);
6686495Sspeer 		}
6697819SRaghuram.Kothakota@Sun.COM 		rv = EBUSY;
6707819SRaghuram.Kothakota@Sun.COM 		goto dest_exit;
6716495Sspeer 	}
6726495Sspeer 	/*
6736495Sspeer 	 * Cleanup the parent's ranges property set
6746495Sspeer 	 * for this Hybrid device.
6756495Sspeer 	 */
6766495Sspeer 	vdds_release_range_prop(nexus_dip, cookie);
6777819SRaghuram.Kothakota@Sun.COM 
6787819SRaghuram.Kothakota@Sun.COM dest_exit:
6797819SRaghuram.Kothakota@Sun.COM 	mutex_exit(&vdds_dev_lock);
6807819SRaghuram.Kothakota@Sun.COM 	DBG1(NULL, "returning rv=%d", rv);
6817819SRaghuram.Kothakota@Sun.COM 	return (rv);
6826495Sspeer }
6836495Sspeer 
6846495Sspeer /*
6856495Sspeer  * vdds_match_niu_nexus -- callback function to verify a node is the
6866495Sspeer  *	NIU nexus node.
6876495Sspeer  */
6886495Sspeer static int
vdds_match_niu_nexus(dev_info_t * dip,void * arg)6896495Sspeer vdds_match_niu_nexus(dev_info_t *dip, void *arg)
6906495Sspeer {
6916495Sspeer 	vdds_cb_arg_t	*warg = (vdds_cb_arg_t *)arg;
6926495Sspeer 	vdds_reg_t	*reg_p;
6936495Sspeer 	char		*name;
6946495Sspeer 	uint64_t	hdl;
6956495Sspeer 	uint_t		reglen;
6966495Sspeer 	int		rv;
6976495Sspeer 
6986495Sspeer 	if (dip == ddi_root_node()) {
6996495Sspeer 		return (DDI_WALK_CONTINUE);
7006495Sspeer 	}
7016495Sspeer 
7026495Sspeer 	name = ddi_node_name(dip);
7036495Sspeer 	if (strcmp(name, "niu")  != 0) {
7046495Sspeer 		return (DDI_WALK_CONTINUE);
7056495Sspeer 	}
7066495Sspeer 	rv = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
7076495Sspeer 	    DDI_PROP_DONTPASS, "reg", (int **)&reg_p, &reglen);
7086495Sspeer 	if (rv != DDI_PROP_SUCCESS) {
7096495Sspeer 		DWARN(NULL, "Failed to get reg property dip=0x%p", dip);
7106495Sspeer 		return (DDI_WALK_CONTINUE);
7116495Sspeer 	}
7126495Sspeer 
7136495Sspeer 	hdl =  reg_p->addr_hi & 0x0FFFFFFF;
7146495Sspeer 	ddi_prop_free(reg_p);
7156495Sspeer 
7166495Sspeer 	DBG2(NULL, "Handle = 0x%lx dip=0x%p", hdl, dip);
7176495Sspeer 	if (hdl == NIUCFGHDL(warg->cookie)) {
7186495Sspeer 		/* Hold before returning */
7197819SRaghuram.Kothakota@Sun.COM 		if (!e_ddi_branch_held(dip))
7207819SRaghuram.Kothakota@Sun.COM 			e_ddi_branch_hold(dip);
7216495Sspeer 		warg->dip = dip;
7226495Sspeer 		DBG2(NULL, "Found dip = 0x%p", dip);
7236495Sspeer 		return (DDI_WALK_TERMINATE);
7246495Sspeer 	}
7256495Sspeer 	return (DDI_WALK_CONTINUE);
7266495Sspeer }
7276495Sspeer 
7286495Sspeer /*
7296495Sspeer  * vdds_match_niu_node -- callback function to verify a node is the
7306495Sspeer  *	NIU Hybrid node.
7316495Sspeer  */
7326495Sspeer static int
vdds_match_niu_node(dev_info_t * dip,void * arg)7336495Sspeer vdds_match_niu_node(dev_info_t *dip, void *arg)
7346495Sspeer {
7356495Sspeer 	vdds_cb_arg_t	*warg = (vdds_cb_arg_t *)arg;
7366495Sspeer 	char		*name;
7376495Sspeer 	vdds_reg_t	*reg_p;
7386495Sspeer 	uint_t		reglen;
7396495Sspeer 	int		rv;
7406495Sspeer 	uint32_t	addr_hi;
7416495Sspeer 
7426495Sspeer 	name = ddi_node_name(dip);
7436495Sspeer 	if (strcmp(name, "network")  != 0) {
7446495Sspeer 		return (DDI_WALK_CONTINUE);
7456495Sspeer 	}
7466495Sspeer 	rv = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
7476495Sspeer 	    DDI_PROP_DONTPASS, "reg", (int **)&reg_p, &reglen);
7486495Sspeer 	if (rv != DDI_PROP_SUCCESS) {
7496495Sspeer 		DWARN(NULL, "Failed to get reg property dip=0x%p", dip);
7506495Sspeer 		return (DDI_WALK_CONTINUE);
7516495Sspeer 	}
7526495Sspeer 
7536495Sspeer 	addr_hi = reg_p->addr_hi;
7546495Sspeer 	DBG1(NULL, "addr_hi = 0x%x dip=0x%p", addr_hi, dip);
7556495Sspeer 	ddi_prop_free(reg_p);
7566495Sspeer 	if (addr_hi == HVCOOKIE(warg->cookie)) {
7576495Sspeer 		warg->dip = dip;
7587819SRaghuram.Kothakota@Sun.COM 		if (!e_ddi_branch_held(dip))
7597819SRaghuram.Kothakota@Sun.COM 			e_ddi_branch_hold(dip);
7606495Sspeer 		DBG1(NULL, "Found dip = 0x%p", dip);
7616495Sspeer 		return (DDI_WALK_TERMINATE);
7626495Sspeer 	}
7636495Sspeer 	return (DDI_WALK_CONTINUE);
7646495Sspeer }
7656495Sspeer 
7666495Sspeer /*
7676495Sspeer  * vdds_new_nexus_node -- callback function to set all the properties
7686495Sspeer  *	a new NIU nexus node.
7696495Sspeer  */
7706495Sspeer static int
vdds_new_nexus_node(dev_info_t * dip,void * arg,uint_t flags)7716495Sspeer vdds_new_nexus_node(dev_info_t *dip, void *arg, uint_t flags)
7726495Sspeer {
7736495Sspeer 	vdds_cb_arg_t	*cba = (vdds_cb_arg_t *)arg;
7746495Sspeer 	char		*compat[] = { "SUNW,niumx" };
7756495Sspeer 	vdds_ranges_t	*rangesp;
7766495Sspeer 	vdds_reg_t	reg;
7776495Sspeer 	uint64_t	nranges;
7786495Sspeer 	int		n;
7796495Sspeer 
7806495Sspeer 	DBG1(NULL, "Called dip=0x%p, flags=0x%X", dip, flags);
7816495Sspeer 
7826495Sspeer 	/* create "niu" property */
7836495Sspeer 	if (ndi_prop_update_string(DDI_DEV_T_NONE, dip, "name", "niu") !=
7846495Sspeer 	    DDI_SUCCESS) {
7856495Sspeer 		DERR(NULL, "Failed to create name property(dip=0x%p)", dip);
7866495Sspeer 		return (DDI_WALK_ERROR);
7876495Sspeer 	}
7886495Sspeer 
7896495Sspeer 	/* create "compatible" property */
7906495Sspeer 	if (ndi_prop_update_string_array(DDI_DEV_T_NONE, dip, "compatible",
7916495Sspeer 	    compat, 1) != DDI_SUCCESS) {
7926495Sspeer 		DERR(NULL, "Failed to create compatible property(dip=0x%p)",
7936495Sspeer 		    dip);
7946495Sspeer 		return (DDI_WALK_ERROR);
7956495Sspeer 	}
7966495Sspeer 
7976495Sspeer 	/* create "device_type" property */
7986495Sspeer 	if (ndi_prop_update_string(DDI_DEV_T_NONE, dip,
7996495Sspeer 	    "device_type", "sun4v") != DDI_SUCCESS) {
8006495Sspeer 		DERR(NULL, "Failed to create device_type property(dip=0x%p)",
8016495Sspeer 		    dip);
8026495Sspeer 		return (DDI_WALK_ERROR);
8036495Sspeer 	}
8046495Sspeer 
8056495Sspeer 	/*
8066495Sspeer 	 * create "reg" property. The first 28 bits of
8076495Sspeer 	 * 'addr_hi'  are NIU cfg_handle, the 0xc in 28-31 bits
8086495Sspeer 	 * indicates non-cacheable config.
8096495Sspeer 	 */
8106495Sspeer 	reg.addr_hi = 0xc0000000 | NIUCFGHDL(cba->cookie);
8116495Sspeer 	reg.addr_lo = 0;
8126495Sspeer 	reg.size_hi = 0;
8136495Sspeer 	reg.size_lo = 0;
8146495Sspeer 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
8156495Sspeer 	    "reg", (int *)&reg, sizeof (reg)/sizeof (int)) != DDI_SUCCESS) {
8166495Sspeer 		DERR(NULL, "Failed to create reg property(dip=0x%p)", dip);
8176495Sspeer 		return (DDI_WALK_ERROR);
8186495Sspeer 	}
8196495Sspeer 
8206495Sspeer 	/*
8216495Sspeer 	 * Create VDDS_MAX_RANGES so that they are already in place
8226495Sspeer 	 * before the children are created. While creating the child
8236495Sspeer 	 * we just modify one of this ranges entries.
8246495Sspeer 	 */
8256495Sspeer 	nranges = VDDS_MAX_RANGES;  /* One range for each VR */
8266495Sspeer 	rangesp = (vdds_ranges_t *)kmem_zalloc(
8276495Sspeer 	    (sizeof (vdds_ranges_t) * nranges), KM_SLEEP);
8286495Sspeer 
8296495Sspeer 	for (n = 0; n < nranges; n++) {
8306495Sspeer 		/* zero all child_hi/lo */
8316495Sspeer 		rangesp[n].child_hi = 0;
8326495Sspeer 		rangesp[n].child_lo = 0;
8336495Sspeer 	}
8346495Sspeer 
8356495Sspeer 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges",
8366495Sspeer 	    (int *)rangesp, (nranges * 6)) != DDI_SUCCESS) {
8376495Sspeer 		DERR(NULL, "Failed to create ranges property(dip=0x%p)", dip);
8386495Sspeer 		kmem_free(rangesp, (sizeof (vdds_ranges_t) * nranges));
8396495Sspeer 		return (DDI_WALK_ERROR);
8406495Sspeer 	}
8416495Sspeer 
8426495Sspeer 	/* create "#size-cells" property */
8436495Sspeer 	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
8446495Sspeer 	    "#size-cells", 2) != DDI_SUCCESS) {
8456495Sspeer 		DERR(NULL, "Failed to create #size-cells property(dip=0x%p)",
8466495Sspeer 		    dip);
8476495Sspeer 		kmem_free(rangesp, (sizeof (vdds_ranges_t) * nranges));
8486495Sspeer 		return (DDI_WALK_ERROR);
8496495Sspeer 	}
8506495Sspeer 
8516495Sspeer 	/* create "#address-cells" property */
8526495Sspeer 	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
8536495Sspeer 	    "#address-cells", 2) != DDI_SUCCESS) {
8546495Sspeer 		DERR(NULL, "Failed to create #address-cells prop(dip=0x%p)",
8556495Sspeer 		    dip);
8566495Sspeer 		kmem_free(rangesp, (sizeof (vdds_ranges_t) * nranges));
8576495Sspeer 		return (DDI_WALK_ERROR);
8586495Sspeer 	}
8596495Sspeer 
8606495Sspeer 	kmem_free(rangesp, (sizeof (vdds_ranges_t) * nranges));
8616495Sspeer 	cba->dip = dip;
8626495Sspeer 	DBG1(NULL, "Returning (dip=0x%p)", dip);
8636495Sspeer 	return (DDI_WALK_TERMINATE);
8646495Sspeer }
8656495Sspeer 
8666495Sspeer /*
8676495Sspeer  * vdds_new_niu_node -- callback function to create a new NIU Hybrid node.
8686495Sspeer  */
8696495Sspeer static int
vdds_new_niu_node(dev_info_t * dip,void * arg,uint_t flags)8706495Sspeer vdds_new_niu_node(dev_info_t *dip, void *arg, uint_t flags)
8716495Sspeer {
8726495Sspeer 	vdds_cb_arg_t *cba = (vdds_cb_arg_t *)arg;
8736495Sspeer 	char *compat[] = { "SUNW,niusl" };
8746495Sspeer 	uint8_t macaddrbytes[ETHERADDRL];
8756495Sspeer 	int interrupts[VDDS_MAX_VRINTRS];
8766495Sspeer 	vdds_ranges_t	*prng;
8776495Sspeer 	vdds_ranges_t	*prp;
8786495Sspeer 	vdds_reg_t	reg;
8796495Sspeer 	dev_info_t	*pdip;
8806495Sspeer 	uint64_t	start;
8816495Sspeer 	uint64_t	size;
8826495Sspeer 	int		prnglen;
8836495Sspeer 	int		nintr = 0;
8846495Sspeer 	int		nrng;
8856495Sspeer 	int		rnum;
8866495Sspeer 	int		rv;
8876495Sspeer 
8886495Sspeer 	DBG1(NULL, "Called dip=0x%p flags=0x%X", dip, flags);
8896495Sspeer 	pdip = ddi_get_parent(dip);
8906495Sspeer 
8916495Sspeer 	if (pdip == NULL) {
8926495Sspeer 		DWARN(NULL, "Failed to get parent dip(dip=0x%p)", dip);
8936495Sspeer 		return (DDI_WALK_ERROR);
8946495Sspeer 	}
8956495Sspeer 
8966495Sspeer 	/* create "network" property */
8976495Sspeer 	if (ndi_prop_update_string(DDI_DEV_T_NONE, dip, "name", "network") !=
8986495Sspeer 	    DDI_SUCCESS) {
8996495Sspeer 		DERR(NULL, "Failed to create name property(dip=0x%p)", dip);
9006495Sspeer 		return (DDI_WALK_ERROR);
9016495Sspeer 	}
9026495Sspeer 
9036495Sspeer 	/*
9046495Sspeer 	 * create "niutype" property, it is set to n2niu to
9056495Sspeer 	 * indicate NIU Hybrid node.
9066495Sspeer 	 */
9076495Sspeer 	if (ndi_prop_update_string(DDI_DEV_T_NONE, dip, "niutype",
9086495Sspeer 	    "n2niu") != DDI_SUCCESS) {
9096495Sspeer 		DERR(NULL, "Failed to create niuopmode property(dip=0x%p)",
9106495Sspeer 		    dip);
9116495Sspeer 		return (DDI_WALK_ERROR);
9126495Sspeer 	}
9136495Sspeer 
9146495Sspeer 	/* create "compatible" property */
9156495Sspeer 	if (ndi_prop_update_string_array(DDI_DEV_T_NONE, dip, "compatible",
9166495Sspeer 	    compat, 1) != DDI_SUCCESS) {
9176495Sspeer 		DERR(NULL, "Failed to create compatible property(dip=0x%p)",
9186495Sspeer 		    dip);
9196495Sspeer 		return (DDI_WALK_ERROR);
9206495Sspeer 	}
9216495Sspeer 
9226495Sspeer 	/* create "device_type" property */
9236495Sspeer 	if (ndi_prop_update_string(DDI_DEV_T_NONE, dip,
9246495Sspeer 	    "device_type", "network") != DDI_SUCCESS) {
9256495Sspeer 		DERR(NULL, "Failed to create device_type property(dip=0x%p)",
9266495Sspeer 		    dip);
9276495Sspeer 		return (DDI_WALK_ERROR);
9286495Sspeer 	}
9296495Sspeer 
9306495Sspeer 	/* create "reg" property */
9316495Sspeer 	if (vdds_hv_niu_vr_getinfo(HVCOOKIE(cba->cookie),
9326495Sspeer 	    &start, &size) != H_EOK) {
9336495Sspeer 		DERR(NULL, "Failed to get vrinfo for cookie(0x%lX)",
9346495Sspeer 		    cba->cookie);
9356495Sspeer 			return (DDI_WALK_ERROR);
9366495Sspeer 	}
9376495Sspeer 	reg.addr_hi = HVCOOKIE(cba->cookie);
9386495Sspeer 	reg.addr_lo = 0;
9396495Sspeer 	reg.size_hi = 0;
9406495Sspeer 	reg.size_lo = size;
9416495Sspeer 
9426495Sspeer 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "reg",
9436495Sspeer 	    (int *)&reg, sizeof (reg) / sizeof (int)) != DDI_SUCCESS) {
9446495Sspeer 		DERR(NULL, "Failed to create reg property(dip=0x%p)", dip);
9456495Sspeer 		return (DDI_WALK_ERROR);
9466495Sspeer 	}
9476495Sspeer 
9486495Sspeer 	/*
9496495Sspeer 	 * Modify the parent's ranges property to map the "reg" property
9506495Sspeer 	 * of the new child.
9516495Sspeer 	 */
9526495Sspeer 	if ((rv = ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
9536495Sspeer 	    "ranges", (caddr_t)&prng, &prnglen)) != DDI_SUCCESS) {
9546495Sspeer 		DERR(NULL,
9556495Sspeer 		    "Failed to get parent's ranges property(pdip=0x%p) rv=%d",
9566495Sspeer 		    pdip, rv);
9576495Sspeer 		return (DDI_WALK_ERROR);
9586495Sspeer 	}
9596495Sspeer 	nrng = prnglen/(sizeof (vdds_ranges_t));
9606495Sspeer 	/*
9616495Sspeer 	 * First scan all ranges to see if a range corresponding
9626495Sspeer 	 * to this virtual NIU exists already.
9636495Sspeer 	 */
9646495Sspeer 	for (rnum = 0; rnum < nrng; rnum++) {
9656495Sspeer 		prp = &prng[rnum];
9666495Sspeer 		if (prp->child_hi == HVCOOKIE(cba->cookie)) {
9676495Sspeer 			break;
9686495Sspeer 		}
9696495Sspeer 	}
9706495Sspeer 	if (rnum == nrng) {
9716495Sspeer 		/* Now to try to find an empty range */
9726495Sspeer 		for (rnum = 0; rnum < nrng; rnum++) {
9736495Sspeer 			prp = &prng[rnum];
9746495Sspeer 			if (prp->child_hi == 0) {
9756495Sspeer 				break;
9766495Sspeer 			}
9776495Sspeer 		}
9786495Sspeer 	}
9796495Sspeer 	if (rnum == nrng) {
9806495Sspeer 		DERR(NULL, "No free ranges entry found");
9816495Sspeer 		return (DDI_WALK_ERROR);
9826495Sspeer 	}
9836495Sspeer 
9846495Sspeer 	/*
9856495Sspeer 	 * child_hi will have HV cookie as HV cookie is more like
9866495Sspeer 	 * a port in the HybridIO.
9876495Sspeer 	 */
9886495Sspeer 	prp->child_hi = HVCOOKIE(cba->cookie);
9896495Sspeer 	prp->child_lo = 0;
9906495Sspeer 	prp->parent_hi = 0x80000000 | (start >> 32);
9916495Sspeer 	prp->parent_lo = start & 0x00000000FFFFFFFF;
9926495Sspeer 	prp->size_hi = (size >> 32);
9936495Sspeer 	prp->size_lo = size & 0x00000000FFFFFFFF;
9946495Sspeer 
9956495Sspeer 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, pdip, "ranges",
9966495Sspeer 	    (int *)prng, (nrng * 6)) != DDI_SUCCESS) {
9976495Sspeer 		DERR(NULL, "Failed to update parent ranges prop(pdip=0x%p)",
9986495Sspeer 		    pdip);
9996495Sspeer 		return (DDI_WALK_ERROR);
10006495Sspeer 	}
10016495Sspeer 	kmem_free((void *)prng, prnglen);
10026495Sspeer 
10036495Sspeer 	vnet_macaddr_ultostr(cba->macaddr, macaddrbytes);
10046495Sspeer 
10056495Sspeer 	/*
10066495Sspeer 	 * create "local-mac-address" property, this will be same as
10076495Sspeer 	 * the vnet's mac-address.
10086495Sspeer 	 */
10096495Sspeer 	if (ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip, "local-mac-address",
10106495Sspeer 	    macaddrbytes, ETHERADDRL) != DDI_SUCCESS) {
10116495Sspeer 		DERR(NULL, "Failed to update mac-addresses property(dip=0x%p)",
10126495Sspeer 		    dip);
10136495Sspeer 		return (DDI_WALK_ERROR);
10146495Sspeer 	}
10156495Sspeer 
10166495Sspeer 	rv = vdds_get_interrupts(cba->cookie, rnum, interrupts, &nintr);
10176495Sspeer 	if (rv != 0) {
10186495Sspeer 		DERR(NULL, "Failed to get interrupts for cookie=0x%lx",
10196495Sspeer 		    cba->cookie);
10206495Sspeer 		return (DDI_WALK_ERROR);
10216495Sspeer 	}
10226495Sspeer 
10236495Sspeer 	/* create "interrupts" property */
10246495Sspeer 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "interrupts",
10256495Sspeer 	    interrupts, nintr) != DDI_SUCCESS) {
10266495Sspeer 		DERR(NULL, "Failed to update interrupts property(dip=0x%p)",
10276495Sspeer 		    dip);
10286495Sspeer 		return (DDI_WALK_ERROR);
10296495Sspeer 	}
10306495Sspeer 
10316495Sspeer 
10327529SSriharsha.Basavapatna@Sun.COM 	/* create "max_frame_size" property */
10337529SSriharsha.Basavapatna@Sun.COM 	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip, "max-frame-size",
10347529SSriharsha.Basavapatna@Sun.COM 	    cba->max_frame_size) != DDI_SUCCESS) {
10357529SSriharsha.Basavapatna@Sun.COM 		DERR(NULL, "Failed to update max-frame-size property(dip=0x%p)",
10367529SSriharsha.Basavapatna@Sun.COM 		    dip);
10377529SSriharsha.Basavapatna@Sun.COM 		return (DDI_WALK_ERROR);
10387529SSriharsha.Basavapatna@Sun.COM 	}
10397529SSriharsha.Basavapatna@Sun.COM 
10406495Sspeer 	cba->dip = dip;
10416495Sspeer 	DBG1(NULL, "Returning dip=0x%p", dip);
10426495Sspeer 	return (DDI_WALK_TERMINATE);
10436495Sspeer }
10446495Sspeer 
10456495Sspeer 
10466495Sspeer /*
10476495Sspeer  * vdds_find_node -- A common function to find a NIU nexus or NIU node.
10486495Sspeer  */
10496495Sspeer static dev_info_t *
vdds_find_node(uint64_t cookie,dev_info_t * sdip,int (* match_func)(dev_info_t * dip,void * arg))10506495Sspeer vdds_find_node(uint64_t cookie, dev_info_t *sdip,
10516495Sspeer 	int (*match_func)(dev_info_t *dip, void *arg))
10526495Sspeer {
10536495Sspeer 	vdds_cb_arg_t arg;
10546495Sspeer 	dev_info_t *pdip;
10556495Sspeer 	int circ;
10566495Sspeer 
10576495Sspeer 	DBG1(NULL, "Called cookie=%lx\n", cookie);
10586495Sspeer 
10596495Sspeer 	arg.dip = NULL;
10606495Sspeer 	arg.cookie = cookie;
10616495Sspeer 
10626495Sspeer 	if (pdip = ddi_get_parent(sdip)) {
10636495Sspeer 		ndi_devi_enter(pdip, &circ);
10646495Sspeer 	}
10656495Sspeer 
10666495Sspeer 	ddi_walk_devs(sdip, match_func, (void *)&arg);
10676495Sspeer 	if (pdip != NULL) {
10686495Sspeer 		ndi_devi_exit(pdip, circ);
10696495Sspeer 	}
10706495Sspeer 
10716495Sspeer 	DBG1(NULL, "Returning dip=0x%p", arg.dip);
10726495Sspeer 	return (arg.dip);
10736495Sspeer }
10746495Sspeer 
10756495Sspeer /*
10766495Sspeer  * vdds_create_new_node -- A common function to create NIU nexus/NIU node.
10776495Sspeer  */
10786495Sspeer static dev_info_t *
vdds_create_new_node(vdds_cb_arg_t * cbap,dev_info_t * pdip,int (* new_node_func)(dev_info_t * dip,void * arg,uint_t flags))10797529SSriharsha.Basavapatna@Sun.COM vdds_create_new_node(vdds_cb_arg_t *cbap, dev_info_t *pdip,
10806495Sspeer     int (*new_node_func)(dev_info_t *dip, void *arg, uint_t flags))
10816495Sspeer {
10826495Sspeer 	devi_branch_t br;
10837819SRaghuram.Kothakota@Sun.COM 	int rv;
10846495Sspeer 
10857529SSriharsha.Basavapatna@Sun.COM 	DBG1(NULL, "Called cookie=0x%lx", cbap->cookie);
10866495Sspeer 
10877529SSriharsha.Basavapatna@Sun.COM 	br.arg = (void *)cbap;
10886495Sspeer 	br.type = DEVI_BRANCH_SID;
10896495Sspeer 	br.create.sid_branch_create = new_node_func;
10906495Sspeer 	br.devi_branch_callback = NULL;
10916495Sspeer 
10927819SRaghuram.Kothakota@Sun.COM 	if (pdip == NULL) {
10936495Sspeer 		pdip = ddi_root_node();
10947819SRaghuram.Kothakota@Sun.COM 	}
10956495Sspeer 	DBG1(NULL, "calling e_ddi_branch_create");
10966495Sspeer 	if ((rv = e_ddi_branch_create(pdip, &br, NULL,
10976495Sspeer 	    DEVI_BRANCH_CHILD | DEVI_BRANCH_CONFIGURE))) {
10986495Sspeer 		DERR(NULL, "e_ddi_branch_create failed=%d", rv);
10996495Sspeer 		return (NULL);
11006495Sspeer 	}
11017529SSriharsha.Basavapatna@Sun.COM 	DBG1(NULL, "Returning(dip=0x%p", cbap->dip);
11027529SSriharsha.Basavapatna@Sun.COM 	return (cbap->dip);
11036495Sspeer }
11046495Sspeer 
11056495Sspeer /*
11066495Sspeer  * vdds_get_interrupts -- A function that binds ino's to channels and
11076495Sspeer  *	then provides them to create interrupts property.
11086495Sspeer  */
11096495Sspeer static int
vdds_get_interrupts(uint64_t cookie,int ino_range,int * intrs,int * nintr)11106495Sspeer vdds_get_interrupts(uint64_t cookie, int ino_range, int *intrs, int *nintr)
11116495Sspeer {
11126495Sspeer 	uint32_t hvcookie = HVCOOKIE(cookie);
11136495Sspeer 	uint64_t txmap;
11146495Sspeer 	uint64_t rxmap;
11156495Sspeer 	uint32_t ino = VDDS_INO_RANGE_START(ino_range);
11166495Sspeer 	int rv;
11176495Sspeer 	uint64_t i;
11186495Sspeer 
11196495Sspeer 	*nintr = 0;
11206495Sspeer 	rv = vdds_hv_niu_vr_get_txmap(hvcookie, &txmap);
11216495Sspeer 	if (rv != H_EOK) {
11226495Sspeer 		DWARN(NULL, "Failed to get txmap for hvcookie=0x%X rv=%d\n",
11236495Sspeer 		    hvcookie, rv);
11246495Sspeer 		return (EIO);
11256495Sspeer 	}
11266495Sspeer 	rv = vdds_hv_niu_vr_get_rxmap(hvcookie, &rxmap);
11276495Sspeer 	if (rv != H_EOK) {
11286495Sspeer 		DWARN(NULL, "Failed to get rxmap for hvcookie=0x%X, rv=%d\n",
11296495Sspeer 		    hvcookie, rv);
11306495Sspeer 		return (EIO);
11316495Sspeer 	}
11326495Sspeer 	/* Check if the number of total channels to be more than 8 */
11336495Sspeer 	for (i = 0; i < 4; i++) {
11346495Sspeer 		if (rxmap & (((uint64_t)0x1) << i)) {
11356495Sspeer 			rv = vdds_hv_niu_vrrx_set_ino(hvcookie, i, ino);
11366495Sspeer 			if (rv != H_EOK) {
11376495Sspeer 				DWARN(NULL, "Failed to get Rx ino for "
11386495Sspeer 				    "hvcookie=0x%X vch_idx=0x%lx rv=%d\n",
11396495Sspeer 				    hvcookie, i, rv);
11406495Sspeer 				return (EIO);
11416495Sspeer 			}
11426495Sspeer 			DWARN(NULL,
11436495Sspeer 			    "hvcookie=0x%X RX vch_idx=0x%lx ino=0x%X\n",
11446495Sspeer 			    hvcookie, i, ino);
11456495Sspeer 			*intrs = ino;
11466495Sspeer 			ino++;
11476495Sspeer 		} else {
11486495Sspeer 			*intrs = VDDS_MAX_INTR_NUM;
11496495Sspeer 		}
11506495Sspeer 		intrs++;
11516495Sspeer 		*nintr += 1;
11526495Sspeer 	}
11536495Sspeer 	for (i = 0; i < 4; i++) {
11546495Sspeer 		if (txmap & (((uint64_t)0x1) << i)) {
11556495Sspeer 			rv = vdds_hv_niu_vrtx_set_ino(hvcookie, i, ino);
11566495Sspeer 			if (rv != H_EOK) {
11576495Sspeer 				DWARN(NULL, "Failed to get Tx ino for "
11586495Sspeer 				    "hvcookie=0x%X vch_idx=0x%lx rv=%d\n",
11596495Sspeer 				    hvcookie, i, rv);
11606495Sspeer 				return (EIO);
11616495Sspeer 			}
11626495Sspeer 			DWARN(NULL, "hvcookie=0x%X TX vch_idx=0x%lx ino=0x%X\n",
11636495Sspeer 			    hvcookie, i, ino);
11646495Sspeer 			*intrs = ino;
11656495Sspeer 			ino++;
11666495Sspeer 		} else {
11676495Sspeer 			*intrs = VDDS_MAX_INTR_NUM;
11686495Sspeer 		}
11696495Sspeer 		intrs++;
11706495Sspeer 		*nintr += 1;
11716495Sspeer 	}
11726495Sspeer 	return (0);
11736495Sspeer }
11746495Sspeer 
11756495Sspeer /*
11766495Sspeer  * vdds_release_range_prop -- cleanups an entry in the ranges property
11776495Sspeer  *	corresponding to a cookie.
11786495Sspeer  */
11796495Sspeer static void
vdds_release_range_prop(dev_info_t * nexus_dip,uint64_t cookie)11806495Sspeer vdds_release_range_prop(dev_info_t *nexus_dip, uint64_t cookie)
11816495Sspeer {
11826495Sspeer 	vdds_ranges_t *prng;
11836495Sspeer 	vdds_ranges_t *prp;
11846495Sspeer 	int prnglen;
11856495Sspeer 	int nrng;
11866495Sspeer 	int rnum;
11876495Sspeer 	boolean_t success = B_FALSE;
11886495Sspeer 	int rv;
11896495Sspeer 
11906495Sspeer 	if ((rv = ddi_getlongprop(DDI_DEV_T_ANY, nexus_dip, DDI_PROP_DONTPASS,
11916495Sspeer 	    "ranges", (caddr_t)&prng, &prnglen)) != DDI_SUCCESS) {
11926495Sspeer 		DERR(NULL,
11936495Sspeer 		    "Failed to get nexus ranges property(dip=0x%p) rv=%d",
11946495Sspeer 		    nexus_dip, rv);
11956495Sspeer 		return;
11966495Sspeer 	}
11976495Sspeer 	nrng = prnglen/(sizeof (vdds_ranges_t));
11986495Sspeer 	for (rnum = 0; rnum < nrng; rnum++) {
11996495Sspeer 		prp = &prng[rnum];
12006495Sspeer 		if (prp->child_hi == HVCOOKIE(cookie)) {
12016495Sspeer 			prp->child_hi = 0;
12026495Sspeer 			success = B_TRUE;
12036495Sspeer 			break;
12046495Sspeer 		}
12056495Sspeer 	}
12066495Sspeer 	if (success) {
12076495Sspeer 		if (ndi_prop_update_int_array(DDI_DEV_T_NONE, nexus_dip,
12086495Sspeer 		    "ranges", (int *)prng, (nrng * 6)) != DDI_SUCCESS) {
12096495Sspeer 			DERR(NULL,
12106495Sspeer 			    "Failed to update nexus ranges prop(dip=0x%p)",
12116495Sspeer 			    nexus_dip);
12126495Sspeer 		}
12136495Sspeer 	}
12146495Sspeer }
1215