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