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 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27
28 /*
29 * Starcat Management Network Driver
30 *
31 * ****** NOTICE **** This file also resides in the SSC gate as
32 * ****** NOTICE **** usr/src/uts/sun4u/scman/scman.c. Any changes
33 * ****** NOTICE **** made here must be propogated there as well.
34 *
35 */
36
37 #include <sys/types.h>
38 #include <sys/proc.h>
39 #include <sys/disp.h>
40 #include <sys/kmem.h>
41 #include <sys/stat.h>
42 #include <sys/kstat.h>
43 #include <sys/ksynch.h>
44 #include <sys/stream.h>
45 #include <sys/dlpi.h>
46 #include <sys/stropts.h>
47 #include <sys/strsubr.h>
48 #include <sys/debug.h>
49 #include <sys/conf.h>
50 #include <sys/kstr.h>
51 #include <sys/errno.h>
52 #include <sys/ethernet.h>
53 #include <sys/byteorder.h>
54 #include <sys/ddi.h>
55 #include <sys/sunddi.h>
56 #include <sys/sunldi.h>
57 #include <sys/modctl.h>
58 #include <sys/strsun.h>
59 #include <sys/callb.h>
60 #include <sys/pci.h>
61 #include <netinet/in.h>
62 #include <inet/common.h>
63 #include <inet/mi.h>
64 #include <inet/nd.h>
65 #include <sys/socket.h>
66 #include <netinet/igmp_var.h>
67 #include <netinet/ip6.h>
68 #include <netinet/icmp6.h>
69 #include <inet/ip.h>
70 #include <inet/ip6.h>
71 #include <sys/file.h>
72 #include <sys/dman.h>
73 #include <sys/autoconf.h>
74 #include <sys/zone.h>
75
76 extern int ddi_create_internal_pathname(dev_info_t *, char *, int, minor_t);
77
78 #define MAN_IDNAME "dman"
79 #define DMAN_INT_PATH "/devices/pseudo/dman@0:dman"
80 #define DMAN_PATH "/devices/pseudo/clone@0:dman"
81 #define ERI_IDNAME "eri"
82 #define ERI_PATH "/devices/pseudo/clone@0:eri"
83
84 #if defined(DEBUG)
85
86 static void man_print_msp(manstr_t *);
87 static void man_print_man(man_t *);
88 static void man_print_mdp(man_dest_t *);
89 static void man_print_dev(man_dev_t *);
90 static void man_print_mip(mi_path_t *);
91 static void man_print_mtp(mi_time_t *);
92 static void man_print_mpg(man_pg_t *);
93 static void man_print_path(man_path_t *);
94 static void man_print_work(man_work_t *);
95
96 /*
97 * Set manstr_t dlpistate (upper half of multiplexor)
98 */
99 #define SETSTATE(msp, state) \
100 MAN_DBG(MAN_DLPI, ("msp=0x%p @ %d state %s=>%s\n", \
101 (void *)msp, __LINE__, dss[msp->ms_dlpistate], \
102 dss[(state)])); \
103 msp->ms_dlpistate = (state);
104 /*
105 * Set man_dest_t dlpistate (lower half of multiplexor)
106 */
107 #define D_SETSTATE(mdp, state) \
108 MAN_DBG(MAN_DLPI, ("dst=0x%p @ %d state %s=>%s\n", \
109 (void *)mdp, __LINE__, dss[mdp->md_dlpistate], \
110 dss[(state)])); \
111 mdp->md_dlpistate = (state);
112
113 static char *promisc[] = { /* DLPI promisc Strings */
114 "not used", /* 0x00 */
115 "DL_PROMISC_PHYS", /* 0x01 */
116 "DL_PROMISC_SAP", /* 0x02 */
117 "DL_PROMISC_MULTI" /* 0x03 */
118 };
119
120 static char *dps[] = { /* DLPI Primitive Strings */
121 "DL_INFO_REQ", /* 0x00 */
122 "DL_BIND_REQ", /* 0x01 */
123 "DL_UNBIND_REQ", /* 0x02 */
124 "DL_INFO_ACK", /* 0x03 */
125 "DL_BIND_ACK", /* 0x04 */
126 "DL_ERROR_ACK", /* 0x05 */
127 "DL_OK_ACK", /* 0x06 */
128 "DL_UNITDATA_REQ", /* 0x07 */
129 "DL_UNITDATA_IND", /* 0x08 */
130 "DL_UDERROR_IND", /* 0x09 */
131 "DL_UDQOS_REQ", /* 0x0a */
132 "DL_ATTACH_REQ", /* 0x0b */
133 "DL_DETACH_REQ", /* 0x0c */
134 "DL_CONNECT_REQ", /* 0x0d */
135 "DL_CONNECT_IND", /* 0x0e */
136 "DL_CONNECT_RES", /* 0x0f */
137 "DL_CONNECT_CON", /* 0x10 */
138 "DL_TOKEN_REQ", /* 0x11 */
139 "DL_TOKEN_ACK", /* 0x12 */
140 "DL_DISCONNECT_REQ", /* 0x13 */
141 "DL_DISCONNECT_IND", /* 0x14 */
142 "DL_SUBS_UNBIND_REQ", /* 0x15 */
143 "DL_LIARLIARPANTSONFIRE", /* 0x16 */
144 "DL_RESET_REQ", /* 0x17 */
145 "DL_RESET_IND", /* 0x18 */
146 "DL_RESET_RES", /* 0x19 */
147 "DL_RESET_CON", /* 0x1a */
148 "DL_SUBS_BIND_REQ", /* 0x1b */
149 "DL_SUBS_BIND_ACK", /* 0x1c */
150 "DL_ENABMULTI_REQ", /* 0x1d */
151 "DL_DISABMULTI_REQ", /* 0x1e */
152 "DL_PROMISCON_REQ", /* 0x1f */
153 "DL_PROMISCOFF_REQ", /* 0x20 */
154 "DL_DATA_ACK_REQ", /* 0x21 */
155 "DL_DATA_ACK_IND", /* 0x22 */
156 "DL_DATA_ACK_STATUS_IND", /* 0x23 */
157 "DL_REPLY_REQ", /* 0x24 */
158 "DL_REPLY_IND", /* 0x25 */
159 "DL_REPLY_STATUS_IND", /* 0x26 */
160 "DL_REPLY_UPDATE_REQ", /* 0x27 */
161 "DL_REPLY_UPDATE_STATUS_IND", /* 0x28 */
162 "DL_XID_REQ", /* 0x29 */
163 "DL_XID_IND", /* 0x2a */
164 "DL_XID_RES", /* 0x2b */
165 "DL_XID_CON", /* 0x2c */
166 "DL_TEST_REQ", /* 0x2d */
167 "DL_TEST_IND", /* 0x2e */
168 "DL_TEST_RES", /* 0x2f */
169 "DL_TEST_CON", /* 0x30 */
170 "DL_PHYS_ADDR_REQ", /* 0x31 */
171 "DL_PHYS_ADDR_ACK", /* 0x32 */
172 "DL_SET_PHYS_ADDR_REQ", /* 0x33 */
173 "DL_GET_STATISTICS_REQ", /* 0x34 */
174 "DL_GET_STATISTICS_ACK", /* 0x35 */
175 };
176
177 #define MAN_DLPI_MAX_PRIM 0x35
178
179 static char *dss[] = { /* DLPI State Strings */
180 "DL_UNBOUND", /* 0x00 */
181 "DL_BIND_PENDING", /* 0x01 */
182 "DL_UNBIND_PENDING", /* 0x02 */
183 "DL_IDLE", /* 0x03 */
184 "DL_UNATTACHED", /* 0x04 */
185 "DL_ATTACH_PENDING", /* 0x05 */
186 "DL_DETACH_PENDING", /* 0x06 */
187 "DL_UDQOS_PENDING", /* 0x07 */
188 "DL_OUTCON_PENDING", /* 0x08 */
189 "DL_INCON_PENDING", /* 0x09 */
190 "DL_CONN_RES_PENDING", /* 0x0a */
191 "DL_DATAXFER", /* 0x0b */
192 "DL_USER_RESET_PENDING", /* 0x0c */
193 "DL_PROV_RESET_PENDING", /* 0x0d */
194 "DL_RESET_RES_PENDING", /* 0x0e */
195 "DL_DISCON8_PENDING", /* 0x0f */
196 "DL_DISCON9_PENDING", /* 0x10 */
197 "DL_DISCON11_PENDING", /* 0x11 */
198 "DL_DISCON12_PENDING", /* 0x12 */
199 "DL_DISCON13_PENDING", /* 0x13 */
200 "DL_SUBS_BIND_PND", /* 0x14 */
201 "DL_SUBS_UNBIND_PND", /* 0x15 */
202 };
203
204 static const char *lss[] = {
205 "UNKNOWN", /* 0x0 */
206 "INIT", /* 0x1 */
207 "GOOD", /* 0x2 */
208 "STALE", /* 0x3 */
209 "FAIL", /* 0x4 */
210 };
211
212 static char *_mw_type[] = {
213 "OPEN_CTL", /* 0x0 */
214 "CLOSE_CTL", /* 0x1 */
215 "SWITCH", /* 0x2 */
216 "PATH_UPDATE", /* 0x3 */
217 "CLOSE", /* 0x4 */
218 "CLOSE_STREAM", /* 0x5 */
219 "DRATTACH", /* 0x6 */
220 "DRDETACH", /* 0x7 */
221 "STOP", /* 0x8 */
222 "DRSWITCH", /* 0x9 */
223 "KSTAT_UPDATE" /* 0xA */
224 };
225
226 uint32_t man_debug = MAN_WARN;
227
228 #define man_kzalloc(a, b) man_dbg_kzalloc(__LINE__, a, b)
229 #define man_kfree(a, b) man_dbg_kfree(__LINE__, a, b)
230 void *man_dbg_kzalloc(int line, size_t size, int kmflags);
231 void man_dbg_kfree(int line, void *buf, size_t size);
232
233 #else /* DEBUG */
234
235 uint32_t man_debug = 0;
236 /*
237 * Set manstr_t dlpistate (upper half of multiplexor)
238 */
239 #define SETSTATE(msp, state) msp->ms_dlpistate = (state);
240 /*
241 * Set man_dest_t dlpistate (lower half of multiplexor)
242 */
243 #define D_SETSTATE(mdp, state) mdp->md_dlpistate = (state);
244
245 #define man_kzalloc(a, b) kmem_zalloc(a, b)
246 #define man_kfree(a, b) kmem_free(a, b)
247
248 #endif /* DEBUG */
249
250 #define DL_PRIM(mp) (((union DL_primitives *)(mp)->b_rptr)->dl_primitive)
251 #define DL_PROMISCON_TYPE(mp) \
252 (((union DL_primitives *)(mp)->b_rptr)->promiscon_req.dl_level)
253 #define IOC_CMD(mp) (((struct iocblk *)(mp)->b_rptr)->ioc_cmd)
254
255 /*
256 * Start of kstat-related declarations
257 */
258 #define MK_NOT_COUNTER (1<<0) /* is it a counter? */
259 #define MK_ERROR (1<<2) /* for error statistics */
260 #define MK_NOT_PHYSICAL (1<<3) /* no matching physical stat */
261
262 typedef struct man_kstat_info_s {
263 char *mk_name; /* e.g. align_errors */
264 char *mk_physname; /* e.g. framing (NULL for same) */
265 char *mk_physalias; /* e.g. framing (NULL for same) */
266 uchar_t mk_type; /* e.g. KSTAT_DATA_UINT32 */
267 int mk_flags;
268 } man_kstat_info_t;
269
270 /*
271 * Master declaration macro, note that it uses token pasting
272 */
273 #define MK_DECLARE(name, pname, palias, bits, flags) \
274 { name, pname, palias, KSTAT_DATA_UINT ## bits, flags }
275
276 /*
277 * Obsolete forms don't have the _sinceswitch forms, they are all errors
278 */
279 #define MK_OBSOLETE32(name, alias) MK_DECLARE(alias, name, alias, 32, MK_ERROR)
280 #define MK_OBSOLETE64(name, alias) MK_DECLARE(alias, name, alias, 64, MK_ERROR)
281
282 /*
283 * The only non-counters don't have any other aliases
284 */
285 #define MK_NOTCOUNTER32(name) MK_DECLARE(name, name, NULL, 32, MK_NOT_COUNTER)
286 #define MK_NOTCOUNTER64(name) MK_DECLARE(name, name, NULL, 64, MK_NOT_COUNTER)
287
288 /*
289 * Normal counter forms
290 */
291 #define MK_DECLARE32(name, alias) \
292 MK_DECLARE(name, name, alias, 32, 0)
293 #define MK_DECLARE64(name, alias) \
294 MK_DECLARE(name, name, alias, 64, 0)
295
296 /*
297 * Error counters need special MK_ERROR flag only for the non-AP form
298 */
299 #define MK_ERROR32(name, alias) \
300 MK_DECLARE(name, name, alias, 32, MK_ERROR)
301 #define MK_ERROR64(name, alias) \
302 MK_DECLARE(name, name, alias, 64, MK_ERROR)
303
304 /*
305 * These AP-specific stats are not backed by physical statistics
306 */
307 #define MK_NOTPHYS32(name) MK_DECLARE(name, NULL, NULL, 32, MK_NOT_PHYSICAL)
308 #define MK_NOTPHYS64(name) MK_DECLARE(name, NULL, NULL, 64, MK_NOT_PHYSICAL)
309
310 /*
311 * START of the actual man_kstat_info declaration using above macros
312 */
313 static man_kstat_info_t man_kstat_info[] = {
314 /*
315 * Link Input/Output stats
316 */
317 MK_DECLARE32("ipackets", NULL),
318 MK_ERROR32("ierrors", NULL),
319 MK_DECLARE32("opackets", NULL),
320 MK_ERROR32("oerrors", NULL),
321 MK_ERROR32("collisions", NULL),
322 MK_NOTCOUNTER64("ifspeed"),
323 /*
324 * These are new MIB-II stats, per PSARC 1997/198
325 */
326 MK_DECLARE32("rbytes", NULL),
327 MK_DECLARE32("obytes", NULL),
328 MK_DECLARE32("multircv", NULL),
329 MK_DECLARE32("multixmt", NULL),
330 MK_DECLARE32("brdcstrcv", NULL),
331 MK_DECLARE32("brdcstxmt", NULL),
332 /*
333 * Error values
334 */
335 MK_ERROR32("norcvbuf", NULL),
336 MK_ERROR32("noxmtbuf", NULL),
337 MK_ERROR32("unknowns", NULL),
338 /*
339 * These are the 64-bit values, they fallback to 32-bit values
340 */
341 MK_DECLARE64("ipackets64", "ipackets"),
342 MK_DECLARE64("opackets64", "opackets"),
343 MK_DECLARE64("rbytes64", "rbytes"),
344 MK_DECLARE64("obytes64", "obytes"),
345
346 /* New AP switching statistics */
347 MK_NOTPHYS64("man_switches"),
348 MK_NOTPHYS64("man_link_fails"),
349 MK_NOTPHYS64("man_link_stales"),
350 MK_NOTPHYS64("man_icmpv4_probes"),
351 MK_NOTPHYS64("man_icmpv6_probes"),
352
353 MK_ERROR32("align_errors", "framing"),
354 MK_ERROR32("fcs_errors", "crc"),
355 MK_ERROR32("first_collisions", NULL),
356 MK_ERROR32("multi_collisions", NULL),
357 MK_ERROR32("sqe_errors", "sqe"),
358
359 MK_ERROR32("tx_late_collisions", NULL),
360 MK_ERROR32("ex_collisions", "excollisions"),
361 MK_ERROR32("macxmt_errors", NULL),
362 MK_ERROR32("carrier_errors", "nocarrier"),
363 MK_ERROR32("toolong_errors", "buff"),
364 MK_ERROR32("macrcv_errors", NULL),
365
366 MK_OBSOLETE32("framing", "align_errors"),
367 MK_OBSOLETE32("crc", "fcs_errors"),
368 MK_OBSOLETE32("sqe", "sqe_errors"),
369 MK_OBSOLETE32("excollisions", "ex_collisions"),
370 MK_OBSOLETE32("nocarrier", "carrier_errors"),
371 MK_OBSOLETE32("buff", "toolong_errors"),
372 };
373
374 #define MAN_NUMSTATS (sizeof (man_kstat_info) / sizeof (man_kstat_info_t))
375
376 /*
377 * Miscellaneous ethernet stuff.
378 *
379 * MANs DL_INFO_ACK template.
380 */
381 static dl_info_ack_t man_infoack = {
382 DL_INFO_ACK, /* dl_primitive */
383 ETHERMTU, /* dl_max_sdu */
384 0, /* dl_min_sdu */
385 MAN_ADDRL, /* dl_addr_length */
386 DL_ETHER, /* dl_mac_type */
387 0, /* dl_reserved */
388 0, /* dl_current_state */
389 -2, /* dl_sap_length */
390 DL_CLDLS, /* dl_service_mode */
391 0, /* dl_qos_length */
392 0, /* dl_qos_offset */
393 0, /* dl_range_length */
394 0, /* dl_range_offset */
395 DL_STYLE2, /* dl_provider_style */
396 sizeof (dl_info_ack_t), /* dl_addr_offset */
397 DL_VERSION_2, /* dl_version */
398 ETHERADDRL, /* dl_brdcst_addr_length */
399 sizeof (dl_info_ack_t) + MAN_ADDRL, /* dl_brdcst_addr_offset */
400 0 /* dl_growth */
401 };
402
403 /*
404 * Ethernet broadcast address definition.
405 */
406 static struct ether_addr etherbroadcast = {
407 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
408 };
409
410 static struct ether_addr zero_ether_addr = {
411 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
412 };
413
414 /*
415 * Set via MAN_SET_SC_IPADDRS ioctl.
416 */
417 man_sc_ipaddrs_t man_sc_ipaddrs = { 0xffffffffU, 0xffffffffU };
418
419 /*
420 * Set via MAN_SET_SC_IP6ADDRS ioctl.
421 */
422 man_sc_ip6addrs_t man_sc_ip6addrs = { 0, 0, 0, 0, 0, 0, 0, 0 };
423
424 /*
425 * IP & ICMP constants
426 */
427 #ifndef ETHERTYPE_IPV6
428 #define ETHERTYPE_IPV6 0x86DD
429 #endif
430
431 /*
432 * Function prototypes.
433 *
434 * Upper multiplexor functions.
435 */
436 static int man_attach(dev_info_t *, ddi_attach_cmd_t);
437 static int man_detach(dev_info_t *, ddi_detach_cmd_t);
438 static int man_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
439 static int man_open(register queue_t *, dev_t *, int, int, cred_t *);
440 static int man_configure(queue_t *);
441 static int man_deconfigure(void);
442 static int man_init_dests(man_t *, manstr_t *);
443 static void man_start_dest(man_dest_t *, manstr_t *, man_pg_t *);
444 static void man_set_optimized_dest(manstr_t *);
445 static int man_close(queue_t *);
446 static void man_cancel_timers(man_adest_t *);
447 static int man_uwput(queue_t *, mblk_t *);
448 static int man_start(queue_t *, mblk_t *, eaddr_t *);
449 static void man_ioctl(queue_t *, mblk_t *);
450 static void man_set_linkcheck_time(queue_t *, mblk_t *);
451 static void man_setpath(queue_t *, mblk_t *);
452 static void man_geteaddr(queue_t *, mblk_t *);
453 static void man_set_sc_ipaddrs(queue_t *, mblk_t *);
454 static void man_set_sc_ip6addrs(queue_t *, mblk_t *);
455 static int man_get_our_etheraddr(eaddr_t *eap);
456 static void man_nd_getset(queue_t *, mblk_t *);
457 static void man_dl_ioc_hdr_info(queue_t *, mblk_t *);
458 static int man_uwsrv(queue_t *);
459 static int man_proto(queue_t *, mblk_t *);
460 static int man_udreq(queue_t *, mblk_t *);
461 static void man_areq(queue_t *, mblk_t *);
462 static mblk_t *man_alloc_physreq_mp(eaddr_t *);
463 static void man_dreq(queue_t *, mblk_t *);
464 static void man_dodetach(manstr_t *, man_work_t *);
465 static void man_dl_clean(mblk_t **);
466 static void man_breq(queue_t *, mblk_t *);
467 static void man_ubreq(queue_t *, mblk_t *);
468 static void man_ireq(queue_t *, mblk_t *);
469 static void man_ponreq(queue_t *, mblk_t *);
470 static void man_poffreq(queue_t *, mblk_t *);
471 static void man_emreq(queue_t *, mblk_t *);
472 static void man_dmreq(queue_t *, mblk_t *);
473 static void man_pareq(queue_t *, mblk_t *);
474 static void man_spareq(queue_t *, mblk_t *);
475 static int man_dlpi(manstr_t *, mblk_t *);
476 static int man_dlioc(manstr_t *, mblk_t *);
477 static int man_dl_catch(mblk_t **, mblk_t *);
478 static void man_dl_release(mblk_t **, mblk_t *);
479 static int man_match_proto(mblk_t *, mblk_t *);
480 static int man_open_ctl();
481 static void man_close_ctl();
482 /*
483 * upper/lower multiplexor functions.
484 */
485 static int man_dlpi_senddown(manstr_t *, mblk_t *);
486 static int man_start_lower(man_dest_t *, mblk_t *, queue_t *, int caller);
487 static int man_lrput(queue_t *, mblk_t *);
488 /*
489 * Lower multiplexor functions.
490 */
491 static int man_lwsrv(queue_t *);
492 static int man_lrsrv(queue_t *);
493 static void man_dlpi_replay(man_dest_t *, mblk_t *);
494 static int man_dlioc_replay(man_dest_t *);
495 /*
496 * Link failover routines.
497 */
498 static int man_gettimer(int, man_dest_t *);
499 static void man_linkcheck_timer(void *);
500 static int man_needs_linkcheck(man_dest_t *);
501 static int man_do_autoswitch(man_dest_t *);
502 static int man_autoswitch(man_pg_t *, man_dev_t *, man_work_t *);
503 static int man_prep_dests_for_switch(man_pg_t *, man_dest_t **, int *);
504 static int man_str_uses_pg(manstr_t *, man_pg_t *);
505 static void man_do_icmp_bcast(man_dest_t *, t_uscalar_t);
506 static mblk_t *man_alloc_udreq(int, man_dladdr_t *);
507 static mblk_t *man_pinger(t_uscalar_t);
508 /*
509 * Functions normally executing outside of the STREAMs perimeter.
510 */
511 /*
512 * Functions supporting/processing work requests.
513 */
514 static void man_bwork(void);
515 static void man_iwork(void); /* inside perimeter */
516 void man_work_add(man_workq_t *, man_work_t *);
517 man_work_t *man_work_alloc(int, int);
518 void man_work_free(man_work_t *);
519 /*
520 * Functions implementing/supporting failover.
521 *
522 * Executed inside perimeter.
523 */
524 static int man_do_dr_attach(man_work_t *);
525 static int man_do_dr_switch(man_work_t *);
526 static void man_do_dr_detach(man_work_t *);
527 static int man_iswitch(man_work_t *);
528 static void man_ifail_dest(man_dest_t *);
529 static man_dest_t *man_switch_match(man_dest_t *, int, void *);
530 static void man_add_dests(man_pg_t *);
531 static void man_reset_dlpi(void *);
532 static mblk_t *man_dup_mplist(mblk_t *);
533 static mblk_t *man_alloc_ubreq_dreq();
534 /*
535 * Executed outside perimeter (us man_lock for synchronization).
536 */
537 static void man_bclose(man_adest_t *);
538 static void man_bswitch(man_adest_t *, man_work_t *);
539 static int man_plumb(man_dest_t *);
540 static void man_unplumb(man_dest_t *);
541 static void man_plink(queue_t *, mblk_t *);
542 static void man_unplink(queue_t *, mblk_t *);
543 static void man_linkrec_insert(man_linkrec_t *);
544 static queue_t *man_linkrec_find(int);
545 /*
546 * Functions supporting pathgroups
547 */
548 int man_pg_cmd(mi_path_t *, man_work_t *);
549 static int man_pg_assign(man_pg_t **, mi_path_t *, int);
550 static int man_pg_create(man_pg_t **, man_pg_t **, mi_path_t *);
551 static int man_pg_unassign(man_pg_t **, mi_path_t *);
552 static int man_pg_activate(man_t *, mi_path_t *, man_work_t *);
553 static int man_pg_read(man_pg_t *, mi_path_t *);
554 static man_pg_t *man_find_path_by_dev(man_pg_t *, man_dev_t *, man_path_t **);
555 static man_pg_t *man_find_pg_by_id(man_pg_t *, int);
556 static man_path_t *man_find_path_by_ppa(man_path_t *, int);
557 static man_path_t *man_find_active_path(man_path_t *);
558 static man_path_t *man_find_alternate_path(man_path_t *);
559 static void man_path_remove(man_path_t **, man_path_t *);
560 static void man_path_insert(man_path_t **, man_path_t *);
561 static void man_path_merge(man_path_t **, man_path_t *);
562 static int man_path_kstat_init(man_path_t *);
563 static void man_path_kstat_uninit(man_path_t *);
564 /*
565 * Functions supporting kstat reporting.
566 */
567 static int man_kstat_update(kstat_t *, int);
568 static void man_do_kstats(man_work_t *);
569 static void man_update_path_kstats(man_t *);
570 static void man_update_dev_kstats(kstat_named_t *, man_path_t *);
571 static void man_sum_dests_kstats(kstat_named_t *, man_pg_t *);
572 static void man_kstat_named_init(kstat_named_t *, int);
573 static int man_kstat_byname(kstat_t *, char *, kstat_named_t *);
574 static void man_sum_kstats(kstat_named_t *, kstat_t *, kstat_named_t *);
575 /*
576 * Functions supporting ndd.
577 */
578 static int man_param_register(param_t *, int);
579 static int man_pathgroups_report(queue_t *, mblk_t *, caddr_t, cred_t *);
580 static void man_preport(man_path_t *, mblk_t *);
581 static int man_set_active_path(queue_t *, mblk_t *, char *, caddr_t,
582 cred_t *);
583 static int man_get_hostinfo(queue_t *, mblk_t *, caddr_t, cred_t *);
584 static char *man_inet_ntoa(in_addr_t);
585 static int man_param_get(queue_t *, mblk_t *, caddr_t, cred_t *);
586 static int man_param_set(queue_t *, mblk_t *, char *, caddr_t, cred_t *);
587 static void man_param_cleanup(void);
588 static void man_nd_free(caddr_t *nd_pparam);
589 /*
590 * MAN SSC/Domain specific externs.
591 */
592 extern int man_get_iosram(manc_t *);
593 extern int man_domain_configure(void);
594 extern int man_domain_deconfigure(void);
595 extern int man_dossc_switch(uint32_t);
596 extern int man_is_on_domain;
597
598 /*
599 * Driver Globals protected by inner perimeter.
600 */
601 static manstr_t *man_strup = NULL; /* list of MAN STREAMS */
602 static caddr_t man_ndlist = NULL; /* head of ndd var list */
603 void *man_softstate = NULL;
604
605 /*
606 * Driver globals protected by man_lock.
607 */
608 kmutex_t man_lock; /* lock protecting vars below */
609 static kthread_id_t man_bwork_id = NULL; /* background thread ID */
610 man_workq_t *man_bwork_q; /* bgthread work q */
611 man_workq_t *man_iwork_q; /* inner perim (uwsrv) work q */
612 static man_linkrec_t *man_linkrec_head = NULL; /* list of linkblks */
613 ldi_handle_t man_ctl_lh = NULL; /* MAN control handle */
614 queue_t *man_ctl_wq = NULL; /* MAN control rq */
615 static int man_config_state = MAN_UNCONFIGURED;
616 static int man_config_error = ENODEV;
617
618 /*
619 * These parameters are accessed via ndd to report the link configuration
620 * for the MAN driver. They can also be used to force configuration changes.
621 */
622 #define MAN_NOTUSR 0x0f000000
623
624 /* ------------------------------------------------------------------------- */
625
626 static param_t man_param_arr[] = {
627 /* min max value name */
628 { 0, 0xFFFF, 0, "man_debug_level"},
629 };
630
631 #define MAN_NDD_GETABLE 1
632 #define MAN_NDD_SETABLE 2
633
634 static uint32_t man_param_display[] = {
635 /* DISPLAY */
636 MAN_NDD_SETABLE, /* man_debug_level */
637 };
638
639 /*
640 * STREAMs information.
641 */
642 static struct module_info man_m_info = {
643 MAN_IDNUM, /* mi_idnum */
644 MAN_IDNAME, /* mi_idname */
645 MAN_MINPSZ, /* mi_minpsz */
646 MAN_MAXPSZ, /* mi_maxpsz */
647 MAN_HIWAT, /* mi_hiwat */
648 MAN_LOWAT /* mi_lowat */
649 };
650
651 /*
652 * Upper read queue does not do anything.
653 */
654 static struct qinit man_urinit = {
655 NULL, /* qi_putp */
656 NULL, /* qi_srvp */
657 man_open, /* qi_qopen */
658 man_close, /* qi_qclose */
659 NULL, /* qi_qadmin */
660 &man_m_info, /* qi_minfo */
661 NULL /* qi_mstat */
662 };
663
664 static struct qinit man_lrinit = {
665 man_lrput, /* qi_putp */
666 man_lrsrv, /* qi_srvp */
667 man_open, /* qi_qopen */
668 man_close, /* qi_qclose */
669 NULL, /* qi_qadmin */
670 &man_m_info, /* qi_minfo */
671 NULL /* qi_mstat */
672 };
673
674 static struct qinit man_uwinit = {
675 man_uwput, /* qi_putp */
676 man_uwsrv, /* qi_srvp */
677 man_open, /* qi_qopen */
678 man_close, /* qi_qclose */
679 NULL, /* qi_qadmin */
680 &man_m_info, /* qi_minfo */
681 NULL /* qi_mstat */
682 };
683
684 static struct qinit man_lwinit = {
685 NULL, /* qi_putp */
686 man_lwsrv, /* qi_srvp */
687 man_open, /* qi_qopen */
688 man_close, /* qi_qclose */
689 NULL, /* qi_qadmin */
690 &man_m_info, /* qi_minfo */
691 NULL /* qi_mstat */
692 };
693
694 static struct streamtab man_maninfo = {
695 &man_urinit, /* st_rdinit */
696 &man_uwinit, /* st_wrinit */
697 &man_lrinit, /* st_muxrinit */
698 &man_lwinit /* st_muxwrinit */
699 };
700
701
702 /*
703 * Module linkage information for the kernel.
704 *
705 * Locking Theory:
706 * D_MTPERMOD - Only an inner perimeter: All routines single
707 * threaded (except put, see below).
708 * D_MTPUTSHARED - Put routines enter inner perimeter shared (not
709 * exclusive) for concurrency/performance reasons.
710 *
711 * Anyone who needs exclusive outer perimeter permission (changing
712 * global data structures) does so via qwriter() calls. The
713 * background thread does all his work outside of perimeter and
714 * submits work via qtimeout() when data structures need to be
715 * modified.
716 */
717
718 #define MAN_MDEV_FLAGS (D_MP|D_MTPERMOD|D_MTPUTSHARED)
719
720 DDI_DEFINE_STREAM_OPS(man_ops, nulldev, nulldev, man_attach,
721 man_detach, nodev, man_info, MAN_MDEV_FLAGS, &man_maninfo,
722 ddi_quiesce_not_supported);
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",
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
_init(void)742 _init(void)
743 {
744 int status = DDI_FAILURE;
745
746 MAN_DBG(MAN_INIT, ("_init:"));
747
748 status = mod_install(&modlinkage);
749 if (status != 0) {
750 cmn_err(CE_WARN, "man_init: mod_install failed"
751 " error = %d", status);
752 return (status);
753 }
754
755 status = ddi_soft_state_init(&man_softstate, sizeof (man_t), 4);
756 if (status != 0) {
757 cmn_err(CE_WARN, "man_init: ddi_soft_state_init failed"
758 " error = %d", status);
759 (void) mod_remove(&modlinkage);
760 return (status);
761 }
762
763 man_bwork_q = man_kzalloc(sizeof (man_workq_t), KM_SLEEP);
764 man_iwork_q = man_kzalloc(sizeof (man_workq_t), KM_SLEEP);
765
766 mutex_init(&man_lock, NULL, MUTEX_DRIVER, NULL);
767 cv_init(&man_bwork_q->q_cv, NULL, CV_DRIVER, NULL);
768 cv_init(&man_iwork_q->q_cv, NULL, CV_DRIVER, NULL);
769
770 return (0);
771 }
772
773 /*
774 * _info is called by modinfo().
775 */
776 int
_info(struct modinfo * modinfop)777 _info(struct modinfo *modinfop)
778 {
779 int status;
780
781 MAN_DBG(MAN_INIT, ("_info:"));
782
783 status = mod_info(&modlinkage, modinfop);
784
785 MAN_DBG(MAN_INIT, ("_info: returns %d", status));
786
787 return (status);
788 }
789
790 /*
791 * _fini called by modunload() just before driver is unloaded from memory.
792 */
793 int
_fini(void)794 _fini(void)
795 {
796 int status = 0;
797
798 MAN_DBG(MAN_INIT, ("_fini:"));
799
800
801 /*
802 * The only upper stream left should be man_ctl_lh. Note that
803 * man_close (upper stream) is synchronous (i.e. it waits for
804 * all STREAMS framework associated with the upper stream to be
805 * torn down). This guarantees that man_ctl_lh will never become
806 * NULL until noone is around to notice. This assumption is made
807 * in a few places like man_plumb, man_unplumb, etc.
808 */
809 if (man_strup && (man_strup->ms_next != NULL))
810 return (EBUSY);
811
812 /*
813 * Deconfigure the driver.
814 */
815 status = man_deconfigure();
816 if (status)
817 goto exit;
818
819 /*
820 * need to detach every instance of the driver
821 */
822 status = mod_remove(&modlinkage);
823 if (status != 0)
824 goto exit;
825
826 ddi_soft_state_fini(&man_softstate);
827
828 /*
829 * Free up locks.
830 */
831 mutex_destroy(&man_lock);
832 cv_destroy(&man_bwork_q->q_cv);
833 cv_destroy(&man_iwork_q->q_cv);
834
835 man_kfree(man_bwork_q, sizeof (man_workq_t));
836 man_kfree(man_iwork_q, sizeof (man_workq_t));
837
838 exit:
839
840 MAN_DBG(MAN_INIT, ("_fini: returns %d", status));
841
842 return (status);
843 }
844
845 /*
846 * Deconfigure the MAN driver.
847 */
848 static int
man_deconfigure()849 man_deconfigure()
850 {
851 man_work_t *wp;
852 int status = 0;
853
854 MAN_DBG(MAN_CONFIG, ("man_deconfigure:\n"));
855
856 mutex_enter(&man_lock);
857
858 if (man_is_on_domain) {
859 status = man_domain_deconfigure();
860 if (status != 0)
861 goto exit;
862 }
863
864 man_param_cleanup(); /* Free up NDD resources */
865
866 /*
867 * I may have to handle straggling work requests. Just qwait?
868 * or cvwait? Called from _fini - TBD
869 */
870 ASSERT(man_bwork_q->q_work == NULL);
871 ASSERT(man_iwork_q->q_work == NULL);
872
873 MAN_DBG(MAN_CONFIG, ("man_deconfigure: submitting CLOSE_CTL\n"));
874
875 if (man_ctl_lh != NULL) {
876 wp = man_work_alloc(MAN_WORK_CLOSE_CTL, KM_SLEEP);
877 wp->mw_flags = MAN_WFLAGS_CVWAITER;
878 man_work_add(man_bwork_q, wp);
879
880 while (!(wp->mw_flags & MAN_WFLAGS_DONE)) {
881 cv_wait(&wp->mw_cv, &man_lock);
882 }
883 man_work_free(wp);
884 }
885
886 MAN_DBG(MAN_CONFIG, ("man_deconfigure: submitting STOP\n"));
887 if (man_bwork_id != NULL) {
888
889 wp = man_work_alloc(MAN_WORK_STOP, KM_SLEEP);
890 wp->mw_flags = MAN_WFLAGS_CVWAITER;
891 man_work_add(man_bwork_q, wp);
892
893 while (!(wp->mw_flags & MAN_WFLAGS_DONE)) {
894 cv_wait(&wp->mw_cv, &man_lock);
895 }
896 man_work_free(wp);
897 }
898 man_config_state = MAN_UNCONFIGURED;
899
900 exit:
901 mutex_exit(&man_lock);
902
903 MAN_DBG(MAN_CONFIG, ("man_deconfigure: returns %d\n", status));
904
905 return (status);
906 }
907
908 /*
909 * man_attach - allocate resources and attach an instance of the MAN driver
910 * The <man>.conf file controls how many instances of the MAN driver are
911 * available.
912 *
913 * dip - devinfo of node
914 * cmd - one of DDI_ATTACH | DDI_RESUME
915 *
916 * returns - success - DDI_SUCCESS
917 * - failure - DDI_FAILURE
918 */
919 static int
man_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)920 man_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
921 {
922 man_t *manp; /* per instance data */
923 uchar_t flag = KSTAT_FLAG_WRITABLE; /* support netstat -kc */
924 kstat_t *ksp;
925 int minor_node_created = 0;
926 int instance;
927 eaddr_t man_eaddr;
928
929 MAN_DBG(MAN_INIT, ("man_attach: \n"));
930
931 if (cmd != DDI_ATTACH) {
932 MAN_DBG(MAN_INIT, ("man_attach: bad command %d\n", cmd));
933 return (DDI_FAILURE);
934 }
935
936 if (man_get_our_etheraddr(&man_eaddr))
937 return (DDI_FAILURE);
938
939 instance = ddi_get_instance(dip);
940
941 /*
942 * we assume that instance is always equal to zero.
943 * and there will always only be one instance.
944 * this is done because when dman opens itself via DMAN_INT_PATH,
945 * the path assumes that the instance number is zero.
946 * if we ever need to support multiple instances of the dman
947 * driver or non-zero instances, this will have to change.
948 */
949 ASSERT(instance == 0);
950
951 /*
952 * Allocate per device info pointer and link in to global list of
953 * MAN devices.
954 */
955 if ((ddi_soft_state_zalloc(man_softstate, instance) != DDI_SUCCESS) ||
956 ((manp = ddi_get_soft_state(man_softstate, instance)) == NULL)) {
957 cmn_err(CE_WARN, "man_attach: cannot zalloc soft state!");
958 return (DDI_FAILURE);
959 }
960
961 ddi_set_driver_private(dip, manp);
962 manp->man_dip = dip;
963 manp->man_meta_major = ddi_driver_major(dip);
964 manp->man_meta_ppa = instance;
965
966 /*
967 * Set ethernet address. Note that this address is duplicated
968 * at md_src_eaddr.
969 */
970 ether_copy(&man_eaddr, &manp->man_eaddr);
971 manp->man_eaddr_v = 1;
972
973 MAN_DBG(MAN_INIT, ("man_attach: set ether to %s",
974 ether_sprintf(&manp->man_eaddr)));
975
976 /*
977 * Initialize failover-related fields (timers and such),
978 * taking values from properties if present.
979 */
980 manp->man_init_time = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
981 "init_time", MAN_INIT_TIME);
982
983 manp->man_linkcheck_time = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
984 "linkcheck_time", MAN_LINKCHECK_TIME);
985
986 manp->man_linkstale_time = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
987 "man_linkstale_time", MAN_LINKSTALE_TIME);
988
989 manp->man_linkstale_retries = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
990 "man_linkstale_retries", MAN_LINKSTALE_RETRIES);
991
992 manp->man_dr_delay = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
993 "man_dr_delay", MAN_DR_DELAY);
994
995 manp->man_dr_retries = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
996 "man_dr_retries", MAN_DR_RETRIES);
997
998 manp->man_kstat_waittime = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
999 "man_kstat_waittime", MAN_KSTAT_WAITTIME);
1000
1001 manp->man_dlpireset_time = ddi_getprop(DDI_DEV_T_ANY, dip, 0,
1002 "man_dlpireset_time", MAN_DLPIRESET_TIME);
1003
1004 if (ddi_create_internal_pathname(dip, MAN_IDNAME, S_IFCHR,
1005 ddi_get_instance(dip)) == DDI_SUCCESS) {
1006 minor_node_created = 1;
1007 } else {
1008 cmn_err(CE_WARN, "man_attach: failed for instance %d",
1009 ddi_get_instance(dip));
1010 goto exit;
1011 }
1012
1013 if (ddi_create_minor_node(dip, MAN_IDNAME, S_IFCHR,
1014 ddi_get_instance(dip), DDI_NT_NET, CLONE_DEV) == DDI_SUCCESS) {
1015 minor_node_created = 1;
1016 } else {
1017 cmn_err(CE_WARN, "man_attach: failed for instance %d",
1018 ddi_get_instance(dip));
1019 goto exit;
1020 }
1021
1022 /*
1023 * Allocate meta kstat_t for this instance of the driver.
1024 * Note that each of man_path_t keeps track of the kstats
1025 * for the real devices via mp_last_knp.
1026 */
1027 #ifdef kstat
1028 flag |= KSTAT_FLAG_PERSISTENT;
1029 #endif
1030 ksp = kstat_create(MAN_IDNAME, ddi_get_instance(dip), NULL, "net",
1031 KSTAT_TYPE_NAMED, MAN_NUMSTATS, flag);
1032
1033 if (ksp == NULL) {
1034 cmn_err(CE_WARN, "man_attach(%d): kstat_create failed"
1035 " - manp(0x%p)", manp->man_meta_ppa,
1036 (void *)manp);
1037 goto exit;
1038 }
1039
1040 man_kstat_named_init(ksp->ks_data, MAN_NUMSTATS);
1041 ksp->ks_update = man_kstat_update;
1042 ksp->ks_private = (void *) manp;
1043 manp->man_ksp = ksp;
1044 kstat_install(manp->man_ksp);
1045
1046 ddi_report_dev(dip);
1047
1048 MAN_DBG(MAN_INIT, ("man_attach(%d) returns DDI_SUCCESS",
1049 ddi_get_instance(dip)));
1050
1051 return (DDI_SUCCESS);
1052
1053 exit:
1054 if (minor_node_created)
1055 ddi_remove_minor_node(dip, NULL);
1056 ddi_set_driver_private(dip, NULL);
1057 ddi_soft_state_free(man_softstate, instance);
1058
1059 MAN_DBG(MAN_INIT, ("man_attach(%d) eaddr returns DDI_FAILIRE",
1060 ddi_get_instance(dip)));
1061
1062 return (DDI_FAILURE);
1063
1064 }
1065
1066 static int
man_get_our_etheraddr(eaddr_t * eap)1067 man_get_our_etheraddr(eaddr_t *eap)
1068 {
1069 manc_t manc;
1070 int status = 0;
1071
1072 if (man_is_on_domain) {
1073 if (status = man_get_iosram(&manc))
1074 return (status);
1075 ether_copy(&manc.manc_dom_eaddr, eap);
1076 } else {
1077 (void) localetheraddr((struct ether_addr *)NULL, eap);
1078 }
1079
1080 return (status);
1081 }
1082
1083 /*
1084 * man_detach - detach an instance of a driver
1085 *
1086 * dip - devinfo of node
1087 * cmd - one of DDI_DETACH | DDI_SUSPEND
1088 *
1089 * returns - success - DDI_SUCCESS
1090 * - failure - DDI_FAILURE
1091 */
1092 static int
man_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)1093 man_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1094 {
1095 register man_t *manp; /* per instance data */
1096 int instance;
1097
1098 MAN_DBG(MAN_INIT, ("man_detach(%d):\n", ddi_get_instance(dip)));
1099
1100 if (cmd != DDI_DETACH) {
1101 MAN_DBG(MAN_INIT, ("man_detach: bad command %d\n", cmd));
1102 return (DDI_FAILURE);
1103 }
1104
1105 if (dip == NULL) {
1106 MAN_DBG(MAN_INIT, ("man_detach: dip == NULL\n"));
1107 return (DDI_FAILURE);
1108 }
1109
1110 instance = ddi_get_instance(dip);
1111
1112 mutex_enter(&man_lock);
1113
1114 manp = (man_t *)ddi_get_soft_state(man_softstate, instance);
1115 if (manp == NULL) {
1116 mutex_exit(&man_lock);
1117
1118 cmn_err(CE_WARN, "man_detach: unable to get softstate"
1119 " for instance = %d, dip = 0x%p!\n", instance,
1120 (void *)dip);
1121 return (DDI_FAILURE);
1122 }
1123
1124 if (manp->man_refcnt != 0) {
1125 mutex_exit(&man_lock);
1126
1127 cmn_err(CE_WARN, "man_detach: %s%d refcnt %d", MAN_IDNAME,
1128 instance, manp->man_refcnt);
1129 MAN_DBGCALL(MAN_INIT, man_print_man(manp));
1130
1131 return (DDI_FAILURE);
1132 }
1133
1134 ddi_remove_minor_node(dip, NULL);
1135
1136 mutex_exit(&man_lock);
1137
1138 kstat_delete(manp->man_ksp);
1139 ddi_soft_state_free(man_softstate, instance);
1140 ddi_set_driver_private(dip, NULL);
1141
1142 MAN_DBG(MAN_INIT, ("man_detach returns DDI_SUCCESS"));
1143
1144 return (DDI_SUCCESS);
1145 }
1146
1147 /*
1148 * man_info:
1149 * As a standard DLPI style-2, man_info() should always return
1150 * DDI_FAILURE.
1151 *
1152 * However, man_open() has special treatment for a direct open
1153 * via kstr_open() without going through the CLONE driver.
1154 * To make this special kstr_open() work, we need to map
1155 * minor of 0 to instance 0.
1156 */
1157 /*ARGSUSED*/
1158 static int
man_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)1159 man_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
1160 {
1161 minor_t minor;
1162
1163 switch (infocmd) {
1164 case DDI_INFO_DEVT2DEVINFO:
1165 break;
1166
1167 case DDI_INFO_DEVT2INSTANCE:
1168 minor = getminor((dev_t)arg);
1169 if (minor == 0) {
1170 *result = (void *)(uintptr_t)minor;
1171 return (DDI_SUCCESS);
1172 }
1173 break;
1174 default:
1175 break;
1176 }
1177 return (DDI_FAILURE);
1178 }
1179
1180 /* Standard Device Driver entry points */
1181
1182 /*
1183 * man_open - open the device
1184 *
1185 * rq - upper read queue of the stream
1186 * devp - pointer to a device number
1187 * flag - information passed from the user program open(2) system call
1188 * sflag - stream flags
1189 * credp - pointer to the cred(9S) user credential structure
1190 *
1191 * returns - success - 0
1192 * - failure - errno value for failure
1193 */
1194 /*ARGSUSED*/
1195 static int
man_open(queue_t * rq,dev_t * devp,int flag,int sflag,cred_t * credp)1196 man_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp)
1197 {
1198 int minordev = -1;
1199 manstr_t *msp;
1200 manstr_t *tsp;
1201 manstr_t **prevmsp;
1202 int status = 0;
1203
1204 MAN_DBG(MAN_OCLOSE, ("man_open: rq(0x%p) sflag(0x%x)\n",
1205 (void *)rq, sflag));
1206
1207 ASSERT(rq);
1208 ASSERT(sflag != MODOPEN);
1209
1210 /*
1211 * reopen; q_ptr set to msp at open completion.
1212 */
1213 if (rq->q_ptr) {
1214 return (0);
1215 }
1216
1217 /*
1218 * Allocate and initialize manstr_t for this device.
1219 */
1220 msp = man_kzalloc(sizeof (manstr_t), KM_SLEEP);
1221 SETSTATE(msp, DL_UNATTACHED);
1222 msp->ms_meta_ppa = -1;
1223 msp->ms_rq = rq;
1224 rq->q_ptr = WR(rq)->q_ptr = msp;
1225
1226 /*
1227 * Get the MAN driver configured on 1st open. Note that the only way
1228 * we get sflag != CLONEOPEN is via the call in man_plumbctl(). All
1229 * CLONEOPEN calls to man_open will be via the file system
1230 * device node /dev/man, a pseudo clone device.
1231 */
1232
1233 qprocson(rq);
1234
1235 if (sflag == CLONEOPEN && man_config_state != MAN_CONFIGURED) {
1236 /*
1237 * First open calls man_configure. Everyone qwaits until
1238 * we get it open. See man_open_ctl() comments for mutex
1239 * lock/synchronization info.
1240 */
1241
1242 mutex_enter(&man_lock);
1243
1244 if (man_config_state == MAN_UNCONFIGURED) {
1245 man_config_state = MAN_CONFIGURING;
1246 mutex_exit(&man_lock);
1247 status = man_configure(rq);
1248 if (status != 0)
1249 goto exit;
1250 } else {
1251 while (man_config_state == MAN_CONFIGURING) {
1252
1253 mutex_exit(&man_lock);
1254 status = qwait_sig(rq);
1255
1256 if (status == 0) {
1257 status = EINTR;
1258 goto exit;
1259 }
1260
1261 mutex_enter(&man_lock);
1262 }
1263 mutex_exit(&man_lock);
1264
1265 if (man_config_error) {
1266 status = man_config_error;
1267 goto exit;
1268 }
1269 }
1270 }
1271
1272 /*
1273 * Determine minor device number. man_open serialized by
1274 * D_MTPERMOD.
1275 */
1276 prevmsp = &man_strup;
1277 if (sflag == CLONEOPEN) {
1278
1279 minordev = 0;
1280 for (; (tsp = *prevmsp) != NULL; prevmsp = &tsp->ms_next) {
1281 if (minordev < tsp->ms_minor)
1282 break;
1283 minordev++;
1284 }
1285 *devp = makedevice(getmajor(*devp), minordev);
1286
1287 } else {
1288 /*
1289 * Should only get here from man_plumbctl().
1290 */
1291 /*LINTED E_ASSIGN_UINT_TO_SIGNED_INT*/
1292 minordev = getminor(*devp);
1293
1294 /*
1295 * No need to protect this here as all opens are
1296 * qwaiting, and the bgthread (who is doing this open)
1297 * is the only one who mucks with this variable.
1298 */
1299 man_ctl_wq = WR(rq);
1300
1301 ASSERT(minordev == 0); /* TBD delete this */
1302 }
1303
1304 msp->ms_meta_maj = getmajor(*devp);
1305 msp->ms_minor = minordev;
1306 if (minordev == 0)
1307 msp->ms_flags = MAN_SFLAG_CONTROL;
1308
1309 /*
1310 * Link new entry into global list of active entries.
1311 */
1312 msp->ms_next = *prevmsp;
1313 *prevmsp = msp;
1314
1315
1316 /*
1317 * Disable automatic enabling of our write service procedure.
1318 * We control this explicitly.
1319 */
1320 noenable(WR(rq));
1321
1322 exit:
1323 MAN_DBG(MAN_OCLOSE, ("man_open: exit rq(0x%p) minor %d errno %d\n",
1324 (void *)rq, minordev, status));
1325
1326 /*
1327 * Clean up on error.
1328 */
1329 if (status) {
1330 qprocsoff(rq);
1331 rq->q_ptr = WR(rq)->q_ptr = NULL;
1332 man_kfree((char *)msp, sizeof (manstr_t));
1333 } else
1334 (void) qassociate(rq, -1);
1335
1336 return (status);
1337 }
1338
1339 /*
1340 * Get the driver configured. Called from first man_open with exclusive
1341 * inner perimeter.
1342 */
1343 static int
man_configure(queue_t * rq)1344 man_configure(queue_t *rq)
1345 {
1346 man_work_t *wp;
1347 int status = 0;
1348
1349 MAN_DBG(MAN_CONFIG, ("man_configure:"));
1350
1351 /*
1352 * Initialize NDD parameters.
1353 */
1354 if (!man_ndlist &&
1355 !man_param_register(man_param_arr, A_CNT(man_param_arr))) {
1356 cmn_err(CE_WARN, "man_configure: man_param_register failed!");
1357 man_config_error = ENOMEM;
1358 goto exit;
1359 }
1360
1361 mutex_enter(&man_lock);
1362
1363 /*
1364 * Start up background thread.
1365 */
1366 if (man_bwork_id == NULL)
1367 man_bwork_id = thread_create(NULL, 2 * DEFAULTSTKSZ,
1368 man_bwork, NULL, 0, &p0, TS_RUN, minclsyspri);
1369
1370 /*
1371 * Submit work to get control stream opened. Qwait until its
1372 * done. See man_open_ctl for mutex lock/synchronization info.
1373 */
1374
1375 if (man_ctl_lh == NULL) {
1376 wp = man_work_alloc(MAN_WORK_OPEN_CTL, KM_SLEEP);
1377 wp->mw_flags |= MAN_WFLAGS_QWAITER;
1378 wp->mw_q = WR(rq);
1379
1380 /*
1381 * Submit work and wait. When man_open_ctl exits
1382 * man_open, it will cause qwait below to return.
1383 */
1384 man_work_add(man_bwork_q, wp);
1385 while (!(wp->mw_flags & MAN_WFLAGS_DONE)) {
1386 mutex_exit(&man_lock);
1387 qwait(rq);
1388 mutex_enter(&man_lock);
1389 }
1390 status = wp->mw_status;
1391 man_work_free(wp);
1392
1393 }
1394 mutex_exit(&man_lock);
1395
1396 /*
1397 * If on domain, setup IOSRAM and build the pathgroups
1398 * automatically.
1399 */
1400 if ((status == 0) && man_is_on_domain)
1401 status = man_domain_configure();
1402
1403 exit:
1404 mutex_enter(&man_lock);
1405
1406 man_config_error = status;
1407 if (status != 0)
1408 man_config_state = MAN_UNCONFIGURED;
1409 else
1410 man_config_state = MAN_CONFIGURED;
1411
1412 mutex_exit(&man_lock);
1413
1414 MAN_DBG(MAN_CONFIG, ("man_configure: returns %d\n", status));
1415
1416 return (status);
1417 }
1418
1419 /*
1420 * man_close - close the device
1421 *
1422 * rq - upper read queue of the stream
1423 *
1424 * returns - success - 0
1425 * - failure - errno value for failure
1426 */
1427 static int
man_close(queue_t * rq)1428 man_close(queue_t *rq)
1429 {
1430 manstr_t *close_msp;
1431 manstr_t *msp;
1432
1433 MAN_DBG(MAN_OCLOSE, ("man_close: rq(0x%p)\n", (void *)rq));
1434
1435 qprocsoff(rq);
1436 close_msp = (manstr_t *)rq->q_ptr;
1437
1438 /*
1439 * Unlink the per-Stream entry from the active list and free it.
1440 */
1441 if (close_msp == man_strup)
1442 man_strup = close_msp->ms_next;
1443 else {
1444 for (msp = man_strup; msp && msp->ms_next != close_msp; )
1445 msp = msp->ms_next;
1446
1447 if (msp == NULL) {
1448 cmn_err(CE_WARN, "man_close: no stream!");
1449 return (ENODEV);
1450 }
1451
1452 msp->ms_next = close_msp->ms_next;
1453 }
1454
1455 if (close_msp->ms_dests != NULL) {
1456 /*
1457 * Still DL_ATTACHED
1458 */
1459 man_work_t *wp;
1460
1461 wp = man_work_alloc(MAN_WORK_CLOSE_STREAM, KM_SLEEP);
1462 man_dodetach(close_msp, wp);
1463 }
1464
1465 if (close_msp->ms_flags & MAN_SFLAG_CONTROL) {
1466 /*
1467 * Driver about to unload.
1468 */
1469 man_ctl_wq = NULL;
1470 }
1471
1472 rq->q_ptr = WR(rq)->q_ptr = NULL;
1473 man_kfree((char *)close_msp, sizeof (manstr_t));
1474 (void) qassociate(rq, -1);
1475
1476 MAN_DBG(MAN_OCLOSE, ("man_close: exit\n"));
1477
1478 return (0);
1479 }
1480
1481 /*
1482 * Ask bgthread to tear down lower stream and qwait
1483 * until its done.
1484 */
1485 static void
man_dodetach(manstr_t * msp,man_work_t * wp)1486 man_dodetach(manstr_t *msp, man_work_t *wp)
1487 {
1488 man_dest_t *mdp;
1489 int i;
1490 mblk_t *mp;
1491
1492 mdp = msp->ms_dests;
1493 msp->ms_dests = NULL;
1494 msp->ms_destp = NULL;
1495
1496 /*
1497 * Excise lower dests array, set it closing and hand it to
1498 * background thread to dispose of.
1499 */
1500 for (i = 0; i < MAN_MAX_DESTS; i++) {
1501
1502 mdp[i].md_state |= MAN_DSTATE_CLOSING;
1503 mdp[i].md_msp = NULL;
1504 mdp[i].md_rq = NULL;
1505
1506 if (mdp[i].md_lc_timer_id != 0) {
1507 (void) quntimeout(man_ctl_wq, mdp[i].md_lc_timer_id);
1508 mdp[i].md_lc_timer_id = 0;
1509 }
1510 if (mdp[i].md_bc_id != 0) {
1511 qunbufcall(man_ctl_wq, mdp[i].md_bc_id);
1512 mdp[i].md_bc_id = 0;
1513 }
1514
1515 mutex_enter(&mdp[i].md_lock);
1516 while ((mp = mdp[i].md_dmp_head) != NULL) {
1517 mdp[i].md_dmp_head = mp->b_next;
1518 mp->b_next = NULL;
1519 freemsg(mp);
1520 }
1521 mdp[i].md_dmp_count = 0;
1522 mdp[i].md_dmp_tail = NULL;
1523 mutex_exit(&mdp[i].md_lock);
1524 }
1525
1526 /*
1527 * Dump any DL type messages previously caught.
1528 */
1529 man_dl_clean(&msp->ms_dl_mp);
1530 man_dl_clean(&msp->ms_dlioc_mp);
1531
1532 /*
1533 * We need to clear fast path flag when dlioc messages are cleaned.
1534 */
1535 msp->ms_flags &= ~MAN_SFLAG_FAST;
1536
1537 /*
1538 * MAN_WORK_CLOSE_STREAM work request preallocated by caller.
1539 */
1540 ASSERT(wp->mw_type == MAN_WORK_CLOSE_STREAM);
1541 ASSERT(mdp != NULL);
1542 wp->mw_arg.a_mdp = mdp;
1543 wp->mw_arg.a_ndests = MAN_MAX_DESTS;
1544 wp->mw_arg.a_pg_id = -1; /* Don't care */
1545
1546 mutex_enter(&man_lock);
1547 man_work_add(man_bwork_q, wp);
1548 msp->ms_manp->man_refcnt--;
1549 mutex_exit(&man_lock);
1550
1551 msp->ms_manp = NULL;
1552
1553 }
1554
1555
1556 /*
1557 * man_uwput - handle DLPI messages issued from upstream, the write
1558 * side of the upper half of multiplexor. Called with shared access to
1559 * the inner perimeter.
1560 *
1561 * wq - upper write queue of mxx
1562 * mp - mblk ptr to DLPI request
1563 */
1564 static int
man_uwput(register queue_t * wq,register mblk_t * mp)1565 man_uwput(register queue_t *wq, register mblk_t *mp)
1566 {
1567 register manstr_t *msp; /* per stream data */
1568 register man_t *manp; /* per instance data */
1569
1570 msp = (manstr_t *)wq->q_ptr;
1571
1572 MAN_DBG(MAN_UWPUT, ("man_uwput: wq(0x%p) mp(0x%p) db_type(0x%x)"
1573 " msp(0x%p)\n",
1574 (void *)wq, (void *)mp, DB_TYPE(mp), (void *)msp));
1575 #if DEBUG
1576 if (man_debug & MAN_UWPUT) {
1577 if (DB_TYPE(mp) == M_IOCTL) {
1578 struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
1579 MAN_DBG(MAN_UWPUT,
1580 ("man_uwput: M_IOCTL ioc_cmd(0x%x)\n",
1581 iocp->ioc_cmd));
1582 } else if (DB_TYPE(mp) == M_CTL) {
1583 struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
1584 MAN_DBG(MAN_UWPUT,
1585 ("man_uwput: M_CTL ioc_cmd(0x%x)\n",
1586 iocp->ioc_cmd));
1587 }
1588 }
1589 #endif /* DEBUG */
1590
1591
1592 switch (DB_TYPE(mp)) {
1593 case M_DATA:
1594 manp = msp->ms_manp;
1595
1596 if (((msp->ms_flags & (MAN_SFLAG_FAST | MAN_SFLAG_RAW)) == 0) ||
1597 (msp->ms_dlpistate != DL_IDLE) ||
1598 (manp == NULL)) {
1599
1600 merror(wq, mp, EPROTO);
1601 break;
1602 }
1603
1604 if (wq->q_first) {
1605 (void) putq(wq, mp);
1606 qenable(wq);
1607 } else {
1608 ehdr_t *ep = (ehdr_t *)mp->b_rptr;
1609
1610 (void) man_start(wq, mp, &ep->ether_dhost);
1611 }
1612 break;
1613
1614 case M_PROTO:
1615 case M_PCPROTO:
1616 if ((DL_PRIM(mp) == DL_UNITDATA_IND) && !wq->q_first) {
1617 (void) man_udreq(wq, mp);
1618 } else {
1619 (void) putq(wq, mp);
1620 qenable(wq);
1621 }
1622 break;
1623
1624 case M_IOCTL:
1625 case M_IOCDATA:
1626 qwriter(wq, mp, man_ioctl, PERIM_INNER);
1627 break;
1628
1629 case M_CTL:
1630 freemsg(mp);
1631 break;
1632
1633 case M_FLUSH:
1634 MAN_DBG(MAN_UWPUT, ("man_wput: M_FLUSH\n"));
1635 if (*mp->b_rptr & FLUSHW)
1636 flushq(wq, FLUSHDATA);
1637 if (*mp->b_rptr & FLUSHR) {
1638 flushq(RD(wq), FLUSHDATA);
1639 *mp->b_rptr &= ~FLUSHW;
1640 qreply(wq, mp);
1641 } else {
1642 freemsg(mp);
1643 }
1644 break;
1645
1646 default:
1647 MAN_DBG(MAN_WARN,
1648 ("man_uwput: illegal mblk(0x%p) type(0x%x)\n",
1649 (void *)mp, DB_TYPE(mp)));
1650 freemsg(mp);
1651 break;
1652 } /* End switch */
1653
1654 MAN_DBG(MAN_UWPUT, ("man_uwput: exit wq(0x%p) mp(0x%p)\n",
1655 (void *)wq, (void *)mp));
1656
1657 return (0);
1658 }
1659
1660 /*
1661 * man_start - handle data messages issued from upstream. Send down
1662 * to particular man_dest based on ether_addr, otherwise send out to all
1663 * valid man_dests.
1664 *
1665 * wq - upper write queue of mxx
1666 * mp - mblk ptr to DLPI request
1667 * caller - Caller ID for decision making on canput failure
1668 *
1669 * Returns:
1670 * 0 - Data xmitted or No flow control situation detected.
1671 * 1 - Flow control situation detected.
1672 *
1673 * STREAMS Flow Control: can be used if there is only one destination
1674 * for a stream (1 to 1 multiplexor). In this case, we will use the upper
1675 * write queue to store mblks when in flow control. If there are multiple
1676 * destinations, we cannot use the STREAMs based flow control (1 to many
1677 * multiplexor). In this case, we will use the lower write queue to store
1678 * mblks when in flow control. Since destinations come and go, we may
1679 * transition between 1-to-1 and 1-to-m. So it may be the case that we have
1680 * some mblks stored on the upper queue, and some on the lower queue. However,
1681 * we will never send mblks out of order. See man_uwput and man_start_lower().
1682 *
1683 * A simple flow control mechanism is implemented for the deferred mblk list,
1684 * as this list is expected to be used temporarily for a very short
1685 * period required for switching paths. This flow control mechanism is
1686 * used only as a defensive approach to avoid infinite growth of this list.
1687 */
1688 static int
man_start(register queue_t * wq,register mblk_t * mp,eaddr_t * eap)1689 man_start(register queue_t *wq, register mblk_t *mp, eaddr_t *eap)
1690 {
1691 register manstr_t *msp; /* per stream data */
1692 register man_dest_t *mdp = NULL; /* destination */
1693 mblk_t *tmp;
1694 int i;
1695 int status = 0;
1696
1697 msp = (manstr_t *)wq->q_ptr;
1698
1699 MAN_DBG(MAN_DATA, ("man_start: msp(0x%p) ether_addr(%s)\n",
1700 (void *)msp, ether_sprintf(eap)));
1701
1702 if (msp->ms_dests == NULL) {
1703 cmn_err(CE_WARN, "man_start: no destinations");
1704 freemsg(mp);
1705 return (0);
1706 }
1707
1708 /*
1709 * Optimization if only one valid destination.
1710 */
1711 mdp = msp->ms_destp;
1712
1713 if (IS_UNICAST(eap)) {
1714 queue_t *flow_wq = NULL;
1715
1716 if (mdp == NULL) {
1717 /*
1718 * TDB - This needs to be optimized (some bits in
1719 * ehp->dhost will act as an index.
1720 */
1721 for (i = 0; i < MAN_MAX_DESTS; i++) {
1722
1723 mdp = &msp->ms_dests[i];
1724
1725 if ((mdp->md_state == MAN_DSTATE_READY) &&
1726 (ether_cmp(eap, &mdp->md_dst_eaddr) == 0))
1727 break;
1728 mdp = NULL;
1729 }
1730 } else {
1731 /*
1732 * 1 to 1 multiplexing, use upper wq for flow control.
1733 */
1734 flow_wq = wq;
1735 }
1736
1737 if (mdp != NULL) {
1738 /*
1739 * Its going somewhere specific
1740 */
1741 status = man_start_lower(mdp, mp, flow_wq, MAN_UPPER);
1742
1743 } else {
1744 MAN_DBG(MAN_DATA, ("man_start: no destination"
1745 " for eaddr %s\n", ether_sprintf(eap)));
1746 freemsg(mp);
1747 }
1748 } else {
1749 /*
1750 * Broadcast or multicast - send everone a copy.
1751 */
1752 if (mdp == NULL) {
1753 for (i = 0; i < MAN_MAX_DESTS; i++) {
1754 mdp = &msp->ms_dests[i];
1755
1756 if (mdp->md_state != MAN_DSTATE_READY)
1757 continue;
1758
1759 if ((tmp = copymsg(mp)) != NULL) {
1760 (void) man_start_lower(mdp, tmp,
1761 NULL, MAN_UPPER);
1762 } else {
1763 MAN_DBG(MAN_DATA, ("man_start: copymsg"
1764 " failed!"));
1765 }
1766 }
1767 freemsg(mp);
1768 } else {
1769 if (mdp->md_state == MAN_DSTATE_READY)
1770 status = man_start_lower(mdp, mp, wq,
1771 MAN_UPPER);
1772 else
1773 freemsg(mp);
1774 }
1775 }
1776 return (status);
1777 }
1778
1779 /*
1780 * Send a DL_UNITDATA or M_DATA fastpath data mblk to a particular
1781 * destination. Others mblk types sent down via * man_dlpi_senddown().
1782 *
1783 * Returns:
1784 * 0 - Data xmitted
1785 * 1 - Data not xmitted due to flow control.
1786 */
1787 static int
man_start_lower(man_dest_t * mdp,mblk_t * mp,queue_t * flow_wq,int caller)1788 man_start_lower(man_dest_t *mdp, mblk_t *mp, queue_t *flow_wq, int caller)
1789 {
1790 queue_t *wq = mdp->md_wq;
1791 int status = 0;
1792
1793 /*
1794 * Lower stream ready for data transmit.
1795 */
1796 if (mdp->md_state == MAN_DSTATE_READY &&
1797 mdp->md_dlpistate == DL_IDLE) {
1798
1799 ASSERT(mdp->md_wq != NULL);
1800
1801 if (caller == MAN_UPPER) {
1802 /*
1803 * Check for flow control conditions for lower
1804 * stream.
1805 */
1806 if (mdp->md_dmp_head == NULL &&
1807 wq->q_first == NULL && canputnext(wq)) {
1808
1809 (void) putnext(wq, mp);
1810
1811 } else {
1812 mutex_enter(&mdp->md_lock);
1813 if (mdp->md_dmp_head != NULL) {
1814 /*
1815 * A simple flow control mechanism.
1816 */
1817 if (mdp->md_dmp_count >= MAN_HIWAT) {
1818 freemsg(mp);
1819 } else {
1820 /*
1821 * Add 'mp' to the deferred
1822 * msg list.
1823 */
1824 mdp->md_dmp_tail->b_next = mp;
1825 mdp->md_dmp_tail = mp;
1826 mdp->md_dmp_count +=
1827 msgsize(mp);
1828 }
1829 mutex_exit(&mdp->md_lock);
1830 /*
1831 * Inform flow control situation
1832 * to the caller.
1833 */
1834 status = 1;
1835 qenable(wq);
1836 goto exit;
1837 }
1838 mutex_exit(&mdp->md_lock);
1839 /*
1840 * If 1 to 1 mux, use upper write queue for
1841 * flow control.
1842 */
1843 if (flow_wq != NULL) {
1844 /*
1845 * putbq() message and indicate
1846 * flow control situation to the
1847 * caller.
1848 */
1849 (void) putbq(flow_wq, mp);
1850 qenable(flow_wq);
1851 status = 1;
1852 goto exit;
1853 }
1854 /*
1855 * 1 to many mux, use lower write queue for
1856 * flow control. Be mindful not to overflow
1857 * the lower MAN STREAM q.
1858 */
1859 if (canput(wq)) {
1860 (void) putq(wq, mp);
1861 qenable(wq);
1862 } else {
1863 MAN_DBG(MAN_DATA, ("man_start_lower:"
1864 " lower q flow controlled -"
1865 " discarding packet"));
1866 freemsg(mp);
1867 goto exit;
1868 }
1869 }
1870
1871 } else {
1872 /*
1873 * man_lwsrv is draining flow controlled mblks.
1874 */
1875 if (canputnext(wq))
1876 (void) putnext(wq, mp);
1877 else
1878 status = 1;
1879 }
1880 goto exit;
1881 }
1882
1883 /*
1884 * Lower stream in transition, do flow control.
1885 */
1886 status = 1;
1887
1888 if (mdp->md_state == MAN_DSTATE_NOTPRESENT) {
1889 nodest:
1890 cmn_err(CE_WARN,
1891 "man_start_lower: no dest for mdp(0x%p), caller(%d)!",
1892 (void *)mdp, caller);
1893 if (caller == MAN_UPPER)
1894 freemsg(mp);
1895 goto exit;
1896 }
1897
1898 if (mdp->md_state & MAN_DSTATE_CLOSING) {
1899 MAN_DBG(MAN_DATA, ("man_start_lower: mdp(0x%p) closing",
1900 (void *)mdp));
1901 if (caller == MAN_UPPER)
1902 freemsg(mp);
1903 goto exit;
1904 }
1905
1906 if ((mdp->md_state & MAN_DSTATE_PLUMBING) ||
1907 (mdp->md_state == MAN_DSTATE_INITIALIZING) ||
1908 (mdp->md_dlpistate != DL_IDLE)) {
1909 /*
1910 * Defer until PLUMBED and DL_IDLE. See man_lwsrv().
1911 */
1912 if (caller == MAN_UPPER) {
1913 /*
1914 * Upper stream sending data down, add to defered mblk
1915 * list for stream.
1916 */
1917 mutex_enter(&mdp->md_lock);
1918 if (mdp->md_dmp_count >= MAN_HIWAT) {
1919 freemsg(mp);
1920 } else {
1921 if (mdp->md_dmp_head == NULL) {
1922 ASSERT(mdp->md_dmp_tail == NULL);
1923 mdp->md_dmp_head = mp;
1924 mdp->md_dmp_tail = mp;
1925 } else {
1926 mdp->md_dmp_tail->b_next = mp;
1927 mdp->md_dmp_tail = mp;
1928 }
1929 mdp->md_dmp_count += msgsize(mp);
1930 }
1931 mutex_exit(&mdp->md_lock);
1932 }
1933
1934 goto exit;
1935 }
1936
1937 exit:
1938 return (status);
1939 }
1940
1941 /*
1942 * man_ioctl - handle ioctl requests for this driver (I_PLINK/I_PUNLINK)
1943 * or pass thru to the physical driver below. Note that most M_IOCTLs we
1944 * care about come down the control msp, but the IOC ones come down the IP.
1945 * Called with exclusive inner perimeter.
1946 *
1947 * wq - upper write queue of mxx
1948 * mp - mblk ptr to DLPI ioctl request
1949 */
1950 static void
man_ioctl(register queue_t * wq,register mblk_t * mp)1951 man_ioctl(register queue_t *wq, register mblk_t *mp)
1952 {
1953 manstr_t *msp;
1954 struct iocblk *iocp;
1955
1956 iocp = (struct iocblk *)mp->b_rptr;
1957 msp = (manstr_t *)wq->q_ptr;
1958
1959 #ifdef DEBUG
1960 {
1961 char ioc_cmd[30];
1962
1963 (void) sprintf(ioc_cmd, "not handled IOCTL 0x%x",
1964 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
man_plink(queue_t * wq,mblk_t * mp)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
man_unplink(queue_t * wq,mblk_t * mp)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
man_linkrec_insert(man_linkrec_t * lrp)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 *
man_linkrec_find(int muxid)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
man_set_linkcheck_time(queue_t * wq,mblk_t * mp)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
man_setpath(queue_t * wq,mblk_t * mp)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
man_geteaddr(queue_t * wq,mblk_t * mp)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
man_set_sc_ipaddrs(queue_t * wq,mblk_t * mp)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
man_set_sc_ip6addrs(queue_t * wq,mblk_t * mp)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
man_dl_ioc_hdr_info(queue_t * wq,mblk_t * mp)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
man_uwsrv(queue_t * wq)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
man_proto(queue_t * wq,mblk_t * mp)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
man_udreq(queue_t * wq,mblk_t * mp)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
man_areq(queue_t * wq,mblk_t * mp)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
man_init_dests(man_t * manp,manstr_t * msp)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
man_start_dest(man_dest_t * mdp,manstr_t * msp,man_pg_t * mpg)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
man_set_optimized_dest(manstr_t * msp)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
man_dlpi(manstr_t * msp,mblk_t * mp)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
man_dlioc(manstr_t * msp,mblk_t * mp)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
man_dl_catch(mblk_t ** mplist,mblk_t * mp)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
man_dlpi_senddown(manstr_t * msp,mblk_t * mp)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
man_dlpi_replay(man_dest_t * mdp,mblk_t * rmp)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
man_dreq(queue_t * wq,mblk_t * mp)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
man_dl_clean(mblk_t ** mplist)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
man_dl_release(mblk_t ** mplist,mblk_t * mp)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
man_match_proto(mblk_t * mp1,mblk_t * mp2)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
man_breq(queue_t * wq,mblk_t * mp)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
man_ubreq(queue_t * wq,mblk_t * mp)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
man_ireq(queue_t * wq,mblk_t * mp)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
man_ponreq(queue_t * wq,mblk_t * mp)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
man_poffreq(queue_t * wq,mblk_t * mp)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
man_emreq(queue_t * wq,mblk_t * mp)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
man_dmreq(queue_t * wq,mblk_t * mp)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
man_pareq(queue_t * wq,mblk_t * mp)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
man_spareq(queue_t * wq,mblk_t * mp)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
man_lwsrv(queue_t * wq)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 (void) 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
man_lrput(queue_t * rq,mblk_t * mp)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 (void) 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
man_lrsrv(queue_t * rq)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 (void) 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
man_needs_linkcheck(man_dest_t * mdp)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
man_iwork()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
man_do_dr_switch(man_work_t * wp)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
man_do_dr_attach(man_work_t * wp)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
man_do_dr_detach(man_work_t * wp)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
man_iswitch(man_work_t * wp)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 *
man_switch_match(man_dest_t * sdp,int pg_id,void * sid)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
man_ifail_dest(man_dest_t * mdp)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
man_reset_dlpi(void * argp)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
man_dlioc_replay(man_dest_t * mdp)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 *
man_alloc_ubreq_dreq()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 *
man_dup_mplist(mblk_t * mp)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 *
man_alloc_physreq_mp(eaddr_t * man_eap)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
man_add_dests(man_pg_t * mpg)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
man_remove_dests(man_pg_t * mpg)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
man_str_uses_pg(manstr_t * msp,man_pg_t * mpg)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
man_gettimer(int timer,man_dest_t * mdp)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
man_linkcheck_timer(void * argp)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
man_do_autoswitch(man_dest_t * mdp)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
man_autoswitch(man_pg_t * mpg,man_dev_t * st_devp,man_work_t * waiter_wp)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
man_prep_dests_for_switch(man_pg_t * mpg,man_dest_t ** mdpp,int * cntp)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
man_do_icmp_bcast(man_dest_t * mdp,t_uscalar_t sap)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 *
man_pinger(t_uscalar_t sap)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 *
man_alloc_udreq(int size,man_dladdr_t * dlsap)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
man_bwork()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
man_open_ctl()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
man_close_ctl()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
man_bclose(man_adest_t * adp)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
man_cancel_timers(man_adest_t * adp)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
man_bswitch(man_adest_t * adp,man_work_t * wp)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
man_plumb(man_dest_t * mdp)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
man_unplumb(man_dest_t * mdp)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
man_pg_cmd(mi_path_t * mip,man_work_t * waiter_wp)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
man_pg_assign(man_pg_t ** mplpp,mi_path_t * mip,int add_only)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
man_pg_unassign(man_pg_t ** plpp,mi_path_t * mip)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
man_pg_activate(man_t * manp,mi_path_t * mip,man_work_t * waiter_wp)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
man_pg_read(man_pg_t * plp,mi_path_t * mip)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
man_pg_create(man_pg_t ** mplpp,man_pg_t ** mpgp,mi_path_t * mip)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 *
man_find_path_by_dev(man_pg_t * plp,man_dev_t * mdevp,man_path_t ** mpp)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 *
man_find_pg_by_id(man_pg_t * mpg,int pg_id)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 *
man_find_path_by_ppa(man_path_t * mplist,int ppa)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 *
man_find_active_path(man_path_t * mplist)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 *
man_find_alternate_path(man_path_t * mlp)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
man_path_remove(man_path_t ** lpp,man_path_t * mp)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
man_path_insert(man_path_t ** lpp,man_path_t * mp)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
man_path_merge(man_path_t ** lpp,man_path_t * np)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
man_path_kstat_init(man_path_t * mpp)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
man_path_kstat_uninit(man_path_t * mp)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 *
man_work_alloc(int type,int kmflag)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
man_work_free(man_work_t * wp)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
man_work_add(man_workq_t * q,man_work_t * wp)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
man_param_register(param_t * manpa,int cnt)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
man_nd_getset(queue_t * wq,mblk_t * mp)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
man_pathgroups_report(queue_t * wq,mblk_t * mp,caddr_t cp,cred_t * cr)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,
7210 "Other SSC\t");
7211 }
7212 man_preport(mpg->mpg_pathp, mp);
7213 }
7214 (void) mi_mpprintf_nr(mp, "\n");
7215 }
7216 }
7217
7218 mutex_exit(&man_lock);
7219 MAN_DBG(MAN_PATH, ("man_pathgroups_report: returns"));
7220
7221 return (0);
7222 }
7223
7224 static void
man_preport(man_path_t * plist,mblk_t * mp)7225 man_preport(man_path_t *plist, mblk_t *mp)
7226 {
7227 man_path_t *ap;
7228
7229 ap = man_find_active_path(plist);
7230 /*
7231 * Active path
7232 */
7233 if (ap != NULL) {
7234 (void) mi_mpprintf_nr(mp, "\t%s%d\t\t",
7235 ddi_major_to_name(ap->mp_device.mdev_major),
7236 ap->mp_device.mdev_ppa);
7237 } else {
7238 (void) mi_mpprintf_nr(mp, "None \t");
7239 }
7240
7241 /*
7242 * Alternate Paths.
7243 */
7244 while (plist != NULL) {
7245 (void) mi_mpprintf_nr(mp, "%s%d exp %d",
7246 ddi_major_to_name(plist->mp_device.mdev_major),
7247 plist->mp_device.mdev_ppa,
7248 plist->mp_device.mdev_exp_id);
7249 if (plist->mp_device.mdev_state & MDEV_FAILED)
7250 (void) mi_mpprintf_nr(mp, "*");
7251 plist = plist->mp_next;
7252 if (plist)
7253 (void) mi_mpprintf_nr(mp, ", ");
7254 }
7255 }
7256
7257 /*
7258 * NDD request to set active path. Calling context is man_ioctl, so we are
7259 * exclusive in the inner perimeter.
7260 *
7261 * Syntax is "ndd -set /dev/dman <man ppa> <pg_id> <phys ppa>"
7262 */
7263 /* ARGSUSED3 */
7264 static int
man_set_active_path(queue_t * wq,mblk_t * mp,char * value,caddr_t cp,cred_t * cr)7265 man_set_active_path(queue_t *wq, mblk_t *mp, char *value, caddr_t cp,
7266 cred_t *cr)
7267 {
7268 char *end, *meta_ppap, *phys_ppap, *pg_idp;
7269 int meta_ppa;
7270 int phys_ppa;
7271 int pg_id;
7272 man_t *manp;
7273 man_pg_t *mpg;
7274 man_path_t *np;
7275 mi_path_t mpath;
7276 int status = 0;
7277
7278 MAN_DBG(MAN_PATH, ("man_set_active_path: wq(0x%p) mp(0x%p)"
7279 " args %s", (void *)wq, (void *)mp, value));
7280
7281 meta_ppap = value;
7282
7283 if ((pg_idp = strchr(value, ' ')) == NULL) {
7284 status = EINVAL;
7285 goto exit;
7286 }
7287
7288 *pg_idp++ = '\0';
7289
7290 if ((phys_ppap = strchr(pg_idp, ' ')) == NULL) {
7291 status = EINVAL;
7292 goto exit;
7293 }
7294
7295 *phys_ppap++ = '\0';
7296
7297 meta_ppa = (int)mi_strtol(meta_ppap, &end, 10);
7298 pg_id = (int)mi_strtol(pg_idp, &end, 10);
7299 phys_ppa = (int)mi_strtol(phys_ppap, &end, 10);
7300
7301 mutex_enter(&man_lock);
7302 manp = ddi_get_soft_state(man_softstate, meta_ppa);
7303 if (manp == NULL || manp->man_pg == NULL) {
7304 status = EINVAL;
7305 mutex_exit(&man_lock);
7306 goto exit;
7307 }
7308
7309 mpg = man_find_pg_by_id(manp->man_pg, pg_id);
7310 if (mpg == NULL) {
7311 status = EINVAL;
7312 mutex_exit(&man_lock);
7313 goto exit;
7314 }
7315
7316 np = man_find_path_by_ppa(mpg->mpg_pathp, phys_ppa);
7317
7318 if (np == NULL) {
7319 status = EINVAL;
7320 mutex_exit(&man_lock);
7321 goto exit;
7322 }
7323
7324 mpath.mip_cmd = MI_PATH_ACTIVATE;
7325 mpath.mip_pg_id = pg_id;
7326 mpath.mip_man_ppa = meta_ppa;
7327 mpath.mip_devs[0] = np->mp_device;
7328 mpath.mip_ndevs = 1;
7329
7330 status = man_pg_cmd(&mpath, NULL);
7331 mutex_exit(&man_lock);
7332
7333 exit:
7334
7335 MAN_DBG(MAN_PATH, ("man_set_active_path: returns %d", status));
7336
7337 return (status);
7338 }
7339
7340 /*
7341 * Dump out the contents of the IOSRAM handoff structure. Note that if
7342 * anything changes here, you must make sure that the sysinit script
7343 * stays in sync with this output.
7344 */
7345 /* ARGSUSED */
7346 static int
man_get_hostinfo(queue_t * wq,mblk_t * mp,caddr_t cp,cred_t * cr)7347 man_get_hostinfo(queue_t *wq, mblk_t *mp, caddr_t cp, cred_t *cr)
7348 {
7349 manc_t manc;
7350 char *ipaddr;
7351 char ipv6addr[INET6_ADDRSTRLEN];
7352 int i;
7353 int status;
7354
7355 if (!man_is_on_domain)
7356 return (0);
7357
7358 if (status = man_get_iosram(&manc)) {
7359 return (status);
7360 }
7361
7362 (void) mi_mpprintf(mp, "manc_magic = 0x%x", manc.manc_magic);
7363 (void) mi_mpprintf(mp, "manc_version = 0%d", manc.manc_version);
7364 (void) mi_mpprintf(mp, "manc_csum = 0x%x", manc.manc_csum);
7365
7366 if (manc.manc_ip_type == AF_INET) {
7367 in_addr_t netnum;
7368
7369 (void) mi_mpprintf(mp, "manc_ip_type = AF_INET");
7370
7371 ipaddr = man_inet_ntoa(manc.manc_dom_ipaddr);
7372 (void) mi_mpprintf(mp, "manc_dom_ipaddr = %s", ipaddr);
7373
7374 ipaddr = man_inet_ntoa(manc.manc_dom_ip_netmask);
7375 (void) mi_mpprintf(mp, "manc_dom_ip_netmask = %s", ipaddr);
7376
7377 netnum = manc.manc_dom_ipaddr & manc.manc_dom_ip_netmask;
7378 ipaddr = man_inet_ntoa(netnum);
7379 (void) mi_mpprintf(mp, "manc_dom_ip_netnum = %s", ipaddr);
7380
7381 ipaddr = man_inet_ntoa(manc.manc_sc_ipaddr);
7382 (void) mi_mpprintf(mp, "manc_sc_ipaddr = %s", ipaddr);
7383
7384 } else if (manc.manc_ip_type == AF_INET6) {
7385
7386 (void) mi_mpprintf(mp, "manc_ip_type = AF_INET6");
7387
7388 (void) inet_ntop(AF_INET6, (void *)&manc.manc_dom_ipv6addr,
7389 ipv6addr, INET6_ADDRSTRLEN);
7390 (void) mi_mpprintf(mp, "manc_dom_ipv6addr = %s", ipv6addr);
7391
7392 (void) mi_mpprintf(mp, "manc_dom_ipv6_netmask = %d",
7393 manc.manc_dom_ipv6_netmask.s6_addr[0]);
7394
7395 (void) inet_ntop(AF_INET6, (void *)&manc.manc_sc_ipv6addr,
7396 ipv6addr, INET6_ADDRSTRLEN);
7397 (void) mi_mpprintf(mp, "manc_sc_ipv6addr = %s", ipv6addr);
7398
7399 } else {
7400
7401 (void) mi_mpprintf(mp, "manc_ip_type = NONE");
7402 }
7403
7404 (void) mi_mpprintf(mp, "manc_dom_eaddr = %s",
7405 ether_sprintf(&manc.manc_dom_eaddr));
7406 (void) mi_mpprintf(mp, "manc_sc_eaddr = %s",
7407 ether_sprintf(&manc.manc_sc_eaddr));
7408
7409 (void) mi_mpprintf(mp, "manc_iob_bitmap = 0x%x\tio boards = ",
7410 manc.manc_iob_bitmap);
7411 for (i = 0; i < MAN_MAX_EXPANDERS; i++) {
7412 if ((manc.manc_iob_bitmap >> i) & 0x1) {
7413 (void) mi_mpprintf_nr(mp, "%d.1, ", i);
7414 }
7415 }
7416 (void) mi_mpprintf(mp, "manc_golden_iob = %d", manc.manc_golden_iob);
7417
7418 return (0);
7419 }
7420
7421 static char *
man_inet_ntoa(in_addr_t in)7422 man_inet_ntoa(in_addr_t in)
7423 {
7424 static char b[18];
7425 unsigned char *p;
7426
7427 p = (unsigned char *)∈
7428 (void) sprintf(b, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
7429 return (b);
7430 }
7431
7432 /*
7433 * parameter value. cp points to the required parameter.
7434 */
7435 /* ARGSUSED */
7436 static int
man_param_get(queue_t * q,mblk_t * mp,caddr_t cp,cred_t * cr)7437 man_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr)
7438 {
7439 param_t *manpa = (param_t *)cp;
7440
7441 (void) mi_mpprintf(mp, "%u", manpa->param_val);
7442 return (0);
7443 }
7444
7445 /*
7446 * Sets the man parameter to the value in the param_register using
7447 * nd_load().
7448 */
7449 /* ARGSUSED */
7450 static int
man_param_set(queue_t * q,mblk_t * mp,char * value,caddr_t cp,cred_t * cr)7451 man_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *cr)
7452 {
7453 char *end;
7454 size_t new_value;
7455 param_t *manpa = (param_t *)cp;
7456
7457 new_value = mi_strtol(value, &end, 10);
7458
7459 if (end == value || new_value < manpa->param_min ||
7460 new_value > manpa->param_max) {
7461 return (EINVAL);
7462 }
7463
7464 manpa->param_val = new_value;
7465
7466 return (0);
7467
7468 }
7469
7470 /*
7471 * Free the Named Dispatch Table by calling man_nd_free
7472 */
7473 static void
man_param_cleanup()7474 man_param_cleanup()
7475 {
7476 if (man_ndlist != NULL)
7477 nd_free(&man_ndlist);
7478 }
7479
7480 /*
7481 * Free the table pointed to by 'ndp'
7482 */
7483 static void
man_nd_free(caddr_t * nd_pparam)7484 man_nd_free(caddr_t *nd_pparam)
7485 {
7486 ND *nd;
7487
7488 if ((nd = (ND *)(*nd_pparam)) != NULL) {
7489 if (nd->nd_tbl)
7490 mi_free((char *)nd->nd_tbl);
7491 mi_free((char *)nd);
7492 *nd_pparam = NULL;
7493 }
7494 }
7495
7496
7497 /*
7498 * man_kstat_update - update the statistics for a meta-interface.
7499 *
7500 * ksp - kstats struct
7501 * rw - flag indicating whether stats are to be read or written.
7502 *
7503 * returns 0
7504 *
7505 * The destination specific kstat information is protected by the
7506 * perimeter lock, so we submit a work request to get the stats
7507 * updated (see man_do_kstats()), and then collect the results
7508 * when cv_signal'd. Note that we are doing cv_timedwait_sig()
7509 * as a precautionary measure only.
7510 */
7511 static int
man_kstat_update(kstat_t * ksp,int rw)7512 man_kstat_update(kstat_t *ksp, int rw)
7513 {
7514 man_t *manp; /* per instance data */
7515 man_work_t *wp;
7516 int status = 0;
7517 kstat_named_t *knp;
7518 kstat_named_t *man_knp;
7519 int i;
7520
7521 MAN_DBG(MAN_KSTAT, ("man_kstat_update: %s\n", rw ? "KSTAT_WRITE" :
7522 "KSTAT_READ"));
7523
7524 mutex_enter(&man_lock);
7525 manp = (man_t *)ksp->ks_private;
7526 manp->man_refcnt++;
7527
7528 /*
7529 * If the driver has been configured, get kstats updated by inner
7530 * perimeter prior to retrieving.
7531 */
7532 if (man_config_state == MAN_CONFIGURED) {
7533 clock_t wait_status;
7534
7535 man_update_path_kstats(manp);
7536 wp = man_work_alloc(MAN_WORK_KSTAT_UPDATE, KM_SLEEP);
7537 wp->mw_arg.a_man_ppa = manp->man_meta_ppa;
7538 wp->mw_flags = MAN_WFLAGS_CVWAITER;
7539 man_work_add(man_iwork_q, wp);
7540
7541 wait_status = cv_reltimedwait_sig(&wp->mw_cv, &man_lock,
7542 drv_usectohz(manp->man_kstat_waittime), TR_CLOCK_TICK);
7543
7544 if (wp->mw_flags & MAN_WFLAGS_DONE) {
7545 status = wp->mw_status;
7546 man_work_free(wp);
7547 } else {
7548 ASSERT(wait_status <= 0);
7549 wp->mw_flags &= ~MAN_WFLAGS_CVWAITER;
7550 if (wait_status == 0)
7551 status = EINTR;
7552 else {
7553 MAN_DBG(MAN_KSTAT, ("man_kstat_update: "
7554 "timedout, returning stale stats."));
7555 status = 0;
7556 }
7557 }
7558 if (status)
7559 goto exit;
7560 }
7561
7562 knp = (kstat_named_t *)ksp->ks_data;
7563 man_knp = (kstat_named_t *)manp->man_ksp->ks_data;
7564
7565 if (rw == KSTAT_READ) {
7566 for (i = 0; i < MAN_NUMSTATS; i++) {
7567 knp[i].value.ui64 = man_knp[i].value.ui64;
7568 }
7569 } else {
7570 for (i = 0; i < MAN_NUMSTATS; i++) {
7571 man_knp[i].value.ui64 = knp[i].value.ui64;
7572 }
7573 }
7574
7575 exit:
7576 manp->man_refcnt--;
7577 mutex_exit(&man_lock);
7578
7579 MAN_DBG(MAN_KSTAT, ("man_kstat_update: returns %d", status));
7580
7581 return (status);
7582 }
7583
7584 /*
7585 * Sum destination kstats for all active paths for a given instance of the
7586 * MAN driver. Called with perimeter lock.
7587 */
7588 static void
man_do_kstats(man_work_t * wp)7589 man_do_kstats(man_work_t *wp)
7590 {
7591 man_t *manp;
7592 man_pg_t *mpg;
7593 man_path_t *mp;
7594
7595 MAN_DBG(MAN_KSTAT, ("man_do_kstats:"));
7596
7597 mutex_enter(&man_lock);
7598 /*
7599 * Sync mp_last_knp for each path associated with the MAN instance.
7600 */
7601 manp = (man_t *)ddi_get_soft_state(man_softstate,
7602 wp->mw_arg.a_man_ppa);
7603 for (mpg = manp->man_pg; mpg != NULL; mpg = mpg->mpg_next) {
7604
7605 ASSERT(mpg->mpg_man_ppa == manp->man_meta_ppa);
7606
7607 if ((mp = man_find_active_path(mpg->mpg_pathp)) != NULL) {
7608
7609 MAN_DBG(MAN_KSTAT, ("\tkstat: path"));
7610 MAN_DBGCALL(MAN_KSTAT, man_print_path(mp));
7611
7612 /*
7613 * We just to update the destination statistics here.
7614 */
7615 man_sum_dests_kstats(mp->mp_last_knp, mpg);
7616 }
7617 }
7618 mutex_exit(&man_lock);
7619 MAN_DBG(MAN_KSTAT, ("man_do_kstats: returns"));
7620 }
7621
7622 /*
7623 * Sum device kstats for all active paths for a given instance of the
7624 * MAN driver. Called with man_lock.
7625 */
7626 static void
man_update_path_kstats(man_t * manp)7627 man_update_path_kstats(man_t *manp)
7628 {
7629 kstat_named_t *man_knp;
7630 man_pg_t *mpg;
7631 man_path_t *mp;
7632
7633 ASSERT(MUTEX_HELD(&man_lock));
7634 MAN_DBG(MAN_KSTAT, ("man_update_path_kstats:"));
7635
7636 man_knp = (kstat_named_t *)manp->man_ksp->ks_data;
7637
7638 for (mpg = manp->man_pg; mpg != NULL; mpg = mpg->mpg_next) {
7639
7640 ASSERT(mpg->mpg_man_ppa == manp->man_meta_ppa);
7641
7642 if ((mp = man_find_active_path(mpg->mpg_pathp)) != NULL) {
7643
7644 man_update_dev_kstats(man_knp, mp);
7645
7646 }
7647 }
7648 MAN_DBG(MAN_KSTAT, ("man_update_path_kstats: returns"));
7649 }
7650
7651 /*
7652 * Update the device kstats.
7653 * As man_kstat_update() is called with kstat_chain_lock held,
7654 * we can safely update the statistics from the underlying driver here.
7655 */
7656 static void
man_update_dev_kstats(kstat_named_t * man_knp,man_path_t * mp)7657 man_update_dev_kstats(kstat_named_t *man_knp, man_path_t *mp)
7658 {
7659 kstat_t *dev_ksp;
7660 major_t major;
7661 int instance;
7662 char buf[KSTAT_STRLEN];
7663
7664
7665 major = mp->mp_device.mdev_major;
7666 instance = mp->mp_device.mdev_ppa;
7667 (void) sprintf(buf, "%s%d", ddi_major_to_name(major), instance);
7668
7669 dev_ksp = kstat_hold_byname(ddi_major_to_name(major), instance, buf,
7670 ALL_ZONES);
7671 if (dev_ksp != NULL) {
7672
7673 KSTAT_ENTER(dev_ksp);
7674 KSTAT_UPDATE(dev_ksp, KSTAT_READ);
7675 man_sum_kstats(man_knp, dev_ksp, mp->mp_last_knp);
7676 KSTAT_EXIT(dev_ksp);
7677 kstat_rele(dev_ksp);
7678
7679 } else {
7680 MAN_DBG(MAN_KSTAT,
7681 ("man_update_dev_kstats: no kstat data found for %s(%d,%d)",
7682 buf, major, instance));
7683 }
7684 }
7685
7686 static void
man_sum_dests_kstats(kstat_named_t * knp,man_pg_t * mpg)7687 man_sum_dests_kstats(kstat_named_t *knp, man_pg_t *mpg)
7688 {
7689 int i;
7690 int flags;
7691 char *statname;
7692 manstr_t *msp;
7693 man_dest_t *mdp;
7694 uint64_t switches = 0;
7695 uint64_t linkfails = 0;
7696 uint64_t linkstales = 0;
7697 uint64_t icmpv4probes = 0;
7698 uint64_t icmpv6probes = 0;
7699
7700 MAN_DBG(MAN_KSTAT, ("man_sum_dests_kstats: mpg 0x%p", (void *)mpg));
7701
7702 for (msp = man_strup; msp != NULL; msp = msp->ms_next) {
7703
7704 if (!man_str_uses_pg(msp, mpg))
7705 continue;
7706
7707 mdp = &msp->ms_dests[mpg->mpg_pg_id];
7708
7709 switches += mdp->md_switches;
7710 linkfails += mdp->md_linkfails;
7711 linkstales += mdp->md_linkstales;
7712 icmpv4probes += mdp->md_icmpv4probes;
7713 icmpv6probes += mdp->md_icmpv6probes;
7714 }
7715
7716 for (i = 0; i < MAN_NUMSTATS; i++) {
7717
7718 statname = man_kstat_info[i].mk_name;
7719 flags = man_kstat_info[i].mk_flags;
7720
7721 if (!(flags & MK_NOT_PHYSICAL))
7722 continue;
7723
7724 if (strcmp(statname, "man_switches") == 0) {
7725 knp[i].value.ui64 = switches;
7726 } else if (strcmp(statname, "man_link_fails") == 0) {
7727 knp[i].value.ui64 = linkfails;
7728 } else if (strcmp(statname, "man_link_stales") == 0) {
7729 knp[i].value.ui64 = linkstales;
7730 } else if (strcmp(statname, "man_icmpv4_probes") == 0) {
7731 knp[i].value.ui64 = icmpv4probes;
7732 } else if (strcmp(statname, "man_icmpv6_probes") == 0) {
7733 knp[i].value.ui64 = icmpv6probes;
7734 }
7735 }
7736
7737 MAN_DBG(MAN_KSTAT, ("man_sum_dests_kstats: returns"));
7738 }
7739
7740 /*
7741 * Initialize MAN named kstats in the space provided.
7742 */
7743 static void
man_kstat_named_init(kstat_named_t * knp,int num_stats)7744 man_kstat_named_init(kstat_named_t *knp, int num_stats)
7745 {
7746 int i;
7747
7748 MAN_DBG(MAN_KSTAT, ("man_kstat_named_init: knp(0x%p) num_stats = %d",
7749 (void *)knp, num_stats));
7750
7751 for (i = 0; i < num_stats; i++) {
7752 kstat_named_init(&knp[i], man_kstat_info[i].mk_name,
7753 man_kstat_info[i].mk_type);
7754 }
7755
7756 MAN_DBG(MAN_KSTAT, ("man_kstat_named_init: returns"));
7757
7758 }
7759
7760 /*
7761 * man_kstat_byname - get a kernel stat value from its structure
7762 *
7763 * ksp - kstat_t structure to play with
7764 * s - string to match names with
7765 * res - in/out result data pointer
7766 *
7767 * returns - success - 1 (found)
7768 * - failure - 0 (not found)
7769 */
7770 static int
man_kstat_byname(kstat_t * ksp,char * s,kstat_named_t * res)7771 man_kstat_byname(kstat_t *ksp, char *s, kstat_named_t *res)
7772 {
7773 int found = 0;
7774
7775 MAN_DBG(MAN_KSTAT2, ("man_kstat_byname: GETTING %s\n", s));
7776
7777 if (ksp->ks_type == KSTAT_TYPE_NAMED) {
7778 kstat_named_t *knp;
7779
7780 for (knp = KSTAT_NAMED_PTR(ksp);
7781 (caddr_t)knp < ((caddr_t)ksp->ks_data+ksp->ks_data_size);
7782 knp++) {
7783
7784 if (strcmp(s, knp->name) == NULL) {
7785
7786 res->data_type = knp->data_type;
7787 res->value = knp->value;
7788 found++;
7789
7790 MAN_DBG(MAN_KSTAT2, ("\t%s: %d\n", knp->name,
7791 (int)knp->value.ul));
7792 }
7793 }
7794 } else {
7795 MAN_DBG(MAN_KSTAT2, ("\tbad kstats type %d\n", ksp->ks_type));
7796 }
7797
7798 /*
7799 * if getting a value but couldn't find the namestring, result = 0.
7800 */
7801 if (!found) {
7802 /*
7803 * a reasonable default
7804 */
7805 res->data_type = KSTAT_DATA_ULONG;
7806 res->value.l = 0;
7807 MAN_DBG(MAN_KSTAT2, ("\tcouldn't find, using defaults\n"));
7808 }
7809
7810 MAN_DBG(MAN_KSTAT2, ("man_kstat_byname: returns\n"));
7811
7812 return (found);
7813 }
7814
7815
7816 /*
7817 *
7818 * Accumulate MAN driver kstats from the incremental values of the underlying
7819 * physical interfaces.
7820 *
7821 * Parameters:
7822 * sum_knp - The named kstat area to put cumulative value,
7823 * NULL if we just want to sync next two params.
7824 * phys_ksp - Physical interface kstat_t pointer. Contains
7825 * more current counts.
7826 * phys_last_knp - counts from the last time we were called for this
7827 * physical interface. Note that the name kstats
7828 * pointed to are actually in MAN format, but they
7829 * hold the mirrored physical devices last read
7830 * kstats.
7831 * Basic algorithm is:
7832 *
7833 * for each named kstat variable {
7834 * sum_knp[i] += (phys_ksp->ksp_data[i] - phys_last_knp[i]);
7835 * phys_last_knp[i] = phys_ksp->ksp_data[i];
7836 * }
7837 *
7838 */
7839 static void
man_sum_kstats(kstat_named_t * sum_knp,kstat_t * phys_ksp,kstat_named_t * phys_last_knp)7840 man_sum_kstats(kstat_named_t *sum_knp, kstat_t *phys_ksp,
7841 kstat_named_t *phys_last_knp)
7842 {
7843 char *physname;
7844 char *physalias;
7845 char *statname;
7846 kstat_named_t phys_kn_entry;
7847 uint64_t delta64;
7848 int i;
7849
7850 MAN_DBG(MAN_KSTAT, ("man_sum_kstats: sum_knp(0x%p) phys_ksp(0x%p)"
7851 " phys_last_knp(0x%p)\n", (void *)sum_knp, (void *)phys_ksp,
7852 (void *)phys_last_knp));
7853
7854 /*
7855 * Now for each entry in man_kstat_info, sum the named kstat.
7856 * Not that all MAN specific kstats will end up !found.
7857 */
7858 for (i = 0; i < MAN_NUMSTATS; i++) {
7859 int found = 0;
7860 int flags = 0;
7861
7862 delta64 = 0;
7863
7864 statname = man_kstat_info[i].mk_name;
7865 physname = man_kstat_info[i].mk_physname;
7866 physalias = man_kstat_info[i].mk_physalias;
7867 flags = man_kstat_info[i].mk_flags;
7868
7869 /*
7870 * Update MAN private kstats.
7871 */
7872 if (flags & MK_NOT_PHYSICAL) {
7873
7874 kstat_named_t *knp = phys_last_knp;
7875
7876 if (sum_knp == NULL)
7877 continue;
7878
7879 if (strcmp(statname, "man_switches") == 0) {
7880 sum_knp[i].value.ui64 = knp[i].value.ui64;
7881 } else if (strcmp(statname, "man_link_fails") == 0) {
7882 sum_knp[i].value.ui64 = knp[i].value.ui64;
7883 } else if (strcmp(statname, "man_link_stales") == 0) {
7884 sum_knp[i].value.ui64 = knp[i].value.ui64;
7885 } else if (strcmp(statname, "man_icmpv4_probes") == 0) {
7886 sum_knp[i].value.ui64 = knp[i].value.ui64;
7887 } else if (strcmp(statname, "man_icmpv6_probes") == 0) {
7888 sum_knp[i].value.ui64 = knp[i].value.ui64;
7889 }
7890
7891 continue; /* phys_ksp doesnt have this stat */
7892 }
7893
7894 /*
7895 * first try it by the "official" name
7896 */
7897 if (phys_ksp) {
7898 if (man_kstat_byname(phys_ksp, physname,
7899 &phys_kn_entry)) {
7900
7901 found = 1;
7902
7903 } else if ((physalias) && (man_kstat_byname(phys_ksp,
7904 physalias, &phys_kn_entry))) {
7905
7906 found = 1;
7907 }
7908 }
7909
7910 if (!found) {
7911 /*
7912 * clear up the "last" value, no change to the sum
7913 */
7914 phys_last_knp[i].value.ui64 = 0;
7915 continue;
7916 }
7917
7918 /*
7919 * at this point, we should have the good underlying
7920 * kstat value stored in phys_kn_entry
7921 */
7922 if (flags & MK_NOT_COUNTER) {
7923 /*
7924 * it isn't a counter, so store the value and
7925 * move on (e.g. ifspeed)
7926 */
7927 phys_last_knp[i].value = phys_kn_entry.value;
7928 continue;
7929 }
7930
7931 switch (phys_kn_entry.data_type) {
7932 case KSTAT_DATA_UINT32:
7933
7934 /*
7935 * this handles 32-bit wrapping
7936 */
7937 if (phys_kn_entry.value.ui32 <
7938 phys_last_knp[i].value.ui32) {
7939
7940 /*
7941 * we've wrapped!
7942 */
7943 delta64 += (UINT_MAX -
7944 phys_last_knp[i].value.ui32);
7945 phys_last_knp[i].value.ui32 = 0;
7946 }
7947
7948 delta64 += phys_kn_entry.value.ui32 -
7949 phys_last_knp[i].value.ui32;
7950 phys_last_knp[i].value.ui32 = phys_kn_entry.value.ui32;
7951 break;
7952
7953 default:
7954 /*
7955 * must be a 64-bit value, we ignore 64-bit
7956 * wraps, since they shouldn't ever happen
7957 * within the life of a machine (if we assume
7958 * machines don't stay up for more than a few
7959 * hundred years without a reboot...)
7960 */
7961 delta64 = phys_kn_entry.value.ui64 -
7962 phys_last_knp[i].value.ui64;
7963 phys_last_knp[i].value.ui64 = phys_kn_entry.value.ui64;
7964 }
7965
7966 if (sum_knp != NULL) {
7967 /*
7968 * now we need to save the value
7969 */
7970 switch (sum_knp[i].data_type) {
7971 case KSTAT_DATA_UINT32:
7972 /* trunk down to 32 bits, possibly lossy */
7973 sum_knp[i].value.ui32 += (uint32_t)delta64;
7974 break;
7975
7976 default:
7977 sum_knp[i].value.ui64 += delta64;
7978 break;
7979 }
7980 }
7981 }
7982
7983 MAN_DBG(MAN_KSTAT, ("man_sum_kstats: returns\n"));
7984 }
7985
7986
7987 #if defined(DEBUG)
7988
7989
7990 static char *_ms_flags[] = {
7991 "NONE",
7992 "FAST", /* 0x1 */
7993 "RAW", /* 0x2 */
7994 "ALLPHYS", /* 0x4 */
7995 "ALLMULTI", /* 0x8 */
7996 "ALLSAP", /* 0x10 */
7997 "CKSUM", /* 0x20 */
7998 "MULTI", /* 0x40 */
7999 "SERLPBK", /* 0x80 */
8000 "MACLPBK", /* 0x100 */
8001 "CLOSING", /* 0x200 */
8002 "CLOSE_DONE", /* 0x400 */
8003 "CONTROL" /* 0x800 */
8004 };
8005
8006 static void
man_print_msp(manstr_t * msp)8007 man_print_msp(manstr_t *msp)
8008 {
8009 char buf[512];
8010 char prbuf[512];
8011 uint_t flags;
8012 int i;
8013
8014 cmn_err(CE_CONT, "\tmsp(0x%p)\n", (void *)msp);
8015
8016 if (msp == NULL)
8017 return;
8018
8019 cmn_err(CE_CONT, "\t%s%d SAP(0x%x):\n",
8020 ddi_major_to_name(msp->ms_meta_maj), msp->ms_meta_ppa,
8021 msp->ms_sap);
8022
8023 buf[0] = '\0';
8024 prbuf[0] = '\0';
8025 flags = msp->ms_flags;
8026 for (i = 0; i < A_CNT(_ms_flags); i++) {
8027 if ((flags >> i) & 0x1) {
8028 (void) sprintf(buf, " %s |", _ms_flags[i+1]);
8029 (void) strcat(prbuf, buf);
8030 }
8031 }
8032 prbuf[strlen(prbuf) - 1] = '\0';
8033 cmn_err(CE_CONT, "\tms_flags: %s\n", prbuf);
8034
8035 cmn_err(CE_CONT, "\tms_dlpistate: %s\n", dss[msp->ms_dlpistate]);
8036
8037 cmn_err(CE_CONT, "\tms_dl_mp: 0x%p\n", (void *)msp->ms_dl_mp);
8038
8039 cmn_err(CE_CONT, "\tms_manp: 0x%p\n", (void *)msp->ms_manp);
8040
8041 cmn_err(CE_CONT, "\tms_dests: 0x%p\n", (void *)msp->ms_dests);
8042
8043 }
8044
8045 static char *_md_state[] = {
8046 "NOTPRESENT", /* 0x0 */
8047 "INITIALIZING", /* 0x1 */
8048 "READY", /* 0x2 */
8049 "PLUMBING", /* 0x4 */
8050 "CLOSING" /* 0x8 */
8051 };
8052
8053 static void
man_print_mdp(man_dest_t * mdp)8054 man_print_mdp(man_dest_t *mdp)
8055 {
8056 uint_t state;
8057 int i;
8058 char buf[64];
8059 char prbuf[512];
8060
8061 buf[0] = '\0';
8062 prbuf[0] = '\0';
8063
8064 cmn_err(CE_CONT, "\tmdp(0x%p)\n", (void *)mdp);
8065
8066 if (mdp == NULL)
8067 return;
8068
8069 cmn_err(CE_CONT, "\tmd_pg_id: %d\n", mdp->md_pg_id);
8070 cmn_err(CE_CONT, "\tmd_dst_eaddr: %s\n",
8071 ether_sprintf(&mdp->md_dst_eaddr));
8072 cmn_err(CE_CONT, "\tmd_src_eaddr: %s\n",
8073 ether_sprintf(&mdp->md_src_eaddr));
8074 cmn_err(CE_CONT, "\tmd_dlpistate: %s", dss[mdp->md_dlpistate]);
8075 cmn_err(CE_CONT, "\tmd_muxid: 0x%u", mdp->md_muxid);
8076 cmn_err(CE_CONT, "\tmd_rcvcnt %lu md_lastrcvcnt %lu", mdp->md_rcvcnt,
8077 mdp->md_lastrcvcnt);
8078
8079 /*
8080 * Print out state as text.
8081 */
8082 state = mdp->md_state;
8083
8084 if (state == 0) {
8085 (void) strcat(prbuf, _md_state[0]);
8086 } else {
8087
8088 for (i = 0; i < A_CNT(_md_state); i++) {
8089 if ((state >> i) & 0x1) {
8090 (void) sprintf(buf, " %s |", _md_state[i+1]);
8091 (void) strcat(prbuf, buf);
8092 }
8093 }
8094 prbuf[strlen(prbuf) -1] = '\0';
8095 }
8096 cmn_err(CE_CONT, "\tmd_state: %s", prbuf);
8097
8098 cmn_err(CE_CONT, "\tmd_device:\n");
8099 man_print_dev(&mdp->md_device);
8100
8101 }
8102
8103 static void
man_print_man(man_t * manp)8104 man_print_man(man_t *manp)
8105 {
8106 char buf[512];
8107 char prbuf[512];
8108
8109 buf[0] = '\0';
8110 prbuf[0] = '\0';
8111
8112 if (manp == NULL)
8113 return;
8114
8115 if (ddi_major_to_name(manp->man_meta_major)) {
8116 (void) sprintf(buf, "\t man_device: %s%d\n",
8117 ddi_major_to_name(manp->man_meta_major),
8118 manp->man_meta_ppa);
8119 } else {
8120 (void) sprintf(buf, "\t major: %d", manp->man_meta_major);
8121 (void) sprintf(buf, "\t ppa: %d", manp->man_meta_ppa);
8122 }
8123
8124 cmn_err(CE_CONT, "%s", buf);
8125
8126 }
8127
8128 static char *_mdev_state[] = {
8129 "UNASSIGNED ",
8130 "ASSIGNED",
8131 "ACTIVE",
8132 "FAILED"
8133 };
8134
8135 static void
man_print_dev(man_dev_t * mdevp)8136 man_print_dev(man_dev_t *mdevp)
8137 {
8138 char buf[512];
8139 char prbuf[512];
8140 int i;
8141 uint_t state;
8142
8143 buf[0] = '\0';
8144 prbuf[0] = '\0';
8145
8146 if (mdevp == NULL)
8147 return;
8148
8149 if (mdevp->mdev_major == 0) {
8150 number:
8151 (void) sprintf(buf, "\t mdev_major: %d\n", mdevp->mdev_major);
8152 } else if (ddi_major_to_name(mdevp->mdev_major)) {
8153 (void) sprintf(buf, "\t mdev_device: %s%d\n",
8154 ddi_major_to_name(mdevp->mdev_major),
8155 mdevp->mdev_ppa);
8156 } else
8157 goto number;
8158
8159 cmn_err(CE_CONT, "%s", buf);
8160
8161 cmn_err(CE_CONT, "\t mdev_exp_id: %d\n", mdevp->mdev_exp_id);
8162
8163 buf[0] = '\0';
8164 prbuf[0] = '\0';
8165 state = mdevp->mdev_state;
8166
8167 if (state == 0) {
8168 (void) strcat(prbuf, _mdev_state[0]);
8169 } else {
8170 for (i = 0; i < A_CNT(_mdev_state); i++) {
8171 if ((state >> i) & 0x1) {
8172 (void) sprintf(buf, " %s |", _mdev_state[i+1]);
8173 (void) strcat(prbuf, buf);
8174 }
8175 }
8176 }
8177
8178 prbuf[strlen(prbuf) - 2] = '\0';
8179
8180 cmn_err(CE_CONT, "\t mdev_state: %s\n", prbuf);
8181
8182 }
8183
8184 static char *_mip_cmd[] = {
8185 "MI_PATH_READ",
8186 "MI_PATH_ASSIGN",
8187 "MI_PATH_ACTIVATE",
8188 "MI_PATH_DEACTIVATE",
8189 "MI_PATH_UNASSIGN"
8190 };
8191
8192 static void
man_print_mtp(mi_time_t * mtp)8193 man_print_mtp(mi_time_t *mtp)
8194 {
8195 cmn_err(CE_CONT, "\tmtp(0x%p)\n", (void *)mtp);
8196
8197 if (mtp == NULL)
8198 return;
8199
8200 cmn_err(CE_CONT, "\tmtp_instance: %d\n", mtp->mtp_man_ppa);
8201
8202 cmn_err(CE_CONT, "\tmtp_time: %d\n", mtp->mtp_time);
8203
8204 }
8205
8206 static void
man_print_mip(mi_path_t * mip)8207 man_print_mip(mi_path_t *mip)
8208 {
8209 cmn_err(CE_CONT, "\tmip(0x%p)\n", (void *)mip);
8210
8211 if (mip == NULL)
8212 return;
8213
8214 cmn_err(CE_CONT, "\tmip_pg_id: %d\n", mip->mip_pg_id);
8215
8216 cmn_err(CE_CONT, "\tmip_cmd: %s\n", _mip_cmd[mip->mip_cmd]);
8217
8218 cmn_err(CE_CONT, "\tmip_eaddr: %s\n", ether_sprintf(&mip->mip_eaddr));
8219
8220 cmn_err(CE_CONT, "\tmip_devs: 0x%p\n", (void *)mip->mip_devs);
8221
8222 cmn_err(CE_CONT, "\tmip_ndevs: %d\n", mip->mip_ndevs);
8223
8224 }
8225
8226 static void
man_print_mpg(man_pg_t * mpg)8227 man_print_mpg(man_pg_t *mpg)
8228 {
8229 cmn_err(CE_CONT, "\tmpg(0x%p)\n", (void *)mpg);
8230
8231 if (mpg == NULL)
8232 return;
8233
8234 cmn_err(CE_CONT, "\tmpg_next: 0x%p\n", (void *)mpg->mpg_next);
8235
8236 cmn_err(CE_CONT, "\tmpg_pg_id: %d\n", mpg->mpg_pg_id);
8237
8238 cmn_err(CE_CONT, "\tmpg_man_ppa: %d\n", mpg->mpg_man_ppa);
8239
8240 cmn_err(CE_CONT, "\tmpg_dst_eaddr: %s\n",
8241 ether_sprintf(&mpg->mpg_dst_eaddr));
8242
8243 cmn_err(CE_CONT, "\tmpg_pathp: 0x%p\n", (void *)mpg->mpg_pathp);
8244
8245 }
8246
8247 static char *_mw_flags[] = {
8248 "NOWAITER", /* 0x0 */
8249 "CVWAITER", /* 0x1 */
8250 "QWAITER", /* 0x2 */
8251 "DONE" /* 0x3 */
8252 };
8253
8254 static void
man_print_work(man_work_t * wp)8255 man_print_work(man_work_t *wp)
8256 {
8257 int i;
8258
8259 cmn_err(CE_CONT, "\twp(0x%p)\n\n", (void *)wp);
8260
8261 if (wp == NULL)
8262 return;
8263
8264 cmn_err(CE_CONT, "\tmw_type: %s\n", _mw_type[wp->mw_type]);
8265
8266 cmn_err(CE_CONT, "\tmw_flags: ");
8267 for (i = 0; i < A_CNT(_mw_flags); i++) {
8268 if ((wp->mw_flags >> i) & 0x1)
8269 cmn_err(CE_CONT, "%s", _mw_flags[i]);
8270 }
8271 cmn_err(CE_CONT, "\n");
8272
8273 cmn_err(CE_CONT, "\twp_status: %d\n", wp->mw_status);
8274
8275 cmn_err(CE_CONT, "\twp_arg: 0x%p\n", (void *)&wp->mw_arg);
8276
8277 cmn_err(CE_CONT, "\tmw_next: 0x%p\n", (void *)wp->mw_next);
8278
8279 cmn_err(CE_CONT, "\twp_q: 0x%p", (void *)wp->mw_q);
8280
8281 }
8282
8283 static void
man_print_path(man_path_t * mp)8284 man_print_path(man_path_t *mp)
8285 {
8286 cmn_err(CE_CONT, "\tmp(0x%p)\n\n", (void *)mp);
8287
8288 if (mp == NULL)
8289 return;
8290
8291 cmn_err(CE_CONT, "\tmp_device:");
8292 man_print_dev(&mp->mp_device);
8293
8294 cmn_err(CE_CONT, "\tmp_next: 0x%p\n", (void *)mp->mp_next);
8295
8296 cmn_err(CE_CONT, "\tmp_last_knp: 0x%p\n", (void *)mp->mp_last_knp);
8297
8298 cmn_err(CE_CONT, "\tmp_lru: 0x%lx", mp->mp_lru);
8299
8300 }
8301
8302 void *
man_dbg_kzalloc(int line,size_t size,int kmflags)8303 man_dbg_kzalloc(int line, size_t size, int kmflags)
8304 {
8305 void *tmp;
8306
8307 tmp = kmem_zalloc(size, kmflags);
8308 MAN_DBG(MAN_KMEM, ("0x%p %lu\tzalloc'd @ %d\n", (void *)tmp,
8309 size, line));
8310
8311 return (tmp);
8312
8313 }
8314
8315 void
man_dbg_kfree(int line,void * buf,size_t size)8316 man_dbg_kfree(int line, void *buf, size_t size)
8317 {
8318
8319 MAN_DBG(MAN_KMEM, ("0x%p %lu\tfree'd @ %d\n", (void *)buf, size, line));
8320
8321 kmem_free(buf, size);
8322
8323 }
8324
8325 #endif /* DEBUG */
8326