xref: /titanic_51/usr/src/uts/common/io/sundlpi.c (revision d62bc4badc1c1f1549c961cfb8b420e650e1272b)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5392b1d6eSyz147064  * Common Development and Distribution License (the "License").
6392b1d6eSyz147064  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*d62bc4baSyz147064  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  *  Common Sun DLPI routines.
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include	<sys/types.h>
337c478bd9Sstevel@tonic-gate #include	<sys/sysmacros.h>
347c478bd9Sstevel@tonic-gate #include	<sys/byteorder.h>
357c478bd9Sstevel@tonic-gate #include	<sys/systm.h>
367c478bd9Sstevel@tonic-gate #include	<sys/stream.h>
377c478bd9Sstevel@tonic-gate #include	<sys/strsun.h>
387c478bd9Sstevel@tonic-gate #include	<sys/dlpi.h>
39*d62bc4baSyz147064 #include	<sys/ddi.h>
40*d62bc4baSyz147064 #include	<sys/sunddi.h>
41*d62bc4baSyz147064 #include	<sys/sunldi.h>
42*d62bc4baSyz147064 #include	<sys/cmn_err.h>
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate #define		DLADDRL		(80)
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate void
477c478bd9Sstevel@tonic-gate dlbindack(
487c478bd9Sstevel@tonic-gate 	queue_t		*wq,
497c478bd9Sstevel@tonic-gate 	mblk_t		*mp,
507c478bd9Sstevel@tonic-gate 	t_scalar_t	sap,
517c478bd9Sstevel@tonic-gate 	void		*addrp,
527c478bd9Sstevel@tonic-gate 	t_uscalar_t	addrlen,
537c478bd9Sstevel@tonic-gate 	t_uscalar_t	maxconind,
547c478bd9Sstevel@tonic-gate 	t_uscalar_t	xidtest)
557c478bd9Sstevel@tonic-gate {
567c478bd9Sstevel@tonic-gate 	union DL_primitives	*dlp;
577c478bd9Sstevel@tonic-gate 	size_t			size;
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate 	size = sizeof (dl_bind_ack_t) + addrlen;
607c478bd9Sstevel@tonic-gate 	if ((mp = mexchange(wq, mp, size, M_PCPROTO, DL_BIND_ACK)) == NULL)
617c478bd9Sstevel@tonic-gate 		return;
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
647c478bd9Sstevel@tonic-gate 	dlp->bind_ack.dl_sap = sap;
657c478bd9Sstevel@tonic-gate 	dlp->bind_ack.dl_addr_length = addrlen;
667c478bd9Sstevel@tonic-gate 	dlp->bind_ack.dl_addr_offset = sizeof (dl_bind_ack_t);
677c478bd9Sstevel@tonic-gate 	dlp->bind_ack.dl_max_conind = maxconind;
687c478bd9Sstevel@tonic-gate 	dlp->bind_ack.dl_xidtest_flg = xidtest;
697c478bd9Sstevel@tonic-gate 	if (addrlen != 0)
707c478bd9Sstevel@tonic-gate 		bcopy(addrp, mp->b_rptr + sizeof (dl_bind_ack_t), addrlen);
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate 	qreply(wq, mp);
737c478bd9Sstevel@tonic-gate }
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate void
767c478bd9Sstevel@tonic-gate dlokack(
777c478bd9Sstevel@tonic-gate 	queue_t		*wq,
787c478bd9Sstevel@tonic-gate 	mblk_t		*mp,
797c478bd9Sstevel@tonic-gate 	t_uscalar_t	correct_primitive)
807c478bd9Sstevel@tonic-gate {
817c478bd9Sstevel@tonic-gate 	union DL_primitives	*dlp;
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate 	if ((mp = mexchange(wq, mp, sizeof (dl_ok_ack_t), M_PCPROTO,
847c478bd9Sstevel@tonic-gate 	    DL_OK_ACK)) == NULL)
857c478bd9Sstevel@tonic-gate 		return;
867c478bd9Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
877c478bd9Sstevel@tonic-gate 	dlp->ok_ack.dl_correct_primitive = correct_primitive;
887c478bd9Sstevel@tonic-gate 	qreply(wq, mp);
897c478bd9Sstevel@tonic-gate }
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate void
927c478bd9Sstevel@tonic-gate dlerrorack(
937c478bd9Sstevel@tonic-gate 	queue_t		*wq,
947c478bd9Sstevel@tonic-gate 	mblk_t		*mp,
957c478bd9Sstevel@tonic-gate 	t_uscalar_t	error_primitive,
967c478bd9Sstevel@tonic-gate 	t_uscalar_t	error,
977c478bd9Sstevel@tonic-gate 	t_uscalar_t	unix_errno)
987c478bd9Sstevel@tonic-gate {
997c478bd9Sstevel@tonic-gate 	union DL_primitives	*dlp;
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 	if ((mp = mexchange(wq, mp, sizeof (dl_error_ack_t), M_PCPROTO,
1027c478bd9Sstevel@tonic-gate 	    DL_ERROR_ACK)) == NULL)
1037c478bd9Sstevel@tonic-gate 		return;
1047c478bd9Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
1057c478bd9Sstevel@tonic-gate 	dlp->error_ack.dl_error_primitive = error_primitive;
1067c478bd9Sstevel@tonic-gate 	dlp->error_ack.dl_errno = error;
1077c478bd9Sstevel@tonic-gate 	dlp->error_ack.dl_unix_errno = unix_errno;
1087c478bd9Sstevel@tonic-gate 	qreply(wq, mp);
1097c478bd9Sstevel@tonic-gate }
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate void
1127c478bd9Sstevel@tonic-gate dluderrorind(
1137c478bd9Sstevel@tonic-gate 	queue_t		*wq,
1147c478bd9Sstevel@tonic-gate 	mblk_t		*mp,
1157c478bd9Sstevel@tonic-gate 	void		*addrp,
1167c478bd9Sstevel@tonic-gate 	t_uscalar_t	addrlen,
1177c478bd9Sstevel@tonic-gate 	t_uscalar_t	error,
1187c478bd9Sstevel@tonic-gate 	t_uscalar_t	unix_errno)
1197c478bd9Sstevel@tonic-gate {
1207c478bd9Sstevel@tonic-gate 	union DL_primitives	*dlp;
1217c478bd9Sstevel@tonic-gate 	char			buf[DLADDRL];
1227c478bd9Sstevel@tonic-gate 	size_t			size;
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 	if (addrlen > DLADDRL)
1257c478bd9Sstevel@tonic-gate 		addrlen = DLADDRL;
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	bcopy(addrp, buf, addrlen);
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	size = sizeof (dl_uderror_ind_t) + addrlen;
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 	if ((mp = mexchange(wq, mp, size, M_PCPROTO, DL_UDERROR_IND)) == NULL)
1327c478bd9Sstevel@tonic-gate 		return;
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
1357c478bd9Sstevel@tonic-gate 	dlp->uderror_ind.dl_dest_addr_length = addrlen;
1367c478bd9Sstevel@tonic-gate 	dlp->uderror_ind.dl_dest_addr_offset = sizeof (dl_uderror_ind_t);
1377c478bd9Sstevel@tonic-gate 	dlp->uderror_ind.dl_unix_errno = unix_errno;
1387c478bd9Sstevel@tonic-gate 	dlp->uderror_ind.dl_errno = error;
1397c478bd9Sstevel@tonic-gate 	bcopy((caddr_t)buf,
1407c478bd9Sstevel@tonic-gate 	    (caddr_t)(mp->b_rptr + sizeof (dl_uderror_ind_t)), addrlen);
1417c478bd9Sstevel@tonic-gate 	qreply(wq, mp);
1427c478bd9Sstevel@tonic-gate }
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate void
1457c478bd9Sstevel@tonic-gate dlphysaddrack(
1467c478bd9Sstevel@tonic-gate 	queue_t		*wq,
1477c478bd9Sstevel@tonic-gate 	mblk_t		*mp,
1487c478bd9Sstevel@tonic-gate 	void		*addrp,
1497c478bd9Sstevel@tonic-gate 	t_uscalar_t	len)
1507c478bd9Sstevel@tonic-gate {
1517c478bd9Sstevel@tonic-gate 	union DL_primitives	*dlp;
1527c478bd9Sstevel@tonic-gate 	size_t			size;
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	size = sizeof (dl_phys_addr_ack_t) + len;
1557c478bd9Sstevel@tonic-gate 	if ((mp = mexchange(wq, mp, size, M_PCPROTO, DL_PHYS_ADDR_ACK)) == NULL)
1567c478bd9Sstevel@tonic-gate 		return;
1577c478bd9Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
1587c478bd9Sstevel@tonic-gate 	dlp->physaddr_ack.dl_addr_length = len;
1597c478bd9Sstevel@tonic-gate 	dlp->physaddr_ack.dl_addr_offset = sizeof (dl_phys_addr_ack_t);
1607c478bd9Sstevel@tonic-gate 	if (len != 0)
1617c478bd9Sstevel@tonic-gate 		bcopy(addrp, mp->b_rptr + sizeof (dl_phys_addr_ack_t), len);
1627c478bd9Sstevel@tonic-gate 	qreply(wq, mp);
1637c478bd9Sstevel@tonic-gate }
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate void
1667c478bd9Sstevel@tonic-gate dlcapabsetqid(dl_mid_t *idp, const queue_t *q)
1677c478bd9Sstevel@tonic-gate {
1687c478bd9Sstevel@tonic-gate #ifndef _LP64
1697c478bd9Sstevel@tonic-gate 	idp->mid[0] = (t_uscalar_t)q;
1707c478bd9Sstevel@tonic-gate #else
1717c478bd9Sstevel@tonic-gate 	idp->mid[0] = (t_uscalar_t)BMASK_32((uint64_t)q);
1727c478bd9Sstevel@tonic-gate 	idp->mid[1] = (t_uscalar_t)BMASK_32(((uint64_t)q) >> 32);
1737c478bd9Sstevel@tonic-gate #endif
1747c478bd9Sstevel@tonic-gate }
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate boolean_t
1777c478bd9Sstevel@tonic-gate dlcapabcheckqid(const dl_mid_t *idp, const queue_t *q)
1787c478bd9Sstevel@tonic-gate {
1797c478bd9Sstevel@tonic-gate #ifndef _LP64
1807c478bd9Sstevel@tonic-gate 	return ((queue_t *)(idp->mid[0]) == q);
1817c478bd9Sstevel@tonic-gate #else
1827c478bd9Sstevel@tonic-gate 	return ((queue_t *)
1837c478bd9Sstevel@tonic-gate 	    ((uint64_t)idp->mid[0] | ((uint64_t)idp->mid[1] << 32)) == q);
1847c478bd9Sstevel@tonic-gate #endif
1857c478bd9Sstevel@tonic-gate }
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate void
1887c478bd9Sstevel@tonic-gate dlnotifyack(
1897c478bd9Sstevel@tonic-gate 	queue_t		*wq,
1907c478bd9Sstevel@tonic-gate 	mblk_t		*mp,
1917c478bd9Sstevel@tonic-gate 	uint32_t	notifications)
1927c478bd9Sstevel@tonic-gate {
1937c478bd9Sstevel@tonic-gate 	union DL_primitives	*dlp;
1947c478bd9Sstevel@tonic-gate 
195392b1d6eSyz147064 	if ((mp = mexchange(wq, mp, sizeof (dl_notify_ack_t), M_PROTO,
1967c478bd9Sstevel@tonic-gate 	    DL_NOTIFY_ACK)) == NULL)
1977c478bd9Sstevel@tonic-gate 		return;
1987c478bd9Sstevel@tonic-gate 	dlp = (union DL_primitives *)mp->b_rptr;
1997c478bd9Sstevel@tonic-gate 	dlp->notify_ack.dl_notifications = notifications;
2007c478bd9Sstevel@tonic-gate 	qreply(wq, mp);
2017c478bd9Sstevel@tonic-gate }
202*d62bc4baSyz147064 
203*d62bc4baSyz147064 static int
204*d62bc4baSyz147064 dl_op(ldi_handle_t lh, mblk_t **mpp, t_uscalar_t expprim, size_t minlen,
205*d62bc4baSyz147064     dl_error_ack_t *dleap, timestruc_t *tvp)
206*d62bc4baSyz147064 {
207*d62bc4baSyz147064 	int		err;
208*d62bc4baSyz147064 	size_t		len;
209*d62bc4baSyz147064 	mblk_t		*mp = *mpp;
210*d62bc4baSyz147064 	t_uscalar_t	reqprim, ackprim, ackreqprim;
211*d62bc4baSyz147064 	union DL_primitives *dlp;
212*d62bc4baSyz147064 
213*d62bc4baSyz147064 	reqprim = ((union DL_primitives *)mp->b_rptr)->dl_primitive;
214*d62bc4baSyz147064 
215*d62bc4baSyz147064 	(void) ldi_putmsg(lh, mp);
216*d62bc4baSyz147064 
217*d62bc4baSyz147064 	switch (err = ldi_getmsg(lh, &mp, tvp)) {
218*d62bc4baSyz147064 	case 0:
219*d62bc4baSyz147064 		break;
220*d62bc4baSyz147064 	case ETIME:
221*d62bc4baSyz147064 		cmn_err(CE_NOTE, "!dl_op: timed out waiting for %s to %s",
222*d62bc4baSyz147064 		    dl_primstr(reqprim), dl_primstr(expprim));
223*d62bc4baSyz147064 		return (ETIME);
224*d62bc4baSyz147064 	default:
225*d62bc4baSyz147064 		cmn_err(CE_NOTE, "!dl_op: ldi_getmsg() for %s failed: %d",
226*d62bc4baSyz147064 		    dl_primstr(expprim), err);
227*d62bc4baSyz147064 		return (err);
228*d62bc4baSyz147064 	}
229*d62bc4baSyz147064 
230*d62bc4baSyz147064 	len = MBLKL(mp);
231*d62bc4baSyz147064 	if (len < sizeof (t_uscalar_t)) {
232*d62bc4baSyz147064 		cmn_err(CE_NOTE, "!dl_op: received runt DLPI message");
233*d62bc4baSyz147064 		freemsg(mp);
234*d62bc4baSyz147064 		return (EBADMSG);
235*d62bc4baSyz147064 	}
236*d62bc4baSyz147064 
237*d62bc4baSyz147064 	dlp = (union DL_primitives *)mp->b_rptr;
238*d62bc4baSyz147064 	ackprim = dlp->dl_primitive;
239*d62bc4baSyz147064 
240*d62bc4baSyz147064 	if (ackprim == expprim) {
241*d62bc4baSyz147064 		if (len < minlen)
242*d62bc4baSyz147064 			goto runt;
243*d62bc4baSyz147064 
244*d62bc4baSyz147064 		if (ackprim == DL_OK_ACK) {
245*d62bc4baSyz147064 			if (dlp->ok_ack.dl_correct_primitive != reqprim) {
246*d62bc4baSyz147064 				ackreqprim = dlp->ok_ack.dl_correct_primitive;
247*d62bc4baSyz147064 				goto mixup;
248*d62bc4baSyz147064 			}
249*d62bc4baSyz147064 		}
250*d62bc4baSyz147064 		*mpp = mp;
251*d62bc4baSyz147064 		return (0);
252*d62bc4baSyz147064 	}
253*d62bc4baSyz147064 
254*d62bc4baSyz147064 	if (ackprim == DL_ERROR_ACK) {
255*d62bc4baSyz147064 		if (len < DL_ERROR_ACK_SIZE)
256*d62bc4baSyz147064 			goto runt;
257*d62bc4baSyz147064 
258*d62bc4baSyz147064 		if (dlp->error_ack.dl_error_primitive != reqprim) {
259*d62bc4baSyz147064 			ackreqprim = dlp->error_ack.dl_error_primitive;
260*d62bc4baSyz147064 			goto mixup;
261*d62bc4baSyz147064 		}
262*d62bc4baSyz147064 
263*d62bc4baSyz147064 		/*
264*d62bc4baSyz147064 		 * Return a special error code (ENOTSUP) indicating that the
265*d62bc4baSyz147064 		 * caller has returned DL_ERROR_ACK.  Callers that want more
266*d62bc4baSyz147064 		 * details an pass a non-NULL dleap.
267*d62bc4baSyz147064 		 */
268*d62bc4baSyz147064 		if (dleap != NULL)
269*d62bc4baSyz147064 			*dleap = dlp->error_ack;
270*d62bc4baSyz147064 
271*d62bc4baSyz147064 		freemsg(mp);
272*d62bc4baSyz147064 		return (ENOTSUP);
273*d62bc4baSyz147064 	}
274*d62bc4baSyz147064 
275*d62bc4baSyz147064 	cmn_err(CE_NOTE, "!dl_op: expected %s but received %s",
276*d62bc4baSyz147064 	    dl_primstr(expprim), dl_primstr(ackprim));
277*d62bc4baSyz147064 	freemsg(mp);
278*d62bc4baSyz147064 	return (EBADMSG);
279*d62bc4baSyz147064 runt:
280*d62bc4baSyz147064 	cmn_err(CE_NOTE, "!dl_op: received runt %s", dl_primstr(ackprim));
281*d62bc4baSyz147064 	freemsg(mp);
282*d62bc4baSyz147064 	return (EBADMSG);
283*d62bc4baSyz147064 mixup:
284*d62bc4baSyz147064 	cmn_err(CE_NOTE, "!dl_op: received %s for %s instead of %s",
285*d62bc4baSyz147064 	    dl_primstr(ackprim), dl_primstr(ackreqprim), dl_primstr(reqprim));
286*d62bc4baSyz147064 	freemsg(mp);
287*d62bc4baSyz147064 	return (EBADMSG);
288*d62bc4baSyz147064 }
289*d62bc4baSyz147064 
290*d62bc4baSyz147064 /*
291*d62bc4baSyz147064  * Send a DL_ATTACH_REQ for `ppa' over `lh' and wait for the response.
292*d62bc4baSyz147064  *
293*d62bc4baSyz147064  * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the
294*d62bc4baSyz147064  * caller can get the contents by passing a non-NULL `dleap').
295*d62bc4baSyz147064  */
296*d62bc4baSyz147064 int
297*d62bc4baSyz147064 dl_attach(ldi_handle_t lh, int ppa, dl_error_ack_t *dleap)
298*d62bc4baSyz147064 {
299*d62bc4baSyz147064 	mblk_t	*mp;
300*d62bc4baSyz147064 	int	err;
301*d62bc4baSyz147064 
302*d62bc4baSyz147064 	mp = mexchange(NULL, NULL, DL_ATTACH_REQ_SIZE, M_PROTO, DL_ATTACH_REQ);
303*d62bc4baSyz147064 	if (mp == NULL)
304*d62bc4baSyz147064 		return (ENOMEM);
305*d62bc4baSyz147064 
306*d62bc4baSyz147064 	((dl_attach_req_t *)mp->b_rptr)->dl_ppa = ppa;
307*d62bc4baSyz147064 
308*d62bc4baSyz147064 	err = dl_op(lh, &mp, DL_OK_ACK, DL_OK_ACK_SIZE, dleap, NULL);
309*d62bc4baSyz147064 	if (err == 0)
310*d62bc4baSyz147064 		freemsg(mp);
311*d62bc4baSyz147064 	return (err);
312*d62bc4baSyz147064 }
313*d62bc4baSyz147064 
314*d62bc4baSyz147064 /*
315*d62bc4baSyz147064  * Send a DL_BIND_REQ for `sap' over `lh' and wait for the response.
316*d62bc4baSyz147064  *
317*d62bc4baSyz147064  * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the
318*d62bc4baSyz147064  * caller can get the contents by passing a non-NULL `dleap').
319*d62bc4baSyz147064  */
320*d62bc4baSyz147064 int
321*d62bc4baSyz147064 dl_bind(ldi_handle_t lh, uint_t sap, dl_error_ack_t *dleap)
322*d62bc4baSyz147064 {
323*d62bc4baSyz147064 	dl_bind_req_t	*dlbrp;
324*d62bc4baSyz147064 	dl_bind_ack_t	*dlbap;
325*d62bc4baSyz147064 	mblk_t 		*mp;
326*d62bc4baSyz147064 	int		err;
327*d62bc4baSyz147064 
328*d62bc4baSyz147064 	mp = mexchange(NULL, NULL, DL_BIND_REQ_SIZE, M_PROTO, DL_BIND_REQ);
329*d62bc4baSyz147064 	if (mp == NULL)
330*d62bc4baSyz147064 		return (ENOMEM);
331*d62bc4baSyz147064 
332*d62bc4baSyz147064 	dlbrp = (dl_bind_req_t *)mp->b_rptr;
333*d62bc4baSyz147064 	dlbrp->dl_sap = sap;
334*d62bc4baSyz147064 	dlbrp->dl_conn_mgmt = 0;
335*d62bc4baSyz147064 	dlbrp->dl_max_conind = 0;
336*d62bc4baSyz147064 	dlbrp->dl_xidtest_flg = 0;
337*d62bc4baSyz147064 	dlbrp->dl_service_mode = DL_CLDLS;
338*d62bc4baSyz147064 
339*d62bc4baSyz147064 	err = dl_op(lh, &mp, DL_BIND_ACK, DL_BIND_ACK_SIZE, dleap, NULL);
340*d62bc4baSyz147064 	if (err == 0) {
341*d62bc4baSyz147064 		dlbap = (dl_bind_ack_t *)mp->b_rptr;
342*d62bc4baSyz147064 		if (dlbap->dl_sap != sap) {
343*d62bc4baSyz147064 			cmn_err(CE_NOTE, "!dl_bind: DL_BIND_ACK: bad sap %u",
344*d62bc4baSyz147064 			    dlbap->dl_sap);
345*d62bc4baSyz147064 			err = EPROTO;
346*d62bc4baSyz147064 		}
347*d62bc4baSyz147064 		freemsg(mp);
348*d62bc4baSyz147064 	}
349*d62bc4baSyz147064 	return (err);
350*d62bc4baSyz147064 }
351*d62bc4baSyz147064 
352*d62bc4baSyz147064 /*
353*d62bc4baSyz147064  * Send a DL_PHYS_ADDR_REQ over `lh' and wait for the response.  The caller
354*d62bc4baSyz147064  * must set `*physlenp' to the size of `physaddr' (both of which must be
355*d62bc4baSyz147064  * non-NULL); upon success they will be updated to contain the actual physical
356*d62bc4baSyz147064  * address and length.
357*d62bc4baSyz147064  *
358*d62bc4baSyz147064  * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the
359*d62bc4baSyz147064  * caller can get the contents by passing a non-NULL `dleap').
360*d62bc4baSyz147064  */
361*d62bc4baSyz147064 int
362*d62bc4baSyz147064 dl_phys_addr(ldi_handle_t lh, uchar_t *physaddr, size_t *physlenp,
363*d62bc4baSyz147064     dl_error_ack_t *dleap)
364*d62bc4baSyz147064 {
365*d62bc4baSyz147064 	dl_phys_addr_ack_t *dlpap;
366*d62bc4baSyz147064 	mblk_t		*mp;
367*d62bc4baSyz147064 	int		err;
368*d62bc4baSyz147064 	t_uscalar_t	paddrlen, paddroff;
369*d62bc4baSyz147064 	timestruc_t	tv;
370*d62bc4baSyz147064 
371*d62bc4baSyz147064 	mp = mexchange(NULL, NULL, DL_PHYS_ADDR_REQ_SIZE, M_PROTO,
372*d62bc4baSyz147064 	    DL_PHYS_ADDR_REQ);
373*d62bc4baSyz147064 	if (mp == NULL)
374*d62bc4baSyz147064 		return (ENOMEM);
375*d62bc4baSyz147064 
376*d62bc4baSyz147064 	((dl_phys_addr_req_t *)mp->b_rptr)->dl_addr_type = DL_CURR_PHYS_ADDR;
377*d62bc4baSyz147064 
378*d62bc4baSyz147064 	/*
379*d62bc4baSyz147064 	 * In case some provider doesn't implement or NAK the
380*d62bc4baSyz147064 	 * request, just wait for 15 seconds.
381*d62bc4baSyz147064 	 */
382*d62bc4baSyz147064 	tv.tv_sec = 15;
383*d62bc4baSyz147064 	tv.tv_nsec = 0;
384*d62bc4baSyz147064 
385*d62bc4baSyz147064 	err = dl_op(lh, &mp, DL_PHYS_ADDR_ACK, DL_PHYS_ADDR_ACK_SIZE, dleap,
386*d62bc4baSyz147064 	    &tv);
387*d62bc4baSyz147064 	if (err == 0) {
388*d62bc4baSyz147064 		dlpap = (dl_phys_addr_ack_t *)mp->b_rptr;
389*d62bc4baSyz147064 		paddrlen = dlpap->dl_addr_length;
390*d62bc4baSyz147064 		paddroff = dlpap->dl_addr_offset;
391*d62bc4baSyz147064 		if (paddroff == 0 || paddrlen == 0 || paddrlen > *physlenp ||
392*d62bc4baSyz147064 		    !MBLKIN(mp, paddroff, paddrlen)) {
393*d62bc4baSyz147064 			cmn_err(CE_NOTE, "!dl_phys_addr: DL_PHYS_ADDR_ACK: "
394*d62bc4baSyz147064 			    "bad length/offset %d/%d", paddrlen, paddroff);
395*d62bc4baSyz147064 			err = EBADMSG;
396*d62bc4baSyz147064 		} else {
397*d62bc4baSyz147064 			bcopy(mp->b_rptr + paddroff, physaddr, paddrlen);
398*d62bc4baSyz147064 			*physlenp = paddrlen;
399*d62bc4baSyz147064 		}
400*d62bc4baSyz147064 		freemsg(mp);
401*d62bc4baSyz147064 	}
402*d62bc4baSyz147064 	return (err);
403*d62bc4baSyz147064 }
404*d62bc4baSyz147064 
405*d62bc4baSyz147064 /*
406*d62bc4baSyz147064  * Send a DL_INFO_REQ over `lh' and wait for the response.  The caller must
407*d62bc4baSyz147064  * pass a non-NULL `dliap', which upon success will contain the dl_info_ack_t
408*d62bc4baSyz147064  * from the provider.  The caller may optionally get the provider's physical
409*d62bc4baSyz147064  * address by passing a non-NULL `physaddr' and setting `*physlenp' to its
410*d62bc4baSyz147064  * size; upon success they will be updated to contain the actual physical
411*d62bc4baSyz147064  * address and its length.
412*d62bc4baSyz147064  *
413*d62bc4baSyz147064  * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the
414*d62bc4baSyz147064  * caller can get the contents by passing a non-NULL `dleap').
415*d62bc4baSyz147064  */
416*d62bc4baSyz147064 int
417*d62bc4baSyz147064 dl_info(ldi_handle_t lh, dl_info_ack_t *dliap, uchar_t *physaddr,
418*d62bc4baSyz147064     size_t *physlenp, dl_error_ack_t *dleap)
419*d62bc4baSyz147064 {
420*d62bc4baSyz147064 	mblk_t	*mp;
421*d62bc4baSyz147064 	int	err;
422*d62bc4baSyz147064 	int	addrlen, addroff;
423*d62bc4baSyz147064 
424*d62bc4baSyz147064 	mp = mexchange(NULL, NULL, DL_INFO_REQ_SIZE, M_PCPROTO, DL_INFO_REQ);
425*d62bc4baSyz147064 	if (mp == NULL)
426*d62bc4baSyz147064 		return (ENOMEM);
427*d62bc4baSyz147064 
428*d62bc4baSyz147064 	err = dl_op(lh, &mp, DL_INFO_ACK, DL_INFO_ACK_SIZE, dleap, NULL);
429*d62bc4baSyz147064 	if (err != 0)
430*d62bc4baSyz147064 		return (err);
431*d62bc4baSyz147064 
432*d62bc4baSyz147064 	*dliap = *(dl_info_ack_t *)mp->b_rptr;
433*d62bc4baSyz147064 	if (physaddr != NULL) {
434*d62bc4baSyz147064 		addrlen = dliap->dl_addr_length - ABS(dliap->dl_sap_length);
435*d62bc4baSyz147064 		addroff = dliap->dl_addr_offset;
436*d62bc4baSyz147064 		if (addroff == 0 || addrlen <= 0 || addrlen > *physlenp ||
437*d62bc4baSyz147064 		    !MBLKIN(mp, addroff, dliap->dl_addr_length)) {
438*d62bc4baSyz147064 			cmn_err(CE_NOTE, "!dl_info: DL_INFO_ACK: "
439*d62bc4baSyz147064 			    "bad length/offset %d/%d", addrlen, addroff);
440*d62bc4baSyz147064 			freemsg(mp);
441*d62bc4baSyz147064 			return (EBADMSG);
442*d62bc4baSyz147064 		}
443*d62bc4baSyz147064 
444*d62bc4baSyz147064 		if (dliap->dl_sap_length > 0)
445*d62bc4baSyz147064 			addroff += dliap->dl_sap_length;
446*d62bc4baSyz147064 		bcopy(mp->b_rptr + addroff, physaddr, addrlen);
447*d62bc4baSyz147064 		*physlenp = addrlen;
448*d62bc4baSyz147064 	}
449*d62bc4baSyz147064 	freemsg(mp);
450*d62bc4baSyz147064 	return (err);
451*d62bc4baSyz147064 }
452*d62bc4baSyz147064 
453*d62bc4baSyz147064 /*
454*d62bc4baSyz147064  * Send a DL_NOTIFY_REQ over `lh' and wait for the response.  The caller
455*d62bc4baSyz147064  * should set `notesp' to the set of notifications they wish to enable;
456*d62bc4baSyz147064  * upon success it will contain the notifications enabled by the provider.
457*d62bc4baSyz147064  *
458*d62bc4baSyz147064  * Returns an errno; ENOTSUP indicates a DL_ERROR_ACK response (and the
459*d62bc4baSyz147064  * caller can get the contents by passing a non-NULL `dleap').
460*d62bc4baSyz147064  */
461*d62bc4baSyz147064 int
462*d62bc4baSyz147064 dl_notify(ldi_handle_t lh, uint32_t *notesp, dl_error_ack_t *dleap)
463*d62bc4baSyz147064 {
464*d62bc4baSyz147064 	mblk_t	*mp;
465*d62bc4baSyz147064 	int	err;
466*d62bc4baSyz147064 
467*d62bc4baSyz147064 	mp = mexchange(NULL, NULL, DL_NOTIFY_REQ_SIZE, M_PROTO, DL_NOTIFY_REQ);
468*d62bc4baSyz147064 	if (mp == NULL)
469*d62bc4baSyz147064 		return (ENOMEM);
470*d62bc4baSyz147064 
471*d62bc4baSyz147064 	((dl_notify_req_t *)mp->b_rptr)->dl_notifications = *notesp;
472*d62bc4baSyz147064 
473*d62bc4baSyz147064 	err = dl_op(lh, &mp, DL_NOTIFY_ACK, DL_NOTIFY_ACK_SIZE, dleap, NULL);
474*d62bc4baSyz147064 	if (err == 0) {
475*d62bc4baSyz147064 		*notesp = ((dl_notify_ack_t *)mp->b_rptr)->dl_notifications;
476*d62bc4baSyz147064 		freemsg(mp);
477*d62bc4baSyz147064 	}
478*d62bc4baSyz147064 	return (err);
479*d62bc4baSyz147064 }
480*d62bc4baSyz147064 
481*d62bc4baSyz147064 const char *
482*d62bc4baSyz147064 dl_primstr(t_uscalar_t prim)
483*d62bc4baSyz147064 {
484*d62bc4baSyz147064 	switch (prim) {
485*d62bc4baSyz147064 	case DL_INFO_REQ:		return ("DL_INFO_REQ");
486*d62bc4baSyz147064 	case DL_INFO_ACK:		return ("DL_INFO_ACK");
487*d62bc4baSyz147064 	case DL_ATTACH_REQ:		return ("DL_ATTACH_REQ");
488*d62bc4baSyz147064 	case DL_DETACH_REQ:		return ("DL_DETACH_REQ");
489*d62bc4baSyz147064 	case DL_BIND_REQ:		return ("DL_BIND_REQ");
490*d62bc4baSyz147064 	case DL_BIND_ACK:		return ("DL_BIND_ACK");
491*d62bc4baSyz147064 	case DL_UNBIND_REQ:		return ("DL_UNBIND_REQ");
492*d62bc4baSyz147064 	case DL_OK_ACK:			return ("DL_OK_ACK");
493*d62bc4baSyz147064 	case DL_ERROR_ACK:		return ("DL_ERROR_ACK");
494*d62bc4baSyz147064 	case DL_ENABMULTI_REQ:		return ("DL_ENABMULTI_REQ");
495*d62bc4baSyz147064 	case DL_DISABMULTI_REQ:		return ("DL_DISABMULTI_REQ");
496*d62bc4baSyz147064 	case DL_PROMISCON_REQ:		return ("DL_PROMISCON_REQ");
497*d62bc4baSyz147064 	case DL_PROMISCOFF_REQ:		return ("DL_PROMISCOFF_REQ");
498*d62bc4baSyz147064 	case DL_UNITDATA_REQ:		return ("DL_UNITDATA_REQ");
499*d62bc4baSyz147064 	case DL_UNITDATA_IND:		return ("DL_UNITDATA_IND");
500*d62bc4baSyz147064 	case DL_UDERROR_IND:		return ("DL_UDERROR_IND");
501*d62bc4baSyz147064 	case DL_PHYS_ADDR_REQ:		return ("DL_PHYS_ADDR_REQ");
502*d62bc4baSyz147064 	case DL_PHYS_ADDR_ACK:		return ("DL_PHYS_ADDR_ACK");
503*d62bc4baSyz147064 	case DL_SET_PHYS_ADDR_REQ:	return ("DL_SET_PHYS_ADDR_REQ");
504*d62bc4baSyz147064 	case DL_NOTIFY_REQ:		return ("DL_NOTIFY_REQ");
505*d62bc4baSyz147064 	case DL_NOTIFY_ACK:		return ("DL_NOTIFY_ACK");
506*d62bc4baSyz147064 	case DL_NOTIFY_IND:		return ("DL_NOTIFY_IND");
507*d62bc4baSyz147064 	case DL_CAPABILITY_REQ:		return ("DL_CAPABILITY_REQ");
508*d62bc4baSyz147064 	case DL_CAPABILITY_ACK:		return ("DL_CAPABILITY_ACK");
509*d62bc4baSyz147064 	case DL_CONTROL_REQ:		return ("DL_CONTROL_REQ");
510*d62bc4baSyz147064 	case DL_CONTROL_ACK:		return ("DL_CONTROL_ACK");
511*d62bc4baSyz147064 	case DL_PASSIVE_REQ:		return ("DL_PASSIVE_REQ");
512*d62bc4baSyz147064 	case DL_INTR_MODE_REQ:		return ("DL_INTR_MODE_REQ");
513*d62bc4baSyz147064 	case DL_UDQOS_REQ:		return ("DL_UDQOS_REQ");
514*d62bc4baSyz147064 	default:			return ("<unknown primitive>");
515*d62bc4baSyz147064 	}
516*d62bc4baSyz147064 }
517*d62bc4baSyz147064 
518*d62bc4baSyz147064 const char *
519*d62bc4baSyz147064 dl_errstr(t_uscalar_t err)
520*d62bc4baSyz147064 {
521*d62bc4baSyz147064 	switch (err) {
522*d62bc4baSyz147064 	case DL_ACCESS:			return ("DL_ACCESS");
523*d62bc4baSyz147064 	case DL_BADADDR:		return ("DL_BADADDR");
524*d62bc4baSyz147064 	case DL_BADCORR:		return ("DL_BADCORR");
525*d62bc4baSyz147064 	case DL_BADDATA:		return ("DL_BADDATA");
526*d62bc4baSyz147064 	case DL_BADPPA:			return ("DL_BADPPA");
527*d62bc4baSyz147064 	case DL_BADPRIM:		return ("DL_BADPRIM");
528*d62bc4baSyz147064 	case DL_BADQOSPARAM:		return ("DL_BADQOSPARAM");
529*d62bc4baSyz147064 	case DL_BADQOSTYPE:		return ("DL_BADQOSTYPE");
530*d62bc4baSyz147064 	case DL_BADSAP:			return ("DL_BADSAP");
531*d62bc4baSyz147064 	case DL_BADTOKEN:		return ("DL_BADTOKEN");
532*d62bc4baSyz147064 	case DL_BOUND:			return ("DL_BOUND");
533*d62bc4baSyz147064 	case DL_INITFAILED:		return ("DL_INITFAILED");
534*d62bc4baSyz147064 	case DL_NOADDR:			return ("DL_NOADDR");
535*d62bc4baSyz147064 	case DL_NOTINIT:		return ("DL_NOTINIT");
536*d62bc4baSyz147064 	case DL_OUTSTATE:		return ("DL_OUTSTATE");
537*d62bc4baSyz147064 	case DL_SYSERR:			return ("DL_SYSERR");
538*d62bc4baSyz147064 	case DL_UNSUPPORTED:		return ("DL_UNSUPPORTED");
539*d62bc4baSyz147064 	case DL_UNDELIVERABLE:		return ("DL_UNDELIVERABLE");
540*d62bc4baSyz147064 	case DL_NOTSUPPORTED:		return ("DL_NOTSUPPORTED ");
541*d62bc4baSyz147064 	case DL_TOOMANY:		return ("DL_TOOMANY");
542*d62bc4baSyz147064 	case DL_NOTENAB:		return ("DL_NOTENAB");
543*d62bc4baSyz147064 	case DL_BUSY:			return ("DL_BUSY");
544*d62bc4baSyz147064 	case DL_NOAUTO:			return ("DL_NOAUTO");
545*d62bc4baSyz147064 	case DL_NOXIDAUTO:		return ("DL_NOXIDAUTO");
546*d62bc4baSyz147064 	case DL_NOTESTAUTO:		return ("DL_NOTESTAUTO");
547*d62bc4baSyz147064 	case DL_XIDAUTO:		return ("DL_XIDAUTO");
548*d62bc4baSyz147064 	case DL_TESTAUTO:		return ("DL_TESTAUTO");
549*d62bc4baSyz147064 	case DL_PENDING:		return ("DL_PENDING");
550*d62bc4baSyz147064 	default:			return ("<unknown error>");
551*d62bc4baSyz147064 	}
552*d62bc4baSyz147064 }
553*d62bc4baSyz147064 
554*d62bc4baSyz147064 const char *
555*d62bc4baSyz147064 dl_mactypestr(t_uscalar_t mactype)
556*d62bc4baSyz147064 {
557*d62bc4baSyz147064 	switch (mactype) {
558*d62bc4baSyz147064 	case DL_CSMACD:		return ("CSMA/CD");
559*d62bc4baSyz147064 	case DL_TPB:		return ("Token Bus");
560*d62bc4baSyz147064 	case DL_TPR:		return ("Token Ring");
561*d62bc4baSyz147064 	case DL_METRO:		return ("Metro Net");
562*d62bc4baSyz147064 	case DL_ETHER:		return ("Ethernet");
563*d62bc4baSyz147064 	case DL_HDLC:		return ("HDLC");
564*d62bc4baSyz147064 	case DL_CHAR:		return ("Sync Character");
565*d62bc4baSyz147064 	case DL_CTCA:		return ("CTCA");
566*d62bc4baSyz147064 	case DL_FDDI:		return ("FDDI");
567*d62bc4baSyz147064 	case DL_FRAME:		return ("Frame Relay (LAPF)");
568*d62bc4baSyz147064 	case DL_MPFRAME:	return ("MP Frame Relay");
569*d62bc4baSyz147064 	case DL_ASYNC:		return ("Async Character");
570*d62bc4baSyz147064 	case DL_IPX25:		return ("X.25 (Classic IP)");
571*d62bc4baSyz147064 	case DL_LOOP:		return ("Software Loopback");
572*d62bc4baSyz147064 	case DL_FC:		return ("Fiber Channel");
573*d62bc4baSyz147064 	case DL_ATM:		return ("ATM");
574*d62bc4baSyz147064 	case DL_IPATM:		return ("ATM (Classic IP)");
575*d62bc4baSyz147064 	case DL_X25:		return ("X.25 (LAPB)");
576*d62bc4baSyz147064 	case DL_ISDN:		return ("ISDN");
577*d62bc4baSyz147064 	case DL_HIPPI:		return ("HIPPI");
578*d62bc4baSyz147064 	case DL_100VG:		return ("100BaseVG Ethernet");
579*d62bc4baSyz147064 	case DL_100VGTPR:	return ("100BaseVG Token Ring");
580*d62bc4baSyz147064 	case DL_ETH_CSMA:	return ("Ethernet/IEEE 802.3");
581*d62bc4baSyz147064 	case DL_100BT:		return ("100BaseT");
582*d62bc4baSyz147064 	case DL_IB:		return ("Infiniband");
583*d62bc4baSyz147064 	case DL_IPV4:		return ("IPv4 Tunnel");
584*d62bc4baSyz147064 	case DL_IPV6:		return ("IPv6 Tunnel");
585*d62bc4baSyz147064 	case DL_WIFI:		return ("IEEE 802.11");
586*d62bc4baSyz147064 	default:		return ("<unknown mactype>");
587*d62bc4baSyz147064 	}
588*d62bc4baSyz147064 }
589