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