xref: /onnv-gate/usr/src/uts/common/io/sundlpi.c (revision 9073:a5a4bb23741e)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55102Syz147064  * Common Development and Distribution License (the "License").
65102Syz147064  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
228518SPeter.Memishian@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  *  Common Sun DLPI routines.
280Sstevel@tonic-gate  */
290Sstevel@tonic-gate 
308518SPeter.Memishian@Sun.COM #include <sys/types.h>
318518SPeter.Memishian@Sun.COM #include <sys/sysmacros.h>
328518SPeter.Memishian@Sun.COM #include <sys/byteorder.h>
338518SPeter.Memishian@Sun.COM #include <sys/stream.h>
348518SPeter.Memishian@Sun.COM #include <sys/strsun.h>
358518SPeter.Memishian@Sun.COM #include <sys/dlpi.h>
368518SPeter.Memishian@Sun.COM #include <sys/ddi.h>
378518SPeter.Memishian@Sun.COM #include <sys/sunddi.h>
388518SPeter.Memishian@Sun.COM #include <sys/sunldi.h>
398518SPeter.Memishian@Sun.COM #include <sys/cmn_err.h>
400Sstevel@tonic-gate 
410Sstevel@tonic-gate void
dlbindack(queue_t * wq,mblk_t * mp,t_scalar_t sap,const void * addrp,t_uscalar_t addrlen,t_uscalar_t maxconind,t_uscalar_t xidtest)420Sstevel@tonic-gate dlbindack(
430Sstevel@tonic-gate 	queue_t		*wq,
440Sstevel@tonic-gate 	mblk_t		*mp,
450Sstevel@tonic-gate 	t_scalar_t	sap,
468518SPeter.Memishian@Sun.COM 	const void	*addrp,
470Sstevel@tonic-gate 	t_uscalar_t	addrlen,
480Sstevel@tonic-gate 	t_uscalar_t	maxconind,
490Sstevel@tonic-gate 	t_uscalar_t	xidtest)
500Sstevel@tonic-gate {
510Sstevel@tonic-gate 	union DL_primitives	*dlp;
520Sstevel@tonic-gate 	size_t			size;
530Sstevel@tonic-gate 
540Sstevel@tonic-gate 	size = sizeof (dl_bind_ack_t) + addrlen;
550Sstevel@tonic-gate 	if ((mp = mexchange(wq, mp, size, M_PCPROTO, DL_BIND_ACK)) == NULL)
560Sstevel@tonic-gate 		return;
570Sstevel@tonic-gate 
580Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
590Sstevel@tonic-gate 	dlp->bind_ack.dl_sap = sap;
600Sstevel@tonic-gate 	dlp->bind_ack.dl_addr_length = addrlen;
610Sstevel@tonic-gate 	dlp->bind_ack.dl_addr_offset = sizeof (dl_bind_ack_t);
620Sstevel@tonic-gate 	dlp->bind_ack.dl_max_conind = maxconind;
630Sstevel@tonic-gate 	dlp->bind_ack.dl_xidtest_flg = xidtest;
640Sstevel@tonic-gate 	if (addrlen != 0)
650Sstevel@tonic-gate 		bcopy(addrp, mp->b_rptr + sizeof (dl_bind_ack_t), addrlen);
660Sstevel@tonic-gate 	qreply(wq, mp);
670Sstevel@tonic-gate }
680Sstevel@tonic-gate 
690Sstevel@tonic-gate void
dlokack(queue_t * wq,mblk_t * mp,t_uscalar_t correct_primitive)700Sstevel@tonic-gate dlokack(
710Sstevel@tonic-gate 	queue_t		*wq,
720Sstevel@tonic-gate 	mblk_t		*mp,
730Sstevel@tonic-gate 	t_uscalar_t	correct_primitive)
740Sstevel@tonic-gate {
750Sstevel@tonic-gate 	union DL_primitives	*dlp;
760Sstevel@tonic-gate 
770Sstevel@tonic-gate 	if ((mp = mexchange(wq, mp, sizeof (dl_ok_ack_t), M_PCPROTO,
780Sstevel@tonic-gate 	    DL_OK_ACK)) == NULL)
790Sstevel@tonic-gate 		return;
800Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
810Sstevel@tonic-gate 	dlp->ok_ack.dl_correct_primitive = correct_primitive;
820Sstevel@tonic-gate 	qreply(wq, mp);
830Sstevel@tonic-gate }
840Sstevel@tonic-gate 
850Sstevel@tonic-gate void
dlerrorack(queue_t * wq,mblk_t * mp,t_uscalar_t error_primitive,t_uscalar_t error,t_uscalar_t unix_errno)860Sstevel@tonic-gate dlerrorack(
870Sstevel@tonic-gate 	queue_t		*wq,
880Sstevel@tonic-gate 	mblk_t		*mp,
890Sstevel@tonic-gate 	t_uscalar_t	error_primitive,
900Sstevel@tonic-gate 	t_uscalar_t	error,
910Sstevel@tonic-gate 	t_uscalar_t	unix_errno)
920Sstevel@tonic-gate {
930Sstevel@tonic-gate 	union DL_primitives	*dlp;
940Sstevel@tonic-gate 
950Sstevel@tonic-gate 	if ((mp = mexchange(wq, mp, sizeof (dl_error_ack_t), M_PCPROTO,
960Sstevel@tonic-gate 	    DL_ERROR_ACK)) == NULL)
970Sstevel@tonic-gate 		return;
980Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
990Sstevel@tonic-gate 	dlp->error_ack.dl_error_primitive = error_primitive;
1000Sstevel@tonic-gate 	dlp->error_ack.dl_errno = error;
1010Sstevel@tonic-gate 	dlp->error_ack.dl_unix_errno = unix_errno;
1020Sstevel@tonic-gate 	qreply(wq, mp);
1030Sstevel@tonic-gate }
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate void
dluderrorind(queue_t * wq,mblk_t * mp,const void * addrp,t_uscalar_t addrlen,t_uscalar_t error,t_uscalar_t unix_errno)1060Sstevel@tonic-gate dluderrorind(
1070Sstevel@tonic-gate 	queue_t		*wq,
1080Sstevel@tonic-gate 	mblk_t		*mp,
1098518SPeter.Memishian@Sun.COM 	const void	*addrp,
1100Sstevel@tonic-gate 	t_uscalar_t	addrlen,
1110Sstevel@tonic-gate 	t_uscalar_t	error,
1120Sstevel@tonic-gate 	t_uscalar_t	unix_errno)
1130Sstevel@tonic-gate {
1140Sstevel@tonic-gate 	union DL_primitives	*dlp;
1150Sstevel@tonic-gate 	size_t			size;
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate 	size = sizeof (dl_uderror_ind_t) + addrlen;
1180Sstevel@tonic-gate 	if ((mp = mexchange(wq, mp, size, M_PCPROTO, DL_UDERROR_IND)) == NULL)
1190Sstevel@tonic-gate 		return;
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
1220Sstevel@tonic-gate 	dlp->uderror_ind.dl_dest_addr_length = addrlen;
1230Sstevel@tonic-gate 	dlp->uderror_ind.dl_dest_addr_offset = sizeof (dl_uderror_ind_t);
1240Sstevel@tonic-gate 	dlp->uderror_ind.dl_unix_errno = unix_errno;
1250Sstevel@tonic-gate 	dlp->uderror_ind.dl_errno = error;
1268518SPeter.Memishian@Sun.COM 	if (addrlen != 0)
1278518SPeter.Memishian@Sun.COM 		bcopy(addrp, mp->b_rptr + sizeof (dl_uderror_ind_t), addrlen);
1280Sstevel@tonic-gate 	qreply(wq, mp);
1290Sstevel@tonic-gate }
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate void
dlphysaddrack(queue_t * wq,mblk_t * mp,const void * addrp,t_uscalar_t len)1320Sstevel@tonic-gate dlphysaddrack(
1330Sstevel@tonic-gate 	queue_t		*wq,
1340Sstevel@tonic-gate 	mblk_t		*mp,
1358518SPeter.Memishian@Sun.COM 	const void	*addrp,
1360Sstevel@tonic-gate 	t_uscalar_t	len)
1370Sstevel@tonic-gate {
1380Sstevel@tonic-gate 	union DL_primitives	*dlp;
1390Sstevel@tonic-gate 	size_t			size;
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 	size = sizeof (dl_phys_addr_ack_t) + len;
1420Sstevel@tonic-gate 	if ((mp = mexchange(wq, mp, size, M_PCPROTO, DL_PHYS_ADDR_ACK)) == NULL)
1430Sstevel@tonic-gate 		return;
1440Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
1450Sstevel@tonic-gate 	dlp->physaddr_ack.dl_addr_length = len;
1460Sstevel@tonic-gate 	dlp->physaddr_ack.dl_addr_offset = sizeof (dl_phys_addr_ack_t);
1470Sstevel@tonic-gate 	if (len != 0)
1480Sstevel@tonic-gate 		bcopy(addrp, mp->b_rptr + sizeof (dl_phys_addr_ack_t), len);
1490Sstevel@tonic-gate 	qreply(wq, mp);
1500Sstevel@tonic-gate }
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate void
dlcapabsetqid(dl_mid_t * idp,const queue_t * q)1530Sstevel@tonic-gate dlcapabsetqid(dl_mid_t *idp, const queue_t *q)
1540Sstevel@tonic-gate {
1550Sstevel@tonic-gate #ifndef _LP64
1560Sstevel@tonic-gate 	idp->mid[0] = (t_uscalar_t)q;
1570Sstevel@tonic-gate #else
1580Sstevel@tonic-gate 	idp->mid[0] = (t_uscalar_t)BMASK_32((uint64_t)q);
1590Sstevel@tonic-gate 	idp->mid[1] = (t_uscalar_t)BMASK_32(((uint64_t)q) >> 32);
1600Sstevel@tonic-gate #endif
1610Sstevel@tonic-gate }
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate boolean_t
dlcapabcheckqid(const dl_mid_t * idp,const queue_t * q)1640Sstevel@tonic-gate dlcapabcheckqid(const dl_mid_t *idp, const queue_t *q)
1650Sstevel@tonic-gate {
1660Sstevel@tonic-gate #ifndef _LP64
1670Sstevel@tonic-gate 	return ((queue_t *)(idp->mid[0]) == q);
1680Sstevel@tonic-gate #else
1690Sstevel@tonic-gate 	return ((queue_t *)
1700Sstevel@tonic-gate 	    ((uint64_t)idp->mid[0] | ((uint64_t)idp->mid[1] << 32)) == q);
1710Sstevel@tonic-gate #endif
1720Sstevel@tonic-gate }
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate void
dlnotifyack(queue_t * wq,mblk_t * mp,uint32_t notifications)1750Sstevel@tonic-gate dlnotifyack(
1760Sstevel@tonic-gate 	queue_t		*wq,
1770Sstevel@tonic-gate 	mblk_t		*mp,
1780Sstevel@tonic-gate 	uint32_t	notifications)
1790Sstevel@tonic-gate {
1800Sstevel@tonic-gate 	union DL_primitives	*dlp;
1810Sstevel@tonic-gate 
1825102Syz147064 	if ((mp = mexchange(wq, mp, sizeof (dl_notify_ack_t), M_PROTO,
1830Sstevel@tonic-gate 	    DL_NOTIFY_ACK)) == NULL)
1840Sstevel@tonic-gate 		return;
1850Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
1860Sstevel@tonic-gate 	dlp->notify_ack.dl_notifications = notifications;
1870Sstevel@tonic-gate 	qreply(wq, mp);
1880Sstevel@tonic-gate }
1895895Syz147064 
1905895Syz147064 static int
dl_op(ldi_handle_t lh,mblk_t ** mpp,t_uscalar_t expprim,size_t minlen,dl_error_ack_t * dleap,timestruc_t * tvp)1915895Syz147064 dl_op(ldi_handle_t lh, mblk_t **mpp, t_uscalar_t expprim, size_t minlen,
1925895Syz147064     dl_error_ack_t *dleap, timestruc_t *tvp)
1935895Syz147064 {
1945895Syz147064 	int		err;
1955895Syz147064 	size_t		len;
1965895Syz147064 	mblk_t		*mp = *mpp;
1975895Syz147064 	t_uscalar_t	reqprim, ackprim, ackreqprim;
1985895Syz147064 	union DL_primitives *dlp;
1995895Syz147064 
2005895Syz147064 	reqprim = ((union DL_primitives *)mp->b_rptr)->dl_primitive;
2015895Syz147064 
2025895Syz147064 	(void) ldi_putmsg(lh, mp);
2035895Syz147064 
2045895Syz147064 	switch (err = ldi_getmsg(lh, &mp, tvp)) {
2055895Syz147064 	case 0:
2065895Syz147064 		break;
2075895Syz147064 	case ETIME:
2085895Syz147064 		cmn_err(CE_NOTE, "!dl_op: timed out waiting for %s to %s",
2095895Syz147064 		    dl_primstr(reqprim), dl_primstr(expprim));
2105895Syz147064 		return (ETIME);
2115895Syz147064 	default:
2125895Syz147064 		cmn_err(CE_NOTE, "!dl_op: ldi_getmsg() for %s failed: %d",
2135895Syz147064 		    dl_primstr(expprim), err);
2145895Syz147064 		return (err);
2155895Syz147064 	}
2165895Syz147064 
2175895Syz147064 	len = MBLKL(mp);
2185895Syz147064 	if (len < sizeof (t_uscalar_t)) {
2195895Syz147064 		cmn_err(CE_NOTE, "!dl_op: received runt DLPI message");
2205895Syz147064 		freemsg(mp);
2215895Syz147064 		return (EBADMSG);
2225895Syz147064 	}
2235895Syz147064 
2245895Syz147064 	dlp = (union DL_primitives *)mp->b_rptr;
2255895Syz147064 	ackprim = dlp->dl_primitive;
2265895Syz147064 
2275895Syz147064 	if (ackprim == expprim) {
2285895Syz147064 		if (len < minlen)
2295895Syz147064 			goto runt;
2305895Syz147064 
2315895Syz147064 		if (ackprim == DL_OK_ACK) {
2325895Syz147064 			if (dlp->ok_ack.dl_correct_primitive != reqprim) {
2335895Syz147064 				ackreqprim = dlp->ok_ack.dl_correct_primitive;
2345895Syz147064 				goto mixup;
2355895Syz147064 			}
2365895Syz147064 		}
2375895Syz147064 		*mpp = mp;
2385895Syz147064 		return (0);
2395895Syz147064 	}
2405895Syz147064 
2415895Syz147064 	if (ackprim == DL_ERROR_ACK) {
2425895Syz147064 		if (len < DL_ERROR_ACK_SIZE)
2435895Syz147064 			goto runt;
2445895Syz147064 
2455895Syz147064 		if (dlp->error_ack.dl_error_primitive != reqprim) {
2465895Syz147064 			ackreqprim = dlp->error_ack.dl_error_primitive;
2475895Syz147064 			goto mixup;
2485895Syz147064 		}
2495895Syz147064 
2505895Syz147064 		/*
2515895Syz147064 		 * Return a special error code (ENOTSUP) indicating that the
2525895Syz147064 		 * caller has returned DL_ERROR_ACK.  Callers that want more
2535895Syz147064 		 * details an pass a non-NULL dleap.
2545895Syz147064 		 */
2555895Syz147064 		if (dleap != NULL)
2565895Syz147064 			*dleap = dlp->error_ack;
2575895Syz147064 
2585895Syz147064 		freemsg(mp);
2595895Syz147064 		return (ENOTSUP);
2605895Syz147064 	}
2615895Syz147064 
2625895Syz147064 	cmn_err(CE_NOTE, "!dl_op: expected %s but received %s",
2635895Syz147064 	    dl_primstr(expprim), dl_primstr(ackprim));
2645895Syz147064 	freemsg(mp);
2655895Syz147064 	return (EBADMSG);
2665895Syz147064 runt:
2675895Syz147064 	cmn_err(CE_NOTE, "!dl_op: received runt %s", dl_primstr(ackprim));
2685895Syz147064 	freemsg(mp);
2695895Syz147064 	return (EBADMSG);
2705895Syz147064 mixup:
2715895Syz147064 	cmn_err(CE_NOTE, "!dl_op: received %s for %s instead of %s",
2725895Syz147064 	    dl_primstr(ackprim), dl_primstr(ackreqprim), dl_primstr(reqprim));
2735895Syz147064 	freemsg(mp);
2745895Syz147064 	return (EBADMSG);
2755895Syz147064 }
2765895Syz147064 
2775895Syz147064 /*
2785895Syz147064  * Send a DL_ATTACH_REQ for `ppa' over `lh' and wait for the response.
2795895Syz147064  *
2805895Syz147064  * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the
2815895Syz147064  * caller can get the contents by passing a non-NULL `dleap').
2825895Syz147064  */
2835895Syz147064 int
dl_attach(ldi_handle_t lh,int ppa,dl_error_ack_t * dleap)2845895Syz147064 dl_attach(ldi_handle_t lh, int ppa, dl_error_ack_t *dleap)
2855895Syz147064 {
2865895Syz147064 	mblk_t	*mp;
2875895Syz147064 	int	err;
2885895Syz147064 
2895895Syz147064 	mp = mexchange(NULL, NULL, DL_ATTACH_REQ_SIZE, M_PROTO, DL_ATTACH_REQ);
2905895Syz147064 	if (mp == NULL)
2915895Syz147064 		return (ENOMEM);
2925895Syz147064 
2935895Syz147064 	((dl_attach_req_t *)mp->b_rptr)->dl_ppa = ppa;
2945895Syz147064 
2955895Syz147064 	err = dl_op(lh, &mp, DL_OK_ACK, DL_OK_ACK_SIZE, dleap, NULL);
2965895Syz147064 	if (err == 0)
2975895Syz147064 		freemsg(mp);
2985895Syz147064 	return (err);
2995895Syz147064 }
3005895Syz147064 
3015895Syz147064 /*
3025895Syz147064  * Send a DL_BIND_REQ for `sap' over `lh' and wait for the response.
3035895Syz147064  *
3045895Syz147064  * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the
3055895Syz147064  * caller can get the contents by passing a non-NULL `dleap').
3065895Syz147064  */
3075895Syz147064 int
dl_bind(ldi_handle_t lh,uint_t sap,dl_error_ack_t * dleap)3085895Syz147064 dl_bind(ldi_handle_t lh, uint_t sap, dl_error_ack_t *dleap)
3095895Syz147064 {
3105895Syz147064 	dl_bind_req_t	*dlbrp;
3115895Syz147064 	dl_bind_ack_t	*dlbap;
3125895Syz147064 	mblk_t 		*mp;
3135895Syz147064 	int		err;
3145895Syz147064 
3155895Syz147064 	mp = mexchange(NULL, NULL, DL_BIND_REQ_SIZE, M_PROTO, DL_BIND_REQ);
3165895Syz147064 	if (mp == NULL)
3175895Syz147064 		return (ENOMEM);
3185895Syz147064 
3195895Syz147064 	dlbrp = (dl_bind_req_t *)mp->b_rptr;
3205895Syz147064 	dlbrp->dl_sap = sap;
3215895Syz147064 	dlbrp->dl_conn_mgmt = 0;
3225895Syz147064 	dlbrp->dl_max_conind = 0;
3235895Syz147064 	dlbrp->dl_xidtest_flg = 0;
3245895Syz147064 	dlbrp->dl_service_mode = DL_CLDLS;
3255895Syz147064 
3265895Syz147064 	err = dl_op(lh, &mp, DL_BIND_ACK, DL_BIND_ACK_SIZE, dleap, NULL);
3275895Syz147064 	if (err == 0) {
3285895Syz147064 		dlbap = (dl_bind_ack_t *)mp->b_rptr;
3295895Syz147064 		if (dlbap->dl_sap != sap) {
3305895Syz147064 			cmn_err(CE_NOTE, "!dl_bind: DL_BIND_ACK: bad sap %u",
3315895Syz147064 			    dlbap->dl_sap);
3325895Syz147064 			err = EPROTO;
3335895Syz147064 		}
3345895Syz147064 		freemsg(mp);
3355895Syz147064 	}
3365895Syz147064 	return (err);
3375895Syz147064 }
3385895Syz147064 
3395895Syz147064 /*
3405895Syz147064  * Send a DL_PHYS_ADDR_REQ over `lh' and wait for the response.  The caller
3415895Syz147064  * must set `*physlenp' to the size of `physaddr' (both of which must be
3425895Syz147064  * non-NULL); upon success they will be updated to contain the actual physical
3435895Syz147064  * address and length.
3445895Syz147064  *
3455895Syz147064  * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the
3465895Syz147064  * caller can get the contents by passing a non-NULL `dleap').
3475895Syz147064  */
3485895Syz147064 int
dl_phys_addr(ldi_handle_t lh,uchar_t * physaddr,size_t * physlenp,dl_error_ack_t * dleap)3495895Syz147064 dl_phys_addr(ldi_handle_t lh, uchar_t *physaddr, size_t *physlenp,
3505895Syz147064     dl_error_ack_t *dleap)
3515895Syz147064 {
3525895Syz147064 	dl_phys_addr_ack_t *dlpap;
3535895Syz147064 	mblk_t		*mp;
3545895Syz147064 	int		err;
3555895Syz147064 	t_uscalar_t	paddrlen, paddroff;
3565895Syz147064 	timestruc_t	tv;
3575895Syz147064 
3585895Syz147064 	mp = mexchange(NULL, NULL, DL_PHYS_ADDR_REQ_SIZE, M_PROTO,
3595895Syz147064 	    DL_PHYS_ADDR_REQ);
3605895Syz147064 	if (mp == NULL)
3615895Syz147064 		return (ENOMEM);
3625895Syz147064 
3635895Syz147064 	((dl_phys_addr_req_t *)mp->b_rptr)->dl_addr_type = DL_CURR_PHYS_ADDR;
3645895Syz147064 
3655895Syz147064 	/*
3665895Syz147064 	 * In case some provider doesn't implement or NAK the
3675895Syz147064 	 * request, just wait for 15 seconds.
3685895Syz147064 	 */
3695895Syz147064 	tv.tv_sec = 15;
3705895Syz147064 	tv.tv_nsec = 0;
3715895Syz147064 
3725895Syz147064 	err = dl_op(lh, &mp, DL_PHYS_ADDR_ACK, DL_PHYS_ADDR_ACK_SIZE, dleap,
3735895Syz147064 	    &tv);
3745895Syz147064 	if (err == 0) {
3755895Syz147064 		dlpap = (dl_phys_addr_ack_t *)mp->b_rptr;
3765895Syz147064 		paddrlen = dlpap->dl_addr_length;
3775895Syz147064 		paddroff = dlpap->dl_addr_offset;
3785895Syz147064 		if (paddroff == 0 || paddrlen == 0 || paddrlen > *physlenp ||
3795895Syz147064 		    !MBLKIN(mp, paddroff, paddrlen)) {
3805895Syz147064 			cmn_err(CE_NOTE, "!dl_phys_addr: DL_PHYS_ADDR_ACK: "
3815895Syz147064 			    "bad length/offset %d/%d", paddrlen, paddroff);
3825895Syz147064 			err = EBADMSG;
3835895Syz147064 		} else {
3845895Syz147064 			bcopy(mp->b_rptr + paddroff, physaddr, paddrlen);
3855895Syz147064 			*physlenp = paddrlen;
3865895Syz147064 		}
3875895Syz147064 		freemsg(mp);
3885895Syz147064 	}
3895895Syz147064 	return (err);
3905895Syz147064 }
3915895Syz147064 
3925895Syz147064 /*
3935895Syz147064  * Send a DL_INFO_REQ over `lh' and wait for the response.  The caller must
3945895Syz147064  * pass a non-NULL `dliap', which upon success will contain the dl_info_ack_t
3955895Syz147064  * from the provider.  The caller may optionally get the provider's physical
3965895Syz147064  * address by passing a non-NULL `physaddr' and setting `*physlenp' to its
3975895Syz147064  * size; upon success they will be updated to contain the actual physical
3985895Syz147064  * address and its length.
3995895Syz147064  *
4005895Syz147064  * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the
4015895Syz147064  * caller can get the contents by passing a non-NULL `dleap').
4025895Syz147064  */
4035895Syz147064 int
dl_info(ldi_handle_t lh,dl_info_ack_t * dliap,uchar_t * physaddr,size_t * physlenp,dl_error_ack_t * dleap)4045895Syz147064 dl_info(ldi_handle_t lh, dl_info_ack_t *dliap, uchar_t *physaddr,
4055895Syz147064     size_t *physlenp, dl_error_ack_t *dleap)
4065895Syz147064 {
4075895Syz147064 	mblk_t	*mp;
4085895Syz147064 	int	err;
4095895Syz147064 	int	addrlen, addroff;
4105895Syz147064 
4115895Syz147064 	mp = mexchange(NULL, NULL, DL_INFO_REQ_SIZE, M_PCPROTO, DL_INFO_REQ);
4125895Syz147064 	if (mp == NULL)
4135895Syz147064 		return (ENOMEM);
4145895Syz147064 
4155895Syz147064 	err = dl_op(lh, &mp, DL_INFO_ACK, DL_INFO_ACK_SIZE, dleap, NULL);
4165895Syz147064 	if (err != 0)
4175895Syz147064 		return (err);
4185895Syz147064 
4195895Syz147064 	*dliap = *(dl_info_ack_t *)mp->b_rptr;
4205895Syz147064 	if (physaddr != NULL) {
4215895Syz147064 		addrlen = dliap->dl_addr_length - ABS(dliap->dl_sap_length);
4225895Syz147064 		addroff = dliap->dl_addr_offset;
4235895Syz147064 		if (addroff == 0 || addrlen <= 0 || addrlen > *physlenp ||
4245895Syz147064 		    !MBLKIN(mp, addroff, dliap->dl_addr_length)) {
4255895Syz147064 			cmn_err(CE_NOTE, "!dl_info: DL_INFO_ACK: "
4265895Syz147064 			    "bad length/offset %d/%d", addrlen, addroff);
4275895Syz147064 			freemsg(mp);
4285895Syz147064 			return (EBADMSG);
4295895Syz147064 		}
4305895Syz147064 
4315895Syz147064 		if (dliap->dl_sap_length > 0)
4325895Syz147064 			addroff += dliap->dl_sap_length;
4335895Syz147064 		bcopy(mp->b_rptr + addroff, physaddr, addrlen);
4345895Syz147064 		*physlenp = addrlen;
4355895Syz147064 	}
4365895Syz147064 	freemsg(mp);
4375895Syz147064 	return (err);
4385895Syz147064 }
4395895Syz147064 
4405895Syz147064 /*
4415895Syz147064  * Send a DL_NOTIFY_REQ over `lh' and wait for the response.  The caller
4425895Syz147064  * should set `notesp' to the set of notifications they wish to enable;
4435895Syz147064  * upon success it will contain the notifications enabled by the provider.
4445895Syz147064  *
4455895Syz147064  * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the
4465895Syz147064  * caller can get the contents by passing a non-NULL `dleap').
4475895Syz147064  */
4485895Syz147064 int
dl_notify(ldi_handle_t lh,uint32_t * notesp,dl_error_ack_t * dleap)4495895Syz147064 dl_notify(ldi_handle_t lh, uint32_t *notesp, dl_error_ack_t *dleap)
4505895Syz147064 {
4515895Syz147064 	mblk_t	*mp;
4525895Syz147064 	int	err;
4535895Syz147064 
4545895Syz147064 	mp = mexchange(NULL, NULL, DL_NOTIFY_REQ_SIZE, M_PROTO, DL_NOTIFY_REQ);
4555895Syz147064 	if (mp == NULL)
4565895Syz147064 		return (ENOMEM);
4575895Syz147064 
4585895Syz147064 	((dl_notify_req_t *)mp->b_rptr)->dl_notifications = *notesp;
4595895Syz147064 
4605895Syz147064 	err = dl_op(lh, &mp, DL_NOTIFY_ACK, DL_NOTIFY_ACK_SIZE, dleap, NULL);
4615895Syz147064 	if (err == 0) {
4625895Syz147064 		*notesp = ((dl_notify_ack_t *)mp->b_rptr)->dl_notifications;
4635895Syz147064 		freemsg(mp);
4645895Syz147064 	}
4655895Syz147064 	return (err);
4665895Syz147064 }
4675895Syz147064 
4685895Syz147064 const char *
dl_primstr(t_uscalar_t prim)4695895Syz147064 dl_primstr(t_uscalar_t prim)
4705895Syz147064 {
4715895Syz147064 	switch (prim) {
4725895Syz147064 	case DL_INFO_REQ:		return ("DL_INFO_REQ");
4735895Syz147064 	case DL_INFO_ACK:		return ("DL_INFO_ACK");
4745895Syz147064 	case DL_ATTACH_REQ:		return ("DL_ATTACH_REQ");
4755895Syz147064 	case DL_DETACH_REQ:		return ("DL_DETACH_REQ");
4765895Syz147064 	case DL_BIND_REQ:		return ("DL_BIND_REQ");
4775895Syz147064 	case DL_BIND_ACK:		return ("DL_BIND_ACK");
4785895Syz147064 	case DL_UNBIND_REQ:		return ("DL_UNBIND_REQ");
4795895Syz147064 	case DL_OK_ACK:			return ("DL_OK_ACK");
4805895Syz147064 	case DL_ERROR_ACK:		return ("DL_ERROR_ACK");
4815895Syz147064 	case DL_ENABMULTI_REQ:		return ("DL_ENABMULTI_REQ");
4825895Syz147064 	case DL_DISABMULTI_REQ:		return ("DL_DISABMULTI_REQ");
4835895Syz147064 	case DL_PROMISCON_REQ:		return ("DL_PROMISCON_REQ");
4845895Syz147064 	case DL_PROMISCOFF_REQ:		return ("DL_PROMISCOFF_REQ");
4855895Syz147064 	case DL_UNITDATA_REQ:		return ("DL_UNITDATA_REQ");
4865895Syz147064 	case DL_UNITDATA_IND:		return ("DL_UNITDATA_IND");
4875895Syz147064 	case DL_UDERROR_IND:		return ("DL_UDERROR_IND");
4885895Syz147064 	case DL_PHYS_ADDR_REQ:		return ("DL_PHYS_ADDR_REQ");
4895895Syz147064 	case DL_PHYS_ADDR_ACK:		return ("DL_PHYS_ADDR_ACK");
4905895Syz147064 	case DL_SET_PHYS_ADDR_REQ:	return ("DL_SET_PHYS_ADDR_REQ");
4915895Syz147064 	case DL_NOTIFY_REQ:		return ("DL_NOTIFY_REQ");
4925895Syz147064 	case DL_NOTIFY_ACK:		return ("DL_NOTIFY_ACK");
4935895Syz147064 	case DL_NOTIFY_IND:		return ("DL_NOTIFY_IND");
494*9073SCathy.Zhou@Sun.COM 	case DL_NOTIFY_CONF:		return ("DL_NOTIFY_CONF");
4955895Syz147064 	case DL_CAPABILITY_REQ:		return ("DL_CAPABILITY_REQ");
4965895Syz147064 	case DL_CAPABILITY_ACK:		return ("DL_CAPABILITY_ACK");
4975895Syz147064 	case DL_CONTROL_REQ:		return ("DL_CONTROL_REQ");
4985895Syz147064 	case DL_CONTROL_ACK:		return ("DL_CONTROL_ACK");
4995895Syz147064 	case DL_PASSIVE_REQ:		return ("DL_PASSIVE_REQ");
5005895Syz147064 	case DL_INTR_MODE_REQ:		return ("DL_INTR_MODE_REQ");
5015895Syz147064 	case DL_UDQOS_REQ:		return ("DL_UDQOS_REQ");
5025895Syz147064 	default:			return ("<unknown primitive>");
5035895Syz147064 	}
5045895Syz147064 }
5055895Syz147064 
5065895Syz147064 const char *
dl_errstr(t_uscalar_t err)5075895Syz147064 dl_errstr(t_uscalar_t err)
5085895Syz147064 {
5095895Syz147064 	switch (err) {
5105895Syz147064 	case DL_ACCESS:			return ("DL_ACCESS");
5115895Syz147064 	case DL_BADADDR:		return ("DL_BADADDR");
5125895Syz147064 	case DL_BADCORR:		return ("DL_BADCORR");
5135895Syz147064 	case DL_BADDATA:		return ("DL_BADDATA");
5145895Syz147064 	case DL_BADPPA:			return ("DL_BADPPA");
5155895Syz147064 	case DL_BADPRIM:		return ("DL_BADPRIM");
5165895Syz147064 	case DL_BADQOSPARAM:		return ("DL_BADQOSPARAM");
5175895Syz147064 	case DL_BADQOSTYPE:		return ("DL_BADQOSTYPE");
5185895Syz147064 	case DL_BADSAP:			return ("DL_BADSAP");
5195895Syz147064 	case DL_BADTOKEN:		return ("DL_BADTOKEN");
5205895Syz147064 	case DL_BOUND:			return ("DL_BOUND");
5215895Syz147064 	case DL_INITFAILED:		return ("DL_INITFAILED");
5225895Syz147064 	case DL_NOADDR:			return ("DL_NOADDR");
5235895Syz147064 	case DL_NOTINIT:		return ("DL_NOTINIT");
5245895Syz147064 	case DL_OUTSTATE:		return ("DL_OUTSTATE");
5255895Syz147064 	case DL_SYSERR:			return ("DL_SYSERR");
5265895Syz147064 	case DL_UNSUPPORTED:		return ("DL_UNSUPPORTED");
5275895Syz147064 	case DL_UNDELIVERABLE:		return ("DL_UNDELIVERABLE");
5285895Syz147064 	case DL_NOTSUPPORTED:		return ("DL_NOTSUPPORTED ");
5295895Syz147064 	case DL_TOOMANY:		return ("DL_TOOMANY");
5305895Syz147064 	case DL_NOTENAB:		return ("DL_NOTENAB");
5315895Syz147064 	case DL_BUSY:			return ("DL_BUSY");
5325895Syz147064 	case DL_NOAUTO:			return ("DL_NOAUTO");
5335895Syz147064 	case DL_NOXIDAUTO:		return ("DL_NOXIDAUTO");
5345895Syz147064 	case DL_NOTESTAUTO:		return ("DL_NOTESTAUTO");
5355895Syz147064 	case DL_XIDAUTO:		return ("DL_XIDAUTO");
5365895Syz147064 	case DL_TESTAUTO:		return ("DL_TESTAUTO");
5375895Syz147064 	case DL_PENDING:		return ("DL_PENDING");
5385895Syz147064 	default:			return ("<unknown error>");
5395895Syz147064 	}
5405895Syz147064 }
5415895Syz147064 
5425895Syz147064 const char *
dl_mactypestr(t_uscalar_t mactype)5435895Syz147064 dl_mactypestr(t_uscalar_t mactype)
5445895Syz147064 {
5455895Syz147064 	switch (mactype) {
5465895Syz147064 	case DL_CSMACD:		return ("CSMA/CD");
5475895Syz147064 	case DL_TPB:		return ("Token Bus");
5485895Syz147064 	case DL_TPR:		return ("Token Ring");
5495895Syz147064 	case DL_METRO:		return ("Metro Net");
5505895Syz147064 	case DL_ETHER:		return ("Ethernet");
5515895Syz147064 	case DL_HDLC:		return ("HDLC");
5525895Syz147064 	case DL_CHAR:		return ("Sync Character");
5535895Syz147064 	case DL_CTCA:		return ("CTCA");
5545895Syz147064 	case DL_FDDI:		return ("FDDI");
5555895Syz147064 	case DL_FRAME:		return ("Frame Relay (LAPF)");
5565895Syz147064 	case DL_MPFRAME:	return ("MP Frame Relay");
5575895Syz147064 	case DL_ASYNC:		return ("Async Character");
5585895Syz147064 	case DL_IPX25:		return ("X.25 (Classic IP)");
5595895Syz147064 	case DL_LOOP:		return ("Software Loopback");
5605895Syz147064 	case DL_FC:		return ("Fiber Channel");
5615895Syz147064 	case DL_ATM:		return ("ATM");
5625895Syz147064 	case DL_IPATM:		return ("ATM (Classic IP)");
5635895Syz147064 	case DL_X25:		return ("X.25 (LAPB)");
5645895Syz147064 	case DL_ISDN:		return ("ISDN");
5655895Syz147064 	case DL_HIPPI:		return ("HIPPI");
5665895Syz147064 	case DL_100VG:		return ("100BaseVG Ethernet");
5675895Syz147064 	case DL_100VGTPR:	return ("100BaseVG Token Ring");
5685895Syz147064 	case DL_ETH_CSMA:	return ("Ethernet/IEEE 802.3");
5695895Syz147064 	case DL_100BT:		return ("100BaseT");
5705895Syz147064 	case DL_IB:		return ("Infiniband");
5715895Syz147064 	case DL_IPV4:		return ("IPv4 Tunnel");
5725895Syz147064 	case DL_IPV6:		return ("IPv6 Tunnel");
5735895Syz147064 	case DL_WIFI:		return ("IEEE 802.11");
5748023SPhil.Kirk@Sun.COM 	case DL_IPNET:		return ("IPNET");
5755895Syz147064 	default:		return ("<unknown mactype>");
5765895Syz147064 	}
5775895Syz147064 }
578