1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Starcat Management Network Driver 31 * 32 * ****** NOTICE **** This file also resides in the SSC gate as 33 * ****** NOTICE **** usr/src/uts/sun4u/scman/scman.c. Any changes 34 * ****** NOTICE **** made here must be propogated there as well. 35 * 36 */ 37 38 #include <sys/types.h> 39 #include <sys/proc.h> 40 #include <sys/disp.h> 41 #include <sys/kmem.h> 42 #include <sys/stat.h> 43 #include <sys/kstat.h> 44 #include <sys/ksynch.h> 45 #include <sys/stream.h> 46 #include <sys/dlpi.h> 47 #include <sys/stropts.h> 48 #include <sys/strsubr.h> 49 #include <sys/debug.h> 50 #include <sys/conf.h> 51 #include <sys/kstr.h> 52 #include <sys/errno.h> 53 #include <sys/ethernet.h> 54 #include <sys/byteorder.h> 55 #include <sys/ddi.h> 56 #include <sys/sunddi.h> 57 #include <sys/sunldi.h> 58 #include <sys/modctl.h> 59 #include <sys/strsun.h> 60 #include <sys/callb.h> 61 #include <sys/pci.h> 62 #include <netinet/in.h> 63 #include <inet/common.h> 64 #include <inet/mi.h> 65 #include <inet/nd.h> 66 #include <sys/socket.h> 67 #include <netinet/igmp_var.h> 68 #include <netinet/ip6.h> 69 #include <netinet/icmp6.h> 70 #include <inet/ip.h> 71 #include <inet/ip6.h> 72 #include <sys/file.h> 73 #include <sys/dman.h> 74 #include <sys/autoconf.h> 75 #include <sys/zone.h> 76 77 extern int ddi_create_internal_pathname(dev_info_t *, char *, int, minor_t); 78 79 #define MAN_IDNAME "dman" 80 #define DMAN_INT_PATH "/devices/pseudo/dman@0:dman" 81 #define DMAN_PATH "/devices/pseudo/clone@0:dman" 82 #define ERI_IDNAME "eri" 83 #define ERI_PATH "/devices/pseudo/clone@0:eri" 84 85 #if defined(DEBUG) 86 87 static void man_print_msp(manstr_t *); 88 static void man_print_man(man_t *); 89 static void man_print_mdp(man_dest_t *); 90 static void man_print_dev(man_dev_t *); 91 static void man_print_mip(mi_path_t *); 92 static void man_print_mtp(mi_time_t *); 93 static void man_print_mpg(man_pg_t *); 94 static void man_print_path(man_path_t *); 95 static void man_print_work(man_work_t *); 96 97 /* 98 * Set manstr_t dlpistate (upper half of multiplexor) 99 */ 100 #define SETSTATE(msp, state) \ 101 MAN_DBG(MAN_DLPI, ("msp=0x%p @ %d state %s=>%s\n", \ 102 (void *)msp, __LINE__, dss[msp->ms_dlpistate], \ 103 dss[(state)])); \ 104 msp->ms_dlpistate = (state); 105 /* 106 * Set man_dest_t dlpistate (lower half of multiplexor) 107 */ 108 #define D_SETSTATE(mdp, state) \ 109 MAN_DBG(MAN_DLPI, ("dst=0x%p @ %d state %s=>%s\n", \ 110 (void *)mdp, __LINE__, dss[mdp->md_dlpistate], \ 111 dss[(state)])); \ 112 mdp->md_dlpistate = (state); 113 114 static char *promisc[] = { /* DLPI promisc Strings */ 115 "not used", /* 0x00 */ 116 "DL_PROMISC_PHYS", /* 0x01 */ 117 "DL_PROMISC_SAP", /* 0x02 */ 118 "DL_PROMISC_MULTI" /* 0x03 */ 119 }; 120 121 static char *dps[] = { /* DLPI Primitive Strings */ 122 "DL_INFO_REQ", /* 0x00 */ 123 "DL_BIND_REQ", /* 0x01 */ 124 "DL_UNBIND_REQ", /* 0x02 */ 125 "DL_INFO_ACK", /* 0x03 */ 126 "DL_BIND_ACK", /* 0x04 */ 127 "DL_ERROR_ACK", /* 0x05 */ 128 "DL_OK_ACK", /* 0x06 */ 129 "DL_UNITDATA_REQ", /* 0x07 */ 130 "DL_UNITDATA_IND", /* 0x08 */ 131 "DL_UDERROR_IND", /* 0x09 */ 132 "DL_UDQOS_REQ", /* 0x0a */ 133 "DL_ATTACH_REQ", /* 0x0b */ 134 "DL_DETACH_REQ", /* 0x0c */ 135 "DL_CONNECT_REQ", /* 0x0d */ 136 "DL_CONNECT_IND", /* 0x0e */ 137 "DL_CONNECT_RES", /* 0x0f */ 138 "DL_CONNECT_CON", /* 0x10 */ 139 "DL_TOKEN_REQ", /* 0x11 */ 140 "DL_TOKEN_ACK", /* 0x12 */ 141 "DL_DISCONNECT_REQ", /* 0x13 */ 142 "DL_DISCONNECT_IND", /* 0x14 */ 143 "DL_SUBS_UNBIND_REQ", /* 0x15 */ 144 "DL_LIARLIARPANTSONFIRE", /* 0x16 */ 145 "DL_RESET_REQ", /* 0x17 */ 146 "DL_RESET_IND", /* 0x18 */ 147 "DL_RESET_RES", /* 0x19 */ 148 "DL_RESET_CON", /* 0x1a */ 149 "DL_SUBS_BIND_REQ", /* 0x1b */ 150 "DL_SUBS_BIND_ACK", /* 0x1c */ 151 "DL_ENABMULTI_REQ", /* 0x1d */ 152 "DL_DISABMULTI_REQ", /* 0x1e */ 153 "DL_PROMISCON_REQ", /* 0x1f */ 154 "DL_PROMISCOFF_REQ", /* 0x20 */ 155 "DL_DATA_ACK_REQ", /* 0x21 */ 156 "DL_DATA_ACK_IND", /* 0x22 */ 157 "DL_DATA_ACK_STATUS_IND", /* 0x23 */ 158 "DL_REPLY_REQ", /* 0x24 */ 159 "DL_REPLY_IND", /* 0x25 */ 160 "DL_REPLY_STATUS_IND", /* 0x26 */ 161 "DL_REPLY_UPDATE_REQ", /* 0x27 */ 162 "DL_REPLY_UPDATE_STATUS_IND", /* 0x28 */ 163 "DL_XID_REQ", /* 0x29 */ 164 "DL_XID_IND", /* 0x2a */ 165 "DL_XID_RES", /* 0x2b */ 166 "DL_XID_CON", /* 0x2c */ 167 "DL_TEST_REQ", /* 0x2d */ 168 "DL_TEST_IND", /* 0x2e */ 169 "DL_TEST_RES", /* 0x2f */ 170 "DL_TEST_CON", /* 0x30 */ 171 "DL_PHYS_ADDR_REQ", /* 0x31 */ 172 "DL_PHYS_ADDR_ACK", /* 0x32 */ 173 "DL_SET_PHYS_ADDR_REQ", /* 0x33 */ 174 "DL_GET_STATISTICS_REQ", /* 0x34 */ 175 "DL_GET_STATISTICS_ACK", /* 0x35 */ 176 }; 177 178 #define MAN_DLPI_MAX_PRIM 0x35 179 180 static char *dss[] = { /* DLPI State Strings */ 181 "DL_UNBOUND", /* 0x00 */ 182 "DL_BIND_PENDING", /* 0x01 */ 183 "DL_UNBIND_PENDING", /* 0x02 */ 184 "DL_IDLE", /* 0x03 */ 185 "DL_UNATTACHED", /* 0x04 */ 186 "DL_ATTACH_PENDING", /* 0x05 */ 187 "DL_DETACH_PENDING", /* 0x06 */ 188 "DL_UDQOS_PENDING", /* 0x07 */ 189 "DL_OUTCON_PENDING", /* 0x08 */ 190 "DL_INCON_PENDING", /* 0x09 */ 191 "DL_CONN_RES_PENDING", /* 0x0a */ 192 "DL_DATAXFER", /* 0x0b */ 193 "DL_USER_RESET_PENDING", /* 0x0c */ 194 "DL_PROV_RESET_PENDING", /* 0x0d */ 195 "DL_RESET_RES_PENDING", /* 0x0e */ 196 "DL_DISCON8_PENDING", /* 0x0f */ 197 "DL_DISCON9_PENDING", /* 0x10 */ 198 "DL_DISCON11_PENDING", /* 0x11 */ 199 "DL_DISCON12_PENDING", /* 0x12 */ 200 "DL_DISCON13_PENDING", /* 0x13 */ 201 "DL_SUBS_BIND_PND", /* 0x14 */ 202 "DL_SUBS_UNBIND_PND", /* 0x15 */ 203 }; 204 205 static const char *lss[] = { 206 "UNKNOWN", /* 0x0 */ 207 "INIT", /* 0x1 */ 208 "GOOD", /* 0x2 */ 209 "STALE", /* 0x3 */ 210 "FAIL", /* 0x4 */ 211 }; 212 213 static char *_mw_type[] = { 214 "OPEN_CTL", /* 0x0 */ 215 "CLOSE_CTL", /* 0x1 */ 216 "SWITCH", /* 0x2 */ 217 "PATH_UPDATE", /* 0x3 */ 218 "CLOSE", /* 0x4 */ 219 "CLOSE_STREAM", /* 0x5 */ 220 "DRATTACH", /* 0x6 */ 221 "DRDETACH", /* 0x7 */ 222 "STOP", /* 0x8 */ 223 "DRSWITCH", /* 0x9 */ 224 "KSTAT_UPDATE" /* 0xA */ 225 }; 226 227 uint32_t man_debug = MAN_WARN; 228 229 #define man_kzalloc(a, b) man_dbg_kzalloc(__LINE__, a, b) 230 #define man_kfree(a, b) man_dbg_kfree(__LINE__, a, b) 231 void *man_dbg_kzalloc(int line, size_t size, int kmflags); 232 void man_dbg_kfree(int line, void *buf, size_t size); 233 234 #else /* DEBUG */ 235 236 uint32_t man_debug = 0; 237 /* 238 * Set manstr_t dlpistate (upper half of multiplexor) 239 */ 240 #define SETSTATE(msp, state) msp->ms_dlpistate = (state); 241 /* 242 * Set man_dest_t dlpistate (lower half of multiplexor) 243 */ 244 #define D_SETSTATE(mdp, state) mdp->md_dlpistate = (state); 245 246 #define man_kzalloc(a, b) kmem_zalloc(a, b) 247 #define man_kfree(a, b) kmem_free(a, b) 248 249 #endif /* DEBUG */ 250 251 #define DL_PRIM(mp) (((union DL_primitives *)(mp)->b_rptr)->dl_primitive) 252 #define DL_PROMISCON_TYPE(mp) \ 253 (((union DL_primitives *)(mp)->b_rptr)->promiscon_req.dl_level) 254 #define IOC_CMD(mp) (((struct iocblk *)(mp)->b_rptr)->ioc_cmd) 255 256 /* 257 * Start of kstat-related declarations 258 */ 259 #define MK_NOT_COUNTER (1<<0) /* is it a counter? */ 260 #define MK_ERROR (1<<2) /* for error statistics */ 261 #define MK_NOT_PHYSICAL (1<<3) /* no matching physical stat */ 262 263 typedef struct man_kstat_info_s { 264 char *mk_name; /* e.g. align_errors */ 265 char *mk_physname; /* e.g. framing (NULL for same) */ 266 char *mk_physalias; /* e.g. framing (NULL for same) */ 267 uchar_t mk_type; /* e.g. KSTAT_DATA_UINT32 */ 268 int mk_flags; 269 } man_kstat_info_t; 270 271 /* 272 * Master declaration macro, note that it uses token pasting 273 */ 274 #define MK_DECLARE(name, pname, palias, bits, flags) \ 275 { name, pname, palias, KSTAT_DATA_UINT ## bits, flags } 276 277 /* 278 * Obsolete forms don't have the _sinceswitch forms, they are all errors 279 */ 280 #define MK_OBSOLETE32(name, alias) MK_DECLARE(alias, name, alias, 32, MK_ERROR) 281 #define MK_OBSOLETE64(name, alias) MK_DECLARE(alias, name, alias, 64, MK_ERROR) 282 283 /* 284 * The only non-counters don't have any other aliases 285 */ 286 #define MK_NOTCOUNTER32(name) MK_DECLARE(name, name, NULL, 32, MK_NOT_COUNTER) 287 #define MK_NOTCOUNTER64(name) MK_DECLARE(name, name, NULL, 64, MK_NOT_COUNTER) 288 289 /* 290 * Normal counter forms 291 */ 292 #define MK_DECLARE32(name, alias) \ 293 MK_DECLARE(name, name, alias, 32, 0) 294 #define MK_DECLARE64(name, alias) \ 295 MK_DECLARE(name, name, alias, 64, 0) 296 297 /* 298 * Error counters need special MK_ERROR flag only for the non-AP form 299 */ 300 #define MK_ERROR32(name, alias) \ 301 MK_DECLARE(name, name, alias, 32, MK_ERROR) 302 #define MK_ERROR64(name, alias) \ 303 MK_DECLARE(name, name, alias, 64, MK_ERROR) 304 305 /* 306 * These AP-specific stats are not backed by physical statistics 307 */ 308 #define MK_NOTPHYS32(name) MK_DECLARE(name, NULL, NULL, 32, MK_NOT_PHYSICAL) 309 #define MK_NOTPHYS64(name) MK_DECLARE(name, NULL, NULL, 64, MK_NOT_PHYSICAL) 310 311 /* 312 * START of the actual man_kstat_info declaration using above macros 313 */ 314 static man_kstat_info_t man_kstat_info[] = { 315 /* 316 * Link Input/Output stats 317 */ 318 MK_DECLARE32("ipackets", NULL), 319 MK_ERROR32("ierrors", NULL), 320 MK_DECLARE32("opackets", NULL), 321 MK_ERROR32("oerrors", NULL), 322 MK_ERROR32("collisions", NULL), 323 MK_NOTCOUNTER64("ifspeed"), 324 /* 325 * These are new MIB-II stats, per PSARC 1997/198 326 */ 327 MK_DECLARE32("rbytes", NULL), 328 MK_DECLARE32("obytes", NULL), 329 MK_DECLARE32("multircv", NULL), 330 MK_DECLARE32("multixmt", NULL), 331 MK_DECLARE32("brdcstrcv", NULL), 332 MK_DECLARE32("brdcstxmt", NULL), 333 /* 334 * Error values 335 */ 336 MK_ERROR32("norcvbuf", NULL), 337 MK_ERROR32("noxmtbuf", NULL), 338 MK_ERROR32("unknowns", NULL), 339 /* 340 * These are the 64-bit values, they fallback to 32-bit values 341 */ 342 MK_DECLARE64("ipackets64", "ipackets"), 343 MK_DECLARE64("opackets64", "opackets"), 344 MK_DECLARE64("rbytes64", "rbytes"), 345 MK_DECLARE64("obytes64", "obytes"), 346 347 /* New AP switching statistics */ 348 MK_NOTPHYS64("man_switches"), 349 MK_NOTPHYS64("man_link_fails"), 350 MK_NOTPHYS64("man_link_stales"), 351 MK_NOTPHYS64("man_icmpv4_probes"), 352 MK_NOTPHYS64("man_icmpv6_probes"), 353 354 MK_ERROR32("align_errors", "framing"), 355 MK_ERROR32("fcs_errors", "crc"), 356 MK_ERROR32("first_collisions", NULL), 357 MK_ERROR32("multi_collisions", NULL), 358 MK_ERROR32("sqe_errors", "sqe"), 359 360 MK_ERROR32("tx_late_collisions", NULL), 361 MK_ERROR32("ex_collisions", "excollisions"), 362 MK_ERROR32("macxmt_errors", NULL), 363 MK_ERROR32("carrier_errors", "nocarrier"), 364 MK_ERROR32("toolong_errors", "buff"), 365 MK_ERROR32("macrcv_errors", NULL), 366 367 MK_OBSOLETE32("framing", "align_errors"), 368 MK_OBSOLETE32("crc", "fcs_errors"), 369 MK_OBSOLETE32("sqe", "sqe_errors"), 370 MK_OBSOLETE32("excollisions", "ex_collisions"), 371 MK_OBSOLETE32("nocarrier", "carrier_errors"), 372 MK_OBSOLETE32("buff", "toolong_errors"), 373 }; 374 375 #define MAN_NUMSTATS (sizeof (man_kstat_info) / sizeof (man_kstat_info_t)) 376 377 /* 378 * Miscellaneous ethernet stuff. 379 * 380 * MANs DL_INFO_ACK template. 381 */ 382 static dl_info_ack_t man_infoack = { 383 DL_INFO_ACK, /* dl_primitive */ 384 ETHERMTU, /* dl_max_sdu */ 385 0, /* dl_min_sdu */ 386 MAN_ADDRL, /* dl_addr_length */ 387 DL_ETHER, /* dl_mac_type */ 388 0, /* dl_reserved */ 389 0, /* dl_current_state */ 390 -2, /* dl_sap_length */ 391 DL_CLDLS, /* dl_service_mode */ 392 0, /* dl_qos_length */ 393 0, /* dl_qos_offset */ 394 0, /* dl_range_length */ 395 0, /* dl_range_offset */ 396 DL_STYLE2, /* dl_provider_style */ 397 sizeof (dl_info_ack_t), /* dl_addr_offset */ 398 DL_VERSION_2, /* dl_version */ 399 ETHERADDRL, /* dl_brdcst_addr_length */ 400 sizeof (dl_info_ack_t) + MAN_ADDRL, /* dl_brdcst_addr_offset */ 401 0 /* dl_growth */ 402 }; 403 404 /* 405 * Ethernet broadcast address definition. 406 */ 407 static struct ether_addr etherbroadcast = { 408 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 409 }; 410 411 static struct ether_addr zero_ether_addr = { 412 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 413 }; 414 415 /* 416 * Set via MAN_SET_SC_IPADDRS ioctl. 417 */ 418 man_sc_ipaddrs_t man_sc_ipaddrs = { 0xffffffffU, 0xffffffffU }; 419 420 /* 421 * Set via MAN_SET_SC_IP6ADDRS ioctl. 422 */ 423 man_sc_ip6addrs_t man_sc_ip6addrs = { 0, 0, 0, 0, 0, 0, 0, 0 }; 424 425 /* 426 * IP & ICMP constants 427 */ 428 #ifndef ETHERTYPE_IPV6 429 #define ETHERTYPE_IPV6 0x86DD 430 #endif 431 432 /* 433 * Function prototypes. 434 * 435 * Upper multiplexor functions. 436 */ 437 static int man_attach(dev_info_t *, ddi_attach_cmd_t); 438 static int man_detach(dev_info_t *, ddi_detach_cmd_t); 439 static int man_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 440 static int man_open(register queue_t *, dev_t *, int, int, cred_t *); 441 static int man_configure(queue_t *); 442 static int man_deconfigure(void); 443 static int man_init_dests(man_t *, manstr_t *); 444 static void man_start_dest(man_dest_t *, manstr_t *, man_pg_t *); 445 static void man_set_optimized_dest(manstr_t *); 446 static int man_close(queue_t *); 447 static void man_cancel_timers(man_adest_t *); 448 static int man_uwput(queue_t *, mblk_t *); 449 static int man_start(queue_t *, mblk_t *, eaddr_t *); 450 static void man_ioctl(queue_t *, mblk_t *); 451 static void man_set_linkcheck_time(queue_t *, mblk_t *); 452 static void man_setpath(queue_t *, mblk_t *); 453 static void man_geteaddr(queue_t *, mblk_t *); 454 static void man_set_sc_ipaddrs(queue_t *, mblk_t *); 455 static void man_set_sc_ip6addrs(queue_t *, mblk_t *); 456 static int man_get_our_etheraddr(eaddr_t *eap); 457 static void man_nd_getset(queue_t *, mblk_t *); 458 static void man_dl_ioc_hdr_info(queue_t *, mblk_t *); 459 static int man_uwsrv(queue_t *); 460 static int man_proto(queue_t *, mblk_t *); 461 static int man_udreq(queue_t *, mblk_t *); 462 static void man_areq(queue_t *, mblk_t *); 463 static mblk_t *man_alloc_physreq_mp(eaddr_t *); 464 static void man_dreq(queue_t *, mblk_t *); 465 static void man_dodetach(manstr_t *, man_work_t *); 466 static void man_dl_clean(mblk_t **); 467 static void man_breq(queue_t *, mblk_t *); 468 static void man_ubreq(queue_t *, mblk_t *); 469 static void man_ireq(queue_t *, mblk_t *); 470 static void man_ponreq(queue_t *, mblk_t *); 471 static void man_poffreq(queue_t *, mblk_t *); 472 static void man_emreq(queue_t *, mblk_t *); 473 static void man_dmreq(queue_t *, mblk_t *); 474 static void man_pareq(queue_t *, mblk_t *); 475 static void man_spareq(queue_t *, mblk_t *); 476 static int man_dlpi(manstr_t *, mblk_t *); 477 static int man_dlioc(manstr_t *, mblk_t *); 478 static int man_dl_catch(mblk_t **, mblk_t *); 479 static void man_dl_release(mblk_t **, mblk_t *); 480 static int man_match_proto(mblk_t *, mblk_t *); 481 static int man_open_ctl(); 482 static void man_close_ctl(); 483 /* 484 * upper/lower multiplexor functions. 485 */ 486 static int man_dlpi_senddown(manstr_t *, mblk_t *); 487 static int man_start_lower(man_dest_t *, mblk_t *, queue_t *, int caller); 488 static int man_lrput(queue_t *, mblk_t *); 489 /* 490 * Lower multiplexor functions. 491 */ 492 static int man_lwsrv(queue_t *); 493 static int man_lrsrv(queue_t *); 494 static void man_dlpi_replay(man_dest_t *, mblk_t *); 495 static int man_dlioc_replay(man_dest_t *); 496 /* 497 * Link failover routines. 498 */ 499 static int man_gettimer(int, man_dest_t *); 500 static void man_linkcheck_timer(void *); 501 static int man_needs_linkcheck(man_dest_t *); 502 static int man_do_autoswitch(man_dest_t *); 503 static int man_autoswitch(man_pg_t *, man_dev_t *, man_work_t *); 504 static int man_prep_dests_for_switch(man_pg_t *, man_dest_t **, int *); 505 static int man_str_uses_pg(manstr_t *, man_pg_t *); 506 static void man_do_icmp_bcast(man_dest_t *, t_uscalar_t); 507 static mblk_t *man_alloc_udreq(int, man_dladdr_t *); 508 static mblk_t *man_pinger(t_uscalar_t); 509 /* 510 * Functions normally executing outside of the STREAMs perimeter. 511 */ 512 /* 513 * Functions supporting/processing work requests. 514 */ 515 static void man_bwork(void); 516 static void man_iwork(void); /* inside perimeter */ 517 void man_work_add(man_workq_t *, man_work_t *); 518 man_work_t *man_work_alloc(int, int); 519 void man_work_free(man_work_t *); 520 /* 521 * Functions implementing/supporting failover. 522 * 523 * Executed inside perimeter. 524 */ 525 static int man_do_dr_attach(man_work_t *); 526 static int man_do_dr_switch(man_work_t *); 527 static void man_do_dr_detach(man_work_t *); 528 static int man_iswitch(man_work_t *); 529 static void man_ifail_dest(man_dest_t *); 530 static man_dest_t *man_switch_match(man_dest_t *, int, void *); 531 static void man_add_dests(man_pg_t *); 532 static void man_reset_dlpi(void *); 533 static mblk_t *man_dup_mplist(mblk_t *); 534 static mblk_t *man_alloc_ubreq_dreq(); 535 /* 536 * Executed outside perimeter (us man_lock for synchronization). 537 */ 538 static void man_bclose(man_adest_t *); 539 static void man_bswitch(man_adest_t *, man_work_t *); 540 static int man_plumb(man_dest_t *); 541 static void man_unplumb(man_dest_t *); 542 static void man_plink(queue_t *, mblk_t *); 543 static void man_unplink(queue_t *, mblk_t *); 544 static void man_linkrec_insert(man_linkrec_t *); 545 static queue_t *man_linkrec_find(int); 546 /* 547 * Functions supporting pathgroups 548 */ 549 int man_pg_cmd(mi_path_t *, man_work_t *); 550 static int man_pg_assign(man_pg_t **, mi_path_t *, int); 551 static int man_pg_create(man_pg_t **, man_pg_t **, mi_path_t *); 552 static int man_pg_unassign(man_pg_t **, mi_path_t *); 553 static int man_pg_activate(man_t *, mi_path_t *, man_work_t *); 554 static int man_pg_read(man_pg_t *, mi_path_t *); 555 static man_pg_t *man_find_path_by_dev(man_pg_t *, man_dev_t *, man_path_t **); 556 static man_pg_t *man_find_pg_by_id(man_pg_t *, int); 557 static man_path_t *man_find_path_by_ppa(man_path_t *, int); 558 static man_path_t *man_find_active_path(man_path_t *); 559 static man_path_t *man_find_alternate_path(man_path_t *); 560 static void man_path_remove(man_path_t **, man_path_t *); 561 static void man_path_insert(man_path_t **, man_path_t *); 562 static void man_path_merge(man_path_t **, man_path_t *); 563 static int man_path_kstat_init(man_path_t *); 564 static void man_path_kstat_uninit(man_path_t *); 565 /* 566 * Functions supporting kstat reporting. 567 */ 568 static int man_kstat_update(kstat_t *, int); 569 static void man_do_kstats(man_work_t *); 570 static void man_update_path_kstats(man_t *); 571 static void man_update_dev_kstats(kstat_named_t *, man_path_t *); 572 static void man_sum_dests_kstats(kstat_named_t *, man_pg_t *); 573 static void man_kstat_named_init(kstat_named_t *, int); 574 static int man_kstat_byname(kstat_t *, char *, kstat_named_t *); 575 static void man_sum_kstats(kstat_named_t *, kstat_t *, kstat_named_t *); 576 /* 577 * Functions supporting ndd. 578 */ 579 static int man_param_register(param_t *, int); 580 static int man_pathgroups_report(queue_t *, mblk_t *, caddr_t, cred_t *); 581 static void man_preport(man_path_t *, mblk_t *); 582 static int man_set_active_path(queue_t *, mblk_t *, char *, caddr_t, 583 cred_t *); 584 static int man_get_hostinfo(queue_t *, mblk_t *, caddr_t, cred_t *); 585 static char *man_inet_ntoa(in_addr_t); 586 static int man_param_get(queue_t *, mblk_t *, caddr_t, cred_t *); 587 static int man_param_set(queue_t *, mblk_t *, char *, caddr_t, cred_t *); 588 static void man_param_cleanup(void); 589 static void man_nd_free(caddr_t *nd_pparam); 590 /* 591 * MAN SSC/Domain specific externs. 592 */ 593 extern int man_get_iosram(manc_t *); 594 extern int man_domain_configure(void); 595 extern int man_domain_deconfigure(void); 596 extern int man_dossc_switch(uint32_t); 597 extern int man_is_on_domain; 598 599 /* 600 * Driver Globals protected by inner perimeter. 601 */ 602 static manstr_t *man_strup = NULL; /* list of MAN STREAMS */ 603 static caddr_t man_ndlist = NULL; /* head of ndd var list */ 604 void *man_softstate = NULL; 605 606 /* 607 * Driver globals protected by man_lock. 608 */ 609 kmutex_t man_lock; /* lock protecting vars below */ 610 static kthread_id_t man_bwork_id = NULL; /* background thread ID */ 611 man_workq_t *man_bwork_q; /* bgthread work q */ 612 man_workq_t *man_iwork_q; /* inner perim (uwsrv) work q */ 613 static man_linkrec_t *man_linkrec_head = NULL; /* list of linkblks */ 614 ldi_handle_t man_ctl_lh = NULL; /* MAN control handle */ 615 queue_t *man_ctl_wq = NULL; /* MAN control rq */ 616 static int man_config_state = MAN_UNCONFIGURED; 617 static int man_config_error = ENODEV; 618 619 /* 620 * These parameters are accessed via ndd to report the link configuration 621 * for the MAN driver. They can also be used to force configuration changes. 622 */ 623 #define MAN_NOTUSR 0x0f000000 624 625 /* ------------------------------------------------------------------------- */ 626 627 static param_t man_param_arr[] = { 628 /* min max value name */ 629 { 0, 0xFFFF, 0, "man_debug_level"}, 630 }; 631 632 #define MAN_NDD_GETABLE 1 633 #define MAN_NDD_SETABLE 2 634 635 static uint32_t man_param_display[] = { 636 /* DISPLAY */ 637 MAN_NDD_SETABLE, /* man_debug_level */ 638 }; 639 640 /* 641 * STREAMs information. 642 */ 643 static struct module_info man_m_info = { 644 MAN_IDNUM, /* mi_idnum */ 645 MAN_IDNAME, /* mi_idname */ 646 MAN_MINPSZ, /* mi_minpsz */ 647 MAN_MAXPSZ, /* mi_maxpsz */ 648 MAN_HIWAT, /* mi_hiwat */ 649 MAN_LOWAT /* mi_lowat */ 650 }; 651 652 /* 653 * Upper read queue does not do anything. 654 */ 655 static struct qinit man_urinit = { 656 NULL, /* qi_putp */ 657 NULL, /* qi_srvp */ 658 man_open, /* qi_qopen */ 659 man_close, /* qi_qclose */ 660 NULL, /* qi_qadmin */ 661 &man_m_info, /* qi_minfo */ 662 NULL /* qi_mstat */ 663 }; 664 665 static struct qinit man_lrinit = { 666 man_lrput, /* qi_putp */ 667 man_lrsrv, /* qi_srvp */ 668 man_open, /* qi_qopen */ 669 man_close, /* qi_qclose */ 670 NULL, /* qi_qadmin */ 671 &man_m_info, /* qi_minfo */ 672 NULL /* qi_mstat */ 673 }; 674 675 static struct qinit man_uwinit = { 676 man_uwput, /* qi_putp */ 677 man_uwsrv, /* qi_srvp */ 678 man_open, /* qi_qopen */ 679 man_close, /* qi_qclose */ 680 NULL, /* qi_qadmin */ 681 &man_m_info, /* qi_minfo */ 682 NULL /* qi_mstat */ 683 }; 684 685 static struct qinit man_lwinit = { 686 NULL, /* qi_putp */ 687 man_lwsrv, /* qi_srvp */ 688 man_open, /* qi_qopen */ 689 man_close, /* qi_qclose */ 690 NULL, /* qi_qadmin */ 691 &man_m_info, /* qi_minfo */ 692 NULL /* qi_mstat */ 693 }; 694 695 static struct streamtab man_maninfo = { 696 &man_urinit, /* st_rdinit */ 697 &man_uwinit, /* st_wrinit */ 698 &man_lrinit, /* st_muxrinit */ 699 &man_lwinit /* st_muxwrinit */ 700 }; 701 702 703 /* 704 * Module linkage information for the kernel. 705 * 706 * Locking Theory: 707 * D_MTPERMOD - Only an inner perimeter: All routines single 708 * threaded (except put, see below). 709 * D_MTPUTSHARED - Put routines enter inner perimeter shared (not 710 * exclusive) for concurrency/performance reasons. 711 * 712 * Anyone who needs exclusive outer perimeter permission (changing 713 * global data structures) does so via qwriter() calls. The 714 * background thread does all his work outside of perimeter and 715 * submits work via qtimeout() when data structures need to be 716 * modified. 717 */ 718 719 #define MAN_MDEV_FLAGS (D_MP|D_MTPERMOD|D_MTPUTSHARED) 720 721 DDI_DEFINE_STREAM_OPS(man_ops, nulldev, nulldev, man_attach, 722 man_detach, nodev, man_info, MAN_MDEV_FLAGS, &man_maninfo); 723 724 extern int nodev(), nulldev(); 725 726 static struct modldrv modldrv = { 727 &mod_driverops, /* Module type. This one is a pseudo driver */ 728 "MAN MetaDriver v%I%", 729 &man_ops, /* driver ops */ 730 }; 731 732 static struct modlinkage modlinkage = { 733 MODREV_1, 734 (void *) &modldrv, 735 NULL 736 }; 737 738 739 /* Virtual Driver loader entry points */ 740 741 int 742 _init(void) 743 { 744 int status = DDI_FAILURE; 745 746 MAN_DBG(MAN_INIT, ("_init:")); 747 MAN_DBG(MAN_INIT, ("_init: compiled %s at %s\n", __DATE__, __TIME__)); 748 749 status = mod_install(&modlinkage); 750 if (status != 0) { 751 cmn_err(CE_WARN, "man_init: mod_install failed" 752 " error = %d", status); 753 return (status); 754 } 755 756 status = ddi_soft_state_init(&man_softstate, sizeof (man_t), 4); 757 if (status != 0) { 758 cmn_err(CE_WARN, "man_init: ddi_soft_state_init failed" 759 " error = %d", status); 760 mod_remove(&modlinkage); 761 return (status); 762 } 763 764 man_bwork_q = man_kzalloc(sizeof (man_workq_t), KM_SLEEP); 765 man_iwork_q = man_kzalloc(sizeof (man_workq_t), KM_SLEEP); 766 767 mutex_init(&man_lock, NULL, MUTEX_DRIVER, NULL); 768 cv_init(&man_bwork_q->q_cv, NULL, CV_DRIVER, NULL); 769 cv_init(&man_iwork_q->q_cv, NULL, CV_DRIVER, NULL); 770 771 return (0); 772 } 773 774 /* 775 * _info is called by modinfo(). 776 */ 777 int 778 _info(struct modinfo *modinfop) 779 { 780 int status; 781 782 MAN_DBG(MAN_INIT, ("_info:")); 783 784 status = mod_info(&modlinkage, modinfop); 785 786 MAN_DBG(MAN_INIT, ("_info: returns %d", status)); 787 788 return (status); 789 } 790 791 /* 792 * _fini called by modunload() just before driver is unloaded from memory. 793 */ 794 int 795 _fini(void) 796 { 797 int status = 0; 798 799 MAN_DBG(MAN_INIT, ("_fini:")); 800 801 802 /* 803 * The only upper stream left should be man_ctl_lh. Note that 804 * man_close (upper stream) is synchronous (i.e. it waits for 805 * all STREAMS framework associated with the upper stream to be 806 * torn down). This guarantees that man_ctl_lh will never become 807 * NULL until noone is around to notice. This assumption is made 808 * in a few places like man_plumb, man_unplumb, etc. 809 */ 810 if (man_strup && (man_strup->ms_next != NULL)) 811 return (EBUSY); 812 813 /* 814 * Deconfigure the driver. 815 */ 816 status = man_deconfigure(); 817 if (status) 818 goto exit; 819 820 /* 821 * need to detach every instance of the driver 822 */ 823 status = mod_remove(&modlinkage); 824 if (status != 0) 825 goto exit; 826 827 ddi_soft_state_fini(&man_softstate); 828 829 /* 830 * Free up locks. 831 */ 832 mutex_destroy(&man_lock); 833 cv_destroy(&man_bwork_q->q_cv); 834 cv_destroy(&man_iwork_q->q_cv); 835 836 man_kfree(man_bwork_q, sizeof (man_workq_t)); 837 man_kfree(man_iwork_q, sizeof (man_workq_t)); 838 839 exit: 840 841 MAN_DBG(MAN_INIT, ("_fini: returns %d", status)); 842 843 return (status); 844 } 845 846 /* 847 * Deconfigure the MAN driver. 848 */ 849 static int 850 man_deconfigure() 851 { 852 man_work_t *wp; 853 int status = 0; 854 855 MAN_DBG(MAN_CONFIG, ("man_deconfigure:\n")); 856 857 mutex_enter(&man_lock); 858 859 if (man_is_on_domain) { 860 status = man_domain_deconfigure(); 861 if (status != 0) 862 goto exit; 863 } 864 865 man_param_cleanup(); /* Free up NDD resources */ 866 867 /* 868 * I may have to handle straggling work requests. Just qwait? 869 * or cvwait? Called from _fini - TBD 870 */ 871 ASSERT(man_bwork_q->q_work == NULL); 872 ASSERT(man_iwork_q->q_work == NULL); 873 874 MAN_DBG(MAN_CONFIG, ("man_deconfigure: submitting CLOSE_CTL\n")); 875 876 if (man_ctl_lh != NULL) { 877 wp = man_work_alloc(MAN_WORK_CLOSE_CTL, KM_SLEEP); 878 wp->mw_flags = MAN_WFLAGS_CVWAITER; 879 man_work_add(man_bwork_q, wp); 880 881 while (!(wp->mw_flags & MAN_WFLAGS_DONE)) { 882 cv_wait(&wp->mw_cv, &man_lock); 883 } 884 man_work_free(wp); 885 } 886 887 MAN_DBG(MAN_CONFIG, ("man_deconfigure: submitting STOP\n")); 888 if (man_bwork_id != NULL) { 889 890 wp = man_work_alloc(MAN_WORK_STOP, KM_SLEEP); 891 wp->mw_flags = MAN_WFLAGS_CVWAITER; 892 man_work_add(man_bwork_q, wp); 893 894 while (!(wp->mw_flags & MAN_WFLAGS_DONE)) { 895 cv_wait(&wp->mw_cv, &man_lock); 896 } 897 man_work_free(wp); 898 } 899 man_config_state = MAN_UNCONFIGURED; 900 901 exit: 902 mutex_exit(&man_lock); 903 904 MAN_DBG(MAN_CONFIG, ("man_deconfigure: returns %d\n", status)); 905 906 return (status); 907 } 908 909 /* 910 * man_attach - allocate resources and attach an instance of the MAN driver 911 * The <man>.conf file controls how many instances of the MAN driver are 912 * available. 913 * 914 * dip - devinfo of node 915 * cmd - one of DDI_ATTACH | DDI_RESUME 916 * 917 * returns - success - DDI_SUCCESS 918 * - failure - DDI_FAILURE 919 */ 920 static int 921 man_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 922 { 923 man_t *manp; /* per instance data */ 924 uchar_t flag = KSTAT_FLAG_WRITABLE; /* support netstat -kc */ 925 kstat_t *ksp; 926 int minor_node_created = 0; 927 int instance; 928 eaddr_t man_eaddr; 929 930 MAN_DBG(MAN_INIT, ("man_attach: \n")); 931 932 if (cmd != DDI_ATTACH) { 933 MAN_DBG(MAN_INIT, ("man_attach: bad command %d\n", cmd)); 934 return (DDI_FAILURE); 935 } 936 937 if (man_get_our_etheraddr(&man_eaddr)) 938 return (DDI_FAILURE); 939 940 instance = ddi_get_instance(dip); 941 942 /* 943 * we assume that instance is always equal to zero. 944 * and there will always only be one instance. 945 * this is done because when dman opens itself via DMAN_INT_PATH, 946 * the path assumes that the instance number is zero. 947 * if we ever need to support multiple instances of the dman 948 * driver or non-zero instances, this will have to change. 949 */ 950 ASSERT(instance == 0); 951 952 /* 953 * Allocate per device info pointer and link in to global list of 954 * MAN devices. 955 */ 956 if ((ddi_soft_state_zalloc(man_softstate, instance) != DDI_SUCCESS) || 957 ((manp = ddi_get_soft_state(man_softstate, instance)) == NULL)) { 958 cmn_err(CE_WARN, "man_attach: cannot zalloc soft state!"); 959 return (DDI_FAILURE); 960 } 961 962 ddi_set_driver_private(dip, manp); 963 manp->man_dip = dip; 964 manp->man_meta_major = ddi_name_to_major(ddi_get_name(dip)); 965 manp->man_meta_ppa = instance; 966 967 /* 968 * Set ethernet address. Note that this address is duplicated 969 * at md_src_eaddr. 970 */ 971 ether_copy(&man_eaddr, &manp->man_eaddr); 972 manp->man_eaddr_v = 1; 973 974 MAN_DBG(MAN_INIT, ("man_attach: set ether to %s", 975 ether_sprintf(&manp->man_eaddr))); 976 977 /* 978 * Initialize failover-related fields (timers and such), 979 * taking values from properties if present. 980 */ 981 manp->man_init_time = ddi_getprop(DDI_DEV_T_ANY, dip, 0, 982 "init_time", MAN_INIT_TIME); 983 984 manp->man_linkcheck_time = ddi_getprop(DDI_DEV_T_ANY, dip, 0, 985 "linkcheck_time", MAN_LINKCHECK_TIME); 986 987 manp->man_linkstale_time = ddi_getprop(DDI_DEV_T_ANY, dip, 0, 988 "man_linkstale_time", MAN_LINKSTALE_TIME); 989 990 manp->man_linkstale_retries = ddi_getprop(DDI_DEV_T_ANY, dip, 0, 991 "man_linkstale_retries", MAN_LINKSTALE_RETRIES); 992 993 manp->man_dr_delay = ddi_getprop(DDI_DEV_T_ANY, dip, 0, 994 "man_dr_delay", MAN_DR_DELAY); 995 996 manp->man_dr_retries = ddi_getprop(DDI_DEV_T_ANY, dip, 0, 997 "man_dr_retries", MAN_DR_RETRIES); 998 999 manp->man_kstat_waittime = ddi_getprop(DDI_DEV_T_ANY, dip, 0, 1000 "man_kstat_waittime", MAN_KSTAT_WAITTIME); 1001 1002 manp->man_dlpireset_time = ddi_getprop(DDI_DEV_T_ANY, dip, 0, 1003 "man_dlpireset_time", MAN_DLPIRESET_TIME); 1004 1005 if (ddi_create_internal_pathname(dip, MAN_IDNAME, S_IFCHR, 1006 ddi_get_instance(dip)) == DDI_SUCCESS) { 1007 minor_node_created = 1; 1008 } else { 1009 cmn_err(CE_WARN, "man_attach: failed for instance %d", 1010 ddi_get_instance(dip)); 1011 goto exit; 1012 } 1013 1014 if (ddi_create_minor_node(dip, MAN_IDNAME, S_IFCHR, 1015 ddi_get_instance(dip), DDI_NT_NET, CLONE_DEV) == DDI_SUCCESS) { 1016 minor_node_created = 1; 1017 } else { 1018 cmn_err(CE_WARN, "man_attach: failed for instance %d", 1019 ddi_get_instance(dip)); 1020 goto exit; 1021 } 1022 1023 /* 1024 * Allocate meta kstat_t for this instance of the driver. 1025 * Note that each of man_path_t keeps track of the kstats 1026 * for the real devices via mp_last_knp. 1027 */ 1028 #ifdef kstat 1029 flag |= KSTAT_FLAG_PERSISTENT; 1030 #endif 1031 ksp = kstat_create(MAN_IDNAME, ddi_get_instance(dip), NULL, "net", 1032 KSTAT_TYPE_NAMED, MAN_NUMSTATS, flag); 1033 1034 if (ksp == NULL) { 1035 cmn_err(CE_WARN, "man_attach(%d): kstat_create failed" 1036 " - manp(0x%p)", manp->man_meta_ppa, 1037 (void *)manp); 1038 goto exit; 1039 } 1040 1041 man_kstat_named_init(ksp->ks_data, MAN_NUMSTATS); 1042 ksp->ks_update = man_kstat_update; 1043 ksp->ks_private = (void *) manp; 1044 manp->man_ksp = ksp; 1045 kstat_install(manp->man_ksp); 1046 1047 ddi_report_dev(dip); 1048 1049 MAN_DBG(MAN_INIT, ("man_attach(%d) returns DDI_SUCCESS", 1050 ddi_get_instance(dip))); 1051 1052 return (DDI_SUCCESS); 1053 1054 exit: 1055 if (minor_node_created) 1056 ddi_remove_minor_node(dip, NULL); 1057 ddi_set_driver_private(dip, NULL); 1058 ddi_soft_state_free(man_softstate, instance); 1059 1060 MAN_DBG(MAN_INIT, ("man_attach(%d) eaddr returns DDI_FAILIRE", 1061 ddi_get_instance(dip))); 1062 1063 return (DDI_FAILURE); 1064 1065 } 1066 1067 static int 1068 man_get_our_etheraddr(eaddr_t *eap) 1069 { 1070 manc_t manc; 1071 int status = 0; 1072 1073 if (man_is_on_domain) { 1074 if (status = man_get_iosram(&manc)) 1075 return (status); 1076 ether_copy(&manc.manc_dom_eaddr, eap); 1077 } else { 1078 (void) localetheraddr((struct ether_addr *)NULL, eap); 1079 } 1080 1081 return (status); 1082 } 1083 1084 /* 1085 * man_detach - detach an instance of a driver 1086 * 1087 * dip - devinfo of node 1088 * cmd - one of DDI_DETACH | DDI_SUSPEND 1089 * 1090 * returns - success - DDI_SUCCESS 1091 * - failure - DDI_FAILURE 1092 */ 1093 static int 1094 man_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 1095 { 1096 register man_t *manp; /* per instance data */ 1097 int instance; 1098 1099 MAN_DBG(MAN_INIT, ("man_detach(%d):\n", ddi_get_instance(dip))); 1100 1101 if (cmd != DDI_DETACH) { 1102 MAN_DBG(MAN_INIT, ("man_detach: bad command %d\n", cmd)); 1103 return (DDI_FAILURE); 1104 } 1105 1106 if (dip == NULL) { 1107 MAN_DBG(MAN_INIT, ("man_detach: dip == NULL\n")); 1108 return (DDI_FAILURE); 1109 } 1110 1111 instance = ddi_get_instance(dip); 1112 1113 mutex_enter(&man_lock); 1114 1115 manp = (man_t *)ddi_get_soft_state(man_softstate, instance); 1116 if (manp == NULL) { 1117 mutex_exit(&man_lock); 1118 1119 cmn_err(CE_WARN, "man_detach: unable to get softstate" 1120 " for instance = %d, dip = 0x%p!\n", instance, 1121 (void *)dip); 1122 return (DDI_FAILURE); 1123 } 1124 1125 if (manp->man_refcnt != 0) { 1126 mutex_exit(&man_lock); 1127 1128 cmn_err(CE_WARN, "man_detach: %s%d refcnt %d", MAN_IDNAME, 1129 instance, manp->man_refcnt); 1130 MAN_DBGCALL(MAN_INIT, man_print_man(manp)); 1131 1132 return (DDI_FAILURE); 1133 } 1134 1135 ddi_remove_minor_node(dip, NULL); 1136 1137 mutex_exit(&man_lock); 1138 1139 kstat_delete(manp->man_ksp); 1140 ddi_soft_state_free(man_softstate, instance); 1141 ddi_set_driver_private(dip, NULL); 1142 1143 MAN_DBG(MAN_INIT, ("man_detach returns DDI_SUCCESS")); 1144 1145 return (DDI_SUCCESS); 1146 } 1147 1148 /* 1149 * man_info: 1150 * As a standard DLPI style-2, man_info() should always return 1151 * DDI_FAILURE. 1152 * 1153 * However, man_open() has special treatment for a direct open 1154 * via kstr_open() without going through the CLONE driver. 1155 * To make this special kstr_open() work, we need to map 1156 * minor of 0 to instance 0. 1157 */ 1158 /*ARGSUSED*/ 1159 static int 1160 man_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 1161 { 1162 minor_t minor; 1163 1164 switch (infocmd) { 1165 case DDI_INFO_DEVT2DEVINFO: 1166 break; 1167 1168 case DDI_INFO_DEVT2INSTANCE: 1169 minor = getminor((dev_t)arg); 1170 if (minor == 0) { 1171 *result = (void *)(uintptr_t)minor; 1172 return (DDI_SUCCESS); 1173 } 1174 break; 1175 default: 1176 break; 1177 } 1178 return (DDI_FAILURE); 1179 } 1180 1181 /* Standard Device Driver entry points */ 1182 1183 /* 1184 * man_open - open the device 1185 * 1186 * rq - upper read queue of the stream 1187 * devp - pointer to a device number 1188 * flag - information passed from the user program open(2) system call 1189 * sflag - stream flags 1190 * credp - pointer to the cred(9S) user credential structure 1191 * 1192 * returns - success - 0 1193 * - failure - errno value for failure 1194 */ 1195 /*ARGSUSED*/ 1196 static int 1197 man_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp) 1198 { 1199 int minordev = -1; 1200 manstr_t *msp; 1201 manstr_t *tsp; 1202 manstr_t **prevmsp; 1203 int status = 0; 1204 1205 MAN_DBG(MAN_OCLOSE, ("man_open: rq(0x%p) sflag(0x%x)\n", 1206 (void *)rq, sflag)); 1207 1208 ASSERT(rq); 1209 ASSERT(sflag != MODOPEN); 1210 1211 /* 1212 * reopen; q_ptr set to msp at open completion. 1213 */ 1214 if (rq->q_ptr) { 1215 return (0); 1216 } 1217 1218 /* 1219 * Allocate and initialize manstr_t for this device. 1220 */ 1221 msp = man_kzalloc(sizeof (manstr_t), KM_SLEEP); 1222 SETSTATE(msp, DL_UNATTACHED); 1223 msp->ms_meta_ppa = -1; 1224 msp->ms_rq = rq; 1225 rq->q_ptr = WR(rq)->q_ptr = msp; 1226 1227 /* 1228 * Get the MAN driver configured on 1st open. Note that the only way 1229 * we get sflag != CLONEOPEN is via the call in man_plumbctl(). All 1230 * CLONEOPEN calls to man_open will be via the file system 1231 * device node /dev/man, a pseudo clone device. 1232 */ 1233 1234 qprocson(rq); 1235 1236 if (sflag == CLONEOPEN && man_config_state != MAN_CONFIGURED) { 1237 /* 1238 * First open calls man_configure. Everyone qwaits until 1239 * we get it open. See man_open_ctl() comments for mutex 1240 * lock/synchronization info. 1241 */ 1242 1243 mutex_enter(&man_lock); 1244 1245 if (man_config_state == MAN_UNCONFIGURED) { 1246 man_config_state = MAN_CONFIGURING; 1247 mutex_exit(&man_lock); 1248 status = man_configure(rq); 1249 if (status != 0) 1250 goto exit; 1251 } else { 1252 while (man_config_state == MAN_CONFIGURING) { 1253 1254 mutex_exit(&man_lock); 1255 status = qwait_sig(rq); 1256 1257 if (status == 0) { 1258 status = EINTR; 1259 goto exit; 1260 } 1261 1262 mutex_enter(&man_lock); 1263 } 1264 mutex_exit(&man_lock); 1265 1266 if (man_config_error) { 1267 status = man_config_error; 1268 goto exit; 1269 } 1270 } 1271 } 1272 1273 /* 1274 * Determine minor device number. man_open serialized by 1275 * D_MTPERMOD. 1276 */ 1277 prevmsp = &man_strup; 1278 if (sflag == CLONEOPEN) { 1279 1280 minordev = 0; 1281 for (; (tsp = *prevmsp) != NULL; prevmsp = &tsp->ms_next) { 1282 if (minordev < tsp->ms_minor) 1283 break; 1284 minordev++; 1285 } 1286 *devp = makedevice(getmajor(*devp), minordev); 1287 1288 } else { 1289 /* 1290 * Should only get here from man_plumbctl(). 1291 */ 1292 /*LINTED E_ASSIGN_UINT_TO_SIGNED_INT*/ 1293 minordev = getminor(*devp); 1294 1295 /* 1296 * No need to protect this here as all opens are 1297 * qwaiting, and the bgthread (who is doing this open) 1298 * is the only one who mucks with this variable. 1299 */ 1300 man_ctl_wq = WR(rq); 1301 1302 ASSERT(minordev == 0); /* TBD delete this */ 1303 } 1304 1305 msp->ms_meta_maj = getmajor(*devp); 1306 msp->ms_minor = minordev; 1307 if (minordev == 0) 1308 msp->ms_flags = MAN_SFLAG_CONTROL; 1309 1310 /* 1311 * Link new entry into global list of active entries. 1312 */ 1313 msp->ms_next = *prevmsp; 1314 *prevmsp = msp; 1315 1316 1317 /* 1318 * Disable automatic enabling of our write service procedure. 1319 * We control this explicitly. 1320 */ 1321 noenable(WR(rq)); 1322 1323 exit: 1324 MAN_DBG(MAN_OCLOSE, ("man_open: exit rq(0x%p) minor %d errno %d\n", 1325 (void *)rq, minordev, status)); 1326 1327 /* 1328 * Clean up on error. 1329 */ 1330 if (status) { 1331 qprocsoff(rq); 1332 rq->q_ptr = WR(rq)->q_ptr = NULL; 1333 man_kfree((char *)msp, sizeof (manstr_t)); 1334 } else 1335 (void) qassociate(rq, -1); 1336 1337 return (status); 1338 } 1339 1340 /* 1341 * Get the driver configured. Called from first man_open with exclusive 1342 * inner perimeter. 1343 */ 1344 static int 1345 man_configure(queue_t *rq) 1346 { 1347 man_work_t *wp; 1348 int status = 0; 1349 1350 MAN_DBG(MAN_CONFIG, ("man_configure:")); 1351 1352 /* 1353 * Initialize NDD parameters. 1354 */ 1355 if (!man_ndlist && 1356 !man_param_register(man_param_arr, A_CNT(man_param_arr))) { 1357 cmn_err(CE_WARN, "man_configure: man_param_register failed!"); 1358 man_config_error = ENOMEM; 1359 goto exit; 1360 } 1361 1362 mutex_enter(&man_lock); 1363 1364 /* 1365 * Start up background thread. 1366 */ 1367 if (man_bwork_id == NULL) 1368 man_bwork_id = thread_create(NULL, 2 * DEFAULTSTKSZ, 1369 man_bwork, NULL, 0, &p0, TS_RUN, minclsyspri); 1370 1371 /* 1372 * Submit work to get control stream opened. Qwait until its 1373 * done. See man_open_ctl for mutex lock/synchronization info. 1374 */ 1375 1376 if (man_ctl_lh == NULL) { 1377 wp = man_work_alloc(MAN_WORK_OPEN_CTL, KM_SLEEP); 1378 wp->mw_flags |= MAN_WFLAGS_QWAITER; 1379 wp->mw_q = WR(rq); 1380 1381 /* 1382 * Submit work and wait. When man_open_ctl exits 1383 * man_open, it will cause qwait below to return. 1384 */ 1385 man_work_add(man_bwork_q, wp); 1386 while (!(wp->mw_flags & MAN_WFLAGS_DONE)) { 1387 mutex_exit(&man_lock); 1388 qwait(rq); 1389 mutex_enter(&man_lock); 1390 } 1391 status = wp->mw_status; 1392 man_work_free(wp); 1393 1394 } 1395 mutex_exit(&man_lock); 1396 1397 /* 1398 * If on domain, setup IOSRAM and build the pathgroups 1399 * automatically. 1400 */ 1401 if ((status == 0) && man_is_on_domain) 1402 status = man_domain_configure(); 1403 1404 exit: 1405 mutex_enter(&man_lock); 1406 1407 man_config_error = status; 1408 if (status != 0) 1409 man_config_state = MAN_UNCONFIGURED; 1410 else 1411 man_config_state = MAN_CONFIGURED; 1412 1413 mutex_exit(&man_lock); 1414 1415 MAN_DBG(MAN_CONFIG, ("man_configure: returns %d\n", status)); 1416 1417 return (status); 1418 } 1419 1420 /* 1421 * man_close - close the device 1422 * 1423 * rq - upper read queue of the stream 1424 * 1425 * returns - success - 0 1426 * - failure - errno value for failure 1427 */ 1428 static int 1429 man_close(queue_t *rq) 1430 { 1431 manstr_t *close_msp; 1432 manstr_t *msp; 1433 1434 MAN_DBG(MAN_OCLOSE, ("man_close: rq(0x%p)\n", (void *)rq)); 1435 1436 qprocsoff(rq); 1437 close_msp = (manstr_t *)rq->q_ptr; 1438 1439 /* 1440 * Unlink the per-Stream entry from the active list and free it. 1441 */ 1442 if (close_msp == man_strup) 1443 man_strup = close_msp->ms_next; 1444 else { 1445 for (msp = man_strup; msp && msp->ms_next != close_msp; ) 1446 msp = msp->ms_next; 1447 1448 if (msp == NULL) { 1449 cmn_err(CE_WARN, "man_close: no stream!"); 1450 return (ENODEV); 1451 } 1452 1453 msp->ms_next = close_msp->ms_next; 1454 } 1455 1456 if (close_msp->ms_dests != NULL) { 1457 /* 1458 * Still DL_ATTACHED 1459 */ 1460 man_work_t *wp; 1461 1462 wp = man_work_alloc(MAN_WORK_CLOSE_STREAM, KM_SLEEP); 1463 man_dodetach(close_msp, wp); 1464 } 1465 1466 if (close_msp->ms_flags & MAN_SFLAG_CONTROL) { 1467 /* 1468 * Driver about to unload. 1469 */ 1470 man_ctl_wq = NULL; 1471 } 1472 1473 rq->q_ptr = WR(rq)->q_ptr = NULL; 1474 man_kfree((char *)close_msp, sizeof (manstr_t)); 1475 (void) qassociate(rq, -1); 1476 1477 MAN_DBG(MAN_OCLOSE, ("man_close: exit\n")); 1478 1479 return (0); 1480 } 1481 1482 /* 1483 * Ask bgthread to tear down lower stream and qwait 1484 * until its done. 1485 */ 1486 static void 1487 man_dodetach(manstr_t *msp, man_work_t *wp) 1488 { 1489 man_dest_t *mdp; 1490 int i; 1491 mblk_t *mp; 1492 1493 mdp = msp->ms_dests; 1494 msp->ms_dests = NULL; 1495 msp->ms_destp = NULL; 1496 1497 /* 1498 * Excise lower dests array, set it closing and hand it to 1499 * background thread to dispose of. 1500 */ 1501 for (i = 0; i < MAN_MAX_DESTS; i++) { 1502 1503 mdp[i].md_state |= MAN_DSTATE_CLOSING; 1504 mdp[i].md_msp = NULL; 1505 mdp[i].md_rq = NULL; 1506 1507 if (mdp[i].md_lc_timer_id != 0) { 1508 (void) quntimeout(man_ctl_wq, mdp[i].md_lc_timer_id); 1509 mdp[i].md_lc_timer_id = 0; 1510 } 1511 if (mdp[i].md_bc_id != 0) { 1512 qunbufcall(man_ctl_wq, mdp[i].md_bc_id); 1513 mdp[i].md_bc_id = 0; 1514 } 1515 1516 mutex_enter(&mdp[i].md_lock); 1517 while ((mp = mdp[i].md_dmp_head) != NULL) { 1518 mdp[i].md_dmp_head = mp->b_next; 1519 mp->b_next = NULL; 1520 freemsg(mp); 1521 } 1522 mdp[i].md_dmp_count = 0; 1523 mdp[i].md_dmp_tail = NULL; 1524 mutex_exit(&mdp[i].md_lock); 1525 } 1526 1527 /* 1528 * Dump any DL type messages previously caught. 1529 */ 1530 man_dl_clean(&msp->ms_dl_mp); 1531 man_dl_clean(&msp->ms_dlioc_mp); 1532 1533 /* 1534 * We need to clear fast path flag when dlioc messages are cleaned. 1535 */ 1536 msp->ms_flags &= ~MAN_SFLAG_FAST; 1537 1538 /* 1539 * MAN_WORK_CLOSE_STREAM work request preallocated by caller. 1540 */ 1541 ASSERT(wp->mw_type == MAN_WORK_CLOSE_STREAM); 1542 ASSERT(mdp != NULL); 1543 wp->mw_arg.a_mdp = mdp; 1544 wp->mw_arg.a_ndests = MAN_MAX_DESTS; 1545 wp->mw_arg.a_pg_id = -1; /* Don't care */ 1546 1547 mutex_enter(&man_lock); 1548 man_work_add(man_bwork_q, wp); 1549 msp->ms_manp->man_refcnt--; 1550 mutex_exit(&man_lock); 1551 1552 msp->ms_manp = NULL; 1553 1554 } 1555 1556 1557 /* 1558 * man_uwput - handle DLPI messages issued from upstream, the write 1559 * side of the upper half of multiplexor. Called with shared access to 1560 * the inner perimeter. 1561 * 1562 * wq - upper write queue of mxx 1563 * mp - mblk ptr to DLPI request 1564 */ 1565 static int 1566 man_uwput(register queue_t *wq, register mblk_t *mp) 1567 { 1568 register manstr_t *msp; /* per stream data */ 1569 register man_t *manp; /* per instance data */ 1570 1571 msp = (manstr_t *)wq->q_ptr; 1572 1573 MAN_DBG(MAN_UWPUT, ("man_uwput: wq(0x%p) mp(0x%p) db_type(0x%x)" 1574 " msp(0x%p)\n", 1575 (void *)wq, (void *)mp, DB_TYPE(mp), (void *)msp)); 1576 #if DEBUG 1577 if (man_debug & MAN_UWPUT) { 1578 if (DB_TYPE(mp) == M_IOCTL) { 1579 struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 1580 MAN_DBG(MAN_UWPUT, 1581 ("man_uwput: M_IOCTL ioc_cmd(0x%x)\n", 1582 iocp->ioc_cmd)); 1583 } else if (DB_TYPE(mp) == M_CTL) { 1584 struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 1585 MAN_DBG(MAN_UWPUT, 1586 ("man_uwput: M_CTL ioc_cmd(0x%x)\n", 1587 iocp->ioc_cmd)); 1588 } 1589 } 1590 #endif /* DEBUG */ 1591 1592 1593 switch (DB_TYPE(mp)) { 1594 case M_DATA: 1595 manp = msp->ms_manp; 1596 1597 if (((msp->ms_flags & (MAN_SFLAG_FAST | MAN_SFLAG_RAW)) == 0) || 1598 (msp->ms_dlpistate != DL_IDLE) || 1599 (manp == NULL)) { 1600 1601 merror(wq, mp, EPROTO); 1602 break; 1603 } 1604 1605 if (wq->q_first) { 1606 (void) putq(wq, mp); 1607 qenable(wq); 1608 } else { 1609 ehdr_t *ep = (ehdr_t *)mp->b_rptr; 1610 1611 (void) man_start(wq, mp, &ep->ether_dhost); 1612 } 1613 break; 1614 1615 case M_PROTO: 1616 case M_PCPROTO: 1617 if ((DL_PRIM(mp) == DL_UNITDATA_IND) && !wq->q_first) { 1618 (void) man_udreq(wq, mp); 1619 } else { 1620 (void) putq(wq, mp); 1621 qenable(wq); 1622 } 1623 break; 1624 1625 case M_IOCTL: 1626 case M_IOCDATA: 1627 qwriter(wq, mp, man_ioctl, PERIM_INNER); 1628 break; 1629 1630 case M_CTL: 1631 freemsg(mp); 1632 break; 1633 1634 case M_FLUSH: 1635 MAN_DBG(MAN_UWPUT, ("man_wput: M_FLUSH\n")); 1636 if (*mp->b_rptr & FLUSHW) 1637 flushq(wq, FLUSHDATA); 1638 if (*mp->b_rptr & FLUSHR) { 1639 flushq(RD(wq), FLUSHDATA); 1640 *mp->b_rptr &= ~FLUSHW; 1641 qreply(wq, mp); 1642 } else { 1643 freemsg(mp); 1644 } 1645 break; 1646 1647 default: 1648 MAN_DBG(MAN_WARN, 1649 ("man_uwput: illegal mblk(0x%p) type(0x%x)\n", 1650 (void *)mp, DB_TYPE(mp))); 1651 freemsg(mp); 1652 break; 1653 } /* End switch */ 1654 1655 MAN_DBG(MAN_UWPUT, ("man_uwput: exit wq(0x%p) mp(0x%p)\n", 1656 (void *)wq, (void *)mp)); 1657 1658 return (0); 1659 } 1660 1661 /* 1662 * man_start - handle data messages issued from upstream. Send down 1663 * to particular man_dest based on ether_addr, otherwise send out to all 1664 * valid man_dests. 1665 * 1666 * wq - upper write queue of mxx 1667 * mp - mblk ptr to DLPI request 1668 * caller - Caller ID for decision making on canput failure 1669 * 1670 * Returns: 1671 * 0 - Data xmitted or No flow control situation detected. 1672 * 1 - Flow control situation detected. 1673 * 1674 * STREAMS Flow Control: can be used if there is only one destination 1675 * for a stream (1 to 1 multiplexor). In this case, we will use the upper 1676 * write queue to store mblks when in flow control. If there are multiple 1677 * destinations, we cannot use the STREAMs based flow control (1 to many 1678 * multiplexor). In this case, we will use the lower write queue to store 1679 * mblks when in flow control. Since destinations come and go, we may 1680 * transition between 1-to-1 and 1-to-m. So it may be the case that we have 1681 * some mblks stored on the upper queue, and some on the lower queue. However, 1682 * we will never send mblks out of order. See man_uwput and man_start_lower(). 1683 * 1684 * A simple flow control mechanism is implemented for the deferred mblk list, 1685 * as this list is expected to be used temporarily for a very short 1686 * period required for switching paths. This flow control mechanism is 1687 * used only as a defensive approach to avoid infinite growth of this list. 1688 */ 1689 static int 1690 man_start(register queue_t *wq, register mblk_t *mp, eaddr_t *eap) 1691 { 1692 register manstr_t *msp; /* per stream data */ 1693 register man_dest_t *mdp = NULL; /* destination */ 1694 mblk_t *tmp; 1695 int i; 1696 int status = 0; 1697 1698 msp = (manstr_t *)wq->q_ptr; 1699 1700 MAN_DBG(MAN_DATA, ("man_start: msp(0x%p) ether_addr(%s)\n", 1701 (void *)msp, ether_sprintf(eap))); 1702 1703 if (msp->ms_dests == NULL) { 1704 cmn_err(CE_WARN, "man_start: no destinations"); 1705 freemsg(mp); 1706 return (0); 1707 } 1708 1709 /* 1710 * Optimization if only one valid destination. 1711 */ 1712 mdp = msp->ms_destp; 1713 1714 if (IS_UNICAST(eap)) { 1715 queue_t *flow_wq = NULL; 1716 1717 if (mdp == NULL) { 1718 /* 1719 * TDB - This needs to be optimized (some bits in 1720 * ehp->dhost will act as an index. 1721 */ 1722 for (i = 0; i < MAN_MAX_DESTS; i++) { 1723 1724 mdp = &msp->ms_dests[i]; 1725 1726 if ((mdp->md_state == MAN_DSTATE_READY) && 1727 (ether_cmp(eap, &mdp->md_dst_eaddr) == 0)) 1728 break; 1729 mdp = NULL; 1730 } 1731 } else { 1732 /* 1733 * 1 to 1 multiplexing, use upper wq for flow control. 1734 */ 1735 flow_wq = wq; 1736 } 1737 1738 if (mdp != NULL) { 1739 /* 1740 * Its going somewhere specific 1741 */ 1742 status = man_start_lower(mdp, mp, flow_wq, MAN_UPPER); 1743 1744 } else { 1745 MAN_DBG(MAN_DATA, ("man_start: no destination" 1746 " for eaddr %s\n", ether_sprintf(eap))); 1747 freemsg(mp); 1748 } 1749 } else { 1750 /* 1751 * Broadcast or multicast - send everone a copy. 1752 */ 1753 if (mdp == NULL) { 1754 for (i = 0; i < MAN_MAX_DESTS; i++) { 1755 mdp = &msp->ms_dests[i]; 1756 1757 if (mdp->md_state != MAN_DSTATE_READY) 1758 continue; 1759 1760 if ((tmp = copymsg(mp)) != NULL) { 1761 (void) man_start_lower(mdp, tmp, 1762 NULL, MAN_UPPER); 1763 } else { 1764 MAN_DBG(MAN_DATA, ("man_start: copymsg" 1765 " failed!")); 1766 } 1767 } 1768 freemsg(mp); 1769 } else { 1770 if (mdp->md_state == MAN_DSTATE_READY) 1771 status = man_start_lower(mdp, mp, wq, 1772 MAN_UPPER); 1773 else 1774 freemsg(mp); 1775 } 1776 } 1777 return (status); 1778 } 1779 1780 /* 1781 * Send a DL_UNITDATA or M_DATA fastpath data mblk to a particular 1782 * destination. Others mblk types sent down via * man_dlpi_senddown(). 1783 * 1784 * Returns: 1785 * 0 - Data xmitted 1786 * 1 - Data not xmitted due to flow control. 1787 */ 1788 static int 1789 man_start_lower(man_dest_t *mdp, mblk_t *mp, queue_t *flow_wq, int caller) 1790 { 1791 queue_t *wq = mdp->md_wq; 1792 int status = 0; 1793 1794 /* 1795 * Lower stream ready for data transmit. 1796 */ 1797 if (mdp->md_state == MAN_DSTATE_READY && 1798 mdp->md_dlpistate == DL_IDLE) { 1799 1800 ASSERT(mdp->md_wq != NULL); 1801 1802 if (caller == MAN_UPPER) { 1803 /* 1804 * Check for flow control conditions for lower 1805 * stream. 1806 */ 1807 if (mdp->md_dmp_head == NULL && 1808 wq->q_first == NULL && canputnext(wq)) { 1809 1810 (void) putnext(wq, mp); 1811 1812 } else { 1813 mutex_enter(&mdp->md_lock); 1814 if (mdp->md_dmp_head != NULL) { 1815 /* 1816 * A simple flow control mechanism. 1817 */ 1818 if (mdp->md_dmp_count >= MAN_HIWAT) { 1819 freemsg(mp); 1820 } else { 1821 /* 1822 * Add 'mp' to the deferred 1823 * msg list. 1824 */ 1825 mdp->md_dmp_tail->b_next = mp; 1826 mdp->md_dmp_tail = mp; 1827 mdp->md_dmp_count += 1828 msgsize(mp); 1829 } 1830 mutex_exit(&mdp->md_lock); 1831 /* 1832 * Inform flow control situation 1833 * to the caller. 1834 */ 1835 status = 1; 1836 qenable(wq); 1837 goto exit; 1838 } 1839 mutex_exit(&mdp->md_lock); 1840 /* 1841 * If 1 to 1 mux, use upper write queue for 1842 * flow control. 1843 */ 1844 if (flow_wq != NULL) { 1845 /* 1846 * putbq() message and indicate 1847 * flow control situation to the 1848 * caller. 1849 */ 1850 putbq(flow_wq, mp); 1851 qenable(flow_wq); 1852 status = 1; 1853 goto exit; 1854 } 1855 /* 1856 * 1 to many mux, use lower write queue for 1857 * flow control. Be mindful not to overflow 1858 * the lower MAN STREAM q. 1859 */ 1860 if (canput(wq)) { 1861 (void) putq(wq, mp); 1862 qenable(wq); 1863 } else { 1864 MAN_DBG(MAN_DATA, ("man_start_lower:" 1865 " lower q flow controlled -" 1866 " discarding packet")); 1867 freemsg(mp); 1868 goto exit; 1869 } 1870 } 1871 1872 } else { 1873 /* 1874 * man_lwsrv is draining flow controlled mblks. 1875 */ 1876 if (canputnext(wq)) 1877 (void) putnext(wq, mp); 1878 else 1879 status = 1; 1880 } 1881 goto exit; 1882 } 1883 1884 /* 1885 * Lower stream in transition, do flow control. 1886 */ 1887 status = 1; 1888 1889 if (mdp->md_state == MAN_DSTATE_NOTPRESENT) { 1890 nodest: 1891 cmn_err(CE_WARN, 1892 "man_start_lower: no dest for mdp(0x%p), caller(%d)!", 1893 (void *)mdp, caller); 1894 if (caller == MAN_UPPER) 1895 freemsg(mp); 1896 goto exit; 1897 } 1898 1899 if (mdp->md_state & MAN_DSTATE_CLOSING) { 1900 MAN_DBG(MAN_DATA, ("man_start_lower: mdp(0x%p) closing", 1901 (void *)mdp)); 1902 if (caller == MAN_UPPER) 1903 freemsg(mp); 1904 goto exit; 1905 } 1906 1907 if ((mdp->md_state & MAN_DSTATE_PLUMBING) || 1908 (mdp->md_state == MAN_DSTATE_INITIALIZING) || 1909 (mdp->md_dlpistate != DL_IDLE)) { 1910 /* 1911 * Defer until PLUMBED and DL_IDLE. See man_lwsrv(). 1912 */ 1913 if (caller == MAN_UPPER) { 1914 /* 1915 * Upper stream sending data down, add to defered mblk 1916 * list for stream. 1917 */ 1918 mutex_enter(&mdp->md_lock); 1919 if (mdp->md_dmp_count >= MAN_HIWAT) { 1920 freemsg(mp); 1921 } else { 1922 if (mdp->md_dmp_head == NULL) { 1923 ASSERT(mdp->md_dmp_tail == NULL); 1924 mdp->md_dmp_head = mp; 1925 mdp->md_dmp_tail = mp; 1926 } else { 1927 mdp->md_dmp_tail->b_next = mp; 1928 mdp->md_dmp_tail = mp; 1929 } 1930 mdp->md_dmp_count += msgsize(mp); 1931 } 1932 mutex_exit(&mdp->md_lock); 1933 } 1934 1935 goto exit; 1936 } 1937 1938 exit: 1939 return (status); 1940 } 1941 1942 /* 1943 * man_ioctl - handle ioctl requests for this driver (I_PLINK/I_PUNLINK) 1944 * or pass thru to the physical driver below. Note that most M_IOCTLs we 1945 * care about come down the control msp, but the IOC ones come down the IP. 1946 * Called with exclusive inner perimeter. 1947 * 1948 * wq - upper write queue of mxx 1949 * mp - mblk ptr to DLPI ioctl request 1950 */ 1951 static void 1952 man_ioctl(register queue_t *wq, register mblk_t *mp) 1953 { 1954 manstr_t *msp; 1955 struct iocblk *iocp; 1956 1957 iocp = (struct iocblk *)mp->b_rptr; 1958 msp = (manstr_t *)wq->q_ptr; 1959 1960 #ifdef DEBUG 1961 { 1962 char ioc_cmd[30]; 1963 1964 sprintf(ioc_cmd, "not handled IOCTL 0x%x", iocp->ioc_cmd); 1965 MAN_DBG((MAN_SWITCH | MAN_PATH | MAN_DLPI), 1966 ("man_ioctl: wq(0x%p) mp(0x%p) cmd(%s)\n", 1967 (void *)wq, (void *)mp, 1968 (iocp->ioc_cmd == I_PLINK) ? "I_PLINK" : 1969 (iocp->ioc_cmd == I_PUNLINK) ? "I_PUNLINK" : 1970 (iocp->ioc_cmd == MAN_SETPATH) ? "MAN_SETPATH" : 1971 (iocp->ioc_cmd == DL_IOC_HDR_INFO) ? "DL_IOC_HDR_INFO" : 1972 (iocp->ioc_cmd == DLIOCRAW) ? "DLIOCRAW" : ioc_cmd)); 1973 } 1974 #endif /* DEBUG */ 1975 1976 1977 /* 1978 * Handle the requests... 1979 */ 1980 switch ((unsigned int)iocp->ioc_cmd) { 1981 1982 case I_PLINK: 1983 man_plink(wq, mp); 1984 break; 1985 1986 case I_PUNLINK: 1987 man_unplink(wq, mp); 1988 break; 1989 1990 case MAN_SETPATH: 1991 man_setpath(wq, mp); 1992 break; 1993 1994 case MAN_GETEADDR: 1995 man_geteaddr(wq, mp); 1996 break; 1997 1998 case MAN_SET_LINKCHECK_TIME: 1999 man_set_linkcheck_time(wq, mp); 2000 break; 2001 2002 case MAN_SET_SC_IPADDRS: 2003 man_set_sc_ipaddrs(wq, mp); 2004 break; 2005 2006 case MAN_SET_SC_IP6ADDRS: 2007 man_set_sc_ip6addrs(wq, mp); 2008 break; 2009 2010 case DLIOCRAW: 2011 if (man_dlioc(msp, mp)) 2012 miocnak(wq, mp, 0, ENOMEM); 2013 else { 2014 msp->ms_flags |= MAN_SFLAG_RAW; 2015 miocack(wq, mp, 0, 0); 2016 } 2017 break; 2018 2019 case DL_IOC_HDR_INFO: 2020 man_dl_ioc_hdr_info(wq, mp); 2021 break; 2022 2023 case MAN_ND_GET: 2024 case MAN_ND_SET: 2025 man_nd_getset(wq, mp); 2026 break; 2027 2028 default: 2029 MAN_DBG(MAN_DDI, ("man_ioctl: unknown ioc_cmd %d\n", 2030 (unsigned int)iocp->ioc_cmd)); 2031 miocnak(wq, mp, 0, EINVAL); 2032 break; 2033 } 2034 exit: 2035 MAN_DBG((MAN_SWITCH | MAN_PATH | MAN_DLPI), ("man_ioctl: exit\n")); 2036 2037 } 2038 2039 /* 2040 * man_plink: handle I_PLINK requests on the control stream 2041 */ 2042 void 2043 man_plink(queue_t *wq, mblk_t *mp) 2044 { 2045 struct linkblk *linkp; 2046 man_linkrec_t *lrp; 2047 int status = 0; 2048 2049 linkp = (struct linkblk *)mp->b_cont->b_rptr; 2050 2051 /* 2052 * Create a record to hold lower stream info. man_plumb will 2053 * retrieve it after calling ldi_ioctl(I_PLINK) 2054 */ 2055 lrp = man_kzalloc(sizeof (man_linkrec_t), KM_NOSLEEP); 2056 if (lrp == NULL) { 2057 status = ENOMEM; 2058 goto exit; 2059 } 2060 2061 lrp->l_muxid = linkp->l_index; 2062 lrp->l_wq = linkp->l_qbot; 2063 lrp->l_rq = RD(linkp->l_qbot); 2064 2065 man_linkrec_insert(lrp); 2066 2067 exit: 2068 if (status) 2069 miocnak(wq, mp, 0, status); 2070 else 2071 miocack(wq, mp, 0, 0); 2072 2073 } 2074 2075 /* 2076 * man_unplink - handle I_PUNLINK requests on the control stream 2077 */ 2078 void 2079 man_unplink(queue_t *wq, mblk_t *mp) 2080 { 2081 struct linkblk *linkp; 2082 2083 linkp = (struct linkblk *)mp->b_cont->b_rptr; 2084 RD(linkp->l_qbot)->q_ptr = NULL; 2085 WR(linkp->l_qbot)->q_ptr = NULL; 2086 miocack(wq, mp, 0, 0); 2087 } 2088 2089 void 2090 man_linkrec_insert(man_linkrec_t *lrp) 2091 { 2092 mutex_enter(&man_lock); 2093 2094 lrp->l_next = man_linkrec_head; 2095 man_linkrec_head = lrp; 2096 2097 mutex_exit(&man_lock); 2098 2099 } 2100 2101 static queue_t * 2102 man_linkrec_find(int muxid) 2103 { 2104 man_linkrec_t *lpp; 2105 man_linkrec_t *lp; 2106 queue_t *wq = NULL; 2107 2108 mutex_enter(&man_lock); 2109 2110 if (man_linkrec_head == NULL) 2111 goto exit; 2112 2113 lp = lpp = man_linkrec_head; 2114 if (lpp->l_muxid == muxid) { 2115 man_linkrec_head = lpp->l_next; 2116 } else { 2117 for (lp = lpp->l_next; lp; lp = lp->l_next) { 2118 if (lp->l_muxid == muxid) 2119 break; 2120 lpp = lp; 2121 } 2122 } 2123 2124 if (lp == NULL) 2125 goto exit; 2126 2127 wq = lp->l_wq; 2128 ASSERT(wq != NULL); 2129 2130 lpp->l_next = lp->l_next; 2131 man_kfree(lp, sizeof (man_linkrec_t)); 2132 2133 exit: 2134 mutex_exit(&man_lock); 2135 2136 return (wq); 2137 } 2138 2139 /* 2140 * Set instance linkcheck timer value. 2141 */ 2142 static void 2143 man_set_linkcheck_time(queue_t *wq, mblk_t *mp) 2144 { 2145 mi_time_t *mtp; 2146 int error; 2147 man_t *manp; 2148 2149 MAN_DBG(MAN_LINK, ("man_set_linkcheck_time: enter")); 2150 2151 error = miocpullup(mp, sizeof (mi_time_t)); 2152 if (error != 0) 2153 goto exit; 2154 2155 mtp = (mi_time_t *)mp->b_cont->b_rptr; 2156 2157 MAN_DBG(MAN_LINK, ("man_set_linkcheck_time: mtp")); 2158 MAN_DBGCALL(MAN_LINK, man_print_mtp(mtp)); 2159 2160 manp = ddi_get_soft_state(man_softstate, mtp->mtp_man_ppa); 2161 if (manp == NULL) { 2162 error = ENODEV; 2163 goto exit; 2164 } 2165 2166 manp->man_linkcheck_time = mtp->mtp_time; 2167 exit: 2168 if (error) 2169 miocnak(wq, mp, 0, error); 2170 else 2171 miocack(wq, mp, sizeof (mi_time_t), 0); 2172 } 2173 2174 /* 2175 * Man path ioctl processing. Should only happen on the SSC. Called 2176 * with exclusive inner perimeter. 2177 */ 2178 static void 2179 man_setpath(queue_t *wq, mblk_t *mp) 2180 { 2181 mi_path_t *mip; 2182 int error; 2183 2184 error = miocpullup(mp, sizeof (mi_path_t)); 2185 if (error != 0) 2186 goto exit; 2187 2188 mip = (mi_path_t *)mp->b_cont->b_rptr; 2189 mutex_enter(&man_lock); 2190 error = man_pg_cmd(mip, NULL); 2191 mutex_exit(&man_lock); 2192 2193 exit: 2194 if (error) 2195 miocnak(wq, mp, 0, error); 2196 else 2197 miocack(wq, mp, sizeof (mi_path_t), 0); 2198 } 2199 2200 /* 2201 * Get the local ethernet address of this machine. 2202 */ 2203 static void 2204 man_geteaddr(queue_t *wq, mblk_t *mp) 2205 { 2206 eaddr_t *eap; 2207 int error; 2208 2209 error = miocpullup(mp, sizeof (eaddr_t)); 2210 if (error != 0) { 2211 miocnak(wq, mp, 0, error); 2212 return; 2213 } 2214 2215 eap = (eaddr_t *)mp->b_cont->b_rptr; 2216 (void) localetheraddr(NULL, eap); 2217 miocack(wq, mp, sizeof (eaddr_t), 0); 2218 } 2219 2220 /* 2221 * Set my SC and other SC IPv4 addresses for use in man_pinger routine. 2222 */ 2223 static void 2224 man_set_sc_ipaddrs(queue_t *wq, mblk_t *mp) 2225 { 2226 int error; 2227 2228 error = miocpullup(mp, sizeof (man_sc_ipaddrs_t)); 2229 if (error != 0) 2230 goto exit; 2231 2232 man_sc_ipaddrs = *(man_sc_ipaddrs_t *)mp->b_cont->b_rptr; 2233 2234 #ifdef DEBUG 2235 { 2236 char buf[INET_ADDRSTRLEN]; 2237 2238 (void) inet_ntop(AF_INET, 2239 (void *) &man_sc_ipaddrs.ip_other_sc_ipaddr, 2240 buf, INET_ADDRSTRLEN); 2241 MAN_DBG(MAN_CONFIG, ("ip_other_sc_ipaddr = %s", buf)); 2242 (void) inet_ntop(AF_INET, 2243 (void *) &man_sc_ipaddrs.ip_my_sc_ipaddr, 2244 buf, INET_ADDRSTRLEN); 2245 MAN_DBG(MAN_CONFIG, ("ip_my_sc_ipaddr = %s", buf)); 2246 } 2247 #endif /* DEBUG */ 2248 exit: 2249 if (error) 2250 miocnak(wq, mp, 0, error); 2251 else 2252 miocack(wq, mp, sizeof (man_sc_ipaddrs_t), 0); 2253 } 2254 2255 /* 2256 * Set my SC and other SC IPv6 addresses for use in man_pinger routine. 2257 */ 2258 static void 2259 man_set_sc_ip6addrs(queue_t *wq, mblk_t *mp) 2260 { 2261 int error; 2262 2263 error = miocpullup(mp, sizeof (man_sc_ip6addrs_t)); 2264 if (error != 0) 2265 goto exit; 2266 2267 man_sc_ip6addrs = *(man_sc_ip6addrs_t *)mp->b_cont->b_rptr; 2268 2269 #ifdef DEBUG 2270 { 2271 char buf[INET6_ADDRSTRLEN]; 2272 2273 (void) inet_ntop(AF_INET6, 2274 (void *) &man_sc_ip6addrs.ip6_other_sc_ipaddr, 2275 buf, INET6_ADDRSTRLEN); 2276 MAN_DBG(MAN_CONFIG, ("ip6_other_sc_ipaddr = %s", buf)); 2277 (void) inet_ntop(AF_INET6, 2278 (void *) &man_sc_ip6addrs.ip6_my_sc_ipaddr, 2279 buf, INET6_ADDRSTRLEN); 2280 MAN_DBG(MAN_CONFIG, ("ip6_my_sc_ipaddr = %s", buf)); 2281 } 2282 #endif /* DEBUG */ 2283 exit: 2284 if (error) 2285 miocnak(wq, mp, 0, error); 2286 else 2287 miocack(wq, mp, sizeof (man_sc_ip6addrs_t), 0); 2288 } 2289 2290 /* 2291 * M_DATA fastpath info request. 2292 */ 2293 static void 2294 man_dl_ioc_hdr_info(queue_t *wq, mblk_t *mp) 2295 { 2296 manstr_t *msp; 2297 man_t *manp; 2298 mblk_t *nmp; 2299 man_dladdr_t *dlap; 2300 dl_unitdata_req_t *dludp; 2301 struct ether_header *headerp; 2302 t_uscalar_t off, len; 2303 int status = 0; 2304 2305 MAN_DBG(MAN_DLPI, ("man_dl_ioc_hdr_info: enter")); 2306 2307 msp = (manstr_t *)wq->q_ptr; 2308 manp = msp->ms_manp; 2309 if (manp == NULL) { 2310 status = EINVAL; 2311 goto exit; 2312 } 2313 2314 status = miocpullup(mp, sizeof (dl_unitdata_req_t) + MAN_ADDRL); 2315 if (status != 0) 2316 goto exit; 2317 2318 /* 2319 * Sanity check the DL_UNITDATA_REQ destination address 2320 * offset and length values. 2321 */ 2322 dludp = (dl_unitdata_req_t *)mp->b_cont->b_rptr; 2323 off = dludp->dl_dest_addr_offset; 2324 len = dludp->dl_dest_addr_length; 2325 if (dludp->dl_primitive != DL_UNITDATA_REQ || 2326 !MBLKIN(mp->b_cont, off, len) || len != MAN_ADDRL) { 2327 status = EINVAL; 2328 goto exit; 2329 } 2330 2331 dlap = (man_dladdr_t *)(mp->b_cont->b_rptr + off); 2332 2333 /* 2334 * Allocate a new mblk to hold the ether header. 2335 */ 2336 if ((nmp = allocb(ETHERHEADER_SIZE, BPRI_MED)) == NULL) { 2337 status = ENOMEM; 2338 goto exit; 2339 } 2340 2341 /* We only need one dl_ioc_hdr mblk for replay */ 2342 if (!(msp->ms_flags & MAN_SFLAG_FAST)) 2343 status = man_dl_catch(&msp->ms_dlioc_mp, mp); 2344 2345 /* Forward the packet to all lower destinations. */ 2346 if ((status != 0) || ((status = man_dlpi_senddown(msp, mp)) != 0)) { 2347 freemsg(nmp); 2348 goto exit; 2349 } 2350 2351 nmp->b_wptr += ETHERHEADER_SIZE; 2352 2353 /* 2354 * Fill in the ether header. 2355 */ 2356 headerp = (struct ether_header *)nmp->b_rptr; 2357 ether_copy(&dlap->dl_phys, &headerp->ether_dhost); 2358 ether_copy(&manp->man_eaddr, &headerp->ether_shost); 2359 put_ether_type(headerp, dlap->dl_sap); 2360 2361 /* 2362 * Link new mblk in after the "request" mblks. 2363 */ 2364 linkb(mp, nmp); 2365 2366 exit: 2367 MAN_DBG(MAN_DLPI, ("man_dl_ioc_hdr_info: returns, status = %d", 2368 status)); 2369 2370 if (status) { 2371 miocnak(wq, mp, 0, status); 2372 } else { 2373 msp = (manstr_t *)wq->q_ptr; 2374 msp->ms_flags |= MAN_SFLAG_FAST; 2375 miocack(wq, mp, msgsize(mp->b_cont), 0); 2376 } 2377 2378 } 2379 2380 /* 2381 * man_uwsrv - Upper write queue service routine to handle deferred 2382 * DLPI messages issued from upstream, the write side of the upper half 2383 * of multiplexor. It is also used by man_bwork to switch the lower 2384 * multiplexor. 2385 * 2386 * wq - upper write queue of mxx 2387 */ 2388 static int 2389 man_uwsrv(queue_t *wq) 2390 { 2391 register mblk_t *mp; 2392 manstr_t *msp; /* per stream data */ 2393 man_t *manp; /* per instance data */ 2394 ehdr_t *ep; 2395 int status; 2396 2397 msp = (manstr_t *)wq->q_ptr; 2398 2399 MAN_DBG(MAN_UWSRV, ("man_uwsrv: wq(0x%p) msp", (void *)wq)); 2400 MAN_DBGCALL(MAN_UWSRV, man_print_msp(msp)); 2401 2402 if (msp == NULL) 2403 goto done; 2404 2405 manp = msp->ms_manp; 2406 2407 while (mp = getq(wq)) { 2408 2409 switch (DB_TYPE(mp)) { 2410 /* 2411 * Can probably remove this as I never put data messages 2412 * here. 2413 */ 2414 case M_DATA: 2415 if (manp) { 2416 ep = (ehdr_t *)mp->b_rptr; 2417 status = man_start(wq, mp, &ep->ether_dhost); 2418 if (status) { 2419 /* 2420 * man_start() indicated flow control 2421 * situation, stop processing now. 2422 */ 2423 goto break_loop; 2424 } 2425 } else 2426 freemsg(mp); 2427 break; 2428 2429 case M_PROTO: 2430 case M_PCPROTO: 2431 status = man_proto(wq, mp); 2432 if (status) { 2433 /* 2434 * man_proto() indicated flow control 2435 * situation detected by man_start(), 2436 * stop processing now. 2437 */ 2438 goto break_loop; 2439 } 2440 break; 2441 2442 default: 2443 MAN_DBG(MAN_UWSRV, ("man_uwsrv: discarding mp(0x%p)", 2444 (void *)mp)); 2445 freemsg(mp); 2446 break; 2447 } 2448 } 2449 2450 break_loop: 2451 /* 2452 * Check to see if bgthread wants us to do something inside the 2453 * perimeter. 2454 */ 2455 if ((msp->ms_flags & MAN_SFLAG_CONTROL) && 2456 man_iwork_q->q_work != NULL) { 2457 2458 man_iwork(); 2459 } 2460 2461 done: 2462 2463 MAN_DBG(MAN_UWSRV, ("man_uwsrv: returns")); 2464 2465 return (0); 2466 } 2467 2468 2469 /* 2470 * man_proto - handle DLPI protocol requests issued from upstream. 2471 * Called by man_uwsrv(). We disassociate upper and lower multiplexor 2472 * DLPI state transitions. The upper stream here (manstr_t) transitions 2473 * appropriately, saves the DLPI requests via man_dlpi(), and then 2474 * arranges for the DLPI request to be sent down via man_dlpi_senddown() if 2475 * appropriate. 2476 * 2477 * wq - upper write queue of mxx 2478 * mp - mbl ptr to protocol request 2479 */ 2480 static int 2481 man_proto(queue_t *wq, mblk_t *mp) 2482 { 2483 union DL_primitives *dlp; 2484 int flow_status = 0; 2485 2486 dlp = (union DL_primitives *)mp->b_rptr; 2487 2488 MAN_DBG((MAN_UWSRV | MAN_DLPI), 2489 ("man_proto: mp(0x%p) prim(%s)\n", (void *)mp, 2490 dps[dlp->dl_primitive])); 2491 2492 switch (dlp->dl_primitive) { 2493 case DL_UNITDATA_REQ: 2494 flow_status = man_udreq(wq, mp); 2495 break; 2496 2497 case DL_ATTACH_REQ: 2498 man_areq(wq, mp); 2499 break; 2500 2501 case DL_DETACH_REQ: 2502 man_dreq(wq, mp); 2503 break; 2504 2505 case DL_BIND_REQ: 2506 man_breq(wq, mp); 2507 break; 2508 2509 case DL_UNBIND_REQ: 2510 man_ubreq(wq, mp); 2511 break; 2512 2513 case DL_INFO_REQ: 2514 man_ireq(wq, mp); 2515 break; 2516 2517 case DL_PROMISCON_REQ: 2518 man_ponreq(wq, mp); 2519 break; 2520 2521 case DL_PROMISCOFF_REQ: 2522 man_poffreq(wq, mp); 2523 break; 2524 2525 case DL_ENABMULTI_REQ: 2526 man_emreq(wq, mp); 2527 break; 2528 2529 case DL_DISABMULTI_REQ: 2530 man_dmreq(wq, mp); 2531 break; 2532 2533 case DL_PHYS_ADDR_REQ: 2534 man_pareq(wq, mp); 2535 break; 2536 2537 case DL_SET_PHYS_ADDR_REQ: 2538 man_spareq(wq, mp); 2539 break; 2540 2541 default: 2542 MAN_DBG((MAN_UWSRV | MAN_DLPI), ("man_proto: prim(%d)\n", 2543 dlp->dl_primitive)); 2544 dlerrorack(wq, mp, dlp->dl_primitive, DL_UNSUPPORTED, 0); 2545 break; 2546 2547 } /* End switch */ 2548 2549 MAN_DBG((MAN_UWSRV | MAN_DLPI), ("man_proto: exit\n")); 2550 return (flow_status); 2551 2552 } 2553 2554 static int 2555 man_udreq(queue_t *wq, mblk_t *mp) 2556 { 2557 manstr_t *msp; 2558 dl_unitdata_req_t *dludp; 2559 mblk_t *nmp; 2560 man_dladdr_t *dlap; 2561 t_uscalar_t off, len; 2562 int flow_status = 0; 2563 2564 msp = (manstr_t *)wq->q_ptr; 2565 2566 2567 if (msp->ms_dlpistate != DL_IDLE) { 2568 dlerrorack(wq, mp, DL_UNITDATA_REQ, DL_OUTSTATE, 0); 2569 return (flow_status); 2570 } 2571 dludp = (dl_unitdata_req_t *)mp->b_rptr; 2572 off = dludp->dl_dest_addr_offset; 2573 len = dludp->dl_dest_addr_length; 2574 2575 /* 2576 * Validate destination address format. 2577 */ 2578 if (!MBLKIN(mp, off, len) || (len != MAN_ADDRL)) { 2579 dluderrorind(wq, mp, mp->b_rptr + off, len, DL_BADADDR, 0); 2580 return (flow_status); 2581 } 2582 2583 /* 2584 * Error if no M_DATA follows. 2585 */ 2586 nmp = mp->b_cont; 2587 if (nmp == NULL) { 2588 dluderrorind(wq, mp, mp->b_rptr + off, len, DL_BADDATA, 0); 2589 return (flow_status); 2590 } 2591 2592 dlap = (man_dladdr_t *)(mp->b_rptr + off); 2593 2594 flow_status = man_start(wq, mp, &dlap->dl_phys); 2595 return (flow_status); 2596 } 2597 2598 /* 2599 * Handle DL_ATTACH_REQ. 2600 */ 2601 static void 2602 man_areq(queue_t *wq, mblk_t *mp) 2603 { 2604 man_t *manp; /* per instance data */ 2605 manstr_t *msp; /* per stream data */ 2606 short ppa; 2607 union DL_primitives *dlp; 2608 mblk_t *preq = NULL; 2609 int did_refcnt = FALSE; 2610 int dlerror = 0; 2611 int status = 0; 2612 2613 msp = (manstr_t *)wq->q_ptr; 2614 dlp = (union DL_primitives *)mp->b_rptr; 2615 2616 /* 2617 * Attach us to MAN PPA (device instance). 2618 */ 2619 if (MBLKL(mp) < DL_ATTACH_REQ_SIZE) { 2620 dlerror = DL_BADPRIM; 2621 goto exit; 2622 } 2623 2624 if (msp->ms_dlpistate != DL_UNATTACHED) { 2625 dlerror = DL_OUTSTATE; 2626 goto exit; 2627 } 2628 2629 ppa = dlp->attach_req.dl_ppa; 2630 if (ppa == -1 || qassociate(wq, ppa) != 0) { 2631 dlerror = DL_BADPPA; 2632 MAN_DBG(MAN_WARN, ("man_areq: bad PPA %d", ppa)); 2633 goto exit; 2634 } 2635 2636 mutex_enter(&man_lock); 2637 manp = ddi_get_soft_state(man_softstate, ppa); 2638 ASSERT(manp != NULL); /* qassociate() succeeded */ 2639 2640 manp->man_refcnt++; 2641 did_refcnt = TRUE; 2642 mutex_exit(&man_lock); 2643 2644 /* 2645 * Create a DL replay list for the lower stream. These wont 2646 * actually be sent down until the lower streams are made active 2647 * (sometime after the call to man_init_dests below). 2648 */ 2649 preq = man_alloc_physreq_mp(&manp->man_eaddr); 2650 if (preq == NULL) { 2651 dlerror = DL_SYSERR; 2652 status = ENOMEM; 2653 goto exit; 2654 } 2655 2656 /* 2657 * Make copy for dlpi resync of upper and lower streams. 2658 */ 2659 if (man_dlpi(msp, mp)) { 2660 dlerror = DL_SYSERR; 2661 status = ENOMEM; 2662 goto exit; 2663 } 2664 2665 /* TBD - need to clean off ATTACH req on failure here. */ 2666 if (man_dlpi(msp, preq)) { 2667 dlerror = DL_SYSERR; 2668 status = ENOMEM; 2669 goto exit; 2670 } 2671 2672 /* 2673 * man_init_dests/man_start_dest needs these set before call. 2674 */ 2675 msp->ms_manp = manp; 2676 msp->ms_meta_ppa = ppa; 2677 2678 /* 2679 * Allocate and init lower destination structures. 2680 */ 2681 ASSERT(msp->ms_dests == NULL); 2682 if (man_init_dests(manp, msp)) { 2683 mblk_t *tmp; 2684 2685 /* 2686 * If we cant get the lower streams ready, then 2687 * remove the messages from the DL replay list and 2688 * fail attach. 2689 */ 2690 while ((tmp = msp->ms_dl_mp) != NULL) { 2691 msp->ms_dl_mp = msp->ms_dl_mp->b_next; 2692 tmp->b_next = tmp->b_prev = NULL; 2693 freemsg(tmp); 2694 } 2695 2696 msp->ms_manp = NULL; 2697 msp->ms_meta_ppa = -1; 2698 2699 dlerror = DL_SYSERR; 2700 status = ENOMEM; 2701 goto exit; 2702 } 2703 2704 MAN_DBG(MAN_DLPI, ("man_areq: ppa 0x%x man_refcnt: %d\n", 2705 ppa, manp->man_refcnt)); 2706 2707 SETSTATE(msp, DL_UNBOUND); 2708 2709 exit: 2710 if (dlerror == 0) { 2711 dlokack(wq, mp, DL_ATTACH_REQ); 2712 } else { 2713 if (did_refcnt) { 2714 mutex_enter(&man_lock); 2715 manp->man_refcnt--; 2716 mutex_exit(&man_lock); 2717 } 2718 dlerrorack(wq, mp, DL_ATTACH_REQ, dlerror, status); 2719 (void) qassociate(wq, -1); 2720 } 2721 if (preq != NULL) 2722 freemsg(preq); 2723 2724 } 2725 2726 /* 2727 * Called at DL_ATTACH time. 2728 * Man_lock is held to protect pathgroup list(man_pg). 2729 */ 2730 static int 2731 man_init_dests(man_t *manp, manstr_t *msp) 2732 { 2733 man_dest_t *mdp; 2734 man_pg_t *mpg; 2735 int i; 2736 2737 mdp = man_kzalloc(MAN_DEST_ARRAY_SIZE, KM_NOSLEEP); 2738 if (mdp == NULL) 2739 return (ENOMEM); 2740 2741 msp->ms_dests = mdp; 2742 2743 mutex_enter(&man_lock); 2744 for (i = 0; i < MAN_MAX_DESTS; i++) { 2745 2746 mdp[i].md_muxid = -1; /* muxid 0 is valid */ 2747 mutex_init(&mdp->md_lock, NULL, MUTEX_DRIVER, NULL); 2748 2749 mpg = man_find_pg_by_id(manp->man_pg, i); 2750 2751 if (mpg && man_find_active_path(mpg->mpg_pathp)) 2752 man_start_dest(&mdp[i], msp, mpg); 2753 } 2754 mutex_exit(&man_lock); 2755 2756 return (0); 2757 } 2758 2759 /* 2760 * Get a destination ready for use. 2761 */ 2762 static void 2763 man_start_dest(man_dest_t *mdp, manstr_t *msp, man_pg_t *mpg) 2764 { 2765 man_path_t *ap; 2766 2767 mdp->md_muxid = -1; 2768 mdp->md_dlpistate = DL_UNATTACHED; 2769 mdp->md_msp = msp; 2770 mdp->md_rq = msp->ms_rq; 2771 mdp->md_pg_id = mpg->mpg_pg_id; 2772 2773 ASSERT(msp->ms_manp); 2774 2775 ether_copy(&msp->ms_manp->man_eaddr, &mdp->md_src_eaddr); 2776 ether_copy(&mpg->mpg_dst_eaddr, &mdp->md_dst_eaddr); 2777 2778 ap = man_find_active_path(mpg->mpg_pathp); 2779 ASSERT(ap); 2780 mdp->md_device = ap->mp_device; 2781 2782 /* 2783 * Set up linktimers so that first time through, we will do 2784 * a failover. 2785 */ 2786 mdp->md_linkstate = MAN_LINKFAIL; 2787 mdp->md_state = MAN_DSTATE_INITIALIZING; 2788 mdp->md_lc_timer_id = qtimeout(man_ctl_wq, man_linkcheck_timer, 2789 (void *)mdp, man_gettimer(MAN_TIMER_INIT, mdp)); 2790 2791 /* 2792 * As an optimization, if there is only one destination, 2793 * remember the destination pointer. Used by man_start(). 2794 */ 2795 man_set_optimized_dest(msp); 2796 2797 MAN_DBG(MAN_DEST, ("man_start_dest: mdp")); 2798 MAN_DBGCALL(MAN_DEST, man_print_mdp(mdp)); 2799 } 2800 2801 static void 2802 man_set_optimized_dest(manstr_t *msp) 2803 { 2804 int count = 0; 2805 int i; 2806 man_dest_t *mdp = NULL; 2807 2808 for (i = 0; i < MAN_MAX_DESTS; i++) { 2809 if (msp->ms_dests[i].md_msp != NULL) { 2810 count++; 2811 mdp = &msp->ms_dests[i]; 2812 } 2813 } 2814 2815 if (count == 1) 2816 msp->ms_destp = mdp; 2817 else 2818 msp->ms_destp = NULL; 2819 2820 } 2821 2822 /* 2823 * Catch dlpi message for replaying, and arrange to send it down 2824 * to any destinations not PLUMBING. See man_dlpi_replay(). 2825 */ 2826 static int 2827 man_dlpi(manstr_t *msp, mblk_t *mp) 2828 { 2829 int status; 2830 2831 status = man_dl_catch(&msp->ms_dl_mp, mp); 2832 if (status == 0) 2833 status = man_dlpi_senddown(msp, mp); 2834 2835 return (status); 2836 } 2837 2838 /* 2839 * Catch IOCTL type DL_ messages. 2840 */ 2841 static int 2842 man_dlioc(manstr_t *msp, mblk_t *mp) 2843 { 2844 int status; 2845 2846 status = man_dl_catch(&msp->ms_dlioc_mp, mp); 2847 if (status == 0) 2848 status = man_dlpi_senddown(msp, mp); 2849 2850 return (status); 2851 } 2852 2853 /* 2854 * We catch all DLPI messages that we have to resend to a new AP'ed 2855 * device to put him in the right state. We link these messages together 2856 * w/ their b_next fields and hang it off of msp->ms_dl_mp. We 2857 * must be careful to restore b_next fields before doing dupmsg/freemsg! 2858 * 2859 * msp - pointer of stream struct to process 2860 * mblk - pointer to DLPI request to catch 2861 */ 2862 static int 2863 man_dl_catch(mblk_t **mplist, mblk_t *mp) 2864 { 2865 mblk_t *dupmp; 2866 mblk_t *tmp; 2867 unsigned prim; 2868 int status = 0; 2869 2870 dupmp = copymsg(mp); 2871 if (dupmp == NULL) { 2872 status = ENOMEM; 2873 goto exit; 2874 } 2875 2876 2877 if (*mplist == NULL) 2878 *mplist = dupmp; 2879 else { 2880 for (tmp = *mplist; tmp->b_next; ) 2881 tmp = tmp->b_next; 2882 2883 tmp->b_next = dupmp; 2884 } 2885 2886 prim = DL_PRIM(mp); 2887 MAN_DBG(MAN_DLPI, 2888 ("man_dl_catch: adding %s\n", 2889 (prim == DL_IOC_HDR_INFO) ? "DL_IOC_HDR_INFO" : 2890 (prim == DLIOCRAW) ? "DLIOCRAW" : 2891 (prim == DL_PROMISCON_REQ) ? promisc[DL_PROMISCON_TYPE(mp)] : 2892 dps[prim])); 2893 2894 exit: 2895 2896 return (status); 2897 } 2898 2899 /* 2900 * Send down a single DLPI M_[PC]PROTO to all currently valid dests. 2901 * 2902 * msp - ptr to NDM stream structure DL_ messages was received on. 2903 * mp - ptr to mblk containing DL_ request. 2904 */ 2905 static int 2906 man_dlpi_senddown(manstr_t *msp, mblk_t *mp) 2907 { 2908 man_dest_t *mdp; 2909 int i; 2910 mblk_t *rmp[MAN_MAX_DESTS]; /* Copy to replay */ 2911 int dstate[MAN_MAX_DESTS]; 2912 int no_dests = TRUE; 2913 int status = 0; 2914 2915 if (msp->ms_dests == NULL) 2916 goto exit; 2917 2918 for (i = 0; i < MAN_MAX_DESTS; i++) { 2919 mdp = &msp->ms_dests[i]; 2920 if (mdp->md_state == MAN_DSTATE_READY) { 2921 dstate[i] = TRUE; 2922 no_dests = FALSE; 2923 } else { 2924 dstate[i] = FALSE; 2925 } 2926 rmp[i] = NULL; 2927 } 2928 2929 if (no_dests) 2930 goto exit; 2931 2932 /* 2933 * Build replay and duplicate list for all possible destinations. 2934 */ 2935 for (i = 0; i < MAN_MAX_DESTS; i++) { 2936 if (dstate[i]) { 2937 rmp[i] = copymsg(mp); 2938 if (rmp[i] == NULL) { 2939 status = ENOMEM; 2940 break; 2941 } 2942 } 2943 } 2944 2945 if (status == 0) { 2946 for (i = 0; i < MAN_MAX_DESTS; i++) 2947 if (dstate[i]) { 2948 mdp = &msp->ms_dests[i]; 2949 2950 ASSERT(mdp->md_wq != NULL); 2951 ASSERT(mp->b_next == NULL); 2952 ASSERT(mp->b_prev == NULL); 2953 2954 man_dlpi_replay(mdp, rmp[i]); 2955 } 2956 } else { 2957 for (; i >= 0; i--) 2958 if (dstate[i] && rmp[i]) 2959 freemsg(rmp[i]); 2960 } 2961 2962 exit: 2963 return (status); 2964 } 2965 2966 /* 2967 * man_dlpi_replay - traverse the list of DLPI requests and reapply them to 2968 * get the upper and lower streams into the same state. Called holding inner 2969 * perimeter lock exclusive. Note thet we defer M_IOCTL type dlpi messages 2970 * until we get an OK_ACK to our ATTACH (see man_lrsrv and 2971 * man_dlioc_replay). 2972 * 2973 * mdp - pointer to lower queue (destination) 2974 * rmp - list of mblks to send down stream. 2975 */ 2976 static void 2977 man_dlpi_replay(man_dest_t *mdp, mblk_t *rmp) 2978 { 2979 mblk_t *mp; 2980 union DL_primitives *dlp = NULL; 2981 2982 MAN_DBG(MAN_DLPI, ("man_dlpi_replay: mdp(0x%p)", (void *)mdp)); 2983 2984 while (rmp) { 2985 mp = rmp; 2986 rmp = rmp->b_next; 2987 mp->b_prev = mp->b_next = NULL; 2988 2989 dlp = (union DL_primitives *)mp->b_rptr; 2990 MAN_DBG(MAN_DLPI, 2991 ("man_dlpi_replay: mdp(0x%p) sending %s\n", 2992 (void *)mdp, 2993 (dlp->dl_primitive == DL_IOC_HDR_INFO) ? 2994 "DL_IOC_HDR_INFO" : (dlp->dl_primitive == DLIOCRAW) ? 2995 "DLIOCRAW" : dps[(unsigned)(dlp->dl_primitive)])); 2996 2997 if (dlp->dl_primitive == DL_ATTACH_REQ) { 2998 /* 2999 * insert the lower devices ppa. 3000 */ 3001 dlp->attach_req.dl_ppa = mdp->md_device.mdev_ppa; 3002 } 3003 3004 (void) putnext(mdp->md_wq, mp); 3005 } 3006 3007 } 3008 3009 static void 3010 man_dreq(queue_t *wq, mblk_t *mp) 3011 { 3012 manstr_t *msp; /* per stream data */ 3013 man_work_t *wp; 3014 3015 msp = (manstr_t *)wq->q_ptr; 3016 3017 if (MBLKL(mp) < DL_DETACH_REQ_SIZE) { 3018 dlerrorack(wq, mp, DL_DETACH_REQ, DL_BADPRIM, 0); 3019 return; 3020 } 3021 3022 if (msp->ms_dlpistate != DL_UNBOUND) { 3023 dlerrorack(wq, mp, DL_DETACH_REQ, DL_OUTSTATE, 0); 3024 return; 3025 } 3026 3027 ASSERT(msp->ms_dests != NULL); 3028 3029 wp = man_work_alloc(MAN_WORK_CLOSE_STREAM, KM_NOSLEEP); 3030 if (wp == NULL) { 3031 dlerrorack(wq, mp, DL_DETACH_REQ, DL_SYSERR, ENOMEM); 3032 return; 3033 } 3034 man_dodetach(msp, wp); 3035 (void) qassociate(wq, -1); 3036 3037 SETSTATE(msp, DL_UNATTACHED); 3038 3039 dlokack(wq, mp, DL_DETACH_REQ); 3040 } 3041 3042 static void 3043 man_dl_clean(mblk_t **mplist) 3044 { 3045 mblk_t *tmp; 3046 3047 /* 3048 * Toss everything. 3049 */ 3050 while ((tmp = *mplist) != NULL) { 3051 *mplist = (*mplist)->b_next; 3052 tmp->b_next = tmp->b_prev = NULL; 3053 freemsg(tmp); 3054 } 3055 3056 } 3057 3058 /* 3059 * man_dl_release - Remove the corresponding DLPI request from the 3060 * catch list. Walk thru the catch list looking for the other half of 3061 * the pair and delete it. If we are detaching, delete the entire list. 3062 * 3063 * msp - pointer of stream struct to process 3064 * mp - pointer to mblk to first half of pair. We will delete other 3065 * half of pair based on this. 3066 */ 3067 static void 3068 man_dl_release(mblk_t **mplist, mblk_t *mp) 3069 { 3070 uchar_t match_dbtype; 3071 mblk_t *tmp; 3072 mblk_t *tmpp; 3073 int matched = FALSE; 3074 3075 if (*mplist == NULL) 3076 goto exit; 3077 3078 match_dbtype = DB_TYPE(mp); 3079 3080 /* 3081 * Currently we only clean DL_ PROTO type messages. There is 3082 * no way to turn off M_CTL or DL_IOC stuff other than sending 3083 * down a DL_DETACH, which resets everything. 3084 */ 3085 if (match_dbtype != M_PROTO && match_dbtype != M_PCPROTO) { 3086 goto exit; 3087 } 3088 3089 /* 3090 * Selectively find a caught mblk that matches this one and 3091 * remove it from the list 3092 */ 3093 tmp = tmpp = *mplist; 3094 matched = man_match_proto(mp, tmp); 3095 if (matched) { 3096 *mplist = tmp->b_next; 3097 tmp->b_next = tmp->b_prev = NULL; 3098 } else { 3099 for (tmp = tmp->b_next; tmp != NULL; tmp = tmp->b_next) { 3100 if (matched = man_match_proto(mp, tmp)) 3101 break; 3102 tmpp = tmp; 3103 } 3104 3105 if (matched) { 3106 tmpp->b_next = tmp->b_next; 3107 tmp->b_next = tmp->b_prev = NULL; 3108 } 3109 } 3110 3111 exit: 3112 if (matched) { 3113 3114 MAN_DBG(MAN_DLPI, ("man_dl_release: release %s", 3115 (DL_PRIM(mp) == DL_IOC_HDR_INFO) ? "DL_IOC_HDR_INFO" : 3116 (DL_PRIM(mp) == DLIOCRAW) ? "DLIOCRAW" : 3117 dps[(int)DL_PRIM(mp)])); 3118 3119 freemsg(tmp); 3120 } 3121 MAN_DBG(MAN_DLPI, ("man_dl_release: returns")); 3122 3123 } 3124 3125 /* 3126 * Compare two DL_ messages. If they are complimentary (e.g. DL_UNBIND 3127 * compliments DL_BIND), return true. 3128 */ 3129 static int 3130 man_match_proto(mblk_t *mp1, mblk_t *mp2) 3131 { 3132 t_uscalar_t prim1; 3133 t_uscalar_t prim2; 3134 int matched = FALSE; 3135 3136 /* 3137 * Primitive to clean off list. 3138 */ 3139 prim1 = DL_PRIM(mp1); 3140 prim2 = DL_PRIM(mp2); 3141 3142 switch (prim1) { 3143 case DL_UNBIND_REQ: 3144 if (prim2 == DL_BIND_REQ) 3145 matched = TRUE; 3146 break; 3147 3148 case DL_PROMISCOFF_REQ: 3149 if (prim2 == DL_PROMISCON_REQ) { 3150 dl_promiscoff_req_t *poff1; 3151 dl_promiscoff_req_t *poff2; 3152 3153 poff1 = (dl_promiscoff_req_t *)mp1->b_rptr; 3154 poff2 = (dl_promiscoff_req_t *)mp2->b_rptr; 3155 3156 if (poff1->dl_level == poff2->dl_level) 3157 matched = TRUE; 3158 } 3159 break; 3160 3161 case DL_DISABMULTI_REQ: 3162 if (prim2 == DL_ENABMULTI_REQ) { 3163 union DL_primitives *dlp; 3164 t_uscalar_t off; 3165 eaddr_t *addrp1; 3166 eaddr_t *addrp2; 3167 3168 dlp = (union DL_primitives *)mp1->b_rptr; 3169 off = dlp->disabmulti_req.dl_addr_offset; 3170 addrp1 = (eaddr_t *)(mp1->b_rptr + off); 3171 3172 dlp = (union DL_primitives *)mp2->b_rptr; 3173 off = dlp->disabmulti_req.dl_addr_offset; 3174 addrp2 = (eaddr_t *)(mp2->b_rptr + off); 3175 3176 if (ether_cmp(addrp1, addrp2) == 0) 3177 matched = 1; 3178 } 3179 break; 3180 3181 default: 3182 break; 3183 } 3184 3185 MAN_DBG(MAN_DLPI, ("man_match_proto returns %d", matched)); 3186 3187 return (matched); 3188 } 3189 3190 /* 3191 * Bind upper stream to a particular SAP. Called with exclusive innerperim 3192 * QPAIR, shared outerperim. 3193 */ 3194 static void 3195 man_breq(queue_t *wq, mblk_t *mp) 3196 { 3197 man_t *manp; /* per instance data */ 3198 manstr_t *msp; /* per stream data */ 3199 union DL_primitives *dlp; 3200 man_dladdr_t man_addr; 3201 t_uscalar_t sap; 3202 t_uscalar_t xidtest; 3203 3204 msp = (manstr_t *)wq->q_ptr; 3205 3206 if (MBLKL(mp) < DL_BIND_REQ_SIZE) { 3207 dlerrorack(wq, mp, DL_BIND_REQ, DL_BADPRIM, 0); 3208 return; 3209 } 3210 3211 if (msp->ms_dlpistate != DL_UNBOUND) { 3212 dlerrorack(wq, mp, DL_BIND_REQ, DL_OUTSTATE, 0); 3213 return; 3214 } 3215 3216 dlp = (union DL_primitives *)mp->b_rptr; 3217 manp = msp->ms_manp; /* valid after attach */ 3218 sap = dlp->bind_req.dl_sap; 3219 xidtest = dlp->bind_req.dl_xidtest_flg; 3220 3221 ASSERT(manp); 3222 3223 if (xidtest) { 3224 dlerrorack(wq, mp, DL_BIND_REQ, DL_NOAUTO, 0); 3225 return; 3226 } 3227 3228 if (sap > ETHERTYPE_MAX) { 3229 dlerrorack(wq, mp, DL_BIND_REQ, DL_BADSAP, 0); 3230 return; 3231 } 3232 3233 if (man_dlpi(msp, mp)) { 3234 dlerrorack(wq, mp, DL_BIND_REQ, DL_SYSERR, ENOMEM); 3235 return; 3236 } 3237 3238 msp->ms_sap = sap; 3239 3240 SETSTATE(msp, DL_IDLE); 3241 3242 man_addr.dl_sap = msp->ms_sap; 3243 ether_copy(&msp->ms_manp->man_eaddr, &man_addr.dl_phys); 3244 3245 dlbindack(wq, mp, msp->ms_sap, &man_addr, MAN_ADDRL, 0, 0); 3246 3247 } 3248 3249 static void 3250 man_ubreq(queue_t *wq, mblk_t *mp) 3251 { 3252 manstr_t *msp; /* per stream data */ 3253 3254 msp = (manstr_t *)wq->q_ptr; 3255 3256 if (MBLKL(mp) < DL_UNBIND_REQ_SIZE) { 3257 dlerrorack(wq, mp, DL_UNBIND_REQ, DL_BADPRIM, 0); 3258 return; 3259 } 3260 3261 if (msp->ms_dlpistate != DL_IDLE) { 3262 dlerrorack(wq, mp, DL_UNBIND_REQ, DL_OUTSTATE, 0); 3263 return; 3264 } 3265 3266 if (man_dlpi_senddown(msp, mp)) { 3267 dlerrorack(wq, mp, DL_UNBIND_REQ, DL_SYSERR, ENOMEM); 3268 return; 3269 } 3270 3271 man_dl_release(&msp->ms_dl_mp, mp); 3272 3273 SETSTATE(msp, DL_UNBOUND); 3274 3275 dlokack(wq, mp, DL_UNBIND_REQ); 3276 3277 } 3278 3279 static void 3280 man_ireq(queue_t *wq, mblk_t *mp) 3281 { 3282 manstr_t *msp; 3283 dl_info_ack_t *dlip; 3284 man_dladdr_t *dlap; 3285 eaddr_t *ep; 3286 size_t size; 3287 3288 msp = (manstr_t *)wq->q_ptr; 3289 3290 if (MBLKL(mp) < DL_INFO_REQ_SIZE) { 3291 dlerrorack(wq, mp, DL_INFO_REQ, DL_BADPRIM, 0); 3292 return; 3293 } 3294 3295 /* Exchange current msg for a DL_INFO_ACK. */ 3296 size = sizeof (dl_info_ack_t) + MAN_ADDRL + ETHERADDRL; 3297 mp = mexchange(wq, mp, size, M_PCPROTO, DL_INFO_ACK); 3298 if (mp == NULL) { 3299 MAN_DBG(MAN_DLPI, ("man_ireq: man_ireq: mp == NULL.")); 3300 return; 3301 } 3302 3303 /* Fill in the DL_INFO_ACK fields and reply. */ 3304 dlip = (dl_info_ack_t *)mp->b_rptr; 3305 *dlip = man_infoack; 3306 dlip->dl_current_state = msp->ms_dlpistate; 3307 dlap = (man_dladdr_t *)(mp->b_rptr + dlip->dl_addr_offset); 3308 dlap->dl_sap = msp->ms_sap; 3309 3310 /* 3311 * If attached, return physical address. 3312 */ 3313 if (msp->ms_manp != NULL) { 3314 ether_copy(&msp->ms_manp->man_eaddr, &dlap->dl_phys); 3315 } else { 3316 bzero((caddr_t)&dlap->dl_phys, ETHERADDRL); 3317 } 3318 3319 ep = (struct ether_addr *)(mp->b_rptr + dlip->dl_brdcst_addr_offset); 3320 ether_copy(ðerbroadcast, ep); 3321 3322 qreply(wq, mp); 3323 3324 } 3325 3326 3327 static void 3328 man_ponreq(queue_t *wq, mblk_t *mp) 3329 { 3330 manstr_t *msp; 3331 int flag; 3332 3333 msp = (manstr_t *)wq->q_ptr; 3334 3335 if (MBLKL(mp) < DL_PROMISCON_REQ_SIZE) { 3336 dlerrorack(wq, mp, DL_PROMISCON_REQ, DL_BADPRIM, 0); 3337 return; 3338 } 3339 3340 switch (((dl_promiscon_req_t *)mp->b_rptr)->dl_level) { 3341 case DL_PROMISC_PHYS: 3342 flag = MAN_SFLAG_ALLPHYS; 3343 break; 3344 3345 case DL_PROMISC_SAP: 3346 flag = MAN_SFLAG_ALLSAP; 3347 break; 3348 3349 case DL_PROMISC_MULTI: 3350 flag = MAN_SFLAG_ALLMULTI; 3351 break; 3352 3353 default: 3354 dlerrorack(wq, mp, DL_PROMISCON_REQ, DL_NOTSUPPORTED, 0); 3355 return; 3356 } 3357 3358 /* 3359 * Catch request for replay, and forward down to any lower 3360 * lower stream. 3361 */ 3362 if (man_dlpi(msp, mp)) { 3363 dlerrorack(wq, mp, DL_PROMISCON_REQ, DL_SYSERR, ENOMEM); 3364 return; 3365 } 3366 3367 msp->ms_flags |= flag; 3368 3369 dlokack(wq, mp, DL_PROMISCON_REQ); 3370 3371 } 3372 3373 static void 3374 man_poffreq(queue_t *wq, mblk_t *mp) 3375 { 3376 manstr_t *msp; 3377 int flag; 3378 3379 msp = (manstr_t *)wq->q_ptr; 3380 3381 if (MBLKL(mp) < DL_PROMISCOFF_REQ_SIZE) { 3382 dlerrorack(wq, mp, DL_PROMISCOFF_REQ, DL_BADPRIM, 0); 3383 return; 3384 } 3385 3386 switch (((dl_promiscoff_req_t *)mp->b_rptr)->dl_level) { 3387 case DL_PROMISC_PHYS: 3388 flag = MAN_SFLAG_ALLPHYS; 3389 break; 3390 3391 case DL_PROMISC_SAP: 3392 flag = MAN_SFLAG_ALLSAP; 3393 break; 3394 3395 case DL_PROMISC_MULTI: 3396 flag = MAN_SFLAG_ALLMULTI; 3397 break; 3398 3399 default: 3400 dlerrorack(wq, mp, DL_PROMISCOFF_REQ, DL_NOTSUPPORTED, 0); 3401 return; 3402 } 3403 3404 if ((msp->ms_flags & flag) == 0) { 3405 dlerrorack(wq, mp, DL_PROMISCOFF_REQ, DL_NOTENAB, 0); 3406 return; 3407 } 3408 3409 if (man_dlpi_senddown(msp, mp)) { 3410 dlerrorack(wq, mp, DL_PROMISCOFF_REQ, DL_SYSERR, ENOMEM); 3411 return; 3412 } 3413 3414 man_dl_release(&msp->ms_dl_mp, mp); 3415 3416 msp->ms_flags &= ~flag; 3417 3418 dlokack(wq, mp, DL_PROMISCOFF_REQ); 3419 3420 } 3421 3422 /* 3423 * Enable multicast requests. We might need to track addresses instead of 3424 * just passing things through (see eri_dmreq) - TBD. 3425 */ 3426 static void 3427 man_emreq(queue_t *wq, mblk_t *mp) 3428 { 3429 manstr_t *msp; 3430 union DL_primitives *dlp; 3431 eaddr_t *addrp; 3432 t_uscalar_t off; 3433 t_uscalar_t len; 3434 3435 msp = (manstr_t *)wq->q_ptr; 3436 3437 if (MBLKL(mp) < DL_ENABMULTI_REQ_SIZE) { 3438 dlerrorack(wq, mp, DL_ENABMULTI_REQ, DL_BADPRIM, 0); 3439 return; 3440 } 3441 3442 if (msp->ms_dlpistate == DL_UNATTACHED) { 3443 dlerrorack(wq, mp, DL_ENABMULTI_REQ, DL_OUTSTATE, 0); 3444 return; 3445 } 3446 3447 dlp = (union DL_primitives *)mp->b_rptr; 3448 len = dlp->enabmulti_req.dl_addr_length; 3449 off = dlp->enabmulti_req.dl_addr_offset; 3450 addrp = (struct ether_addr *)(mp->b_rptr + off); 3451 3452 if ((len != ETHERADDRL) || 3453 !MBLKIN(mp, off, len) || 3454 ((addrp->ether_addr_octet[0] & 01) == 0)) { 3455 dlerrorack(wq, mp, DL_ENABMULTI_REQ, DL_BADADDR, 0); 3456 return; 3457 } 3458 3459 /* 3460 * Catch request for replay, and forward down to any lower 3461 * lower stream. 3462 */ 3463 if (man_dlpi(msp, mp)) { 3464 dlerrorack(wq, mp, DL_ENABMULTI_REQ, DL_SYSERR, ENOMEM); 3465 return; 3466 } 3467 3468 dlokack(wq, mp, DL_ENABMULTI_REQ); 3469 3470 } 3471 3472 static void 3473 man_dmreq(queue_t *wq, mblk_t *mp) 3474 { 3475 manstr_t *msp; 3476 union DL_primitives *dlp; 3477 eaddr_t *addrp; 3478 t_uscalar_t off; 3479 t_uscalar_t len; 3480 3481 msp = (manstr_t *)wq->q_ptr; 3482 3483 if (MBLKL(mp) < DL_DISABMULTI_REQ_SIZE) { 3484 dlerrorack(wq, mp, DL_DISABMULTI_REQ, DL_BADPRIM, 0); 3485 return; 3486 } 3487 3488 if (msp->ms_dlpistate == DL_UNATTACHED) { 3489 dlerrorack(wq, mp, DL_ENABMULTI_REQ, DL_OUTSTATE, 0); 3490 return; 3491 } 3492 3493 dlp = (union DL_primitives *)mp->b_rptr; 3494 len = dlp->enabmulti_req.dl_addr_length; 3495 off = dlp->enabmulti_req.dl_addr_offset; 3496 addrp = (struct ether_addr *)(mp->b_rptr + off); 3497 3498 if ((len != ETHERADDRL) || 3499 !MBLKIN(mp, off, len) || 3500 ((addrp->ether_addr_octet[0] & 01) == 0)) { 3501 dlerrorack(wq, mp, DL_ENABMULTI_REQ, DL_BADADDR, 0); 3502 return; 3503 } 3504 3505 if (man_dlpi_senddown(msp, mp)) { 3506 dlerrorack(wq, mp, DL_ENABMULTI_REQ, DL_SYSERR, ENOMEM); 3507 return; 3508 } 3509 3510 man_dl_release(&msp->ms_dl_mp, mp); 3511 3512 dlokack(wq, mp, DL_DISABMULTI_REQ); 3513 3514 } 3515 3516 static void 3517 man_pareq(queue_t *wq, mblk_t *mp) 3518 { 3519 manstr_t *msp; 3520 union DL_primitives *dlp; 3521 uint32_t type; 3522 struct ether_addr addr; 3523 3524 msp = (manstr_t *)wq->q_ptr; 3525 3526 if (MBLKL(mp) < DL_PHYS_ADDR_REQ_SIZE) { 3527 dlerrorack(wq, mp, DL_PHYS_ADDR_REQ, DL_BADPRIM, 0); 3528 return; 3529 } 3530 3531 dlp = (union DL_primitives *)mp->b_rptr; 3532 type = dlp->physaddr_req.dl_addr_type; 3533 if (msp->ms_manp == NULL) { 3534 dlerrorack(wq, mp, DL_PHYS_ADDR_REQ, DL_OUTSTATE, 0); 3535 return; 3536 } 3537 3538 switch (type) { 3539 case DL_FACT_PHYS_ADDR: 3540 (void) localetheraddr((struct ether_addr *)NULL, &addr); 3541 break; 3542 3543 case DL_CURR_PHYS_ADDR: 3544 ether_bcopy(&msp->ms_manp->man_eaddr, &addr); 3545 break; 3546 3547 default: 3548 dlerrorack(wq, mp, DL_PHYS_ADDR_REQ, DL_NOTSUPPORTED, 0); 3549 return; 3550 } 3551 3552 dlphysaddrack(wq, mp, &addr, ETHERADDRL); 3553 } 3554 3555 /* 3556 * TBD - this routine probably should be protected w/ an ndd 3557 * tuneable, or a man.conf parameter. 3558 */ 3559 static void 3560 man_spareq(queue_t *wq, mblk_t *mp) 3561 { 3562 manstr_t *msp; 3563 union DL_primitives *dlp; 3564 t_uscalar_t off; 3565 t_uscalar_t len; 3566 eaddr_t *addrp; 3567 3568 msp = (manstr_t *)wq->q_ptr; 3569 3570 if (MBLKL(mp) < DL_SET_PHYS_ADDR_REQ_SIZE) { 3571 dlerrorack(wq, mp, DL_SET_PHYS_ADDR_REQ, DL_BADPRIM, 0); 3572 return; 3573 } 3574 3575 dlp = (union DL_primitives *)mp->b_rptr; 3576 len = dlp->set_physaddr_req.dl_addr_length; 3577 off = dlp->set_physaddr_req.dl_addr_offset; 3578 3579 if (!MBLKIN(mp, off, len)) { 3580 dlerrorack(wq, mp, DL_SET_PHYS_ADDR_REQ, DL_BADPRIM, 0); 3581 return; 3582 } 3583 3584 addrp = (struct ether_addr *)(mp->b_rptr + off); 3585 3586 /* 3587 * Error if length of address isn't right or the address 3588 * specified is a multicast or broadcast address. 3589 */ 3590 if ((len != ETHERADDRL) || 3591 ((addrp->ether_addr_octet[0] & 01) == 1) || 3592 (ether_cmp(addrp, ðerbroadcast) == 0)) { 3593 dlerrorack(wq, mp, DL_SET_PHYS_ADDR_REQ, DL_BADADDR, 0); 3594 return; 3595 } 3596 /* 3597 * Error if this stream is not attached to a device. 3598 */ 3599 if (msp->ms_manp == NULL) { 3600 dlerrorack(wq, mp, DL_SET_PHYS_ADDR_REQ, DL_OUTSTATE, 0); 3601 return; 3602 } 3603 3604 /* 3605 * We will also resend DL_SET_PHYS_ADDR_REQ for each dest 3606 * when it is linked under us. 3607 */ 3608 if (man_dlpi_senddown(msp, mp)) { 3609 dlerrorack(wq, mp, DL_SET_PHYS_ADDR_REQ, DL_SYSERR, ENOMEM); 3610 return; 3611 } 3612 3613 ether_copy(addrp, msp->ms_manp->man_eaddr.ether_addr_octet); 3614 3615 MAN_DBG(MAN_DLPI, ("man_sareq: snagged %s\n", 3616 ether_sprintf(&msp->ms_manp->man_eaddr))); 3617 3618 dlokack(wq, mp, DL_SET_PHYS_ADDR_REQ); 3619 3620 } 3621 3622 /* 3623 * These routines make up the lower part of the MAN streams framework. 3624 */ 3625 3626 /* 3627 * man_lwsrv - Deferred mblks for down stream. We end up here when 3628 * the destination is not DL_IDLE when traffic comes downstream. 3629 * 3630 * wq - lower write queue of mxx 3631 */ 3632 static int 3633 man_lwsrv(queue_t *wq) 3634 { 3635 mblk_t *mp; 3636 mblk_t *mlistp; 3637 man_dest_t *mdp; 3638 size_t count; 3639 3640 mdp = (man_dest_t *)wq->q_ptr; 3641 3642 MAN_DBG(MAN_LWSRV, ("man_lwsrv: wq(0x%p) mdp(0x%p)" 3643 " md_rq(0x%p)\n", (void *)wq, (void *)mdp, 3644 mdp ? (void *)mdp->md_rq : NULL)); 3645 3646 if (mdp == NULL) 3647 goto exit; 3648 3649 if (mdp->md_state & MAN_DSTATE_CLOSING) { 3650 flushq(wq, FLUSHDATA); 3651 flushq(RD(wq), FLUSHDATA); 3652 goto exit; 3653 } 3654 3655 /* 3656 * Arrange to send deferred mp's first, then mblks on the 3657 * service queue. Since we are exclusive in the inner perimeter, 3658 * we dont have to worry about md_lock, like the put procedures, 3659 * which are MTPUTSHARED. 3660 */ 3661 mutex_enter(&mdp->md_lock); 3662 mlistp = mdp->md_dmp_head; 3663 mdp->md_dmp_head = NULL; 3664 count = mdp->md_dmp_count; 3665 mdp->md_dmp_count = 0; 3666 mutex_exit(&mdp->md_lock); 3667 3668 while (mlistp != NULL) { 3669 mp = mlistp; 3670 mlistp = mp->b_next; 3671 mp->b_next = NULL; 3672 count -= msgsize(mp); 3673 if (man_start_lower(mdp, mp, NULL, MAN_LOWER)) { 3674 3675 mutex_enter(&mdp->md_lock); 3676 mdp->md_dmp_count += count + msgsize(mp); 3677 mp->b_next = mlistp; 3678 mdp->md_dmp_head = mp; 3679 mutex_exit(&mdp->md_lock); 3680 goto exit; 3681 } 3682 } 3683 mdp->md_dmp_tail = NULL; 3684 3685 while (mp = getq(wq)) { 3686 if (man_start_lower(mdp, mp, NULL, MAN_LOWER)) { 3687 /* 3688 * Put it back on queue, making sure to avoid 3689 * infinite loop mentioned in putbq(9F) 3690 */ 3691 noenable(wq); 3692 putbq(wq, mp); 3693 enableok(wq); 3694 3695 break; 3696 } 3697 } 3698 3699 exit: 3700 3701 return (0); 3702 } 3703 3704 /* 3705 * man_lrput - handle DLPI messages issued from downstream. 3706 * 3707 * rq - lower read queue of mxx 3708 * mp - mblk ptr to DLPI request 3709 * 3710 * returns 0 3711 */ 3712 static int 3713 man_lrput(queue_t *rq, mblk_t *mp) 3714 { 3715 man_dest_t *mdp; 3716 manstr_t *msp; 3717 3718 #if defined(DEBUG) 3719 union DL_primitives *dlp; 3720 t_uscalar_t prim = MAN_DLPI_MAX_PRIM + 1; 3721 char *prim_str; 3722 #endif /* DEBUG */ 3723 3724 mdp = (man_dest_t *)rq->q_ptr; 3725 3726 #if defined(DEBUG) 3727 if (DB_TYPE(mp) == M_PROTO) { 3728 dlp = (union DL_primitives *)mp->b_rptr; 3729 prim = dlp->dl_primitive; 3730 } 3731 3732 prim_str = (prim > MAN_DLPI_MAX_PRIM) ? "NON DLPI" : 3733 (prim == DL_IOC_HDR_INFO) ? "DL_IOC_HDR_INFO" : 3734 (prim == DLIOCRAW) ? "DLIOCRAW" : 3735 dps[(unsigned int)prim]; 3736 MAN_DBG(MAN_LRPUT, ("man_lrput: rq(0x%p) mp(0x%p) mdp(0x%p)" 3737 " db_type(0x%x) dl_prim %s", (void *)rq, 3738 (void *)mp, (void *)mdp, DB_TYPE(mp), prim_str)); 3739 MAN_DBGCALL(MAN_LRPUT2, man_print_mdp(mdp)); 3740 #endif /* DEBUG */ 3741 3742 if (DB_TYPE(mp) == M_FLUSH) { 3743 /* Turn around */ 3744 if (*mp->b_rptr & FLUSHW) { 3745 *mp->b_rptr &= ~FLUSHR; 3746 qreply(rq, mp); 3747 } else 3748 freemsg(mp); 3749 return (0); 3750 } 3751 3752 if (mdp == NULL || mdp->md_state != MAN_DSTATE_READY) { 3753 3754 MAN_DBG(MAN_LRPUT, ("man_lrput: not ready mdp(0x%p)," 3755 " state(%d)", (void *)mdp, mdp ? mdp->md_state : -1)); 3756 freemsg(mp); 3757 return (0); 3758 } 3759 3760 /* 3761 * If we have a destination in the right state, forward on datagrams. 3762 */ 3763 if (MAN_IS_DATA(mp)) { 3764 if (mdp->md_dlpistate == DL_IDLE && canputnext(mdp->md_rq)) { 3765 3766 msp = mdp->md_msp; 3767 if (!(msp->ms_flags & MAN_SFLAG_PROMISC)) 3768 mdp->md_rcvcnt++; /* Count for failover */ 3769 /* 3770 * go put mblk_t directly up to next queue. 3771 */ 3772 MAN_DBG(MAN_LRPUT, ("man_lrput: putnext to rq(0x%p)", 3773 (void *)mdp->md_rq)); 3774 (void) putnext(mdp->md_rq, mp); 3775 } else { 3776 freemsg(mp); 3777 } 3778 } else { 3779 /* 3780 * Handle in man_lrsrv with exclusive inner perimeter lock. 3781 */ 3782 putq(rq, mp); 3783 } 3784 3785 return (0); 3786 } 3787 3788 /* 3789 * Either this is a response from our attempt to sync the upper and lower 3790 * stream states, or its data. If its not data. Do DL_* response processing 3791 * and transition md_dlpistate accordingly. If its data, toss it. 3792 */ 3793 static int 3794 man_lrsrv(queue_t *rq) 3795 { 3796 man_dest_t *mdp; 3797 mblk_t *mp; 3798 union DL_primitives *dlp; 3799 ulong_t prim; 3800 ulong_t cprim; 3801 int need_dl_reset = FALSE; 3802 3803 #if defined(DEBUG) 3804 struct iocblk *iocp; 3805 char ioc_cmd[256]; 3806 #endif /* DEBUG */ 3807 3808 MAN_DBG(MAN_LRSRV, ("man_lrsrv: rq(0x%p)", (void *)rq)); 3809 3810 mdp = (man_dest_t *)rq->q_ptr; 3811 3812 if ((mdp == NULL) || (mdp->md_state & MAN_DSTATE_CLOSING)) { 3813 flushq(rq, FLUSHDATA); 3814 flushq(WR(rq), FLUSHDATA); 3815 goto exit; 3816 } 3817 3818 while (mp = getq(rq)) { 3819 3820 3821 /* 3822 * If we're not connected, or its a datagram, toss it. 3823 */ 3824 if (MAN_IS_DATA(mp) || mdp->md_state != MAN_DSTATE_READY) { 3825 3826 MAN_DBG(MAN_LRSRV, ("man_lrsrv: dropping mblk mdp(0x%p)" 3827 " is_data(%d)", (void *)mdp, MAN_IS_DATA(mp))); 3828 freemsg(mp); 3829 continue; 3830 } 3831 3832 /* 3833 * Should be response to man_dlpi_replay. Discard unless there 3834 * is a failure we care about. 3835 */ 3836 3837 switch (DB_TYPE(mp)) { 3838 case M_PROTO: 3839 case M_PCPROTO: 3840 /* Do proto processing below. */ 3841 break; 3842 3843 case M_IOCNAK: 3844 /* 3845 * DL_IOC* failed for some reason. 3846 */ 3847 need_dl_reset = TRUE; 3848 3849 #if defined(DEBUG) 3850 iocp = (struct iocblk *)mp->b_rptr; 3851 3852 sprintf(ioc_cmd, "0x%x", iocp->ioc_cmd); 3853 MAN_DBG(MAN_LRSRV, ("man_lrsrv: M_IOCNAK err %d for cmd(%s)\n", 3854 iocp->ioc_error, 3855 (iocp->ioc_cmd == DL_IOC_HDR_INFO) ? "DL_IOC_HDR_INFO" : 3856 (iocp->ioc_cmd == DLIOCRAW) ? "DLIOCRAW" : ioc_cmd)); 3857 #endif /* DEBUG */ 3858 3859 /* FALLTHRU */ 3860 3861 case M_IOCACK: 3862 case M_CTL: 3863 /* 3864 * OK response from DL_IOC*, ignore. 3865 */ 3866 goto dl_reset; 3867 } 3868 3869 dlp = (union DL_primitives *)mp->b_rptr; 3870 prim = dlp->dl_primitive; 3871 3872 MAN_DBG(MAN_LRSRV, ("man_lrsrv: prim %s", dps[(int)prim])); 3873 3874 /* 3875 * DLPI state processing big theory: We do not rigorously check 3876 * DLPI states (e.g. PENDING stuff). Simple rules: 3877 * 3878 * 1) If we see an OK_ACK to an ATTACH_REQ, dlpistate = DL_UNBOUND. 3879 * 2) If we see an BIND_ACK to a BIND_REQ, dlpistate = DL_IDLE. 3880 * 3) If we see a OK_ACK response to an UNBIND_REQ 3881 * dlpistate = DL_UNBOUND. 3882 * 4) If we see a OK_ACK response to a DETACH_REQ, 3883 * dlpistate = DL_UNATTACHED. 3884 * 3885 * Everything that isn't handle by 1-4 above is handled by 5) 3886 * 3887 * 5) A NAK to any DL_* messages we care about causes 3888 * dlpistate = DL_UNATTACHED and man_reset_dlpi to run 3889 * 3890 * TBD - need a reset counter so we can try a switch if it gets 3891 * too high. 3892 */ 3893 3894 switch (prim) { 3895 case DL_OK_ACK: 3896 cprim = dlp->ok_ack.dl_correct_primitive; 3897 3898 switch (cprim) { 3899 case DL_ATTACH_REQ: 3900 if (man_dlioc_replay(mdp)) { 3901 D_SETSTATE(mdp, DL_UNBOUND); 3902 } else { 3903 need_dl_reset = TRUE; 3904 break; 3905 } 3906 break; 3907 3908 case DL_DETACH_REQ: 3909 D_SETSTATE(mdp, DL_UNATTACHED); 3910 break; 3911 3912 case DL_UNBIND_REQ: 3913 /* 3914 * Cancel timer and set md_dlpistate. 3915 */ 3916 D_SETSTATE(mdp, DL_UNBOUND); 3917 3918 ASSERT(mdp->md_bc_id == 0); 3919 if (mdp->md_lc_timer_id != 0) { 3920 (void) quntimeout(man_ctl_wq, 3921 mdp->md_lc_timer_id); 3922 mdp->md_lc_timer_id = 0; 3923 } 3924 } 3925 MAN_DBG(MAN_DLPI, 3926 (" cprim %s", dps[(int)cprim])); 3927 break; 3928 3929 case DL_BIND_ACK: 3930 /* 3931 * We're ready for data. Get man_lwsrv to run to 3932 * process any defered data and start linkcheck timer. 3933 */ 3934 D_SETSTATE(mdp, DL_IDLE); 3935 qenable(mdp->md_wq); 3936 mdp->md_linkstate = MAN_LINKGOOD; 3937 if (man_needs_linkcheck(mdp)) { 3938 mdp->md_lc_timer_id = qtimeout(man_ctl_wq, 3939 man_linkcheck_timer, (void *)mdp, 3940 man_gettimer(MAN_TIMER_LINKCHECK, mdp)); 3941 } 3942 3943 break; 3944 3945 case DL_ERROR_ACK: 3946 cprim = dlp->error_ack.dl_error_primitive; 3947 switch (cprim) { 3948 case DL_ATTACH_REQ: 3949 case DL_BIND_REQ: 3950 case DL_DISABMULTI_REQ: 3951 case DL_ENABMULTI_REQ: 3952 case DL_PROMISCON_REQ: 3953 case DL_PROMISCOFF_REQ: 3954 case DL_SET_PHYS_ADDR_REQ: 3955 need_dl_reset = TRUE; 3956 break; 3957 3958 /* 3959 * ignore error TBD (better comment) 3960 */ 3961 case DL_UNBIND_REQ: 3962 case DL_DETACH_REQ: 3963 break; 3964 } 3965 3966 MAN_DBG(MAN_DLPI, 3967 ("\tdl_errno %d dl_unix_errno %d cprim %s", 3968 dlp->error_ack.dl_errno, dlp->error_ack.dl_unix_errno, 3969 dps[(int)cprim])); 3970 break; 3971 3972 case DL_UDERROR_IND: 3973 MAN_DBG(MAN_DLPI, 3974 ("\tdl_errno %d unix_errno %d", 3975 dlp->uderror_ind.dl_errno, 3976 dlp->uderror_ind.dl_unix_errno)); 3977 break; 3978 3979 case DL_INFO_ACK: 3980 break; 3981 3982 default: 3983 /* 3984 * We should not get here. 3985 */ 3986 cmn_err(CE_WARN, "man_lrsrv: unexpected DL prim 0x%lx!", 3987 prim); 3988 need_dl_reset = TRUE; 3989 break; 3990 } 3991 3992 dl_reset: 3993 freemsg(mp); 3994 3995 if (need_dl_reset) { 3996 man_pg_t *mpg; 3997 man_path_t *mp; 3998 3999 if (qsize(rq)) { /* Dump all messages. */ 4000 flushq(rq, FLUSHDATA); 4001 flushq(WR(rq), FLUSHDATA); 4002 } 4003 4004 mdp->md_dlpierrors++; 4005 D_SETSTATE(mdp, DL_UNATTACHED); 4006 if (mdp->md_lc_timer_id != 0) { 4007 (void) quntimeout(man_ctl_wq, mdp->md_lc_timer_id); 4008 mdp->md_lc_timer_id = 0; 4009 } 4010 4011 mutex_enter(&man_lock); 4012 ASSERT(mdp->md_msp != NULL); 4013 ASSERT(mdp->md_msp->ms_manp != NULL); 4014 mpg = man_find_pg_by_id(mdp->md_msp->ms_manp->man_pg, 4015 mdp->md_pg_id); 4016 ASSERT(mpg != NULL); 4017 mp = man_find_path_by_ppa(mpg->mpg_pathp, 4018 mdp->md_device.mdev_ppa); 4019 ASSERT(mp != NULL); 4020 mp->mp_device.mdev_state |= MDEV_FAILED; 4021 if ((mdp->md_dlpierrors >= MAN_MAX_DLPIERRORS) && 4022 (man_is_on_domain || 4023 mdp->md_msp->ms_manp->man_meta_ppa == 1)) { 4024 /* 4025 * Autoswitching is disabled for instance 0 4026 * on the SC as we expect the domain to 4027 * initiate the path switching. 4028 */ 4029 (void) man_do_autoswitch((man_dest_t *)mdp); 4030 MAN_DBG(MAN_WARN, ("man_lrsrv: dlpi failure(%d,%d)," 4031 " switching path", mdp->md_device.mdev_major, 4032 mdp->md_device.mdev_ppa)); 4033 } else { 4034 mdp->md_lc_timer_id = qtimeout(man_ctl_wq, 4035 man_reset_dlpi, (void *)mdp, 4036 man_gettimer(MAN_TIMER_DLPIRESET, mdp)); 4037 } 4038 mutex_exit(&man_lock); 4039 } 4040 4041 4042 } /* End while (getq()) */ 4043 4044 exit: 4045 MAN_DBG(MAN_DLPI, ("man_lrsrv: returns")); 4046 4047 return (0); 4048 } 4049 4050 static int 4051 man_needs_linkcheck(man_dest_t *mdp) 4052 { 4053 /* 4054 * Not ready for linkcheck. 4055 */ 4056 if (mdp->md_msp == NULL || mdp->md_msp->ms_manp == NULL) 4057 return (0); 4058 4059 /* 4060 * Linkchecking needs to be done on IP streams. For domain, all 4061 * driver instances need checking, for SC only instance 1 needs it. 4062 */ 4063 if ((man_is_on_domain || mdp->md_msp->ms_manp->man_meta_ppa == 1) && 4064 (mdp->md_msp->ms_sap == ETHERTYPE_IP || 4065 mdp->md_msp->ms_sap == ETHERTYPE_IPV6)) 4066 4067 return (1); 4068 4069 /* 4070 * Linkcheck not need on this link. 4071 */ 4072 return (0); 4073 } 4074 4075 /* 4076 * The following routines process work requests posted to man_iwork_q 4077 * from the non-STREAMS half of the driver (see man_bwork.c). The work 4078 * requires access to the inner perimeter lock of the driver. This 4079 * lock is acquired by man_uwsrv, who calls man_iwork to process the 4080 * man_iwork_q-> 4081 */ 4082 4083 /* 4084 * The man_bwork has posted some work for us to do inside the 4085 * perimeter. This mainly involves updating lower multiplexor data 4086 * structures (non-blocking type stuff). So, we can hold the man_lock 4087 * until we are done processing all work items. Note that some of these 4088 * routines in turn submit work back to the bgthread, which they can do 4089 * since we hold the man_lock. 4090 */ 4091 static void 4092 man_iwork() 4093 { 4094 man_work_t *wp; 4095 int wp_finished; 4096 4097 MAN_DBG(MAN_SWITCH, ("man_iwork: q_work(0x%p)", 4098 (void *)man_iwork_q->q_work)); 4099 4100 mutex_enter(&man_lock); 4101 4102 while (man_iwork_q->q_work) { 4103 4104 wp = man_iwork_q->q_work; 4105 man_iwork_q->q_work = wp->mw_next; 4106 wp->mw_next = NULL; 4107 4108 mutex_exit(&man_lock); 4109 4110 MAN_DBG(MAN_SWITCH, ("man_iwork: type %s", 4111 _mw_type[wp->mw_type])); 4112 4113 wp_finished = TRUE; 4114 4115 switch (wp->mw_type) { 4116 case MAN_WORK_DRATTACH: 4117 (void) man_do_dr_attach(wp); 4118 break; 4119 4120 case MAN_WORK_DRSWITCH: 4121 /* 4122 * Return status to man_dr_detach immediately. If 4123 * no error submitting SWITCH request, man_iswitch 4124 * or man_bclose will cv_signal man_dr_detach on 4125 * completion of SWITCH work request. 4126 */ 4127 if (man_do_dr_switch(wp) == 0) 4128 wp_finished = FALSE; 4129 break; 4130 4131 case MAN_WORK_DRDETACH: 4132 man_do_dr_detach(wp); 4133 break; 4134 4135 case MAN_WORK_SWITCH: 4136 if (man_iswitch(wp)) 4137 wp_finished = FALSE; 4138 break; 4139 4140 case MAN_WORK_KSTAT_UPDATE: 4141 man_do_kstats(wp); 4142 break; 4143 4144 default: 4145 cmn_err(CE_WARN, "man_iwork: " 4146 "illegal work type(%d)", wp->mw_type); 4147 break; 4148 } 4149 4150 mutex_enter(&man_lock); 4151 4152 /* 4153 * If we've completed the work request, delete, or 4154 * cv_signal waiter. 4155 */ 4156 if (wp_finished) { 4157 wp->mw_flags |= MAN_WFLAGS_DONE; 4158 4159 if (wp->mw_flags & MAN_WFLAGS_CVWAITER) 4160 cv_signal(&wp->mw_cv); 4161 else 4162 man_work_free(wp); 4163 } 4164 } 4165 4166 mutex_exit(&man_lock); 4167 } 4168 4169 /* 4170 * man_dr_detach has submitted a request to DRSWITCH a path. 4171 * He is in cv_wait_sig(wp->mw_cv). We forward the work request on to 4172 * man_bwork as a switch request. It should end up back at 4173 * man_iwork, who will cv_signal(wp->mw_cv) man_dr_detach. 4174 * 4175 * Called holding inner perimeter lock. 4176 * man_lock is held to synchronize access to pathgroup list(man_pg). 4177 */ 4178 static int 4179 man_do_dr_switch(man_work_t *wp) 4180 { 4181 man_t *manp; 4182 man_pg_t *mpg; 4183 man_path_t *mp; 4184 man_path_t *ap; 4185 man_adest_t *adp; 4186 mi_path_t mpath; 4187 int status = 0; 4188 4189 adp = &wp->mw_arg; 4190 4191 MAN_DBG(MAN_SWITCH, ("man_do_dr_switch: pg_id %d work:", adp->a_pg_id)); 4192 MAN_DBGCALL(MAN_SWITCH, man_print_work(wp)); 4193 4194 mutex_enter(&man_lock); 4195 manp = ddi_get_soft_state(man_softstate, adp->a_man_ppa); 4196 if (manp == NULL || manp->man_pg == NULL) { 4197 status = ENODEV; 4198 goto exit; 4199 } 4200 4201 mpg = man_find_pg_by_id(manp->man_pg, adp->a_pg_id); 4202 if (mpg == NULL) { 4203 status = ENODEV; 4204 goto exit; 4205 } 4206 4207 if (mpg->mpg_flags & MAN_PG_SWITCHING) { 4208 status = EAGAIN; 4209 goto exit; 4210 } 4211 4212 /* 4213 * Check to see if detaching device is active. If so, activate 4214 * an alternate. 4215 */ 4216 mp = man_find_active_path(mpg->mpg_pathp); 4217 if (mp && mp->mp_device.mdev_ppa == adp->a_sf_dev.mdev_ppa) { 4218 4219 ap = man_find_alternate_path(mpg->mpg_pathp); 4220 if (ap == NULL) { 4221 status = EBUSY; 4222 goto exit; 4223 } 4224 4225 bzero((char *)&mpath, sizeof (mi_path_t)); 4226 4227 mpath.mip_cmd = MI_PATH_ACTIVATE; 4228 mpath.mip_man_ppa = 0; 4229 mpath.mip_pg_id = 0; 4230 mpath.mip_devs[0] = ap->mp_device; 4231 mpath.mip_ndevs = 1; 4232 ether_copy(&manp->man_eaddr, &mpath.mip_eaddr); 4233 4234 /* 4235 * DR thread is sleeping on wp->mw_cv. We change the work 4236 * request from DRSWITCH to SWITCH and submit it to 4237 * for processing by man_bwork (via man_pg_cmd). At 4238 * completion the SWITCH work request is processed by 4239 * man_iswitch() or man_bclose and the DR thread will 4240 * be cv_signal'd. 4241 */ 4242 wp->mw_type = MAN_WORK_SWITCH; 4243 if (status = man_pg_cmd(&mpath, wp)) 4244 goto exit; 4245 4246 } else { 4247 /* 4248 * Tell man_dr_detach that detaching device is not currently 4249 * in use. 4250 */ 4251 status = ENODEV; 4252 } 4253 4254 exit: 4255 if (status) { 4256 /* 4257 * ENODEV is a noop, not really an error. 4258 */ 4259 if (status != ENODEV) 4260 wp->mw_status = status; 4261 } 4262 mutex_exit(&man_lock); 4263 4264 return (status); 4265 } 4266 4267 /* 4268 * man_dr_attach has submitted a request to DRATTACH a path, 4269 * add that path to the path list. 4270 * 4271 * Called holding perimeter lock. 4272 */ 4273 static int 4274 man_do_dr_attach(man_work_t *wp) 4275 { 4276 man_t *manp; 4277 man_adest_t *adp; 4278 mi_path_t mpath; 4279 manc_t manc; 4280 int status = 0; 4281 4282 adp = &wp->mw_arg; 4283 4284 MAN_DBG(MAN_SWITCH, ("man_do_dr_attach: pg_id %d work:", adp->a_pg_id)); 4285 MAN_DBGCALL(MAN_SWITCH, man_print_work(wp)); 4286 4287 mutex_enter(&man_lock); 4288 manp = ddi_get_soft_state(man_softstate, adp->a_man_ppa); 4289 if (manp == NULL || manp->man_pg == NULL) { 4290 status = ENODEV; 4291 goto exit; 4292 } 4293 4294 if (status = man_get_iosram(&manc)) { 4295 goto exit; 4296 } 4297 /* 4298 * Extract SC ethernet address from IOSRAM. 4299 */ 4300 ether_copy(&manc.manc_sc_eaddr, &mpath.mip_eaddr); 4301 4302 mpath.mip_pg_id = adp->a_pg_id; 4303 mpath.mip_man_ppa = adp->a_man_ppa; 4304 /* 4305 * man_dr_attach passes the new device info in a_sf_dev. 4306 */ 4307 MAN_DBG(MAN_DR, ("man_do_dr_attach: ")); 4308 MAN_DBGCALL(MAN_DR, man_print_dev(&adp->a_sf_dev)); 4309 mpath.mip_devs[0] = adp->a_sf_dev; 4310 mpath.mip_ndevs = 1; 4311 mpath.mip_cmd = MI_PATH_ADD; 4312 status = man_pg_cmd(&mpath, NULL); 4313 4314 exit: 4315 mutex_exit(&man_lock); 4316 return (status); 4317 } 4318 4319 /* 4320 * man_dr_detach has submitted a request to DRDETACH a path. 4321 * He is in cv_wait_sig(wp->mw_cv). We remove the path and 4322 * cv_signal(wp->mw_cv) man_dr_detach. 4323 * 4324 * Called holding perimeter lock. 4325 */ 4326 static void 4327 man_do_dr_detach(man_work_t *wp) 4328 { 4329 man_t *manp; 4330 man_pg_t *mpg; 4331 man_path_t *mp; 4332 man_adest_t *adp; 4333 manc_t manc; 4334 mi_path_t mpath; 4335 int i; 4336 int found; 4337 int status = 0; 4338 4339 adp = &wp->mw_arg; 4340 4341 MAN_DBG(MAN_SWITCH, ("man_do_dr_detach: pg_id %d work:", adp->a_pg_id)); 4342 MAN_DBGCALL(MAN_SWITCH, man_print_work(wp)); 4343 4344 mutex_enter(&man_lock); 4345 manp = ddi_get_soft_state(man_softstate, adp->a_man_ppa); 4346 if (manp == NULL || manp->man_pg == NULL) { 4347 status = ENODEV; 4348 goto exit; 4349 } 4350 4351 mpg = man_find_pg_by_id(manp->man_pg, adp->a_pg_id); 4352 if (mpg == NULL) { 4353 status = ENODEV; 4354 goto exit; 4355 } 4356 4357 if (mpg->mpg_flags & MAN_PG_SWITCHING) { 4358 status = EAGAIN; 4359 goto exit; 4360 } 4361 4362 /* 4363 * We should have switched detaching path if it was active. 4364 */ 4365 mp = man_find_active_path(mpg->mpg_pathp); 4366 if (mp && mp->mp_device.mdev_ppa == adp->a_sf_dev.mdev_ppa) { 4367 status = EAGAIN; 4368 goto exit; 4369 } 4370 4371 /* 4372 * Submit an ASSIGN command, minus the detaching device. 4373 */ 4374 bzero((char *)&mpath, sizeof (mi_path_t)); 4375 4376 if (status = man_get_iosram(&manc)) { 4377 goto exit; 4378 } 4379 4380 mpath.mip_cmd = MI_PATH_ASSIGN; 4381 mpath.mip_man_ppa = 0; 4382 mpath.mip_pg_id = 0; 4383 4384 mp = mpg->mpg_pathp; 4385 i = 0; 4386 found = FALSE; 4387 while (mp != NULL) { 4388 if (mp->mp_device.mdev_ppa != adp->a_sf_dev.mdev_ppa) { 4389 mpath.mip_devs[i] = mp->mp_device; 4390 i++; 4391 } else { 4392 found = TRUE; 4393 } 4394 mp = mp->mp_next; 4395 } 4396 4397 if (found) { 4398 /* 4399 * Need to include SCs ethernet address in command. 4400 */ 4401 mpath.mip_ndevs = i; 4402 ether_copy(&manc.manc_sc_eaddr, &mpath.mip_eaddr); 4403 4404 status = man_pg_cmd(&mpath, NULL); 4405 } 4406 4407 /* 4408 * Hand back status to man_dr_detach request. 4409 */ 4410 exit: 4411 if (status != ENODEV) 4412 wp->mw_status = status; 4413 4414 mutex_exit(&man_lock); 4415 4416 } 4417 4418 4419 /* 4420 * The background thread has configured new lower multiplexor streams for 4421 * the given destinations. Update the appropriate destination data structures 4422 * inside the inner perimeter. We must take care to deal with destinations 4423 * whose upper stream has closed or detached from lower streams. 4424 * 4425 * Returns 4426 * 0 Done with work request. 4427 * 1 Reused work request. 4428 */ 4429 static int 4430 man_iswitch(man_work_t *wp) 4431 { 4432 man_adest_t *adp; 4433 man_t *manp; 4434 man_pg_t *mpg; 4435 man_path_t *mp = NULL; 4436 man_dest_t *mdp; 4437 man_dest_t *tdp; 4438 int i; 4439 int switch_ok = TRUE; 4440 4441 adp = &wp->mw_arg; 4442 4443 if (wp->mw_status != 0) { 4444 switch_ok = FALSE; /* Never got things opened */ 4445 } 4446 4447 /* 4448 * Update destination structures as appropriate. 4449 */ 4450 for (i = 0; i < adp->a_ndests; i++) { 4451 man_dest_t tmp; 4452 4453 /* 4454 * Check to see if lower stream we just switch is still 4455 * around. 4456 */ 4457 tdp = &adp->a_mdp[i]; 4458 mdp = man_switch_match(tdp, adp->a_pg_id, tdp->md_switch_id); 4459 4460 if (mdp == NULL) 4461 continue; 4462 4463 if (switch_ok == FALSE) { 4464 /* 4465 * Switch failed for some reason. Clear 4466 * PLUMBING flag and retry switch again later. 4467 */ 4468 man_ifail_dest(mdp); 4469 continue; 4470 } 4471 4472 /* 4473 * Swap new info, for old. We return the old info to 4474 * man_bwork to close things up below. 4475 */ 4476 bcopy((char *)mdp, (char *)&tmp, sizeof (man_dest_t)); 4477 4478 ASSERT(mdp->md_state & MAN_DSTATE_PLUMBING); 4479 ASSERT(mdp->md_state == tdp->md_state); 4480 4481 mdp->md_state = tdp->md_state; 4482 4483 /* 4484 * save the wq from the destination passed(tdp). 4485 */ 4486 mdp->md_wq = tdp->md_wq; 4487 RD(mdp->md_wq)->q_ptr = (void *)(mdp); 4488 WR(mdp->md_wq)->q_ptr = (void *)(mdp); 4489 4490 mdp->md_state &= ~MAN_DSTATE_INITIALIZING; 4491 mdp->md_state |= MAN_DSTATE_READY; 4492 4493 ASSERT(mdp->md_device.mdev_major == adp->a_sf_dev.mdev_major); 4494 4495 ASSERT(tdp->md_device.mdev_ppa == adp->a_st_dev.mdev_ppa); 4496 ASSERT(tdp->md_device.mdev_major == adp->a_st_dev.mdev_major); 4497 4498 mdp->md_device = tdp->md_device; 4499 mdp->md_muxid = tdp->md_muxid; 4500 mdp->md_linkstate = MAN_LINKUNKNOWN; 4501 (void) drv_getparm(TIME, &mdp->md_lastswitch); 4502 mdp->md_state &= ~MAN_DSTATE_PLUMBING; 4503 mdp->md_switch_id = 0; 4504 mdp->md_switches++; 4505 mdp->md_dlpierrors = 0; 4506 D_SETSTATE(mdp, DL_UNATTACHED); 4507 4508 /* 4509 * Resync lower w/ upper dlpi state. This will start link 4510 * timer if/when lower stream goes to DL_IDLE (see man_lrsrv). 4511 */ 4512 man_reset_dlpi((void *)mdp); 4513 4514 bcopy((char *)&tmp, (char *)tdp, sizeof (man_dest_t)); 4515 } 4516 4517 if (switch_ok) { 4518 for (i = 0; i < adp->a_ndests; i++) { 4519 tdp = &adp->a_mdp[i]; 4520 4521 tdp->md_state &= ~MAN_DSTATE_PLUMBING; 4522 tdp->md_state &= ~MAN_DSTATE_INITIALIZING; 4523 tdp->md_state |= MAN_DSTATE_READY; 4524 } 4525 } else { 4526 /* 4527 * Never got switch-to destinations open, free them. 4528 */ 4529 man_kfree(adp->a_mdp, 4530 sizeof (man_dest_t) * adp->a_ndests); 4531 } 4532 4533 /* 4534 * Clear pathgroup switching flag and update path flags. 4535 */ 4536 mutex_enter(&man_lock); 4537 manp = ddi_get_soft_state(man_softstate, adp->a_man_ppa); 4538 4539 ASSERT(manp != NULL); 4540 ASSERT(manp->man_pg != NULL); 4541 4542 mpg = man_find_pg_by_id(manp->man_pg, adp->a_pg_id); 4543 ASSERT(mpg != NULL); 4544 ASSERT(mpg->mpg_flags & MAN_PG_SWITCHING); 4545 mpg->mpg_flags &= ~MAN_PG_SWITCHING; 4546 4547 /* 4548 * Switch succeeded, mark path we switched from as failed, and 4549 * device we switch to as active and clear its failed flag (if set). 4550 * Sync up kstats. 4551 */ 4552 if (switch_ok) { 4553 mp = man_find_active_path(mpg->mpg_pathp); 4554 if (mp != NULL) { 4555 4556 ASSERT(adp->a_sf_dev.mdev_major != 0); 4557 4558 MAN_DBG(MAN_SWITCH, ("man_iswitch: switch from dev:")); 4559 MAN_DBGCALL(MAN_SWITCH, man_print_dev(&adp->a_sf_dev)); 4560 4561 mp->mp_device.mdev_state &= ~MDEV_ACTIVE; 4562 } else 4563 ASSERT(adp->a_sf_dev.mdev_major == 0); 4564 4565 MAN_DBG(MAN_SWITCH, ("man_iswitch: switch to dev:")); 4566 MAN_DBGCALL(MAN_SWITCH, man_print_dev(&adp->a_st_dev)); 4567 4568 ASSERT(adp->a_st_dev.mdev_major != 0); 4569 4570 mp = man_find_path_by_ppa(mpg->mpg_pathp, 4571 adp->a_st_dev.mdev_ppa); 4572 4573 ASSERT(mp != NULL); 4574 4575 mp->mp_device.mdev_state |= MDEV_ACTIVE; 4576 } 4577 4578 /* 4579 * Decrement manp reference count and hand back work request if 4580 * needed. 4581 */ 4582 manp->man_refcnt--; 4583 4584 if (switch_ok) { 4585 wp->mw_type = MAN_WORK_CLOSE; 4586 man_work_add(man_bwork_q, wp); 4587 } 4588 4589 mutex_exit(&man_lock); 4590 4591 return (switch_ok); 4592 } 4593 4594 /* 4595 * Find the destination in the upper stream that we just switched. 4596 */ 4597 man_dest_t * 4598 man_switch_match(man_dest_t *sdp, int pg_id, void *sid) 4599 { 4600 man_dest_t *mdp = NULL; 4601 manstr_t *msp; 4602 4603 for (msp = man_strup; msp != NULL; msp = msp->ms_next) { 4604 /* 4605 * Check if upper stream closed, or detached. 4606 */ 4607 if (msp != sdp->md_msp) 4608 continue; 4609 4610 if (msp->ms_dests == NULL) 4611 break; 4612 4613 mdp = &msp->ms_dests[pg_id]; 4614 4615 /* 4616 * Upper stream detached and reattached while we were 4617 * switching. 4618 */ 4619 if (mdp->md_switch_id != sid) { 4620 mdp = NULL; 4621 break; 4622 } 4623 } 4624 4625 return (mdp); 4626 } 4627 4628 /* 4629 * bg_thread cant complete the switch for some reason. (Re)start the 4630 * linkcheck timer again. 4631 */ 4632 static void 4633 man_ifail_dest(man_dest_t *mdp) 4634 { 4635 ASSERT(mdp->md_lc_timer_id == 0); 4636 ASSERT(mdp->md_bc_id == 0); 4637 ASSERT(mdp->md_state & MAN_DSTATE_PLUMBING); 4638 4639 MAN_DBG(MAN_SWITCH, ("man_ifail_dest")); 4640 MAN_DBGCALL(MAN_SWITCH, man_print_mdp(mdp)); 4641 4642 mdp->md_state &= ~MAN_DSTATE_PLUMBING; 4643 mdp->md_linkstate = MAN_LINKFAIL; 4644 4645 /* 4646 * If we have not yet initialized link, or the upper stream is 4647 * DL_IDLE, restart the linktimer. 4648 */ 4649 if ((mdp->md_state & MAN_DSTATE_INITIALIZING) || 4650 ((mdp->md_msp->ms_sap == ETHERTYPE_IPV6 || 4651 mdp->md_msp->ms_sap == ETHERTYPE_IP) && 4652 mdp->md_msp->ms_dlpistate == DL_IDLE)) { 4653 4654 mdp->md_lc_timer_id = qtimeout(man_ctl_wq, man_linkcheck_timer, 4655 (void *)mdp, man_gettimer(MAN_TIMER_LINKCHECK, mdp)); 4656 } 4657 4658 } 4659 4660 /* 4661 * Arrange to replay all of ms_dl_mp on the new lower stream to get it 4662 * in sync with the upper stream. Note that this includes setting the 4663 * physical address. 4664 * 4665 * Called from qtimeout with inner perimeter lock. 4666 */ 4667 static void 4668 man_reset_dlpi(void *argp) 4669 { 4670 man_dest_t *mdp = (man_dest_t *)argp; 4671 manstr_t *msp; 4672 mblk_t *mp; 4673 mblk_t *rmp = NULL; 4674 mblk_t *tmp; 4675 4676 mdp->md_lc_timer_id = 0; 4677 4678 if (mdp->md_state != MAN_DSTATE_READY) { 4679 MAN_DBG(MAN_DLPI, ("man_reset_dlpi: not ready!")); 4680 return; 4681 } 4682 4683 msp = mdp->md_msp; 4684 4685 rmp = man_dup_mplist(msp->ms_dl_mp); 4686 if (rmp == NULL) 4687 goto fail; 4688 4689 /* 4690 * Send down an unbind and detach request, just to clean things 4691 * out, we ignore ERROR_ACKs for unbind and detach in man_lrsrv. 4692 */ 4693 tmp = man_alloc_ubreq_dreq(); 4694 if (tmp == NULL) { 4695 goto fail; 4696 } 4697 mp = tmp; 4698 while (mp->b_next != NULL) 4699 mp = mp->b_next; 4700 mp->b_next = rmp; 4701 rmp = tmp; 4702 4703 man_dlpi_replay(mdp, rmp); 4704 4705 return; 4706 4707 fail: 4708 4709 while (rmp) { 4710 mp = rmp; 4711 rmp = rmp->b_next; 4712 mp->b_next = mp->b_prev = NULL; 4713 freemsg(mp); 4714 } 4715 4716 ASSERT(mdp->md_lc_timer_id == 0); 4717 ASSERT(mdp->md_bc_id == 0); 4718 4719 /* 4720 * If low on memory, try again later. I Could use qbufcall, but that 4721 * could fail and I would have to try and recover from that w/ 4722 * qtimeout anyway. 4723 */ 4724 mdp->md_lc_timer_id = qtimeout(man_ctl_wq, man_reset_dlpi, 4725 (void *)mdp, man_gettimer(MAN_TIMER_LINKCHECK, mdp)); 4726 } 4727 4728 /* 4729 * Once we receive acknowledgement that DL_ATTACH_REQ was successful, 4730 * we can send down the DL_* related IOCTLs (e.g. DL_IOC_HDR). If we 4731 * try and send them downsteam w/o waiting, the ioctl's get processed before 4732 * the ATTACH_REQ and they are rejected. TBD - could just do the lower 4733 * dlpi state change in lock step. TBD 4734 */ 4735 static int 4736 man_dlioc_replay(man_dest_t *mdp) 4737 { 4738 mblk_t *rmp; 4739 int status = 1; 4740 4741 if (mdp->md_msp->ms_dlioc_mp == NULL) 4742 goto exit; 4743 4744 rmp = man_dup_mplist(mdp->md_msp->ms_dlioc_mp); 4745 if (rmp == NULL) { 4746 status = 0; 4747 goto exit; 4748 } 4749 4750 man_dlpi_replay(mdp, rmp); 4751 exit: 4752 return (status); 4753 } 4754 4755 static mblk_t * 4756 man_alloc_ubreq_dreq() 4757 { 4758 mblk_t *dreq; 4759 mblk_t *ubreq = NULL; 4760 union DL_primitives *dlp; 4761 4762 dreq = allocb(DL_DETACH_REQ_SIZE, BPRI_MED); 4763 if (dreq == NULL) 4764 goto exit; 4765 4766 dreq->b_datap->db_type = M_PROTO; 4767 dlp = (union DL_primitives *)dreq->b_rptr; 4768 dlp->dl_primitive = DL_DETACH_REQ; 4769 dreq->b_wptr += DL_DETACH_REQ_SIZE; 4770 4771 ubreq = allocb(DL_UNBIND_REQ_SIZE, BPRI_MED); 4772 if (ubreq == NULL) { 4773 freemsg(dreq); 4774 goto exit; 4775 } 4776 4777 ubreq->b_datap->db_type = M_PROTO; 4778 dlp = (union DL_primitives *)ubreq->b_rptr; 4779 dlp->dl_primitive = DL_UNBIND_REQ; 4780 ubreq->b_wptr += DL_UNBIND_REQ_SIZE; 4781 4782 ubreq->b_next = dreq; 4783 4784 exit: 4785 4786 return (ubreq); 4787 } 4788 4789 static mblk_t * 4790 man_dup_mplist(mblk_t *mp) 4791 { 4792 mblk_t *listp = NULL; 4793 mblk_t *tailp = NULL; 4794 4795 for (; mp != NULL; mp = mp->b_next) { 4796 4797 mblk_t *nmp; 4798 mblk_t *prev; 4799 mblk_t *next; 4800 4801 prev = mp->b_prev; 4802 next = mp->b_next; 4803 mp->b_prev = mp->b_next = NULL; 4804 4805 nmp = copymsg(mp); 4806 4807 mp->b_prev = prev; 4808 mp->b_next = next; 4809 4810 if (nmp == NULL) 4811 goto nomem; 4812 4813 if (listp == NULL) { 4814 listp = tailp = nmp; 4815 } else { 4816 tailp->b_next = nmp; 4817 tailp = nmp; 4818 } 4819 } 4820 4821 return (listp); 4822 nomem: 4823 4824 while (listp) { 4825 mp = listp; 4826 listp = mp->b_next; 4827 mp->b_next = mp->b_prev = NULL; 4828 freemsg(mp); 4829 } 4830 4831 return (NULL); 4832 4833 } 4834 4835 static mblk_t * 4836 man_alloc_physreq_mp(eaddr_t *man_eap) 4837 { 4838 4839 mblk_t *mp; 4840 union DL_primitives *dlp; 4841 t_uscalar_t off; 4842 eaddr_t *eap; 4843 4844 mp = allocb(DL_SET_PHYS_ADDR_REQ_SIZE + ETHERADDRL, BPRI_MED); 4845 if (mp == NULL) 4846 goto exit; 4847 4848 mp->b_datap->db_type = M_PROTO; 4849 dlp = (union DL_primitives *)mp->b_wptr; 4850 dlp->set_physaddr_req.dl_primitive = DL_SET_PHYS_ADDR_REQ; 4851 dlp->set_physaddr_req.dl_addr_length = ETHERADDRL; 4852 off = DL_SET_PHYS_ADDR_REQ_SIZE; 4853 dlp->set_physaddr_req.dl_addr_offset = off; 4854 mp->b_wptr += DL_SET_PHYS_ADDR_REQ_SIZE + ETHERADDRL; 4855 4856 eap = (eaddr_t *)(mp->b_rptr + off); 4857 ether_copy(man_eap, eap); 4858 4859 exit: 4860 MAN_DBG(MAN_DLPI, ("man_alloc_physreq: physaddr %s\n", 4861 ether_sprintf(eap))); 4862 4863 return (mp); 4864 } 4865 4866 /* 4867 * A new path in a pathgroup has become active for the first time. Setup 4868 * the lower destinations in prepartion for man_pg_activate to call 4869 * man_autoswitch. 4870 */ 4871 static void 4872 man_add_dests(man_pg_t *mpg) 4873 { 4874 manstr_t *msp; 4875 man_dest_t *mdp; 4876 4877 for (msp = man_strup; msp != NULL; msp = msp->ms_next) { 4878 4879 if (!man_str_uses_pg(msp, mpg)) 4880 continue; 4881 4882 mdp = &msp->ms_dests[mpg->mpg_pg_id]; 4883 4884 /* 4885 * TBD - Take out 4886 * ASSERT(mdp->md_device.mdev_state == MDEV_UNASSIGNED); 4887 * ASSERT(mdp->md_state == MAN_DSTATE_NOTPRESENT); 4888 */ 4889 if (mdp->md_device.mdev_state != MDEV_UNASSIGNED) { 4890 cmn_err(CE_NOTE, "man_add_dests mdev !unassigned"); 4891 MAN_DBGCALL(MAN_PATH, man_print_mdp(mdp)); 4892 } 4893 4894 man_start_dest(mdp, msp, mpg); 4895 } 4896 4897 } 4898 4899 static int 4900 man_remove_dests(man_pg_t *mpg) 4901 { 4902 manstr_t *msp; 4903 int close_cnt = 0; 4904 man_dest_t *cdp; 4905 man_dest_t *mdp; 4906 man_dest_t *tdp; 4907 man_work_t *wp; 4908 mblk_t *mp; 4909 int status = 0; 4910 4911 wp = man_work_alloc(MAN_WORK_CLOSE, KM_NOSLEEP); 4912 if (wp == NULL) { 4913 status = ENOMEM; 4914 goto exit; 4915 } 4916 4917 /* 4918 * Count up number of destinations we need to close. 4919 */ 4920 for (msp = man_strup; msp != NULL; msp = msp->ms_next) { 4921 if (!man_str_uses_pg(msp, mpg)) 4922 continue; 4923 4924 close_cnt++; 4925 } 4926 4927 if (close_cnt == 0) 4928 goto exit; 4929 4930 cdp = man_kzalloc(sizeof (man_dest_t) * close_cnt, KM_NOSLEEP); 4931 if (cdp == NULL) { 4932 status = ENOMEM; 4933 man_work_free(wp); 4934 goto exit; 4935 } 4936 4937 tdp = cdp; 4938 for (msp = man_strup; msp != NULL; msp = msp->ms_next) { 4939 if (!man_str_uses_pg(msp, mpg)) 4940 continue; 4941 4942 mdp = &msp->ms_dests[mpg->mpg_pg_id]; 4943 4944 mdp->md_state |= MAN_DSTATE_CLOSING; 4945 mdp->md_device.mdev_state = MDEV_UNASSIGNED; 4946 mdp->md_msp = NULL; 4947 mdp->md_rq = NULL; 4948 4949 /* 4950 * Clean up optimized destination pointer if we are 4951 * closing it. 4952 */ 4953 man_set_optimized_dest(msp); 4954 4955 if (mdp->md_lc_timer_id != 0) { 4956 (void) quntimeout(man_ctl_wq, mdp->md_lc_timer_id); 4957 mdp->md_lc_timer_id = 0; 4958 } 4959 if (mdp->md_bc_id != 0) { 4960 qunbufcall(man_ctl_wq, mdp->md_bc_id); 4961 mdp->md_bc_id = 0; 4962 } 4963 4964 mutex_enter(&mdp->md_lock); 4965 while ((mp = mdp->md_dmp_head) != NULL) { 4966 mdp->md_dmp_head = mp->b_next; 4967 mp->b_next = NULL; 4968 freemsg(mp); 4969 } 4970 mdp->md_dmp_count = 0; 4971 mdp->md_dmp_tail = NULL; 4972 mutex_exit(&mdp->md_lock); 4973 4974 *tdp++ = *mdp; 4975 4976 mdp->md_state = MAN_DSTATE_NOTPRESENT; 4977 mdp->md_muxid = -1; 4978 } 4979 4980 wp->mw_arg.a_mdp = cdp; 4981 wp->mw_arg.a_ndests = close_cnt; 4982 man_work_add(man_bwork_q, wp); 4983 4984 exit: 4985 return (status); 4986 4987 } 4988 4989 /* 4990 * Returns TRUE if stream uses pathgroup, FALSE otherwise. 4991 */ 4992 static int 4993 man_str_uses_pg(manstr_t *msp, man_pg_t *mpg) 4994 { 4995 int status; 4996 4997 status = ((msp->ms_flags & MAN_SFLAG_CONTROL) || 4998 (msp->ms_dests == NULL) || 4999 (msp->ms_manp == NULL) || 5000 (msp->ms_manp->man_meta_ppa != mpg->mpg_man_ppa)); 5001 5002 return (!status); 5003 } 5004 5005 static int 5006 man_gettimer(int timer, man_dest_t *mdp) 5007 { 5008 5009 int attached = TRUE; 5010 int time = 0; 5011 5012 if (mdp == NULL || mdp->md_msp == NULL || mdp->md_msp->ms_manp == NULL) 5013 attached = FALSE; 5014 5015 switch (timer) { 5016 case MAN_TIMER_INIT: 5017 if (attached) 5018 time = mdp->md_msp->ms_manp->man_init_time; 5019 else 5020 time = MAN_INIT_TIME; 5021 break; 5022 5023 case MAN_TIMER_LINKCHECK: 5024 if (attached) { 5025 if (mdp->md_linkstate == MAN_LINKSTALE) 5026 time = mdp->md_msp->ms_manp->man_linkstale_time; 5027 else 5028 time = mdp->md_msp->ms_manp->man_linkcheck_time; 5029 } else 5030 time = MAN_LINKCHECK_TIME; 5031 break; 5032 5033 case MAN_TIMER_DLPIRESET: 5034 if (attached) 5035 time = mdp->md_msp->ms_manp->man_dlpireset_time; 5036 else 5037 time = MAN_DLPIRESET_TIME; 5038 break; 5039 5040 default: 5041 MAN_DBG(MAN_LINK, ("man_gettimer: unknown timer %d", timer)); 5042 time = MAN_LINKCHECK_TIME; 5043 break; 5044 } 5045 5046 return (drv_usectohz(time)); 5047 } 5048 5049 /* 5050 * Check the links for each active destination. Called inside inner 5051 * perimeter via qtimeout. This timer only runs on the domain side of the 5052 * driver. It should never run on the SC side. 5053 * 5054 * On a MAN_LINKGOOD link, we check/probe the link health every 5055 * MAN_LINKCHECK_TIME seconds. If the link goes MAN_LINKSTALE, the we probe 5056 * the link every MAN_LINKSTALE_TIME seconds, and fail the link after probing 5057 * the link MAN_LINKSTALE_RETRIES times. 5058 * The man_lock is held to synchronize access pathgroup list(man_pg). 5059 */ 5060 void 5061 man_linkcheck_timer(void *argp) 5062 { 5063 man_dest_t *mdp = (man_dest_t *)argp; 5064 int restart_timer = TRUE; 5065 int send_ping = TRUE; 5066 int newstate; 5067 int oldstate; 5068 man_pg_t *mpg; 5069 man_path_t *mp; 5070 5071 MAN_DBG(MAN_LINK, ("man_linkcheck_timer: mdp")); 5072 MAN_DBGCALL(MAN_LINK, man_print_mdp(mdp)); 5073 5074 /* 5075 * Clear timeout id and check if someones waiting on us to 5076 * complete a close. 5077 */ 5078 mdp->md_lc_timer_id = 0; 5079 5080 if (mdp->md_state == MAN_DSTATE_NOTPRESENT || 5081 mdp->md_state & MAN_DSTATE_BUSY) { 5082 5083 MAN_DBG(MAN_LINK, ("man_linkcheck_timer: not ready mdp")); 5084 MAN_DBGCALL(MAN_LINK, man_print_mdp(mdp)); 5085 goto exit; 5086 } 5087 5088 mutex_enter(&man_lock); 5089 /* 5090 * If the lower stream needs initializing, just go straight to 5091 * switch code. As the linkcheck timer is started for all 5092 * SAPs, do not send ping packets during the initialization. 5093 */ 5094 if (mdp->md_state == MAN_DSTATE_INITIALIZING) { 5095 send_ping = FALSE; 5096 goto do_switch; 5097 } 5098 5099 newstate = oldstate = mdp->md_linkstate; 5100 5101 if (!man_needs_linkcheck(mdp)) { 5102 cmn_err(CE_NOTE, 5103 "man_linkcheck_timer: unneeded linkcheck on mdp(0x%p)", 5104 (void *)mdp); 5105 mutex_exit(&man_lock); 5106 return; 5107 } 5108 5109 /* 5110 * The above call to man_needs_linkcheck() validates 5111 * mdp->md_msp and mdp->md_msp->ms_manp pointers. 5112 */ 5113 mpg = man_find_pg_by_id(mdp->md_msp->ms_manp->man_pg, mdp->md_pg_id); 5114 ASSERT(mpg != NULL); 5115 mp = man_find_path_by_ppa(mpg->mpg_pathp, mdp->md_device.mdev_ppa); 5116 ASSERT(mp != NULL); 5117 5118 /* 5119 * This is the most common case, when traffic is flowing. 5120 */ 5121 if (mdp->md_rcvcnt != mdp->md_lastrcvcnt) { 5122 5123 newstate = MAN_LINKGOOD; 5124 mdp->md_lastrcvcnt = mdp->md_rcvcnt; 5125 send_ping = FALSE; 5126 5127 /* 5128 * Clear the FAILED flag and update lru. 5129 */ 5130 mp->mp_device.mdev_state &= ~MDEV_FAILED; 5131 (void) drv_getparm(TIME, &mp->mp_lru); 5132 5133 if (mdp->md_link_updown_msg == MAN_LINK_DOWN_MSG) { 5134 man_t *manp = mdp->md_msp->ms_manp; 5135 5136 cmn_err(CE_NOTE, "%s%d Link up", 5137 ddi_major_to_name(manp->man_meta_major), 5138 manp->man_meta_ppa); 5139 5140 mdp->md_link_updown_msg = MAN_LINK_UP_MSG; 5141 } 5142 5143 goto done; 5144 } 5145 5146 /* 5147 * If we're here, it means we have not seen any traffic 5148 */ 5149 switch (oldstate) { 5150 case MAN_LINKINIT: 5151 case MAN_LINKGOOD: 5152 newstate = MAN_LINKSTALE; 5153 mdp->md_linkstales++; 5154 mdp->md_linkstale_retries = 5155 mdp->md_msp->ms_manp->man_linkstale_retries; 5156 break; 5157 5158 case MAN_LINKSTALE: 5159 case MAN_LINKFAIL: 5160 mdp->md_linkstales++; 5161 mdp->md_linkstale_retries--; 5162 if (mdp->md_linkstale_retries < 0) { 5163 newstate = MAN_LINKFAIL; 5164 mdp->md_linkfails++; 5165 mdp->md_linkstale_retries = 5166 mdp->md_msp->ms_manp->man_linkstale_retries; 5167 /* 5168 * Mark the destination as FAILED and 5169 * update lru. 5170 */ 5171 if (oldstate != MAN_LINKFAIL) { 5172 mp->mp_device.mdev_state |= MDEV_FAILED; 5173 (void) drv_getparm(TIME, &mp->mp_lru); 5174 } 5175 } 5176 break; 5177 5178 default: 5179 cmn_err(CE_WARN, "man_linkcheck_timer: illegal link" 5180 " state %d", oldstate); 5181 break; 5182 } 5183 done: 5184 5185 if (oldstate != newstate) { 5186 5187 MAN_DBG(MAN_LINK, ("man_linkcheck_timer" 5188 " link state %s -> %s", lss[oldstate], 5189 lss[newstate])); 5190 5191 mdp->md_linkstate = newstate; 5192 } 5193 5194 /* 5195 * Do any work required from state transitions above. 5196 */ 5197 if (newstate == MAN_LINKFAIL) { 5198 do_switch: 5199 if (!man_do_autoswitch(mdp)) { 5200 /* 5201 * Stop linkcheck timer until switch completes. 5202 */ 5203 restart_timer = FALSE; 5204 send_ping = FALSE; 5205 } 5206 } 5207 5208 mutex_exit(&man_lock); 5209 if (send_ping) 5210 man_do_icmp_bcast(mdp, mdp->md_msp->ms_sap); 5211 5212 if (restart_timer) 5213 mdp->md_lc_timer_id = qtimeout(man_ctl_wq, man_linkcheck_timer, 5214 (void *)mdp, man_gettimer(MAN_TIMER_LINKCHECK, mdp)); 5215 5216 exit: 5217 MAN_DBG(MAN_LINK, ("man_linkcheck_timer: returns")); 5218 5219 } 5220 5221 /* 5222 * Handle linkcheck initiated autoswitching. 5223 * Called with man_lock held. 5224 */ 5225 static int 5226 man_do_autoswitch(man_dest_t *mdp) 5227 { 5228 man_pg_t *mpg; 5229 man_path_t *ap; 5230 int status = 0; 5231 5232 ASSERT(MUTEX_HELD(&man_lock)); 5233 /* 5234 * Set flags and refcnt. Cleared in man_iswitch when SWITCH completes. 5235 */ 5236 mdp->md_msp->ms_manp->man_refcnt++; 5237 5238 mpg = man_find_pg_by_id(mdp->md_msp->ms_manp->man_pg, mdp->md_pg_id); 5239 ASSERT(mpg); 5240 5241 if (mpg->mpg_flags & MAN_PG_SWITCHING) 5242 return (EBUSY); 5243 5244 mpg->mpg_flags |= MAN_PG_SWITCHING; 5245 5246 if (mdp->md_state == MAN_DSTATE_INITIALIZING) { 5247 /* 5248 * We're initializing, ask for a switch to our currently 5249 * active device. 5250 */ 5251 status = man_autoswitch(mpg, &mdp->md_device, NULL); 5252 } else { 5253 5254 if (mdp->md_msp != NULL && mdp->md_msp->ms_manp != NULL && 5255 mdp->md_link_updown_msg == MAN_LINK_UP_MSG) { 5256 5257 man_t *manp = mdp->md_msp->ms_manp; 5258 5259 cmn_err(CE_NOTE, "%s%d Link down", 5260 ddi_major_to_name(manp->man_meta_major), 5261 manp->man_meta_ppa); 5262 } 5263 mdp->md_link_updown_msg = MAN_LINK_DOWN_MSG; 5264 5265 MAN_DBG(MAN_LINK, ("man_linkcheck_timer: link failure on %s%d", 5266 ddi_major_to_name(mdp->md_device.mdev_major), 5267 mdp->md_device.mdev_ppa)); 5268 5269 ap = man_find_alternate_path(mpg->mpg_pathp); 5270 5271 if (ap == NULL) { 5272 status = ENODEV; 5273 goto exit; 5274 } 5275 status = man_autoswitch(mpg, &ap->mp_device, NULL); 5276 } 5277 exit: 5278 if (status != 0) { 5279 /* 5280 * man_iswitch not going to run, clean up. 5281 */ 5282 mpg->mpg_flags &= ~MAN_PG_SWITCHING; 5283 mdp->md_msp->ms_manp->man_refcnt--; 5284 } 5285 5286 return (status); 5287 } 5288 5289 /* 5290 * Gather up all lower multiplexor streams that have this link open and 5291 * try to switch them. Called from inner perimeter and holding man_lock. 5292 * 5293 * pg_id - Pathgroup to do switch for. 5294 * st_devp - New device to switch to. 5295 * wait_for_switch - whether or not to qwait for completion. 5296 */ 5297 static int 5298 man_autoswitch(man_pg_t *mpg, man_dev_t *st_devp, man_work_t *waiter_wp) 5299 { 5300 man_work_t *wp; 5301 int sdp_cnt = 0; 5302 man_dest_t *sdp; 5303 int status = 0; 5304 5305 ASSERT(MUTEX_HELD(&man_lock)); 5306 if (waiter_wp == NULL) { 5307 wp = man_work_alloc(MAN_WORK_SWITCH, KM_NOSLEEP); 5308 if (wp == NULL) { 5309 status = ENOMEM; 5310 goto exit; 5311 } 5312 } else { 5313 ASSERT(waiter_wp->mw_type == MAN_WORK_SWITCH); 5314 wp = waiter_wp; 5315 } 5316 5317 /* 5318 * Set dests as PLUMBING, cancel timers and return array of dests 5319 * that need a switch. 5320 */ 5321 status = man_prep_dests_for_switch(mpg, &sdp, &sdp_cnt); 5322 if (status) { 5323 if (waiter_wp == NULL) 5324 man_work_free(wp); 5325 goto exit; 5326 } 5327 5328 /* 5329 * If no streams are active, there are no streams to switch. 5330 * Return ENODEV (see man_pg_activate). 5331 */ 5332 if (sdp_cnt == 0) { 5333 if (waiter_wp == NULL) 5334 man_work_free(wp); 5335 status = ENODEV; 5336 goto exit; 5337 } 5338 5339 /* 5340 * Ask the bgthread to switch. See man_bwork. 5341 */ 5342 wp->mw_arg.a_sf_dev = sdp->md_device; 5343 wp->mw_arg.a_st_dev = *st_devp; 5344 wp->mw_arg.a_pg_id = mpg->mpg_pg_id; 5345 wp->mw_arg.a_man_ppa = mpg->mpg_man_ppa; 5346 5347 wp->mw_arg.a_mdp = sdp; 5348 wp->mw_arg.a_ndests = sdp_cnt; 5349 man_work_add(man_bwork_q, wp); 5350 5351 exit: 5352 5353 return (status); 5354 } 5355 5356 /* 5357 * If an alternate path exists for pathgroup, arrange for switch to 5358 * happen. Note that we need to switch each of msp->dests[pg_id], for 5359 * all on man_strup. We must: 5360 * 5361 * Cancel any timers 5362 * Mark dests as PLUMBING 5363 * Submit switch request to man_bwork_q-> 5364 */ 5365 static int 5366 man_prep_dests_for_switch(man_pg_t *mpg, man_dest_t **mdpp, int *cntp) 5367 { 5368 manstr_t *msp; 5369 man_dest_t *mdp; 5370 int sdp_cnt = 0; 5371 man_dest_t *sdp = NULL; 5372 man_dest_t *tdp; 5373 int status = 0; 5374 5375 MAN_DBG(MAN_SWITCH, ("man_prep_dests_for_switch: pg_id %d", 5376 mpg->mpg_pg_id)); 5377 5378 /* 5379 * Count up number of streams, there is one destination that needs 5380 * switching per stream. 5381 */ 5382 for (msp = man_strup; msp != NULL; msp = msp->ms_next) { 5383 if (man_str_uses_pg(msp, mpg)) 5384 sdp_cnt++; 5385 } 5386 5387 if (sdp_cnt == 0) 5388 goto exit; 5389 5390 sdp = man_kzalloc(sizeof (man_dest_t) * sdp_cnt, KM_NOSLEEP); 5391 if (sdp == NULL) { 5392 status = ENOMEM; 5393 goto exit; 5394 } 5395 tdp = sdp; 5396 /* 5397 * Mark each destination as unusable. 5398 */ 5399 for (msp = man_strup; msp != NULL; msp = msp->ms_next) { 5400 if (man_str_uses_pg(msp, mpg)) { 5401 5402 /* 5403 * Mark destination as plumbing and store the 5404 * address of sdp as a way to identify the 5405 * SWITCH request when it comes back (see man_iswitch). 5406 */ 5407 mdp = &msp->ms_dests[mpg->mpg_pg_id]; 5408 mdp->md_state |= MAN_DSTATE_PLUMBING; 5409 mdp->md_switch_id = sdp; 5410 5411 /* 5412 * Copy destination info. 5413 */ 5414 bcopy(mdp, tdp, sizeof (man_dest_t)); 5415 tdp++; 5416 5417 /* 5418 * Cancel timers. 5419 */ 5420 if (mdp->md_lc_timer_id) { 5421 (void) quntimeout(man_ctl_wq, 5422 mdp->md_lc_timer_id); 5423 mdp->md_lc_timer_id = 0; 5424 } 5425 if (mdp->md_bc_id) { 5426 qunbufcall(man_ctl_wq, mdp->md_bc_id); 5427 mdp->md_bc_id = 0; 5428 } 5429 } 5430 } 5431 5432 *mdpp = sdp; 5433 *cntp = sdp_cnt; 5434 status = 0; 5435 exit: 5436 5437 MAN_DBG(MAN_SWITCH, ("man_prep_dests_for_switch: returns %d" 5438 " sdp(0x%p) sdp_cnt(%d)", status, (void *)sdp, sdp_cnt)); 5439 5440 return (status); 5441 5442 } 5443 5444 /* 5445 * The code below generates an ICMP echo packet and sends it to the 5446 * broadcast address in the hopes that the other end will respond 5447 * and the man_linkcheck_timer logic will see the traffic. 5448 * 5449 * This assumes ethernet-like media. 5450 */ 5451 /* 5452 * Generate an ICMP packet. Called exclusive inner perimeter. 5453 * 5454 * mdp - destination to send packet to. 5455 * sap - either ETHERTYPE_ARP or ETHERTYPE_IPV6 5456 */ 5457 static void 5458 man_do_icmp_bcast(man_dest_t *mdp, t_uscalar_t sap) 5459 { 5460 mblk_t *mp = NULL; 5461 5462 /* TBD - merge pinger and this routine. */ 5463 5464 ASSERT(sap == ETHERTYPE_IPV6 || sap == ETHERTYPE_IP); 5465 5466 if (sap == ETHERTYPE_IPV6) { 5467 mdp->md_icmpv6probes++; 5468 } else { 5469 mdp->md_icmpv4probes++; 5470 } 5471 /* 5472 * Send the ICMP message 5473 */ 5474 mp = man_pinger(sap); 5475 5476 MAN_DBG(MAN_LINK, ("man_do_icmp_bcast: sap=0x%x mp=0x%p", 5477 sap, (void *)mp)); 5478 if (mp == NULL) 5479 return; 5480 5481 /* 5482 * Send it out. 5483 */ 5484 if (man_start_lower(mdp, mp, NULL, MAN_LOWER)) { 5485 5486 MAN_DBG(MAN_LINK, ("man_do_icmp_broadcast: xmit failed")); 5487 5488 freemsg(mp); 5489 } 5490 5491 } 5492 5493 static mblk_t * 5494 man_pinger(t_uscalar_t sap) 5495 { 5496 mblk_t *mp = NULL; 5497 man_dladdr_t dlsap; 5498 icmph_t *icmph; 5499 int ipver; 5500 ipha_t *ipha; 5501 ip6_t *ip6h; 5502 int iph_hdr_len; 5503 int datalen = 64; 5504 uchar_t *datap; 5505 uint16_t size; 5506 uchar_t i; 5507 5508 dlsap.dl_sap = htons(sap); 5509 bcopy(ðerbroadcast, &dlsap.dl_phys, sizeof (dlsap.dl_phys)); 5510 5511 if (sap == ETHERTYPE_IPV6) { 5512 ipver = IPV6_VERSION; 5513 iph_hdr_len = sizeof (ip6_t); 5514 size = ICMP6_MINLEN; 5515 } else { 5516 ipver = IPV4_VERSION; 5517 iph_hdr_len = sizeof (ipha_t); 5518 size = ICMPH_SIZE; 5519 } 5520 size += (uint16_t)iph_hdr_len; 5521 size += datalen; 5522 5523 mp = man_alloc_udreq(size, &dlsap); 5524 if (mp == NULL) 5525 goto exit; 5526 5527 /* 5528 * fill out the ICMP echo packet headers 5529 */ 5530 mp->b_cont->b_wptr += iph_hdr_len; 5531 if (ipver == IPV4_VERSION) { 5532 ipha = (ipha_t *)mp->b_cont->b_rptr; 5533 ipha->ipha_version_and_hdr_length = (IP_VERSION << 4) 5534 | IP_SIMPLE_HDR_LENGTH_IN_WORDS; 5535 ipha->ipha_type_of_service = 0; 5536 ipha->ipha_length = size; 5537 ipha->ipha_fragment_offset_and_flags = IPH_DF; 5538 ipha->ipha_ttl = 1; 5539 ipha->ipha_protocol = IPPROTO_ICMP; 5540 if (man_is_on_domain) { 5541 manc_t manc; 5542 5543 if (man_get_iosram(&manc)) { 5544 freemsg(mp); 5545 mp = NULL; 5546 goto exit; 5547 } 5548 5549 /* 5550 * Domain generates ping packets for domain to 5551 * SC network (dman0 <--> scman0). 5552 */ 5553 ipha->ipha_dst = manc.manc_sc_ipaddr; 5554 ipha->ipha_src = manc.manc_dom_ipaddr; 5555 } else { 5556 /* 5557 * Note that ping packets are only generated 5558 * by the SC across scman1 (SC to SC network). 5559 */ 5560 ipha->ipha_dst = man_sc_ipaddrs.ip_other_sc_ipaddr; 5561 ipha->ipha_src = man_sc_ipaddrs.ip_my_sc_ipaddr; 5562 } 5563 5564 ipha->ipha_ident = 0; 5565 5566 ipha->ipha_hdr_checksum = 0; 5567 ipha->ipha_hdr_checksum = IP_CSUM(mp->b_cont, 0, 0); 5568 5569 } else { 5570 ip6h = (ip6_t *)mp->b_cont->b_rptr; 5571 /* 5572 * IP version = 6, priority = 0, flow = 0 5573 */ 5574 ip6h->ip6_flow = (IPV6_VERSION << 28); 5575 ip6h->ip6_plen = 5576 htons((short)(size - iph_hdr_len)); 5577 ip6h->ip6_nxt = IPPROTO_ICMPV6; 5578 ip6h->ip6_hlim = 1; /* stay on link */ 5579 5580 if (man_is_on_domain) { 5581 manc_t manc; 5582 5583 if (man_get_iosram(&manc)) { 5584 freemsg(mp); 5585 mp = NULL; 5586 goto exit; 5587 } 5588 5589 /* 5590 * Domain generates ping packets for domain to 5591 * SC network (dman0 <--> scman0). 5592 */ 5593 ip6h->ip6_src = manc.manc_dom_ipv6addr; 5594 ip6h->ip6_dst = manc.manc_sc_ipv6addr; 5595 } else { 5596 /* 5597 * Note that ping packets are only generated 5598 * by the SC across scman1 (SC to SC network). 5599 */ 5600 ip6h->ip6_src = man_sc_ip6addrs.ip6_my_sc_ipaddr; 5601 ip6h->ip6_dst = man_sc_ip6addrs.ip6_other_sc_ipaddr; 5602 } 5603 } 5604 5605 /* 5606 * IPv6 and IP are the same for ICMP as far as I'm concerned. 5607 */ 5608 icmph = (icmph_t *)mp->b_cont->b_wptr; 5609 if (ipver == IPV4_VERSION) { 5610 mp->b_cont->b_wptr += ICMPH_SIZE; 5611 icmph->icmph_type = ICMP_ECHO_REQUEST; 5612 icmph->icmph_code = 0; 5613 } else { 5614 mp->b_cont->b_wptr += ICMP6_MINLEN; 5615 icmph->icmph_type = ICMP6_ECHO_REQUEST; 5616 icmph->icmph_code = 0; 5617 } 5618 5619 datap = mp->b_cont->b_wptr; 5620 mp->b_cont->b_wptr += datalen; 5621 5622 for (i = 0; i < datalen; i++) 5623 *datap++ = i; 5624 5625 if (ipver == IPV4_VERSION) { 5626 icmph->icmph_checksum = IP_CSUM(mp->b_cont, iph_hdr_len, 0); 5627 } else { 5628 uint32_t sum; 5629 5630 sum = htons(IPPROTO_ICMPV6) + ip6h->ip6_plen; 5631 icmph->icmph_checksum = IP_CSUM(mp->b_cont, iph_hdr_len - 32, 5632 (sum & 0xffff) + (sum >> 16)); 5633 } 5634 5635 /* 5636 * TBD 5637 * icp->icmp_time = ???; 5638 */ 5639 5640 exit: 5641 return (mp); 5642 } 5643 5644 static mblk_t * 5645 man_alloc_udreq(int size, man_dladdr_t *dlsap) 5646 { 5647 dl_unitdata_req_t *udreq; 5648 mblk_t *bp; 5649 mblk_t *mp; 5650 5651 mp = allocb(sizeof (dl_unitdata_req_t) + sizeof (*dlsap), BPRI_MED); 5652 5653 if (mp == NULL) { 5654 cmn_err(CE_NOTE, "man_preparepkt: allocb failed"); 5655 return (NULL); 5656 } 5657 5658 if ((bp = allocb(size, BPRI_MED)) == NULL) { 5659 freemsg(mp); 5660 cmn_err(CE_NOTE, "man_preparepkts: allocb failed"); 5661 return (NULL); 5662 } 5663 bzero(bp->b_rptr, size); 5664 5665 mp->b_cont = bp; 5666 mp->b_datap->db_type = M_PROTO; 5667 udreq = (dl_unitdata_req_t *)mp->b_wptr; 5668 mp->b_wptr += sizeof (dl_unitdata_req_t); 5669 5670 /* 5671 * phys addr first - TBD 5672 */ 5673 bcopy((char *)dlsap, mp->b_wptr, sizeof (*dlsap)); 5674 mp->b_wptr += sizeof (*dlsap); 5675 5676 udreq->dl_primitive = DL_UNITDATA_REQ; 5677 udreq->dl_dest_addr_length = sizeof (*dlsap); 5678 udreq->dl_dest_addr_offset = sizeof (*udreq); 5679 udreq->dl_priority.dl_min = 0; 5680 udreq->dl_priority.dl_max = 0; 5681 5682 return (mp); 5683 } 5684 5685 5686 /* 5687 * The routines in this file are executed by the MAN background thread, 5688 * which executes outside of the STREAMS framework (see man_str.c). It is 5689 * allowed to do the things required to modify the STREAMS driver (things 5690 * that are normally done from a user process). These routines do things like 5691 * open and close drivers, PLINK and PUNLINK streams to/from the multiplexor, 5692 * etc. 5693 * 5694 * The mechanism of communication between the STREAMS portion of the driver 5695 * and the background thread portion are two work queues, man_bwork_q 5696 * and man_iwork_q (background work q and streams work q). Work 5697 * requests are placed on those queues when one half of the driver wants 5698 * the other half to do some work for it. 5699 * 5700 * The MAN background thread executes the man_bwork routine. Its sole 5701 * job is to process work requests placed on this work q. The MAN upper 5702 * write service routine is responsible for processing work requests posted 5703 * to the man_iwork_q-> 5704 * 5705 * Both work queues are protected by the global mutex man_lock. The 5706 * man_bwork is signalged via the condvarman_bwork_q->q_cv. The man_uwsrv 5707 * routine is signaled by calling qenable (forcing man_uwsrv to run). 5708 */ 5709 5710 /* 5711 * man_bwork - Work thread for this device. It is responsible for 5712 * performing operations which can't occur within the STREAMS framework. 5713 * 5714 * Locking: 5715 * - Called holding no locks 5716 * - Obtains the global mutex man_lock to remove work from 5717 * man_bwork_q, and post work to man_iwork_q-> 5718 * - Note that we do not want to hold any locks when making 5719 * any ldi_ calls. 5720 */ 5721 void 5722 man_bwork() 5723 { 5724 man_work_t *wp; 5725 int done = 0; 5726 callb_cpr_t cprinfo; 5727 int wp_finished; 5728 5729 CALLB_CPR_INIT(&cprinfo, &man_lock, callb_generic_cpr, 5730 "mn_work_thrd"); 5731 5732 MAN_DBG(MAN_CONFIG, ("man_bwork: enter")); 5733 5734 while (done == 0) { 5735 5736 mutex_enter(&man_lock); 5737 /* 5738 * While there is nothing to do, sit in cv_wait. If work 5739 * request is made, requester will signal. 5740 */ 5741 while (man_bwork_q->q_work == NULL) { 5742 5743 CALLB_CPR_SAFE_BEGIN(&cprinfo); 5744 5745 cv_wait(&man_bwork_q->q_cv, &man_lock); 5746 5747 CALLB_CPR_SAFE_END(&cprinfo, &man_lock); 5748 } 5749 5750 wp = man_bwork_q->q_work; 5751 man_bwork_q->q_work = wp->mw_next; 5752 wp->mw_next = NULL; 5753 mutex_exit(&man_lock); 5754 5755 wp_finished = TRUE; 5756 5757 MAN_DBG(MAN_SWITCH, ("man_bwork: type %s", 5758 _mw_type[wp->mw_type])); 5759 5760 switch (wp->mw_type) { 5761 case MAN_WORK_OPEN_CTL: 5762 wp->mw_status = man_open_ctl(); 5763 break; 5764 5765 case MAN_WORK_CLOSE_CTL: 5766 man_close_ctl(); 5767 break; 5768 5769 case MAN_WORK_CLOSE: 5770 case MAN_WORK_CLOSE_STREAM: 5771 man_bclose(&wp->mw_arg); 5772 break; 5773 5774 case MAN_WORK_SWITCH: 5775 man_bswitch(&wp->mw_arg, wp); 5776 wp_finished = FALSE; 5777 break; 5778 5779 case MAN_WORK_STOP: /* man_bwork_stop() */ 5780 done = 1; 5781 mutex_enter(&man_lock); 5782 CALLB_CPR_EXIT(&cprinfo); /* Unlocks man_lock */ 5783 break; 5784 5785 default: 5786 cmn_err(CE_WARN, "man_bwork: " 5787 "illegal work type(%d)", wp->mw_type); 5788 break; 5789 } 5790 5791 mutex_enter(&man_lock); 5792 5793 if (wp_finished) { 5794 wp->mw_flags |= MAN_WFLAGS_DONE; 5795 if (wp->mw_flags & MAN_WFLAGS_CVWAITER) 5796 cv_signal(&wp->mw_cv); 5797 else if (wp->mw_flags & MAN_WFLAGS_QWAITER) 5798 qenable(wp->mw_q); 5799 else 5800 man_work_free(wp); 5801 } 5802 5803 mutex_exit(&man_lock); 5804 } 5805 5806 MAN_DBG(MAN_CONFIG, ("man_bwork: thread_exit")); 5807 5808 mutex_enter(&man_lock); 5809 man_bwork_id = NULL; 5810 mutex_exit(&man_lock); 5811 5812 thread_exit(); 5813 } 5814 5815 /* 5816 * man_open_ctl - Open the control stream. 5817 * 5818 * returns - success - 0 5819 * - failure - errno code 5820 * 5821 * Mutex Locking Notes: 5822 * We need a way to keep the CLONE_OPEN qwaiters in man_open from 5823 * checking the man_config variables after the ldi_open call below 5824 * returns from man_open, leaving the inner perimeter. So, we use the 5825 * man_lock to synchronize the threads in man_open_ctl and man_open. We 5826 * hold man_lock across this call into man_open, which in general is a 5827 * no-no. But, the STREAMs portion of the driver (other than open) 5828 * doesn't use it. So, if ldi_open gets hijacked to run any part of 5829 * the MAN streams driver, it wont end up recursively trying to acquire 5830 * man_lock. Note that the non-CLONE_OPEN portion of man_open doesnt 5831 * acquire it either, so again no recursive mutex. 5832 */ 5833 static int 5834 man_open_ctl() 5835 { 5836 int status = 0; 5837 ldi_handle_t ctl_lh = NULL; 5838 ldi_ident_t li = NULL; 5839 5840 MAN_DBG(MAN_CONFIG, ("man_open_ctl: plumbing control stream\n")); 5841 5842 /* 5843 * Get eri driver loaded and kstats initialized. Is there a better 5844 * way to do this? - TBD. 5845 */ 5846 status = ldi_ident_from_mod(&modlinkage, &li); 5847 if (status) { 5848 cmn_err(CE_WARN, 5849 "man_open_ctl: ident alloc failed, error %d", status); 5850 goto exit; 5851 } 5852 5853 status = ldi_open_by_name(ERI_PATH, FREAD | FWRITE | FNOCTTY, 5854 kcred, &ctl_lh, li); 5855 if (status) { 5856 cmn_err(CE_WARN, 5857 "man_open_ctl: eri open failed, error %d", status); 5858 ctl_lh = NULL; 5859 goto exit; 5860 } 5861 (void) ldi_close(ctl_lh, NULL, kcred); 5862 ctl_lh = NULL; 5863 5864 mutex_enter(&man_lock); 5865 5866 if (man_ctl_lh != NULL) { 5867 mutex_exit(&man_lock); 5868 goto exit; 5869 } 5870 5871 ASSERT(man_ctl_wq == NULL); 5872 mutex_exit(&man_lock); 5873 5874 status = ldi_open_by_name(DMAN_INT_PATH, FREAD | FWRITE | FNOCTTY, 5875 kcred, &ctl_lh, li); 5876 if (status) { 5877 cmn_err(CE_WARN, 5878 "man_open_ctl: man control dev open failed, " 5879 "error %d", status); 5880 goto exit; 5881 } 5882 5883 /* 5884 * Update global config state. TBD - dont need lock here, since 5885 * everyone is stuck in open until we finish. Only other modifier 5886 * is man_deconfigure via _fini, which returns EBUSY if there is 5887 * any open streams (other than control). Do need to signal qwaiters 5888 * on error. 5889 */ 5890 mutex_enter(&man_lock); 5891 ASSERT(man_config_state == MAN_CONFIGURING); 5892 ASSERT(man_ctl_lh == NULL); 5893 man_ctl_lh = ctl_lh; 5894 mutex_exit(&man_lock); 5895 5896 exit: 5897 if (li) 5898 ldi_ident_release(li); 5899 5900 MAN_DBG(MAN_CONFIG, ("man_open_ctl: man_ctl_lh(0x%p) errno = %d\n", 5901 (void *)man_ctl_lh, status)); 5902 5903 return (status); 5904 } 5905 5906 /* 5907 * man_close_ctl - Close control stream, we are about to unload driver. 5908 * 5909 * Locking: 5910 * - Called holding no locks. 5911 */ 5912 static void 5913 man_close_ctl() 5914 { 5915 ldi_handle_t tlh; 5916 5917 MAN_DBG(MAN_CONFIG, ("man_close_ctl: unplumbing control stream\n")); 5918 5919 mutex_enter(&man_lock); 5920 if ((tlh = man_ctl_lh) != NULL) 5921 man_ctl_lh = NULL; 5922 mutex_exit(&man_lock); 5923 5924 if (tlh != NULL) { 5925 (void) ldi_close(tlh, NULL, kcred); 5926 } 5927 5928 } 5929 5930 /* 5931 * Close the lower streams. Get all the timers canceled, close the lower 5932 * stream and delete the dest array. 5933 * 5934 * Returns: 5935 * 0 Closed all streams. 5936 * 1 Couldn't close one or more streams, timers still running. 5937 * 5938 * Locking: 5939 * - Called holding no locks. 5940 */ 5941 static void 5942 man_bclose(man_adest_t *adp) 5943 { 5944 int i; 5945 man_dest_t *mdp; 5946 5947 man_cancel_timers(adp); 5948 5949 for (i = 0; i < adp->a_ndests; i++) { 5950 mdp = &adp->a_mdp[i]; 5951 5952 if (mdp->md_muxid != -1) 5953 man_unplumb(mdp); 5954 } 5955 5956 mutex_destroy(&mdp->md_lock); 5957 man_kfree(adp->a_mdp, sizeof (man_dest_t) * adp->a_ndests); 5958 adp->a_mdp = NULL; 5959 } 5960 5961 /* 5962 * We want to close down all lower streams. Need to wait until all 5963 * timers and work related to these lower streams is quiesced. 5964 * 5965 * Returns 1 if lower streams are quiesced, 0 if we need to wait 5966 * a bit longer. 5967 */ 5968 static void 5969 man_cancel_timers(man_adest_t *adp) 5970 { 5971 man_dest_t *mdp; 5972 int cnt; 5973 int i; 5974 5975 mdp = adp->a_mdp; 5976 cnt = adp->a_ndests; 5977 5978 MAN_DBG(MAN_SWITCH, ("man_cancel_timers: mdp(0x%p) cnt %d", 5979 (void *)mdp, cnt)); 5980 5981 for (i = 0; i < cnt; i++) { 5982 5983 if (mdp[i].md_lc_timer_id != 0) { 5984 (void) quntimeout(man_ctl_wq, mdp[i].md_lc_timer_id); 5985 mdp[i].md_lc_timer_id = 0; 5986 } 5987 5988 if (mdp[i].md_bc_id != 0) { 5989 qunbufcall(man_ctl_wq, mdp[i].md_bc_id); 5990 mdp[i].md_bc_id = 0; 5991 } 5992 } 5993 5994 MAN_DBG(MAN_SWITCH, ("man_cancel_timers: returns")); 5995 } 5996 5997 /* 5998 * A failover is started at start of day, when the driver detects a 5999 * link failure (see man_linkcheck_timer), or when DR detaches 6000 * the IO board containing the current active link between SC and 6001 * domain (see man_dr_detach, man_iwork, and man_do_dr_detach). A 6002 * MAN_WORK_SWITCH work request containing all the lower streams that 6003 * should be switched is posted on the man_bwork_q-> This work request is 6004 * processed here. Once all lower streams have been switched to an 6005 * alternate path, the MAN_WORK_SWITCH work request is passed back to 6006 * man_iwork_q where it is processed within the inner perimeter of the 6007 * STREAMS framework (see man_iswitch). 6008 * 6009 * Note that when the switch fails for whatever reason, we just hand 6010 * back the lower streams untouched and let another failover happen. 6011 * Hopefully we will sooner or later succeed at the failover. 6012 */ 6013 static void 6014 man_bswitch(man_adest_t *adp, man_work_t *wp) 6015 { 6016 man_dest_t *tdp; 6017 man_t *manp; 6018 int i; 6019 int status = 0; 6020 6021 /* 6022 * Make a temporary copy of dest array, updating device to the 6023 * alternate and try to open all lower streams. bgthread can sleep. 6024 */ 6025 6026 tdp = man_kzalloc(sizeof (man_dest_t) * adp->a_ndests, 6027 KM_SLEEP); 6028 bcopy(adp->a_mdp, tdp, sizeof (man_dest_t) * adp->a_ndests); 6029 6030 /* 6031 * Before we switch to the new path, lets sync the kstats. 6032 */ 6033 mutex_enter(&man_lock); 6034 6035 manp = ddi_get_soft_state(man_softstate, adp->a_man_ppa); 6036 if (manp != NULL) { 6037 man_update_path_kstats(manp); 6038 } else 6039 status = ENODEV; 6040 6041 mutex_exit(&man_lock); 6042 6043 if (status != 0) 6044 goto exit; 6045 6046 for (i = 0; i < adp->a_ndests; i++) { 6047 6048 tdp[i].md_device = adp->a_st_dev; 6049 tdp[i].md_muxid = -1; 6050 6051 if (man_plumb(&tdp[i])) 6052 break; 6053 } 6054 6055 /* 6056 * Didn't plumb everyone, unplumb new lower stuff and return. 6057 */ 6058 if (i < adp->a_ndests) { 6059 int j; 6060 6061 for (j = 0; j <= i; j++) 6062 man_unplumb(&tdp[j]); 6063 status = EAGAIN; 6064 goto exit; 6065 } 6066 6067 if (man_is_on_domain && man_dossc_switch(adp->a_st_dev.mdev_exp_id)) { 6068 /* 6069 * If we cant set new path on the SSC, then fail the 6070 * failover. 6071 */ 6072 for (i = 0; i < adp->a_ndests; i++) 6073 man_unplumb(&tdp[i]); 6074 status = EAGAIN; 6075 goto exit; 6076 } 6077 6078 man_kfree(adp->a_mdp, sizeof (man_dest_t) * adp->a_ndests); 6079 adp->a_mdp = tdp; 6080 6081 exit: 6082 if (status) 6083 man_kfree(tdp, sizeof (man_dest_t) * adp->a_ndests); 6084 6085 6086 MAN_DBG(MAN_SWITCH, ("man_bswitch: returns %d", status)); 6087 6088 /* 6089 * Hand processed switch request back to man_iwork for 6090 * processing in man_iswitch. 6091 */ 6092 wp->mw_status = status; 6093 6094 mutex_enter(&man_lock); 6095 man_work_add(man_iwork_q, wp); 6096 mutex_exit(&man_lock); 6097 6098 } 6099 6100 /* 6101 * man_plumb - Configure a lower stream for this destination. 6102 * 6103 * Locking: 6104 * - Called holding no locks. 6105 * 6106 * Returns: 6107 * - success - 0 6108 * - failure - error code of failure 6109 */ 6110 static int 6111 man_plumb(man_dest_t *mdp) 6112 { 6113 int status; 6114 int muxid; 6115 ldi_handle_t lh; 6116 ldi_ident_t li = NULL; 6117 6118 MAN_DBG(MAN_SWITCH, ("man_plumb: mdp(0x%p) %s%d exp(%d)", 6119 (void *)mdp, ddi_major_to_name(mdp->md_device.mdev_major), 6120 mdp->md_device.mdev_ppa, mdp->md_device.mdev_exp_id)); 6121 6122 /* 6123 * Control stream should already be open. 6124 */ 6125 if (man_ctl_lh == NULL) { 6126 status = EAGAIN; 6127 goto exit; 6128 } 6129 6130 mutex_enter(&man_lock); 6131 ASSERT(man_ctl_wq != NULL); 6132 status = ldi_ident_from_stream(man_ctl_wq, &li); 6133 if (status != 0) { 6134 cmn_err(CE_WARN, 6135 "man_plumb: ident alloc failed, error %d", status); 6136 goto exit; 6137 } 6138 mutex_exit(&man_lock); 6139 6140 /* 6141 * previously opens were done by a dev_t of makedev(clone_major, 6142 * mdev_major) which should always map to /devices/pseudo/clone@0:eri 6143 */ 6144 ASSERT(strcmp(ERI_IDNAME, 6145 ddi_major_to_name(mdp->md_device.mdev_major)) == 0); 6146 6147 status = ldi_open_by_name(ERI_PATH, FREAD | FWRITE | FNOCTTY, 6148 kcred, &lh, li); 6149 if (status) { 6150 cmn_err(CE_WARN, 6151 "man_plumb: eri open failed, error %d", status); 6152 goto exit; 6153 } 6154 6155 /* 6156 * Link netdev under MAN. 6157 */ 6158 ASSERT(mdp->md_muxid == -1); 6159 6160 status = ldi_ioctl(man_ctl_lh, I_PLINK, (intptr_t)lh, 6161 FREAD+FWRITE+FNOCTTY+FKIOCTL, kcred, &muxid); 6162 if (status) { 6163 cmn_err(CE_WARN, 6164 "man_plumb: ldi_ioctl(I_PLINK) failed, error %d", status); 6165 (void) ldi_close(lh, NULL, kcred); 6166 goto exit; 6167 6168 } 6169 mdp->md_muxid = muxid; 6170 mdp->md_wq = man_linkrec_find(muxid); 6171 /* 6172 * If we can't find the linkrec then return an 6173 * error. It will be automatically unplumbed on failure. 6174 */ 6175 if (mdp->md_wq == NULL) 6176 status = EAGAIN; 6177 6178 (void) ldi_close(lh, NULL, kcred); 6179 exit: 6180 if (li) 6181 ldi_ident_release(li); 6182 6183 MAN_DBG(MAN_SWITCH, ("man_plumb: exit\n")); 6184 6185 return (status); 6186 } 6187 6188 /* 6189 * man_unplumb - tear down the STREAMs framework for the lower multiplexor. 6190 * 6191 * mdp - destination struct of interest 6192 * 6193 * returns - success - 0 6194 * - failure - return error from ldi_ioctl 6195 */ 6196 static void 6197 man_unplumb(man_dest_t *mdp) 6198 { 6199 int status, rval; 6200 6201 MAN_DBG(MAN_SWITCH, ("man_unplumb: mdp")); 6202 MAN_DBGCALL(MAN_SWITCH, man_print_mdp(mdp)); 6203 6204 if (mdp->md_muxid == -1) 6205 return; 6206 6207 ASSERT(man_ctl_lh != NULL); 6208 6209 /* 6210 * I_PUNLINK causes the multiplexor resources to be freed. 6211 */ 6212 status = ldi_ioctl(man_ctl_lh, I_PUNLINK, (intptr_t)mdp->md_muxid, 6213 FREAD+FWRITE+FNOCTTY+FKIOCTL, kcred, &rval); 6214 if (status) { 6215 cmn_err(CE_WARN, "man_unplumb: ldi_ioctl(I_PUNLINK) failed" 6216 " errno %d\n", status); 6217 } 6218 /* 6219 * Delete linkrec if it exists. 6220 */ 6221 (void) man_linkrec_find(mdp->md_muxid); 6222 mdp->md_muxid = -1; 6223 6224 } 6225 6226 /* 6227 * The routines below deal with paths and pathgroups. These data structures 6228 * are used to track the physical devices connecting the domain and SSC. 6229 * These devices make up the lower streams of the MAN multiplexor. The 6230 * routines all expect the man_lock to be held. 6231 * 6232 * A pathgroup consists of all paths that connect a particular domain and the 6233 * SSC. The concept of a pathgroup id (pg_id) is used to uniquely identify 6234 * a pathgroup. For Domains, there is just one pathgroup, that connecting 6235 * the domain to the SSC (pg_id == 0). On the SSC, there is one pathgroup per 6236 * domain. The pg_id field corresponds to the domain tags A-R. A pg_id of 6237 * 0 means domain tag A, a pg_id of 1 means domain B, etc. 6238 * 6239 * The path data structure identifies one path between the SSC and a domain. 6240 * It describes the information for the path: the major and minor number of 6241 * the physical device; kstat pointers; and ethernet address of the 6242 * other end of the path. 6243 * 6244 * The pathgroups are anchored at man_pg_head and are protected by the 6245 * by the inner perimeter. The routines are only called by the STREAMs 6246 * portion of the driver. 6247 */ 6248 6249 /* 6250 * Update man instance pathgroup info. Exclusive inner perimeter assures 6251 * this code is single threaded. man_refcnt assures man_t wont detach 6252 * while we are playing with man_pg stuff. 6253 * 6254 * Returns 0 on success, errno on failure. 6255 */ 6256 int 6257 man_pg_cmd(mi_path_t *mip, man_work_t *waiter_wp) 6258 { 6259 int status = 0; 6260 man_t *manp; 6261 6262 if (mip->mip_ndevs < 0) { 6263 status = EINVAL; 6264 cmn_err(CE_WARN, "man_pg_cmd: EINVAL: mip_ndevs %d", 6265 mip->mip_ndevs); 6266 goto exit; 6267 } 6268 6269 ASSERT(MUTEX_HELD(&man_lock)); 6270 manp = ddi_get_soft_state(man_softstate, mip->mip_man_ppa); 6271 if (manp == NULL) { 6272 status = ENODEV; 6273 goto exit; 6274 } 6275 6276 MAN_DBG(MAN_PATH, ("man_pg_cmd: mip")); 6277 MAN_DBGCALL(MAN_PATH, man_print_mip(mip)); 6278 6279 MAN_DBG(MAN_PATH, ("\tman_t")); 6280 MAN_DBGCALL(MAN_PATH, man_print_man(manp)); 6281 6282 switch (mip->mip_cmd) { 6283 case MI_PATH_ASSIGN: 6284 status = man_pg_assign(&manp->man_pg, mip, FALSE); 6285 break; 6286 6287 case MI_PATH_ADD: 6288 status = man_pg_assign(&manp->man_pg, mip, TRUE); 6289 break; 6290 6291 case MI_PATH_UNASSIGN: 6292 status = man_pg_unassign(&manp->man_pg, mip); 6293 break; 6294 6295 case MI_PATH_ACTIVATE: 6296 status = man_pg_activate(manp, mip, waiter_wp); 6297 break; 6298 6299 case MI_PATH_READ: 6300 status = man_pg_read(manp->man_pg, mip); 6301 break; 6302 6303 default: 6304 status = EINVAL; 6305 cmn_err(CE_NOTE, "man_pg_cmd: invalid command"); 6306 break; 6307 } 6308 6309 exit: 6310 MAN_DBG(MAN_PATH, ("man_pg_cmd: returns %d", status)); 6311 6312 return (status); 6313 } 6314 6315 /* 6316 * Assign paths to a pathgroup. If pathgroup doesnt exists, create it. 6317 * If path doesnt exist, create it. If ethernet address of existing 6318 * pathgroup different, change it. If an existing path is not in the new 6319 * list, remove it. If anything changed, send PATH_UPDATE request to 6320 * man_iwork to update all man_dest_t's. 6321 * 6322 * mplpp - man pathgroup list point to point. 6323 * mip - new/updated pathgroup info to assign. 6324 */ 6325 static int 6326 man_pg_assign(man_pg_t **mplpp, mi_path_t *mip, int add_only) 6327 { 6328 man_pg_t *mpg; 6329 man_path_t *mp; 6330 man_path_t *add_paths = NULL; 6331 int cnt; 6332 int i; 6333 int first_pass = TRUE; 6334 int status = 0; 6335 6336 ASSERT(MUTEX_HELD(&man_lock)); 6337 6338 cnt = mip->mip_ndevs; 6339 if (cnt == 0) { 6340 status = EINVAL; 6341 cmn_err(CE_NOTE, "man_pg_assign: mip_ndevs == 0"); 6342 goto exit; 6343 } 6344 6345 /* 6346 * Assure the devices to be assigned are not assigned to some other 6347 * pathgroup. 6348 */ 6349 for (i = 0; i < cnt; i++) { 6350 mpg = man_find_path_by_dev(*mplpp, &mip->mip_devs[i], NULL); 6351 6352 if (mpg == NULL) 6353 continue; 6354 6355 if ((mpg->mpg_man_ppa != mip->mip_man_ppa) || 6356 (mpg->mpg_pg_id != mip->mip_pg_id)) { 6357 /* 6358 * Already assigned to some other man instance 6359 * or pathgroup. 6360 */ 6361 status = EEXIST; 6362 goto exit; 6363 } 6364 } 6365 6366 /* 6367 * Find pathgroup, or allocate new one if it doesnt exist and 6368 * add it to list at mplpp. Result is that mpg points to 6369 * pathgroup to modify. 6370 */ 6371 mpg = man_find_pg_by_id(*mplpp, mip->mip_pg_id); 6372 if (mpg == NULL) { 6373 6374 status = man_pg_create(mplpp, &mpg, mip); 6375 if (status) 6376 goto exit; 6377 6378 } else if (ether_cmp(&mip->mip_eaddr, &mpg->mpg_dst_eaddr) != 0) { 6379 6380 cmn_err(CE_WARN, "man_pg_assign: ethernet address mismatch"); 6381 cmn_err(CE_CONT, "existing %s", 6382 ether_sprintf(&mpg->mpg_dst_eaddr)); 6383 cmn_err(CE_CONT, "new %s", 6384 ether_sprintf(&mip->mip_eaddr)); 6385 6386 status = EINVAL; 6387 goto exit; 6388 } 6389 6390 /* 6391 * Create list of new paths to add to pathgroup. 6392 */ 6393 for (i = 0; i < cnt; i++) { 6394 6395 if (man_find_path_by_dev(*mplpp, &mip->mip_devs[i], NULL)) 6396 continue; /* Already exists in this pathgroup */ 6397 6398 mp = man_kzalloc(sizeof (man_path_t), KM_NOSLEEP); 6399 if (mp == NULL) { 6400 status = ENOMEM; 6401 goto exit; 6402 } 6403 6404 mp->mp_device = mip->mip_devs[i]; 6405 mp->mp_device.mdev_state = MDEV_ASSIGNED; 6406 6407 MAN_DBG(MAN_PATH, ("man_pg_assign: assigning mdp")); 6408 MAN_DBGCALL(MAN_PATH, man_print_dev(&mp->mp_device)); 6409 6410 status = man_path_kstat_init(mp); 6411 if (status) { 6412 man_kfree(mp, sizeof (man_path_t)); 6413 goto exit; 6414 } 6415 6416 man_path_insert(&add_paths, mp); 6417 } 6418 6419 /* 6420 * man_dr_attach passes only the path which is being DRd in. 6421 * So just add the path and don't worry about removing paths. 6422 */ 6423 if (add_only == TRUE) 6424 goto exit; 6425 6426 6427 /* 6428 * Check if any paths we want to remove are ACTIVE. If not, 6429 * do a second pass and remove them. 6430 */ 6431 again: 6432 mp = mpg->mpg_pathp; 6433 while (mp != NULL) { 6434 int in_new_list; 6435 man_path_t *rp; 6436 6437 rp = NULL; 6438 in_new_list = FALSE; 6439 6440 for (i = 0; i < cnt; i++) { 6441 if (mp->mp_device.mdev_ppa == 6442 mip->mip_devs[i].mdev_ppa) { 6443 6444 in_new_list = TRUE; 6445 break; 6446 } 6447 } 6448 6449 if (!in_new_list) { 6450 if (first_pass) { 6451 if (mp->mp_device.mdev_state & MDEV_ACTIVE) { 6452 status = EBUSY; 6453 goto exit; 6454 } 6455 } else { 6456 rp = mp; 6457 } 6458 } 6459 mp = mp->mp_next; 6460 6461 if (rp != NULL) 6462 man_path_remove(&mpg->mpg_pathp, rp); 6463 } 6464 6465 if (first_pass == TRUE) { 6466 first_pass = FALSE; 6467 goto again; 6468 } 6469 6470 exit: 6471 if (status == 0) { 6472 if (add_paths) 6473 man_path_merge(&mpg->mpg_pathp, add_paths); 6474 } else { 6475 while (add_paths != NULL) { 6476 mp = add_paths; 6477 add_paths = mp->mp_next; 6478 mp->mp_next = NULL; 6479 6480 man_path_kstat_uninit(mp); 6481 man_kfree(mp, sizeof (man_path_t)); 6482 } 6483 } 6484 6485 return (status); 6486 } 6487 6488 /* 6489 * Remove all paths from a pathgroup (domain shutdown). If there is an 6490 * active path in the group, shut down all destinations referencing it 6491 * first. 6492 */ 6493 static int 6494 man_pg_unassign(man_pg_t **plpp, mi_path_t *mip) 6495 { 6496 man_pg_t *mpg; 6497 man_pg_t *tpg; 6498 man_pg_t *tppg; 6499 man_path_t *mp = NULL; 6500 int status = 0; 6501 6502 ASSERT(MUTEX_HELD(&man_lock)); 6503 6504 /* 6505 * Check for existence of pathgroup. 6506 */ 6507 if ((mpg = man_find_pg_by_id(*plpp, mip->mip_pg_id)) == NULL) 6508 goto exit; 6509 6510 if (man_find_active_path(mpg->mpg_pathp) != NULL) { 6511 status = man_remove_dests(mpg); 6512 if (status) 6513 goto exit; 6514 } 6515 6516 /* 6517 * Free all the paths for this pathgroup. 6518 */ 6519 while (mpg->mpg_pathp) { 6520 mp = mpg->mpg_pathp; 6521 mpg->mpg_pathp = mp->mp_next; 6522 mp->mp_next = NULL; 6523 6524 man_path_kstat_uninit(mp); 6525 man_kfree(mp, sizeof (man_path_t)); 6526 } 6527 6528 /* 6529 * Remove this pathgroup from the list, and free it. 6530 */ 6531 tpg = tppg = *plpp; 6532 if (tpg == mpg) { 6533 *plpp = tpg->mpg_next; 6534 goto free_pg; 6535 } 6536 6537 for (tpg = tpg->mpg_next; tpg != NULL; tpg = tpg->mpg_next) { 6538 if (tpg == mpg) 6539 break; 6540 tppg = tpg; 6541 } 6542 6543 ASSERT(tpg != NULL); 6544 6545 tppg->mpg_next = tpg->mpg_next; 6546 tpg->mpg_next = NULL; 6547 6548 free_pg: 6549 man_kfree(tpg, sizeof (man_pg_t)); 6550 6551 exit: 6552 return (status); 6553 6554 } 6555 6556 /* 6557 * Set a new active path. This is done via man_ioctl so we are 6558 * exclusive in the inner perimeter. 6559 */ 6560 static int 6561 man_pg_activate(man_t *manp, mi_path_t *mip, man_work_t *waiter_wp) 6562 { 6563 man_pg_t *mpg1; 6564 man_pg_t *mpg2; 6565 man_pg_t *plp; 6566 man_path_t *mp; 6567 man_path_t *ap; 6568 int status = 0; 6569 6570 ASSERT(MUTEX_HELD(&man_lock)); 6571 MAN_DBG(MAN_PATH, ("man_pg_activate: dev")); 6572 MAN_DBGCALL(MAN_PATH, man_print_dev(mip->mip_devs)); 6573 6574 if (mip->mip_ndevs != 1) { 6575 status = EINVAL; 6576 goto exit; 6577 } 6578 6579 plp = manp->man_pg; 6580 mpg1 = man_find_pg_by_id(plp, mip->mip_pg_id); 6581 if (mpg1 == NULL) { 6582 status = EINVAL; 6583 goto exit; 6584 } 6585 6586 mpg2 = man_find_path_by_dev(plp, mip->mip_devs, &mp); 6587 if (mpg2 == NULL) { 6588 status = ENODEV; 6589 goto exit; 6590 } 6591 6592 if (mpg1 != mpg2) { 6593 status = EINVAL; 6594 goto exit; 6595 } 6596 6597 ASSERT(mp->mp_device.mdev_ppa == mip->mip_devs->mdev_ppa); 6598 6599 if (mpg1->mpg_flags & MAN_PG_SWITCHING) { 6600 status = EAGAIN; 6601 goto exit; 6602 } 6603 6604 ap = man_find_active_path(mpg1->mpg_pathp); 6605 if (ap == NULL) { 6606 /* 6607 * This is the first time a path has been activated for 6608 * this pathgroup. Initialize all upper streams dest 6609 * structure for this pathgroup so autoswitch will find 6610 * them. 6611 */ 6612 mp->mp_device.mdev_state |= MDEV_ACTIVE; 6613 man_add_dests(mpg1); 6614 goto exit; 6615 } 6616 6617 /* 6618 * Path already active, nothing to do. 6619 */ 6620 if (ap == mp) 6621 goto exit; 6622 6623 /* 6624 * Try to autoswitch to requested device. Set flags and refcnt. 6625 * Cleared in man_iswitch when SWITCH completes. 6626 */ 6627 manp->man_refcnt++; 6628 mpg1->mpg_flags |= MAN_PG_SWITCHING; 6629 6630 /* 6631 * Switch to path specified. 6632 */ 6633 status = man_autoswitch(mpg1, mip->mip_devs, waiter_wp); 6634 6635 if (status != 0) { 6636 /* 6637 * man_iswitch not going to run, clean up. 6638 */ 6639 manp->man_refcnt--; 6640 mpg1->mpg_flags &= ~MAN_PG_SWITCHING; 6641 6642 if (status == ENODEV) { 6643 /* 6644 * Device not plumbed isn't really an error. Change 6645 * active device setting here, since man_iswitch isn't 6646 * going to be run to do it. 6647 */ 6648 status = 0; 6649 ap->mp_device.mdev_state &= ~MDEV_ACTIVE; 6650 mp->mp_device.mdev_state |= MDEV_ACTIVE; 6651 } 6652 } 6653 6654 exit: 6655 MAN_DBG(MAN_PATH, ("man_pg_activate: returns %d", status)); 6656 6657 return (status); 6658 } 6659 6660 static int 6661 man_pg_read(man_pg_t *plp, mi_path_t *mip) 6662 { 6663 man_pg_t *mpg; 6664 man_path_t *mp; 6665 int cnt; 6666 int status = 0; 6667 6668 ASSERT(MUTEX_HELD(&man_lock)); 6669 6670 if ((mpg = man_find_pg_by_id(plp, mip->mip_pg_id)) == NULL) { 6671 status = ENODEV; 6672 goto exit; 6673 } 6674 6675 cnt = 0; 6676 for (mp = mpg->mpg_pathp; mp != NULL; mp = mp->mp_next) { 6677 bcopy(&mp->mp_device, &mip->mip_devs[cnt], sizeof (man_dev_t)); 6678 if (cnt == mip->mip_ndevs) 6679 break; 6680 cnt++; 6681 } 6682 6683 MAN_DBG(MAN_PATH, ("man_pg_read: pg(0x%p) id(%d) found %d paths", 6684 (void *)mpg, mpg->mpg_pg_id, cnt)); 6685 6686 mip->mip_ndevs = cnt; 6687 6688 /* 6689 * TBD - What should errno be if user buffer too small ? 6690 */ 6691 if (mp != NULL) { 6692 status = ENOMEM; 6693 } 6694 6695 exit: 6696 6697 return (status); 6698 } 6699 6700 /* 6701 * return existing pathgroup, or create it. TBD - Need to update 6702 * all of destinations if we added a pathgroup. Also, need to update 6703 * all of man_strup if we add a path. 6704 * 6705 * mplpp - man pathgroup list point to pointer. 6706 * mpgp - returns newly created man pathgroup. 6707 * mip - info to fill in mpgp. 6708 */ 6709 static int 6710 man_pg_create(man_pg_t **mplpp, man_pg_t **mpgp, mi_path_t *mip) 6711 { 6712 man_pg_t *mpg; 6713 man_pg_t *tpg; 6714 int status = 0; 6715 6716 ASSERT(MUTEX_HELD(&man_lock)); 6717 6718 if (ether_cmp(&mip->mip_eaddr, &zero_ether_addr) == 0) { 6719 cmn_err(CE_NOTE, "man_ioctl: man_pg_create: ether" 6720 " addresss not set!"); 6721 status = EINVAL; 6722 goto exit; 6723 } 6724 6725 mpg = man_kzalloc(sizeof (man_pg_t), KM_NOSLEEP); 6726 if (mpg == NULL) { 6727 status = ENOMEM; 6728 goto exit; 6729 } 6730 6731 mpg->mpg_flags = MAN_PG_IDLE; 6732 mpg->mpg_pg_id = mip->mip_pg_id; 6733 mpg->mpg_man_ppa = mip->mip_man_ppa; 6734 ether_copy(&mip->mip_eaddr, &mpg->mpg_dst_eaddr); 6735 6736 MAN_DBG(MAN_PATH, ("man_pg_create: new mpg")); 6737 MAN_DBGCALL(MAN_PATH, man_print_mpg(mpg)); 6738 6739 tpg = *mplpp; 6740 if (tpg == NULL) { 6741 *mplpp = mpg; 6742 } else { 6743 while (tpg->mpg_next != NULL) 6744 tpg = tpg->mpg_next; 6745 tpg->mpg_next = mpg; 6746 } 6747 6748 exit: 6749 *mpgp = mpg; 6750 6751 return (status); 6752 } 6753 6754 /* 6755 * Return pointer to pathgroup containing mdevp, null otherwise. Also, 6756 * if a path pointer is passed in, set it to matching path in pathgroup. 6757 * 6758 * Called holding man_lock. 6759 */ 6760 static man_pg_t * 6761 man_find_path_by_dev(man_pg_t *plp, man_dev_t *mdevp, man_path_t **mpp) 6762 { 6763 man_pg_t *mpg; 6764 man_path_t *mp; 6765 6766 ASSERT(MUTEX_HELD(&man_lock)); 6767 for (mpg = plp; mpg != NULL; mpg = mpg->mpg_next) { 6768 for (mp = mpg->mpg_pathp; mp != NULL; mp = mp->mp_next) { 6769 if (mp->mp_device.mdev_major == mdevp->mdev_major && 6770 mp->mp_device.mdev_ppa == mdevp->mdev_ppa) { 6771 6772 if (mpp != NULL) 6773 *mpp = mp; 6774 return (mpg); 6775 } 6776 } 6777 } 6778 6779 return (NULL); 6780 } 6781 6782 /* 6783 * Return pointer to pathgroup assigned to destination, null if not found. 6784 * 6785 * Called holding man_lock. 6786 */ 6787 static man_pg_t * 6788 man_find_pg_by_id(man_pg_t *mpg, int pg_id) 6789 { 6790 ASSERT(MUTEX_HELD(&man_lock)); 6791 for (; mpg != NULL; mpg = mpg->mpg_next) { 6792 if (mpg->mpg_pg_id == pg_id) 6793 return (mpg); 6794 } 6795 6796 return (NULL); 6797 } 6798 6799 static man_path_t * 6800 man_find_path_by_ppa(man_path_t *mplist, int ppa) 6801 { 6802 man_path_t *mp; 6803 6804 ASSERT(MUTEX_HELD(&man_lock)); 6805 for (mp = mplist; mp != NULL; mp = mp->mp_next) { 6806 if (mp->mp_device.mdev_ppa == ppa) 6807 return (mp); 6808 } 6809 6810 return (NULL); 6811 } 6812 6813 static man_path_t * 6814 man_find_active_path(man_path_t *mplist) 6815 { 6816 man_path_t *mp; 6817 6818 ASSERT(MUTEX_HELD(&man_lock)); 6819 for (mp = mplist; mp != NULL; mp = mp->mp_next) 6820 if (mp->mp_device.mdev_state & MDEV_ACTIVE) 6821 return (mp); 6822 6823 return (NULL); 6824 } 6825 6826 /* 6827 * Try and find an alternate path. 6828 */ 6829 static man_path_t * 6830 man_find_alternate_path(man_path_t *mlp) 6831 { 6832 man_path_t *ap; /* Active path */ 6833 man_path_t *np; /* New alternate path */ 6834 man_path_t *fp = NULL; /* LRU failed path */ 6835 6836 ASSERT(MUTEX_HELD(&man_lock)); 6837 ap = man_find_active_path(mlp); 6838 6839 /* 6840 * Find a non-failed path, or the lru failed path and switch to it. 6841 */ 6842 for (np = mlp; np != NULL; np = np->mp_next) { 6843 if (np == ap) 6844 continue; 6845 6846 if (np->mp_device.mdev_state == MDEV_ASSIGNED) 6847 goto exit; 6848 6849 if (np->mp_device.mdev_state & MDEV_FAILED) { 6850 if (fp == NULL) 6851 fp = np; 6852 else 6853 if (fp->mp_lru > np->mp_lru) 6854 fp = np; 6855 } 6856 } 6857 6858 /* 6859 * Nowhere to switch to. 6860 */ 6861 if (np == NULL && (np = fp) == NULL) 6862 goto exit; 6863 6864 exit: 6865 return (np); 6866 } 6867 6868 /* 6869 * Assumes caller has verified existence. 6870 */ 6871 static void 6872 man_path_remove(man_path_t **lpp, man_path_t *mp) 6873 { 6874 man_path_t *tp; 6875 man_path_t *tpp; 6876 6877 ASSERT(MUTEX_HELD(&man_lock)); 6878 MAN_DBG(MAN_PATH, ("man_path_remove: removing path")); 6879 MAN_DBGCALL(MAN_PATH, man_print_path(mp)); 6880 6881 tp = tpp = *lpp; 6882 if (tp == mp) { 6883 *lpp = tp->mp_next; 6884 goto exit; 6885 } 6886 6887 for (tp = tp->mp_next; tp != NULL; tp = tp->mp_next) { 6888 if (tp == mp) 6889 break; 6890 tpp = tp; 6891 } 6892 6893 ASSERT(tp != NULL); 6894 6895 tpp->mp_next = tp->mp_next; 6896 tp->mp_next = NULL; 6897 6898 exit: 6899 man_path_kstat_uninit(tp); 6900 man_kfree(tp, sizeof (man_path_t)); 6901 6902 } 6903 6904 /* 6905 * Insert path into list, ascending order by ppa. 6906 */ 6907 static void 6908 man_path_insert(man_path_t **lpp, man_path_t *mp) 6909 { 6910 man_path_t *tp; 6911 man_path_t *tpp; 6912 6913 ASSERT(MUTEX_HELD(&man_lock)); 6914 if (*lpp == NULL) { 6915 *lpp = mp; 6916 return; 6917 } 6918 6919 tp = tpp = *lpp; 6920 if (tp->mp_device.mdev_ppa > mp->mp_device.mdev_ppa) { 6921 mp->mp_next = tp; 6922 *lpp = mp; 6923 return; 6924 } 6925 6926 for (tp = tp->mp_next; tp != NULL; tp = tp->mp_next) { 6927 if (tp->mp_device.mdev_ppa > mp->mp_device.mdev_ppa) 6928 break; 6929 tpp = tp; 6930 } 6931 6932 if (tp == NULL) { 6933 tpp->mp_next = mp; 6934 } else { 6935 tpp->mp_next = mp; 6936 mp->mp_next = tp; 6937 } 6938 } 6939 6940 /* 6941 * Merge npp into lpp, ascending order by ppa. Assumes no 6942 * duplicates in either list. 6943 */ 6944 static void 6945 man_path_merge(man_path_t **lpp, man_path_t *np) 6946 { 6947 man_path_t *tmp; 6948 6949 ASSERT(MUTEX_HELD(&man_lock)); 6950 while (np != NULL) { 6951 tmp = np; 6952 np = np->mp_next; 6953 tmp->mp_next = NULL; 6954 6955 man_path_insert(lpp, tmp); 6956 } 6957 6958 } 6959 6960 static int 6961 man_path_kstat_init(man_path_t *mpp) 6962 { 6963 6964 kstat_named_t *dev_knp; 6965 int status = 0; 6966 6967 ASSERT(MUTEX_HELD(&man_lock)); 6968 MAN_DBG(MAN_PATH, ("man_path_kstat_init: mpp(0x%p)\n", (void *)mpp)); 6969 6970 /* 6971 * Create named kstats for accounting purposes. 6972 */ 6973 dev_knp = man_kzalloc(MAN_NUMSTATS * sizeof (kstat_named_t), 6974 KM_NOSLEEP); 6975 if (dev_knp == NULL) { 6976 status = ENOMEM; 6977 goto exit; 6978 } 6979 man_kstat_named_init(dev_knp, MAN_NUMSTATS); 6980 mpp->mp_last_knp = dev_knp; 6981 6982 exit: 6983 6984 MAN_DBG(MAN_PATH, ("man_path_kstat_init: returns %d\n", status)); 6985 6986 return (status); 6987 } 6988 6989 static void 6990 man_path_kstat_uninit(man_path_t *mp) 6991 { 6992 ASSERT(MUTEX_HELD(&man_lock)); 6993 man_kfree(mp->mp_last_knp, MAN_NUMSTATS * sizeof (kstat_named_t)); 6994 } 6995 6996 /* 6997 * man_work_alloc - allocate and initiate a work request structure 6998 * 6999 * type - type of request to allocate 7000 * returns - success - ptr to an initialized work structure 7001 * - failure - NULL 7002 */ 7003 man_work_t * 7004 man_work_alloc(int type, int kmflag) 7005 { 7006 man_work_t *wp; 7007 7008 wp = man_kzalloc(sizeof (man_work_t), kmflag); 7009 if (wp == NULL) 7010 goto exit; 7011 7012 cv_init(&wp->mw_cv, NULL, CV_DRIVER, NULL); \ 7013 wp->mw_type = type; 7014 7015 exit: 7016 return (wp); 7017 } 7018 7019 /* 7020 * man_work_free - deallocate a work request structure 7021 * 7022 * wp - ptr to work structure to be freed 7023 */ 7024 void 7025 man_work_free(man_work_t *wp) 7026 { 7027 cv_destroy(&wp->mw_cv); 7028 man_kfree((void *)wp, sizeof (man_work_t)); 7029 } 7030 7031 /* 7032 * Post work to a work queue. The man_bwork sleeps on 7033 * man_bwork_q->q_cv, and work requesters may sleep on mw_cv. 7034 * The man_lock is used to protect both cv's. 7035 */ 7036 void 7037 man_work_add(man_workq_t *q, man_work_t *wp) 7038 { 7039 man_work_t *lp = q->q_work; 7040 7041 if (lp) { 7042 while (lp->mw_next != NULL) 7043 lp = lp->mw_next; 7044 7045 lp->mw_next = wp; 7046 7047 } else { 7048 q->q_work = wp; 7049 } 7050 7051 /* 7052 * cv_signal for man_bwork_q, qenable for man_iwork_q 7053 */ 7054 if (q == man_bwork_q) { 7055 cv_signal(&q->q_cv); 7056 7057 } else { /* q == man_iwork_q */ 7058 7059 if (man_ctl_wq != NULL) 7060 qenable(man_ctl_wq); 7061 } 7062 7063 } 7064 7065 /* <<<<<<<<<<<<<<<<<<<<<<< NDD SUPPORT FUNCTIONS >>>>>>>>>>>>>>>>>>> */ 7066 /* 7067 * ndd support functions to get/set parameters 7068 */ 7069 7070 /* 7071 * Register each element of the parameter array with the 7072 * named dispatch handler. Each element is loaded using 7073 * nd_load() 7074 * 7075 * cnt - the number of elements present in the parameter array 7076 */ 7077 static int 7078 man_param_register(param_t *manpa, int cnt) 7079 { 7080 int i; 7081 ndgetf_t getp; 7082 ndsetf_t setp; 7083 int status = B_TRUE; 7084 7085 MAN_DBG(MAN_CONFIG, ("man_param_register: manpa(0x%p) cnt %d\n", 7086 (void *)manpa, cnt)); 7087 7088 getp = man_param_get; 7089 7090 for (i = 0; i < cnt; i++, manpa++) { 7091 switch (man_param_display[i]) { 7092 case MAN_NDD_GETABLE: 7093 setp = NULL; 7094 break; 7095 7096 case MAN_NDD_SETABLE: 7097 setp = man_param_set; 7098 break; 7099 7100 default: 7101 continue; 7102 } 7103 7104 if (!nd_load(&man_ndlist, manpa->param_name, getp, 7105 setp, (caddr_t)manpa)) { 7106 7107 (void) man_nd_free(&man_ndlist); 7108 status = B_FALSE; 7109 goto exit; 7110 } 7111 } 7112 7113 if (!nd_load(&man_ndlist, "man_pathgroups_report", 7114 man_pathgroups_report, NULL, NULL)) { 7115 7116 (void) man_nd_free(&man_ndlist); 7117 status = B_FALSE; 7118 goto exit; 7119 } 7120 7121 if (!nd_load(&man_ndlist, "man_set_active_path", 7122 NULL, man_set_active_path, NULL)) { 7123 7124 (void) man_nd_free(&man_ndlist); 7125 status = B_FALSE; 7126 goto exit; 7127 } 7128 7129 if (!nd_load(&man_ndlist, "man_get_hostinfo", 7130 man_get_hostinfo, NULL, NULL)) { 7131 7132 (void) man_nd_free(&man_ndlist); 7133 status = B_FALSE; 7134 goto exit; 7135 } 7136 7137 exit: 7138 7139 MAN_DBG(MAN_CONFIG, ("man_param_register: returns %d\n", status)); 7140 7141 return (status); 7142 } 7143 7144 static void 7145 man_nd_getset(queue_t *wq, mblk_t *mp) 7146 { 7147 7148 if (!nd_getset(wq, man_ndlist, mp)) 7149 miocnak(wq, mp, 0, ENOENT); 7150 else 7151 qreply(wq, mp); 7152 } 7153 7154 /*ARGSUSED*/ 7155 static int 7156 man_pathgroups_report(queue_t *wq, mblk_t *mp, caddr_t cp, cred_t *cr) 7157 { 7158 7159 man_t *manp; 7160 man_pg_t *mpg; 7161 int i; 7162 char pad[] = " "; /* 17 spaces */ 7163 int pad_end; 7164 7165 7166 MAN_DBG(MAN_PATH, ("man_pathgroups_report: wq(0x%p) mp(0x%p)" 7167 " caddr 0x%p", (void *)wq, (void *)mp, (void *)cp)); 7168 7169 (void) mi_mpprintf(mp, "MAN Pathgroup report: (* == failed)"); 7170 (void) mi_mpprintf(mp, "=====================================" 7171 "=========================================="); 7172 7173 mutex_enter(&man_lock); 7174 7175 for (i = 0; i < 2; i++) { 7176 manp = ddi_get_soft_state(man_softstate, i); 7177 if (manp == NULL) 7178 continue; 7179 7180 (void) mi_mpprintf(mp, 7181 "Interface\tDestination\t\tActive Path\tAlternate Paths"); 7182 (void) mi_mpprintf(mp, "---------------------------------------" 7183 "----------------------------------------"); 7184 7185 for (mpg = manp->man_pg; mpg != NULL; mpg = mpg->mpg_next) { 7186 7187 (void) mi_mpprintf(mp, "%s%d\t\t", 7188 ddi_major_to_name(manp->man_meta_major), 7189 manp->man_meta_ppa); 7190 7191 if (man_is_on_domain) { 7192 (void) mi_mpprintf_nr(mp, "Master SSC\t"); 7193 man_preport(mpg->mpg_pathp, mp); 7194 } else { 7195 if (i == 0) { 7196 pad_end = 17 - strlen(ether_sprintf( 7197 &mpg->mpg_dst_eaddr)); 7198 if (pad_end < 0 || pad_end > 16) 7199 pad_end = 0; 7200 pad[pad_end] = '\0'; 7201 7202 (void) mi_mpprintf_nr(mp, "%c %s%s", 7203 mpg->mpg_pg_id + 'A', 7204 ether_sprintf(&mpg->mpg_dst_eaddr), 7205 pad); 7206 7207 pad[pad_end] = ' '; 7208 } else { 7209 (void) mi_mpprintf_nr(mp, "Other SSC\t"); 7210 } 7211 man_preport(mpg->mpg_pathp, mp); 7212 } 7213 (void) mi_mpprintf_nr(mp, "\n"); 7214 } 7215 } 7216 7217 mutex_exit(&man_lock); 7218 MAN_DBG(MAN_PATH, ("man_pathgroups_report: returns")); 7219 7220 return (0); 7221 } 7222 7223 static void 7224 man_preport(man_path_t *plist, mblk_t *mp) 7225 { 7226 man_path_t *ap; 7227 7228 ap = man_find_active_path(plist); 7229 /* 7230 * Active path 7231 */ 7232 if (ap != NULL) { 7233 (void) mi_mpprintf_nr(mp, "\t%s%d\t\t", 7234 ddi_major_to_name(ap->mp_device.mdev_major), 7235 ap->mp_device.mdev_ppa); 7236 } else { 7237 (void) mi_mpprintf_nr(mp, "None \t"); 7238 } 7239 7240 /* 7241 * Alternate Paths. 7242 */ 7243 while (plist != NULL) { 7244 (void) mi_mpprintf_nr(mp, "%s%d exp %d", 7245 ddi_major_to_name(plist->mp_device.mdev_major), 7246 plist->mp_device.mdev_ppa, 7247 plist->mp_device.mdev_exp_id); 7248 if (plist->mp_device.mdev_state & MDEV_FAILED) 7249 (void) mi_mpprintf_nr(mp, "*"); 7250 plist = plist->mp_next; 7251 if (plist) 7252 (void) mi_mpprintf_nr(mp, ", "); 7253 } 7254 } 7255 7256 /* 7257 * NDD request to set active path. Calling context is man_ioctl, so we are 7258 * exclusive in the inner perimeter. 7259 * 7260 * Syntax is "ndd -set /dev/dman <man ppa> <pg_id> <phys ppa>" 7261 */ 7262 /* ARGSUSED3 */ 7263 static int 7264 man_set_active_path(queue_t *wq, mblk_t *mp, char *value, caddr_t cp, 7265 cred_t *cr) 7266 { 7267 char *end, *meta_ppap, *phys_ppap, *pg_idp; 7268 int meta_ppa; 7269 int phys_ppa; 7270 int pg_id; 7271 man_t *manp; 7272 man_pg_t *mpg; 7273 man_path_t *np; 7274 mi_path_t mpath; 7275 int status = 0; 7276 7277 MAN_DBG(MAN_PATH, ("man_set_active_path: wq(0x%p) mp(0x%p)" 7278 " args %s", (void *)wq, (void *)mp, value)); 7279 7280 meta_ppap = value; 7281 7282 if ((pg_idp = strchr(value, ' ')) == NULL) { 7283 status = EINVAL; 7284 goto exit; 7285 } 7286 7287 *pg_idp++ = '\0'; 7288 7289 if ((phys_ppap = strchr(pg_idp, ' ')) == NULL) { 7290 status = EINVAL; 7291 goto exit; 7292 } 7293 7294 *phys_ppap++ = '\0'; 7295 7296 meta_ppa = (int)mi_strtol(meta_ppap, &end, 10); 7297 pg_id = (int)mi_strtol(pg_idp, &end, 10); 7298 phys_ppa = (int)mi_strtol(phys_ppap, &end, 10); 7299 7300 mutex_enter(&man_lock); 7301 manp = ddi_get_soft_state(man_softstate, meta_ppa); 7302 if (manp == NULL || manp->man_pg == NULL) { 7303 status = EINVAL; 7304 mutex_exit(&man_lock); 7305 goto exit; 7306 } 7307 7308 mpg = man_find_pg_by_id(manp->man_pg, pg_id); 7309 if (mpg == NULL) { 7310 status = EINVAL; 7311 mutex_exit(&man_lock); 7312 goto exit; 7313 } 7314 7315 np = man_find_path_by_ppa(mpg->mpg_pathp, phys_ppa); 7316 7317 if (np == NULL) { 7318 status = EINVAL; 7319 mutex_exit(&man_lock); 7320 goto exit; 7321 } 7322 7323 mpath.mip_cmd = MI_PATH_ACTIVATE; 7324 mpath.mip_pg_id = pg_id; 7325 mpath.mip_man_ppa = meta_ppa; 7326 mpath.mip_devs[0] = np->mp_device; 7327 mpath.mip_ndevs = 1; 7328 7329 status = man_pg_cmd(&mpath, NULL); 7330 mutex_exit(&man_lock); 7331 7332 exit: 7333 7334 MAN_DBG(MAN_PATH, ("man_set_active_path: returns %d", status)); 7335 7336 return (status); 7337 } 7338 7339 /* 7340 * Dump out the contents of the IOSRAM handoff structure. Note that if 7341 * anything changes here, you must make sure that the sysinit script 7342 * stays in sync with this output. 7343 */ 7344 /* ARGSUSED */ 7345 static int 7346 man_get_hostinfo(queue_t *wq, mblk_t *mp, caddr_t cp, cred_t *cr) 7347 { 7348 manc_t manc; 7349 char *ipaddr; 7350 char ipv6addr[INET6_ADDRSTRLEN]; 7351 int i; 7352 int status; 7353 7354 if (!man_is_on_domain) 7355 return (0); 7356 7357 if (status = man_get_iosram(&manc)) { 7358 return (status); 7359 } 7360 7361 mi_mpprintf(mp, "manc_magic = 0x%x", manc.manc_magic); 7362 mi_mpprintf(mp, "manc_version = 0%d", manc.manc_version); 7363 mi_mpprintf(mp, "manc_csum = 0x%x", manc.manc_csum); 7364 7365 if (manc.manc_ip_type == AF_INET) { 7366 in_addr_t netnum; 7367 7368 mi_mpprintf(mp, "manc_ip_type = AF_INET"); 7369 7370 ipaddr = man_inet_ntoa(manc.manc_dom_ipaddr); 7371 mi_mpprintf(mp, "manc_dom_ipaddr = %s", ipaddr); 7372 7373 ipaddr = man_inet_ntoa(manc.manc_dom_ip_netmask); 7374 mi_mpprintf(mp, "manc_dom_ip_netmask = %s", ipaddr); 7375 7376 netnum = manc.manc_dom_ipaddr & manc.manc_dom_ip_netmask; 7377 ipaddr = man_inet_ntoa(netnum); 7378 mi_mpprintf(mp, "manc_dom_ip_netnum = %s", ipaddr); 7379 7380 ipaddr = man_inet_ntoa(manc.manc_sc_ipaddr); 7381 mi_mpprintf(mp, "manc_sc_ipaddr = %s", ipaddr); 7382 7383 } else if (manc.manc_ip_type == AF_INET6) { 7384 7385 mi_mpprintf(mp, "manc_ip_type = AF_INET6"); 7386 7387 (void) inet_ntop(AF_INET6, (void *)&manc.manc_dom_ipv6addr, 7388 ipv6addr, INET6_ADDRSTRLEN); 7389 mi_mpprintf(mp, "manc_dom_ipv6addr = %s", ipv6addr); 7390 7391 mi_mpprintf(mp, "manc_dom_ipv6_netmask = %d", 7392 manc.manc_dom_ipv6_netmask.s6_addr[0]); 7393 7394 (void) inet_ntop(AF_INET6, (void *)&manc.manc_sc_ipv6addr, 7395 ipv6addr, INET6_ADDRSTRLEN); 7396 mi_mpprintf(mp, "manc_sc_ipv6addr = %s", ipv6addr); 7397 7398 } else { 7399 7400 mi_mpprintf(mp, "manc_ip_type = NONE"); 7401 } 7402 7403 mi_mpprintf(mp, "manc_dom_eaddr = %s", 7404 ether_sprintf(&manc.manc_dom_eaddr)); 7405 mi_mpprintf(mp, "manc_sc_eaddr = %s", 7406 ether_sprintf(&manc.manc_sc_eaddr)); 7407 7408 mi_mpprintf(mp, "manc_iob_bitmap = 0x%x\tio boards = ", 7409 manc.manc_iob_bitmap); 7410 for (i = 0; i < MAN_MAX_EXPANDERS; i++) { 7411 if ((manc.manc_iob_bitmap >> i) & 0x1) { 7412 mi_mpprintf_nr(mp, "%d.1, ", i); 7413 } 7414 } 7415 mi_mpprintf(mp, "manc_golden_iob = %d", manc.manc_golden_iob); 7416 7417 return (0); 7418 } 7419 7420 static char * 7421 man_inet_ntoa(in_addr_t in) 7422 { 7423 static char b[18]; 7424 unsigned char *p; 7425 7426 p = (unsigned char *)∈ 7427 (void) sprintf(b, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); 7428 return (b); 7429 } 7430 7431 /* 7432 * parameter value. cp points to the required parameter. 7433 */ 7434 /* ARGSUSED */ 7435 static int 7436 man_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr) 7437 { 7438 param_t *manpa = (param_t *)cp; 7439 7440 (void) mi_mpprintf(mp, "%u", manpa->param_val); 7441 return (0); 7442 } 7443 7444 /* 7445 * Sets the man parameter to the value in the param_register using 7446 * nd_load(). 7447 */ 7448 /* ARGSUSED */ 7449 static int 7450 man_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *cr) 7451 { 7452 char *end; 7453 size_t new_value; 7454 param_t *manpa = (param_t *)cp; 7455 7456 new_value = mi_strtol(value, &end, 10); 7457 7458 if (end == value || new_value < manpa->param_min || 7459 new_value > manpa->param_max) { 7460 return (EINVAL); 7461 } 7462 7463 manpa->param_val = new_value; 7464 7465 return (0); 7466 7467 } 7468 7469 /* 7470 * Free the Named Dispatch Table by calling man_nd_free 7471 */ 7472 static void 7473 man_param_cleanup() 7474 { 7475 if (man_ndlist != NULL) 7476 nd_free(&man_ndlist); 7477 } 7478 7479 /* 7480 * Free the table pointed to by 'ndp' 7481 */ 7482 static void 7483 man_nd_free(caddr_t *nd_pparam) 7484 { 7485 ND *nd; 7486 7487 if ((nd = (ND *)(*nd_pparam)) != NULL) { 7488 if (nd->nd_tbl) 7489 mi_free((char *)nd->nd_tbl); 7490 mi_free((char *)nd); 7491 *nd_pparam = NULL; 7492 } 7493 } 7494 7495 7496 /* 7497 * man_kstat_update - update the statistics for a meta-interface. 7498 * 7499 * ksp - kstats struct 7500 * rw - flag indicating whether stats are to be read or written. 7501 * 7502 * returns 0 7503 * 7504 * The destination specific kstat information is protected by the 7505 * perimeter lock, so we submit a work request to get the stats 7506 * updated (see man_do_kstats()), and then collect the results 7507 * when cv_signal'd. Note that we are doing cv_timedwait_sig() 7508 * as a precautionary measure only. 7509 */ 7510 static int 7511 man_kstat_update(kstat_t *ksp, int rw) 7512 { 7513 man_t *manp; /* per instance data */ 7514 man_work_t *wp; 7515 int status = 0; 7516 kstat_named_t *knp; 7517 kstat_named_t *man_knp; 7518 int i; 7519 7520 MAN_DBG(MAN_KSTAT, ("man_kstat_update: %s\n", rw ? "KSTAT_WRITE" : 7521 "KSTAT_READ")); 7522 7523 mutex_enter(&man_lock); 7524 manp = (man_t *)ksp->ks_private; 7525 manp->man_refcnt++; 7526 7527 /* 7528 * If the driver has been configured, get kstats updated by inner 7529 * perimeter prior to retrieving. 7530 */ 7531 if (man_config_state == MAN_CONFIGURED) { 7532 clock_t wait_status; 7533 7534 man_update_path_kstats(manp); 7535 wp = man_work_alloc(MAN_WORK_KSTAT_UPDATE, KM_SLEEP); 7536 wp->mw_arg.a_man_ppa = manp->man_meta_ppa; 7537 wp->mw_flags = MAN_WFLAGS_CVWAITER; 7538 man_work_add(man_iwork_q, wp); 7539 7540 wait_status = cv_timedwait_sig(&wp->mw_cv, &man_lock, 7541 ddi_get_lbolt() + drv_usectohz(manp->man_kstat_waittime)); 7542 7543 if (wp->mw_flags & MAN_WFLAGS_DONE) { 7544 status = wp->mw_status; 7545 man_work_free(wp); 7546 } else { 7547 ASSERT(wait_status <= 0); 7548 wp->mw_flags &= ~MAN_WFLAGS_CVWAITER; 7549 if (wait_status == 0) 7550 status = EINTR; 7551 else { 7552 MAN_DBG(MAN_KSTAT, ("man_kstat_update: " 7553 "timedout, returning stale stats.")); 7554 status = 0; 7555 } 7556 } 7557 if (status) 7558 goto exit; 7559 } 7560 7561 knp = (kstat_named_t *)ksp->ks_data; 7562 man_knp = (kstat_named_t *)manp->man_ksp->ks_data; 7563 7564 if (rw == KSTAT_READ) { 7565 for (i = 0; i < MAN_NUMSTATS; i++) { 7566 knp[i].value.ui64 = man_knp[i].value.ui64; 7567 } 7568 } else { 7569 for (i = 0; i < MAN_NUMSTATS; i++) { 7570 man_knp[i].value.ui64 = knp[i].value.ui64; 7571 } 7572 } 7573 7574 exit: 7575 manp->man_refcnt--; 7576 mutex_exit(&man_lock); 7577 7578 MAN_DBG(MAN_KSTAT, ("man_kstat_update: returns %d", status)); 7579 7580 return (status); 7581 } 7582 7583 /* 7584 * Sum destination kstats for all active paths for a given instance of the 7585 * MAN driver. Called with perimeter lock. 7586 */ 7587 static void 7588 man_do_kstats(man_work_t *wp) 7589 { 7590 man_t *manp; 7591 man_pg_t *mpg; 7592 man_path_t *mp; 7593 7594 MAN_DBG(MAN_KSTAT, ("man_do_kstats:")); 7595 7596 mutex_enter(&man_lock); 7597 /* 7598 * Sync mp_last_knp for each path associated with the MAN instance. 7599 */ 7600 manp = (man_t *)ddi_get_soft_state(man_softstate, 7601 wp->mw_arg.a_man_ppa); 7602 for (mpg = manp->man_pg; mpg != NULL; mpg = mpg->mpg_next) { 7603 7604 ASSERT(mpg->mpg_man_ppa == manp->man_meta_ppa); 7605 7606 if ((mp = man_find_active_path(mpg->mpg_pathp)) != NULL) { 7607 7608 MAN_DBG(MAN_KSTAT, ("\tkstat: path")); 7609 MAN_DBGCALL(MAN_KSTAT, man_print_path(mp)); 7610 7611 /* 7612 * We just to update the destination statistics here. 7613 */ 7614 man_sum_dests_kstats(mp->mp_last_knp, mpg); 7615 } 7616 } 7617 mutex_exit(&man_lock); 7618 MAN_DBG(MAN_KSTAT, ("man_do_kstats: returns")); 7619 } 7620 7621 /* 7622 * Sum device kstats for all active paths for a given instance of the 7623 * MAN driver. Called with man_lock. 7624 */ 7625 static void 7626 man_update_path_kstats(man_t *manp) 7627 { 7628 kstat_named_t *man_knp; 7629 man_pg_t *mpg; 7630 man_path_t *mp; 7631 7632 ASSERT(MUTEX_HELD(&man_lock)); 7633 MAN_DBG(MAN_KSTAT, ("man_update_path_kstats:")); 7634 7635 man_knp = (kstat_named_t *)manp->man_ksp->ks_data; 7636 7637 for (mpg = manp->man_pg; mpg != NULL; mpg = mpg->mpg_next) { 7638 7639 ASSERT(mpg->mpg_man_ppa == manp->man_meta_ppa); 7640 7641 if ((mp = man_find_active_path(mpg->mpg_pathp)) != NULL) { 7642 7643 man_update_dev_kstats(man_knp, mp); 7644 7645 } 7646 } 7647 MAN_DBG(MAN_KSTAT, ("man_update_path_kstats: returns")); 7648 } 7649 7650 /* 7651 * Update the device kstats. 7652 * As man_kstat_update() is called with kstat_chain_lock held, 7653 * we can safely update the statistics from the underlying driver here. 7654 */ 7655 static void 7656 man_update_dev_kstats(kstat_named_t *man_knp, man_path_t *mp) 7657 { 7658 kstat_t *dev_ksp; 7659 major_t major; 7660 int instance; 7661 char buf[KSTAT_STRLEN]; 7662 7663 7664 major = mp->mp_device.mdev_major; 7665 instance = mp->mp_device.mdev_ppa; 7666 (void) sprintf(buf, "%s%d", ddi_major_to_name(major), instance); 7667 7668 dev_ksp = kstat_hold_byname(ddi_major_to_name(major), instance, buf, 7669 ALL_ZONES); 7670 if (dev_ksp != NULL) { 7671 7672 KSTAT_ENTER(dev_ksp); 7673 KSTAT_UPDATE(dev_ksp, KSTAT_READ); 7674 man_sum_kstats(man_knp, dev_ksp, mp->mp_last_knp); 7675 KSTAT_EXIT(dev_ksp); 7676 kstat_rele(dev_ksp); 7677 7678 } else { 7679 MAN_DBG(MAN_KSTAT, 7680 ("man_update_dev_kstats: no kstat data found for %s(%d,%d)", 7681 buf, major, instance)); 7682 } 7683 } 7684 7685 static void 7686 man_sum_dests_kstats(kstat_named_t *knp, man_pg_t *mpg) 7687 { 7688 int i; 7689 int flags; 7690 char *statname; 7691 manstr_t *msp; 7692 man_dest_t *mdp; 7693 uint64_t switches = 0; 7694 uint64_t linkfails = 0; 7695 uint64_t linkstales = 0; 7696 uint64_t icmpv4probes = 0; 7697 uint64_t icmpv6probes = 0; 7698 7699 MAN_DBG(MAN_KSTAT, ("man_sum_dests_kstats: mpg 0x%p", (void *)mpg)); 7700 7701 for (msp = man_strup; msp != NULL; msp = msp->ms_next) { 7702 7703 if (!man_str_uses_pg(msp, mpg)) 7704 continue; 7705 7706 mdp = &msp->ms_dests[mpg->mpg_pg_id]; 7707 7708 switches += mdp->md_switches; 7709 linkfails += mdp->md_linkfails; 7710 linkstales += mdp->md_linkstales; 7711 icmpv4probes += mdp->md_icmpv4probes; 7712 icmpv6probes += mdp->md_icmpv6probes; 7713 } 7714 7715 for (i = 0; i < MAN_NUMSTATS; i++) { 7716 7717 statname = man_kstat_info[i].mk_name; 7718 flags = man_kstat_info[i].mk_flags; 7719 7720 if (!(flags & MK_NOT_PHYSICAL)) 7721 continue; 7722 7723 if (strcmp(statname, "man_switches") == 0) { 7724 knp[i].value.ui64 = switches; 7725 } else if (strcmp(statname, "man_link_fails") == 0) { 7726 knp[i].value.ui64 = linkfails; 7727 } else if (strcmp(statname, "man_link_stales") == 0) { 7728 knp[i].value.ui64 = linkstales; 7729 } else if (strcmp(statname, "man_icmpv4_probes") == 0) { 7730 knp[i].value.ui64 = icmpv4probes; 7731 } else if (strcmp(statname, "man_icmpv6_probes") == 0) { 7732 knp[i].value.ui64 = icmpv6probes; 7733 } 7734 } 7735 7736 MAN_DBG(MAN_KSTAT, ("man_sum_dests_kstats: returns")); 7737 } 7738 7739 /* 7740 * Initialize MAN named kstats in the space provided. 7741 */ 7742 static void 7743 man_kstat_named_init(kstat_named_t *knp, int num_stats) 7744 { 7745 int i; 7746 7747 MAN_DBG(MAN_KSTAT, ("man_kstat_named_init: knp(0x%p) num_stats = %d", 7748 (void *)knp, num_stats)); 7749 7750 for (i = 0; i < num_stats; i++) { 7751 kstat_named_init(&knp[i], man_kstat_info[i].mk_name, 7752 man_kstat_info[i].mk_type); 7753 } 7754 7755 MAN_DBG(MAN_KSTAT, ("man_kstat_named_init: returns")); 7756 7757 } 7758 7759 /* 7760 * man_kstat_byname - get a kernel stat value from its structure 7761 * 7762 * ksp - kstat_t structure to play with 7763 * s - string to match names with 7764 * res - in/out result data pointer 7765 * 7766 * returns - success - 1 (found) 7767 * - failure - 0 (not found) 7768 */ 7769 static int 7770 man_kstat_byname(kstat_t *ksp, char *s, kstat_named_t *res) 7771 { 7772 int found = 0; 7773 7774 MAN_DBG(MAN_KSTAT2, ("man_kstat_byname: GETTING %s\n", s)); 7775 7776 if (ksp->ks_type == KSTAT_TYPE_NAMED) { 7777 kstat_named_t *knp; 7778 7779 for (knp = KSTAT_NAMED_PTR(ksp); 7780 (caddr_t)knp < ((caddr_t)ksp->ks_data+ksp->ks_data_size); 7781 knp++) { 7782 7783 if (strcmp(s, knp->name) == NULL) { 7784 7785 res->data_type = knp->data_type; 7786 res->value = knp->value; 7787 found++; 7788 7789 MAN_DBG(MAN_KSTAT2, ("\t%s: %d\n", knp->name, 7790 (int)knp->value.ul)); 7791 } 7792 } 7793 } else { 7794 MAN_DBG(MAN_KSTAT2, ("\tbad kstats type %d\n", ksp->ks_type)); 7795 } 7796 7797 /* 7798 * if getting a value but couldn't find the namestring, result = 0. 7799 */ 7800 if (!found) { 7801 /* 7802 * a reasonable default 7803 */ 7804 res->data_type = KSTAT_DATA_ULONG; 7805 res->value.l = 0; 7806 MAN_DBG(MAN_KSTAT2, ("\tcouldn't find, using defaults\n")); 7807 } 7808 7809 MAN_DBG(MAN_KSTAT2, ("man_kstat_byname: returns\n")); 7810 7811 return (found); 7812 } 7813 7814 7815 /* 7816 * 7817 * Accumulate MAN driver kstats from the incremental values of the underlying 7818 * physical interfaces. 7819 * 7820 * Parameters: 7821 * sum_knp - The named kstat area to put cumulative value, 7822 * NULL if we just want to sync next two params. 7823 * phys_ksp - Physical interface kstat_t pointer. Contains 7824 * more current counts. 7825 * phys_last_knp - counts from the last time we were called for this 7826 * physical interface. Note that the name kstats 7827 * pointed to are actually in MAN format, but they 7828 * hold the mirrored physical devices last read 7829 * kstats. 7830 * Basic algorithm is: 7831 * 7832 * for each named kstat variable { 7833 * sum_knp[i] += (phys_ksp->ksp_data[i] - phys_last_knp[i]); 7834 * phys_last_knp[i] = phys_ksp->ksp_data[i]; 7835 * } 7836 * 7837 */ 7838 static void 7839 man_sum_kstats(kstat_named_t *sum_knp, kstat_t *phys_ksp, 7840 kstat_named_t *phys_last_knp) 7841 { 7842 char *physname; 7843 char *physalias; 7844 char *statname; 7845 kstat_named_t phys_kn_entry; 7846 uint64_t delta64; 7847 int i; 7848 7849 MAN_DBG(MAN_KSTAT, ("man_sum_kstats: sum_knp(0x%p) phys_ksp(0x%p)" 7850 " phys_last_knp(0x%p)\n", (void *)sum_knp, (void *)phys_ksp, 7851 (void *)phys_last_knp)); 7852 7853 /* 7854 * Now for each entry in man_kstat_info, sum the named kstat. 7855 * Not that all MAN specific kstats will end up !found. 7856 */ 7857 for (i = 0; i < MAN_NUMSTATS; i++) { 7858 int found = 0; 7859 int flags = 0; 7860 7861 delta64 = 0; 7862 7863 statname = man_kstat_info[i].mk_name; 7864 physname = man_kstat_info[i].mk_physname; 7865 physalias = man_kstat_info[i].mk_physalias; 7866 flags = man_kstat_info[i].mk_flags; 7867 7868 /* 7869 * Update MAN private kstats. 7870 */ 7871 if (flags & MK_NOT_PHYSICAL) { 7872 7873 kstat_named_t *knp = phys_last_knp; 7874 7875 if (sum_knp == NULL) 7876 continue; 7877 7878 if (strcmp(statname, "man_switches") == 0) { 7879 sum_knp[i].value.ui64 = knp[i].value.ui64; 7880 } else if (strcmp(statname, "man_link_fails") == 0) { 7881 sum_knp[i].value.ui64 = knp[i].value.ui64; 7882 } else if (strcmp(statname, "man_link_stales") == 0) { 7883 sum_knp[i].value.ui64 = knp[i].value.ui64; 7884 } else if (strcmp(statname, "man_icmpv4_probes") == 0) { 7885 sum_knp[i].value.ui64 = knp[i].value.ui64; 7886 } else if (strcmp(statname, "man_icmpv6_probes") == 0) { 7887 sum_knp[i].value.ui64 = knp[i].value.ui64; 7888 } 7889 7890 continue; /* phys_ksp doesnt have this stat */ 7891 } 7892 7893 /* 7894 * first try it by the "official" name 7895 */ 7896 if (phys_ksp) { 7897 if (man_kstat_byname(phys_ksp, physname, 7898 &phys_kn_entry)) { 7899 7900 found = 1; 7901 7902 } else if ((physalias) && (man_kstat_byname(phys_ksp, 7903 physalias, &phys_kn_entry))) { 7904 7905 found = 1; 7906 } 7907 } 7908 7909 if (!found) { 7910 /* 7911 * clear up the "last" value, no change to the sum 7912 */ 7913 phys_last_knp[i].value.ui64 = 0; 7914 continue; 7915 } 7916 7917 /* 7918 * at this point, we should have the good underlying 7919 * kstat value stored in phys_kn_entry 7920 */ 7921 if (flags & MK_NOT_COUNTER) { 7922 /* 7923 * it isn't a counter, so store the value and 7924 * move on (e.g. ifspeed) 7925 */ 7926 phys_last_knp[i].value = phys_kn_entry.value; 7927 continue; 7928 } 7929 7930 switch (phys_kn_entry.data_type) { 7931 case KSTAT_DATA_UINT32: 7932 7933 /* 7934 * this handles 32-bit wrapping 7935 */ 7936 if (phys_kn_entry.value.ui32 < 7937 phys_last_knp[i].value.ui32) { 7938 7939 /* 7940 * we've wrapped! 7941 */ 7942 delta64 += (UINT_MAX - 7943 phys_last_knp[i].value.ui32); 7944 phys_last_knp[i].value.ui32 = 0; 7945 } 7946 7947 delta64 += phys_kn_entry.value.ui32 - 7948 phys_last_knp[i].value.ui32; 7949 phys_last_knp[i].value.ui32 = phys_kn_entry.value.ui32; 7950 break; 7951 7952 default: 7953 /* 7954 * must be a 64-bit value, we ignore 64-bit 7955 * wraps, since they shouldn't ever happen 7956 * within the life of a machine (if we assume 7957 * machines don't stay up for more than a few 7958 * hundred years without a reboot...) 7959 */ 7960 delta64 = phys_kn_entry.value.ui64 - 7961 phys_last_knp[i].value.ui64; 7962 phys_last_knp[i].value.ui64 = phys_kn_entry.value.ui64; 7963 } 7964 7965 if (sum_knp != NULL) { 7966 /* 7967 * now we need to save the value 7968 */ 7969 switch (sum_knp[i].data_type) { 7970 case KSTAT_DATA_UINT32: 7971 /* trunk down to 32 bits, possibly lossy */ 7972 sum_knp[i].value.ui32 += (uint32_t)delta64; 7973 break; 7974 7975 default: 7976 sum_knp[i].value.ui64 += delta64; 7977 break; 7978 } 7979 } 7980 } 7981 7982 MAN_DBG(MAN_KSTAT, ("man_sum_kstats: returns\n")); 7983 } 7984 7985 7986 #if defined(DEBUG) 7987 7988 7989 static char *_ms_flags[] = { 7990 "NONE", 7991 "FAST", /* 0x1 */ 7992 "RAW", /* 0x2 */ 7993 "ALLPHYS", /* 0x4 */ 7994 "ALLMULTI", /* 0x8 */ 7995 "ALLSAP", /* 0x10 */ 7996 "CKSUM", /* 0x20 */ 7997 "MULTI", /* 0x40 */ 7998 "SERLPBK", /* 0x80 */ 7999 "MACLPBK", /* 0x100 */ 8000 "CLOSING", /* 0x200 */ 8001 "CLOSE_DONE", /* 0x400 */ 8002 "CONTROL" /* 0x800 */ 8003 }; 8004 8005 static void 8006 man_print_msp(manstr_t *msp) 8007 { 8008 char buf[512]; 8009 char prbuf[512]; 8010 uint_t flags; 8011 int i; 8012 8013 cmn_err(CE_CONT, "\tmsp(0x%p)\n", (void *)msp); 8014 8015 if (msp == NULL) 8016 return; 8017 8018 cmn_err(CE_CONT, "\t%s%d SAP(0x%x):\n", 8019 ddi_major_to_name(msp->ms_meta_maj), msp->ms_meta_ppa, 8020 msp->ms_sap); 8021 8022 buf[0] = '\0'; 8023 prbuf[0] = '\0'; 8024 flags = msp->ms_flags; 8025 for (i = 0; i < A_CNT(_ms_flags); i++) { 8026 if ((flags >> i) & 0x1) { 8027 sprintf(buf, " %s |", _ms_flags[i+1]); 8028 strcat(prbuf, buf); 8029 } 8030 } 8031 prbuf[strlen(prbuf) - 1] = '\0'; 8032 cmn_err(CE_CONT, "\tms_flags: %s\n", prbuf); 8033 8034 cmn_err(CE_CONT, "\tms_dlpistate: %s\n", dss[msp->ms_dlpistate]); 8035 8036 cmn_err(CE_CONT, "\tms_dl_mp: 0x%p\n", (void *)msp->ms_dl_mp); 8037 8038 cmn_err(CE_CONT, "\tms_manp: 0x%p\n", (void *)msp->ms_manp); 8039 8040 cmn_err(CE_CONT, "\tms_dests: 0x%p\n", (void *)msp->ms_dests); 8041 8042 } 8043 8044 static char *_md_state[] = { 8045 "NOTPRESENT", /* 0x0 */ 8046 "INITIALIZING", /* 0x1 */ 8047 "READY", /* 0x2 */ 8048 "PLUMBING", /* 0x4 */ 8049 "CLOSING" /* 0x8 */ 8050 }; 8051 8052 static void 8053 man_print_mdp(man_dest_t *mdp) 8054 { 8055 uint_t state; 8056 int i; 8057 char buf[64]; 8058 char prbuf[512]; 8059 8060 buf[0] = '\0'; 8061 prbuf[0] = '\0'; 8062 8063 cmn_err(CE_CONT, "\tmdp(0x%p)\n", (void *)mdp); 8064 8065 if (mdp == NULL) 8066 return; 8067 8068 cmn_err(CE_CONT, "\tmd_pg_id: %d\n", mdp->md_pg_id); 8069 cmn_err(CE_CONT, "\tmd_dst_eaddr: %s\n", 8070 ether_sprintf(&mdp->md_dst_eaddr)); 8071 cmn_err(CE_CONT, "\tmd_src_eaddr: %s\n", 8072 ether_sprintf(&mdp->md_src_eaddr)); 8073 cmn_err(CE_CONT, "\tmd_dlpistate: %s", dss[mdp->md_dlpistate]); 8074 cmn_err(CE_CONT, "\tmd_muxid: 0x%u", mdp->md_muxid); 8075 cmn_err(CE_CONT, "\tmd_rcvcnt %lu md_lastrcvcnt %lu", mdp->md_rcvcnt, 8076 mdp->md_lastrcvcnt); 8077 8078 /* 8079 * Print out state as text. 8080 */ 8081 state = mdp->md_state; 8082 8083 if (state == 0) { 8084 strcat(prbuf, _md_state[0]); 8085 } else { 8086 8087 for (i = 0; i < A_CNT(_md_state); i++) { 8088 if ((state >> i) & 0x1) { 8089 sprintf(buf, " %s |", _md_state[i+1]); 8090 strcat(prbuf, buf); 8091 } 8092 } 8093 prbuf[strlen(prbuf) -1] = '\0'; 8094 } 8095 cmn_err(CE_CONT, "\tmd_state: %s", prbuf); 8096 8097 cmn_err(CE_CONT, "\tmd_device:\n"); 8098 man_print_dev(&mdp->md_device); 8099 8100 } 8101 8102 static void 8103 man_print_man(man_t *manp) 8104 { 8105 char buf[512]; 8106 char prbuf[512]; 8107 8108 buf[0] = '\0'; 8109 prbuf[0] = '\0'; 8110 8111 if (manp == NULL) 8112 return; 8113 8114 if (ddi_major_to_name(manp->man_meta_major)) { 8115 sprintf(buf, "\t man_device: %s%d\n", 8116 ddi_major_to_name(manp->man_meta_major), 8117 manp->man_meta_ppa); 8118 } else { 8119 sprintf(buf, "\t major: %d", manp->man_meta_major); 8120 sprintf(buf, "\t ppa: %d", manp->man_meta_ppa); 8121 } 8122 8123 cmn_err(CE_CONT, "%s", buf); 8124 8125 } 8126 8127 static char *_mdev_state[] = { 8128 "UNASSIGNED ", 8129 "ASSIGNED", 8130 "ACTIVE", 8131 "FAILED" 8132 }; 8133 8134 static void 8135 man_print_dev(man_dev_t *mdevp) 8136 { 8137 char buf[512]; 8138 char prbuf[512]; 8139 int i; 8140 uint_t state; 8141 8142 buf[0] = '\0'; 8143 prbuf[0] = '\0'; 8144 8145 if (mdevp == NULL) 8146 return; 8147 8148 if (mdevp->mdev_major == 0) { 8149 number: 8150 sprintf(buf, "\t mdev_major: %d\n", mdevp->mdev_major); 8151 } else if (ddi_major_to_name(mdevp->mdev_major)) { 8152 sprintf(buf, "\t mdev_device: %s%d\n", 8153 ddi_major_to_name(mdevp->mdev_major), 8154 mdevp->mdev_ppa); 8155 } else 8156 goto number; 8157 8158 cmn_err(CE_CONT, "%s", buf); 8159 8160 cmn_err(CE_CONT, "\t mdev_exp_id: %d\n", mdevp->mdev_exp_id); 8161 8162 buf[0] = '\0'; 8163 prbuf[0] = '\0'; 8164 state = mdevp->mdev_state; 8165 8166 if (state == 0) { 8167 strcat(prbuf, _mdev_state[0]); 8168 } else { 8169 for (i = 0; i < A_CNT(_mdev_state); i++) { 8170 if ((state >> i) & 0x1) { 8171 sprintf(buf, " %s |", _mdev_state[i+1]); 8172 strcat(prbuf, buf); 8173 } 8174 } 8175 } 8176 8177 prbuf[strlen(prbuf) - 2] = '\0'; 8178 8179 cmn_err(CE_CONT, "\t mdev_state: %s\n", prbuf); 8180 8181 } 8182 8183 static char *_mip_cmd[] = { 8184 "MI_PATH_READ", 8185 "MI_PATH_ASSIGN", 8186 "MI_PATH_ACTIVATE", 8187 "MI_PATH_DEACTIVATE", 8188 "MI_PATH_UNASSIGN" 8189 }; 8190 8191 static void 8192 man_print_mtp(mi_time_t *mtp) 8193 { 8194 cmn_err(CE_CONT, "\tmtp(0x%p)\n", (void *)mtp); 8195 8196 if (mtp == NULL) 8197 return; 8198 8199 cmn_err(CE_CONT, "\tmtp_instance: %d\n", mtp->mtp_man_ppa); 8200 8201 cmn_err(CE_CONT, "\tmtp_time: %d\n", mtp->mtp_time); 8202 8203 } 8204 8205 static void 8206 man_print_mip(mi_path_t *mip) 8207 { 8208 cmn_err(CE_CONT, "\tmip(0x%p)\n", (void *)mip); 8209 8210 if (mip == NULL) 8211 return; 8212 8213 cmn_err(CE_CONT, "\tmip_pg_id: %d\n", mip->mip_pg_id); 8214 8215 cmn_err(CE_CONT, "\tmip_cmd: %s\n", _mip_cmd[mip->mip_cmd]); 8216 8217 cmn_err(CE_CONT, "\tmip_eaddr: %s\n", ether_sprintf(&mip->mip_eaddr)); 8218 8219 cmn_err(CE_CONT, "\tmip_devs: 0x%p\n", (void *)mip->mip_devs); 8220 8221 cmn_err(CE_CONT, "\tmip_ndevs: %d\n", mip->mip_ndevs); 8222 8223 } 8224 8225 static void 8226 man_print_mpg(man_pg_t *mpg) 8227 { 8228 cmn_err(CE_CONT, "\tmpg(0x%p)\n", (void *)mpg); 8229 8230 if (mpg == NULL) 8231 return; 8232 8233 cmn_err(CE_CONT, "\tmpg_next: 0x%p\n", (void *)mpg->mpg_next); 8234 8235 cmn_err(CE_CONT, "\tmpg_pg_id: %d\n", mpg->mpg_pg_id); 8236 8237 cmn_err(CE_CONT, "\tmpg_man_ppa: %d\n", mpg->mpg_man_ppa); 8238 8239 cmn_err(CE_CONT, "\tmpg_dst_eaddr: %s\n", 8240 ether_sprintf(&mpg->mpg_dst_eaddr)); 8241 8242 cmn_err(CE_CONT, "\tmpg_pathp: 0x%p\n", (void *)mpg->mpg_pathp); 8243 8244 } 8245 8246 static char *_mw_flags[] = { 8247 "NOWAITER", /* 0x0 */ 8248 "CVWAITER", /* 0x1 */ 8249 "QWAITER", /* 0x2 */ 8250 "DONE" /* 0x3 */ 8251 }; 8252 8253 static void 8254 man_print_work(man_work_t *wp) 8255 { 8256 int i; 8257 8258 cmn_err(CE_CONT, "\twp(0x%p)\n\n", (void *)wp); 8259 8260 if (wp == NULL) 8261 return; 8262 8263 cmn_err(CE_CONT, "\tmw_type: %s\n", _mw_type[wp->mw_type]); 8264 8265 cmn_err(CE_CONT, "\tmw_flags: "); 8266 for (i = 0; i < A_CNT(_mw_flags); i++) { 8267 if ((wp->mw_flags >> i) & 0x1) 8268 cmn_err(CE_CONT, "%s", _mw_flags[i]); 8269 } 8270 cmn_err(CE_CONT, "\n"); 8271 8272 cmn_err(CE_CONT, "\twp_status: %d\n", wp->mw_status); 8273 8274 cmn_err(CE_CONT, "\twp_arg: 0x%p\n", (void *)&wp->mw_arg); 8275 8276 cmn_err(CE_CONT, "\tmw_next: 0x%p\n", (void *)wp->mw_next); 8277 8278 cmn_err(CE_CONT, "\twp_q: 0x%p", (void *)wp->mw_q); 8279 8280 } 8281 8282 static void 8283 man_print_path(man_path_t *mp) 8284 { 8285 cmn_err(CE_CONT, "\tmp(0x%p)\n\n", (void *)mp); 8286 8287 if (mp == NULL) 8288 return; 8289 8290 cmn_err(CE_CONT, "\tmp_device:"); 8291 man_print_dev(&mp->mp_device); 8292 8293 cmn_err(CE_CONT, "\tmp_next: 0x%p\n", (void *)mp->mp_next); 8294 8295 cmn_err(CE_CONT, "\tmp_last_knp: 0x%p\n", (void *)mp->mp_last_knp); 8296 8297 cmn_err(CE_CONT, "\tmp_lru: 0x%lx", mp->mp_lru); 8298 8299 } 8300 8301 void * 8302 man_dbg_kzalloc(int line, size_t size, int kmflags) 8303 { 8304 void *tmp; 8305 8306 tmp = kmem_zalloc(size, kmflags); 8307 MAN_DBG(MAN_KMEM, ("0x%p %lu\tzalloc'd @ %d\n", (void *)tmp, 8308 size, line)); 8309 8310 return (tmp); 8311 8312 } 8313 8314 void 8315 man_dbg_kfree(int line, void *buf, size_t size) 8316 { 8317 8318 MAN_DBG(MAN_KMEM, ("0x%p %lu\tfree'd @ %d\n", (void *)buf, size, line)); 8319 8320 kmem_free(buf, size); 8321 8322 } 8323 8324 #endif /* DEBUG */ 8325