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 * Domain specific portion of the Starcat Management Network Driver
29 */
30
31 #include <sys/types.h>
32 #include <sys/proc.h>
33 #include <sys/kmem.h>
34 #include <sys/stat.h>
35 #include <sys/kstat.h>
36 #include <sys/ksynch.h>
37 #include <sys/stream.h>
38 #include <sys/dlpi.h>
39 #include <sys/stropts.h>
40 #include <sys/strsubr.h>
41 #include <sys/debug.h>
42 #include <sys/conf.h>
43 #include <sys/kstr.h>
44 #include <sys/errno.h>
45 #include <sys/ethernet.h>
46 #include <sys/byteorder.h>
47 #include <sys/ddi.h>
48 #include <sys/sunddi.h>
49 #include <sys/modctl.h>
50 #include <sys/strsun.h>
51 #include <sys/pci.h>
52 #include <sys/callb.h>
53 #include <sys/pci.h>
54 #include <sys/iosramio.h>
55 #include <sys/mboxsc.h>
56 #include <netinet/in.h>
57 #include <inet/common.h>
58 #include <inet/mi.h>
59 #include <inet/nd.h>
60 #include <sys/socket.h>
61 #include <netinet/igmp_var.h>
62 #include <netinet/ip6.h>
63 #include <netinet/icmp6.h>
64 #include <inet/ip.h>
65 #include <inet/ip6.h>
66 #include <sys/dman.h>
67 #include <sys/ddi_impldefs.h>
68 #include <sys/sunndi.h>
69
70 #define MAN_SCHIZO_BINDING_NAME "pci108e,8001"
71 #define MAN_XMITS_BINDING_NAME "pci108e,8002"
72
73 int man_is_on_domain = TRUE;
74
75 /*
76 * Domain side function prototypes.
77 */
78 int man_get_iosram(manc_t *);
79 int man_domain_configure(void);
80 int man_domain_deconfigure(void);
81 int man_path_discovery(void);
82 int man_dossc_switch(uint32_t);
83 int man_dr_attach(dev_info_t *);
84 int man_dr_detach(dev_info_t *);
85 static int man_dr_submit_work_wait(dev_info_t *, int);
86 static int man_find_devs(mi_path_t *, uchar_t);
87 static int man_dip_is_schizoxmits0_pcib(dev_info_t *, int *, int *);
88 static int man_dip_is_eri(dev_info_t *, man_dev_t *);
89 static int man_dip_is_attached(dev_info_t *);
90 static int man_get_eri_dev_info(dev_info_t *, man_dev_t *);
91 static int man_mbox_initialized = FALSE;
92
93 /*
94 * Externs
95 */
96 extern int man_pg_cmd(mi_path_t *, man_work_t *);
97 extern kmutex_t man_lock;
98 extern void *man_softstate;
99 extern man_work_t *man_work_alloc(int, int);
100 extern void man_work_free(man_work_t *);
101 extern void man_work_add(man_workq_t *, man_work_t *);
102 extern man_workq_t *man_bwork_q;
103 extern man_workq_t *man_iwork_q;
104 extern queue_t *man_ctl_wq;
105
106 #if defined(DEBUG)
107 static void man_print_manc(manc_t *);
108 extern uint32_t man_debug;
109 #endif /* DEBUG */
110
111 int
man_domain_configure(void)112 man_domain_configure(void)
113 {
114 int status = 0;
115
116 /*
117 * man_mbox_initialized is protected by inner perimiter lock.
118 */
119 if (man_mbox_initialized == TRUE)
120 goto exit;
121
122 status = mboxsc_init(IOSRAM_KEY_SCMD, MBOXSC_MBOX_IN, NULL);
123
124 if (status != 0) {
125 cmn_err(CE_WARN, "man_domain_configure: failed to initialize"
126 " MBOXSC_MBOX_IN, errno = %d", status);
127 goto exit;
128 }
129
130 status = mboxsc_init(IOSRAM_KEY_MDSC, MBOXSC_MBOX_OUT, NULL);
131 if (status != 0) {
132 (void) mboxsc_fini(IOSRAM_KEY_SCMD);
133 cmn_err(CE_WARN, "man_domain_configure: failed to initialize"
134 " MBOXSC_MBOX_OUT, errno = %d", status);
135 goto exit;
136 }
137
138 man_mbox_initialized = TRUE;
139
140 status = man_path_discovery();
141 if (status != 0) {
142 (void) mboxsc_fini(IOSRAM_KEY_SCMD);
143 (void) mboxsc_fini(IOSRAM_KEY_MDSC);
144 man_mbox_initialized = FALSE;
145 }
146
147 exit:
148 return (status);
149 }
150
151 /*
152 * Build pathgroup connecting a domain to the SSC. Only called on domains
153 * at first man_open. On the SSC, pathgroups are built by IOCTL requests
154 * from the MAN daemon (see man_ioctl and mand(1M)).
155 *
156 * Locks held
157 * - exclusive innerperim.
158 */
159 int
man_path_discovery(void)160 man_path_discovery(void)
161 {
162 manc_t manc;
163 mi_path_t mpath;
164 int num_devs;
165 int status = 0;
166 int i;
167
168 MAN_DBG(MAN_CONFIG, ("man_path_discovery:"));
169
170 if (status = man_get_iosram(&manc)) {
171 goto exit;
172 }
173
174 /*
175 * If manc_ip_type indicates MAN network is not enabled
176 * for this domain, then lets just bailout from here as if no
177 * devices were found.
178 */
179 if ((manc.manc_ip_type != AF_INET) &&
180 (manc.manc_ip_type != AF_INET6)) {
181 goto exit;
182 }
183
184 MAN_DBGCALL(MAN_CONFIG, man_print_manc(&manc));
185
186 /*
187 * Extract SC ethernet address from IOSRAM.
188 */
189 ether_copy(&manc.manc_sc_eaddr, &mpath.mip_eaddr);
190
191 mpath.mip_pg_id = 0; /* SC is always pathgroup ID 0 */
192 mpath.mip_man_ppa = 0; /* Domain only has one ppa, 0 */
193
194 /*
195 * Get list of present devices, and update man_paths[] as needed.
196 */
197 num_devs = man_find_devs(&mpath, MAN_MAX_EXPANDERS);
198 if (num_devs <= 0) {
199 status = ENODEV;
200 goto exit;
201 }
202
203 mpath.mip_cmd = MI_PATH_ASSIGN;
204
205 mutex_enter(&man_lock);
206 status = man_pg_cmd(&mpath, NULL);
207 if (status) {
208 mutex_exit(&man_lock);
209 goto exit;
210 }
211
212 /*
213 * Now activate the ethernet on the golden io board.
214 */
215 for (i = 0; i < num_devs; i++) {
216 if (mpath.mip_devs[i].mdev_exp_id == manc.manc_golden_iob)
217 mpath.mip_devs[0] = mpath.mip_devs[i];
218 }
219 mpath.mip_ndevs = 1;
220 mpath.mip_cmd = MI_PATH_ACTIVATE;
221 status = man_pg_cmd(&mpath, NULL);
222 mutex_exit(&man_lock);
223
224 exit:
225 MAN_DBG(MAN_CONFIG, ("man_path_discovery: returns %d\n", status));
226
227 return (status);
228 }
229
230 int
man_domain_deconfigure(void)231 man_domain_deconfigure(void)
232 {
233
234 (void) mboxsc_fini(IOSRAM_KEY_SCMD);
235 (void) mboxsc_fini(IOSRAM_KEY_MDSC);
236 /*
237 * We are about to unload and know that there are no open
238 * streams, so this change outside of the perimiter is ok.
239 */
240 man_mbox_initialized = FALSE;
241
242 return (0);
243 }
244
245 /*
246 * Add a work request to the inner perimeter with the new eri device info.
247 */
248 /* ARGSUSED */
249 int
man_dr_attach(dev_info_t * dip)250 man_dr_attach(dev_info_t *dip)
251 {
252 man_t *manp;
253 man_work_t *wp;
254 int status = 0;
255 man_dev_t mdev;
256
257
258 mutex_enter(&man_lock);
259 manp = ddi_get_soft_state(man_softstate, 0);
260 if (manp == NULL || manp->man_pg == NULL) {
261 goto exit;
262 }
263
264 if (man_get_eri_dev_info(dip, &mdev) == FALSE) {
265 status = ENODEV;
266 goto exit;
267 }
268 MAN_DBG(MAN_DR, ("man_dr_attach: dip major = %d instance =%d",
269 mdev.mdev_major, mdev.mdev_ppa));
270 wp = man_work_alloc(MAN_WORK_DRATTACH, KM_NOSLEEP);
271 if (wp == NULL) {
272 status = ENOMEM;
273 goto exit;
274 }
275
276 wp->mw_arg.a_man_ppa = 0; /* Domain only has one ppa, 0 */
277 wp->mw_arg.a_pg_id = 0; /* SC is always pathgroup ID 0 */
278 wp->mw_arg.a_sf_dev = mdev;
279 wp->mw_flags = MAN_WFLAGS_NOWAITER;
280
281 man_work_add(man_iwork_q, wp);
282
283 if (man_ctl_wq)
284 qenable(man_ctl_wq);
285
286 exit:
287 mutex_exit(&man_lock);
288
289 return (status);
290 }
291
292 int
man_dr_detach(dev_info_t * dip)293 man_dr_detach(dev_info_t *dip)
294 {
295 man_t *manp;
296 int status = 0;
297 int retries = 0;
298
299
300 mutex_enter(&man_lock);
301 manp = ddi_get_soft_state(man_softstate, 0);
302 if (manp == NULL || manp->man_pg == NULL) {
303 mutex_exit(&man_lock);
304 goto exit;
305 }
306 mutex_exit(&man_lock);
307
308 /*
309 * Arrange to have the detaching path switched if it is active.
310 * We will cv_wait_sig for the switch to complete if it is needed.
311 */
312 again:
313 status = man_dr_submit_work_wait(dip, MAN_WORK_DRSWITCH);
314 if (status == EAGAIN && retries < manp->man_dr_retries) {
315 /*
316 * Delay a bit and retry.
317 */
318 MAN_DBG(MAN_DR,
319 ("man_dr_detach(switch): EAGAIN - retrying..."));
320 retries++;
321 delay(drv_usectohz(manp->man_dr_delay));
322 goto again;
323 }
324
325 if (status)
326 goto exit;
327
328 retries = 0;
329
330 /*
331 * Detaching device no longer in use, remove it from our
332 * pathgroup.
333 */
334 status = man_dr_submit_work_wait(dip, MAN_WORK_DRDETACH);
335 if (status == EAGAIN && retries < manp->man_dr_retries) {
336 MAN_DBG(MAN_DR,
337 ("man_dr_detach(detach): EAGAIN - retrying..."));
338 retries++;
339 goto again;
340 }
341
342 exit:
343 MAN_DBG(MAN_DR, ("man_dr_detach: returns %d", status));
344 return (status);
345 }
346
347 static int
man_dr_submit_work_wait(dev_info_t * dip,int work_type)348 man_dr_submit_work_wait(dev_info_t *dip, int work_type)
349 {
350 man_work_t *wp;
351 int status = 0;
352
353 wp = man_work_alloc(work_type, KM_NOSLEEP);
354 if (wp == NULL) {
355 status = ENOMEM;
356 goto exit;
357 }
358
359 wp->mw_arg.a_man_ppa = 0;
360 wp->mw_arg.a_pg_id = 0;
361 wp->mw_arg.a_sf_dev.mdev_major = ddi_driver_major(dip);
362 wp->mw_arg.a_sf_dev.mdev_ppa = ddi_get_instance(dip);
363
364 mutex_enter(&man_lock);
365 wp->mw_flags = MAN_WFLAGS_CVWAITER;
366 man_work_add(man_iwork_q, wp);
367
368 /* TBD - change to ASSERT ? */
369 if (man_ctl_wq)
370 qenable(man_ctl_wq);
371
372 while (!(wp->mw_flags & MAN_WFLAGS_DONE)) {
373 if (!cv_wait_sig(&wp->mw_cv, &man_lock)) {
374 wp->mw_flags &= ~MAN_WFLAGS_CVWAITER;
375 status = EINTR;
376 break;
377 }
378 }
379
380 /*
381 * Note that if cv_wait_sig() returns zero because a signal
382 * was received, MAN_WFLAGS_DONE may not be set.
383 * This will happen if man_dr_submit_work_wait() reacquires
384 * man_lock before man_iwork() can acquire man_lock just before
385 * signalling its work is complete.
386 * In this case, it is not necessary to call man_work_free()
387 * here because it will be called by man_iwork() because
388 * MAN_WFLAGS_CVWAITER was cleared.
389 * Should man_iwork() obtain man_lock to signal completion,
390 * MAN_WFLAGS_DONE will be set which will ensure man_work_free()
391 * is called here.
392 */
393 if (wp->mw_flags & MAN_WFLAGS_DONE) {
394 status = wp->mw_status;
395 man_work_free(wp);
396 }
397
398 mutex_exit(&man_lock);
399
400 exit:
401 return (status);
402 }
403
404 /*
405 * Notify SSC of switch request and wait for response.
406 */
407 int
man_dossc_switch(uint32_t exp_id)408 man_dossc_switch(uint32_t exp_id)
409 {
410 uint64_t req_tid;
411 uint32_t req_cmd;
412 uint64_t resp_tid;
413 uint32_t resp_cmd;
414 uint32_t type;
415 man_mbox_msg_t req;
416 man_mbox_msg_t resp;
417 uint32_t length;
418 int status = 0;
419
420 /*
421 * There should be nothing in inbound mailbox.
422 */
423 resp_tid = resp_cmd = type = 0;
424 length = sizeof (man_mbox_msg_t);
425 bzero((char *)&resp, sizeof (man_mbox_msg_t));
426 while (mboxsc_getmsg(IOSRAM_KEY_SCMD, &type, &resp_cmd, &resp_tid,
427 &length, &resp, 0) == 0) {
428
429 resp_tid = resp_cmd = type = 0;
430 length = sizeof (man_mbox_msg_t);
431 bzero((char *)&resp, sizeof (man_mbox_msg_t));
432
433 MAN_DBG(MAN_IOSRAM, ("man_dossc_switch: dumping message"));
434 MAN_DBG(MAN_IOSRAM, ("\tcommand = 0x%x", resp_cmd));
435 }
436
437 MAN_DBG(MAN_IOSRAM, ("man_dossc_switch: sending message"));
438
439 bzero((char *)&req, sizeof (man_mbox_msg_t));
440 req.mb_status = 0;
441 req.mb_exp_id = exp_id;
442 req_tid = 0;
443 req_cmd = MAN_WORK_SWITCH;
444
445 status = mboxsc_putmsg(IOSRAM_KEY_MDSC, MBOXSC_MSG_REQUEST,
446 req_cmd, &req_tid, sizeof (man_mbox_msg_t), &req,
447 MAN_IOSRAM_TIMEOUT);
448
449 if (status != 0) {
450 cmn_err(CE_WARN, "man_dossc_switch: mboxsc_putmsg failed,"
451 " errno = %d", status);
452 goto exit;
453 }
454
455 bzero((char *)&resp, sizeof (man_mbox_msg_t));
456
457 resp_tid = type = resp_cmd = 0;
458 length = sizeof (man_mbox_msg_t);
459 status = mboxsc_getmsg(IOSRAM_KEY_SCMD, &type, &resp_cmd, &resp_tid,
460 &length, (void *)&resp, MAN_IOSRAM_TIMEOUT);
461 if (status != 0) {
462 cmn_err(CE_WARN, "man_dossc_switch: mboxsc_getmsg failed,"
463 " errno = %d", status);
464 goto exit;
465 }
466
467 MAN_DBG(MAN_IOSRAM, ("man_dossc_switch: received message"));
468
469 if (req_cmd != resp_cmd || req_tid != resp_tid) {
470 cmn_err(CE_WARN, "man_dossc_switch: failed,"
471 " cmd/transid mismatch (%d, %d)/(%d, %d)",
472 req_cmd, resp_cmd, (int)req_tid, (int)resp_tid);
473 status = EINVAL;
474 goto exit;
475 }
476
477 status = resp.mb_status;
478 if (status != 0) {
479 cmn_err(CE_WARN, "man_dossc_switch: failed errno == %d",
480 status);
481 }
482 exit:
483 return (status);
484 }
485
486
487 /*
488 * Read IOSRAM info.
489 */
490 int
man_get_iosram(manc_t * mcp)491 man_get_iosram(manc_t *mcp)
492 {
493 int status;
494
495 if (mcp == NULL)
496 return (EINVAL);
497
498 status = iosram_rd(IOSRAM_KEY_MANC, 0, sizeof (manc_t), (caddr_t)mcp);
499 if (status) {
500 cmn_err(CE_WARN, "man_get_iosram: iosram_rd failed"
501 " errno = %d\n", status);
502 return (status);
503 }
504
505 MAN_DBG(MAN_PATH, ("man_get_iosram:"));
506 MAN_DBGCALL(MAN_PATH, man_print_manc(mcp));
507
508 if (mcp->manc_magic != IOSRAM_KEY_MANC) {
509 cmn_err(CE_WARN, "man_get_iosram: bad magic - got(0x%x)"
510 " expected(0x%x)\n", mcp->manc_magic, IOSRAM_KEY_MANC);
511 status = EIO;
512 } else if (mcp->manc_version != MANC_VERSION) {
513 cmn_err(CE_WARN, "man_get_iosram: version mismatch -"
514 " got(0x%x) expected(0x%x)\n", mcp->manc_version,
515 MANC_VERSION);
516 status = EIO;
517 }
518
519 return (status);
520 }
521
522 #if defined(MAN_NO_IOSRAM)
523
524 static manc_t manc = {
525 IOSRAM_KEY_MANC,
526 MANC_VERSION,
527 0,
528 AF_INET,
529 /* 0x10010102, Two */
530 0x10010103, /* Scot */
531 0xFF000000, /* Scot netmask */
532 0x10010101, /* SC 10.1.1.1 */
533 {0}, /* AF_INET6 addrs */
534 {0}, /* AF_INET6 addrs */
535 {0},
536 /* {0x8, 0x0, 0x20, 0x21, 0x44, 0x83}, Domain eaddr "two" */
537 {0x8, 0x0, 0x20, 0x8f, 0x84, 0x63}, /* Domain eaddr "scot" */
538 {0x8, 0x0, 0x20, 0x1f, 0xe3, 0x46}, /* SC eaddr "one" */
539 0x1,
540 0x1
541 };
542
543
544 /*
545 * Get IOSRAM info or release it.
546 */
547 int
man_get_iosram(manc_t * mcp)548 man_get_iosram(manc_t *mcp)
549 {
550 int status = 0;
551
552 if (mcp == NULL)
553 return (EINVAL);
554
555 *mcp = manc;
556
557 if (mcp->manc_magic != IOSRAM_KEY_MANC) {
558 cmn_err(CE_WARN, "man_get_iosram: bad magic - got(0x%x)"
559 " expected(0x%x)\n", mcp->manc_magic, IOSRAM_KEY_MANC);
560 status = EIO;
561 } else if (mcp->manc_version != MANC_VERSION) {
562 cmn_err(CE_WARN, "man_get_iosram: version mismatch -"
563 " got(0x%x) expected(0x%x)\n", mcp->manc_version,
564 MANC_VERSION);
565 status = EIO;
566 }
567
568 return (status);
569 }
570 #endif /* MAN_NO_IOSRAM */
571
572 /*
573 * Find all RIOs on the IO boards for the domain. We walk all the children
574 * of the root node looking for a PCI devinfo with a safari port ID of
575 * 0xDC that has a child with device ID of 3. This is gauranteed to be
576 * the network portion of the RIO by virtue of the way Starcats are
577 * physically built.
578 */
579 static int
man_find_devs(mi_path_t * mipathp,uchar_t golden_iob)580 man_find_devs(mi_path_t *mipathp, uchar_t golden_iob)
581 {
582 dev_info_t *bus_dip;
583 dev_info_t *eri_dip;
584 dev_info_t *rdip, *pdip;
585 int exp_id;
586 int found = 0;
587 int circ;
588 int circ2;
589 man_dev_t ndev;
590 int xmits;
591
592 MAN_DBG(MAN_PATH, ("man_find_devs: mdevpp(0x%p) golden_iob(%d)\n",
593 (void *)(mipathp), golden_iob));
594
595 /*
596 * Hold parent busy while walking its child list.
597 */
598 rdip = ddi_root_node();
599 ndi_devi_enter(rdip, &circ);
600 bus_dip = ddi_get_child(rdip);
601
602 while (bus_dip != NULL) {
603 exp_id = -1;
604 xmits = 0;
605 if (man_dip_is_schizoxmits0_pcib(bus_dip, &exp_id, &xmits)) {
606 eri_dip = NULL;
607 pdip = bus_dip;
608 if (xmits) {
609 /*
610 * If this is XMITS0 PCI_B leaf, then the
611 * pci_pci bridge which is the only child,
612 * is the parent to MAN RIO.
613 */
614 pdip = ddi_get_child(bus_dip);
615 if (pdip == NULL) {
616 bus_dip = ddi_get_next_sibling(bus_dip);
617 continue;
618 }
619 }
620 ndi_devi_enter(pdip, &circ2);
621 eri_dip = ddi_get_child(pdip);
622 while (eri_dip != NULL) {
623 MAN_DBG(MAN_PATH, ("man_find_devs: "
624 "eri_dip %s\n",
625 ddi_binding_name(eri_dip)));
626 if (man_dip_is_eri(eri_dip, &ndev) &&
627 man_dip_is_attached(eri_dip)) {
628
629 ASSERT(exp_id != -1);
630 ndev.mdev_exp_id = exp_id;
631 ndev.mdev_state = MDEV_ASSIGNED;
632 mipathp->mip_devs[found] = ndev;
633 found++;
634
635 MAN_DBG(MAN_PATH,
636 ("man_find_devs: found eri maj(%d) "
637 "ppa(%d) on expander(%d)\n",
638 ndev.mdev_major,
639 ndev.mdev_ppa, exp_id));
640 }
641 eri_dip = ddi_get_next_sibling(eri_dip);
642 }
643 ndi_devi_exit(pdip, circ2);
644 }
645 bus_dip = ddi_get_next_sibling(bus_dip);
646 }
647 ndi_devi_exit(rdip, circ);
648
649 MAN_DBG(MAN_PATH, ("man_find_devs returns found = %d\n", found));
650
651 mipathp->mip_ndevs = found;
652 return (found);
653 }
654
655 /*
656 * Verify if the dip passed is an instance of 'eri' and set
657 * the device info in mdevp.
658 */
659 static int
man_get_eri_dev_info(dev_info_t * dip,man_dev_t * mdevp)660 man_get_eri_dev_info(dev_info_t *dip, man_dev_t *mdevp)
661 {
662 dev_info_t *parent_dip;
663 int exp_id;
664 int xmits;
665 char *name;
666
667 ASSERT(dip != NULL);
668 /*
669 * Verify if the parent is schizo(xmits)0 and pci B leaf.
670 */
671 if (((parent_dip = ddi_get_parent(dip)) == NULL) ||
672 ((name = ddi_binding_name(parent_dip)) == NULL))
673 return (FALSE);
674 if (strcmp(name, MAN_SCHIZO_BINDING_NAME) != 0) {
675 /*
676 * This RIO could be on XMITS, so get the dip to
677 * XMITS PCI Leaf.
678 */
679 if ((parent_dip = ddi_get_parent(parent_dip)) == NULL)
680 return (FALSE);
681 if (((name = ddi_binding_name(parent_dip)) == NULL) ||
682 (strcmp(name, MAN_XMITS_BINDING_NAME) != 0)) {
683 return (FALSE);
684 }
685 }
686 if (man_dip_is_schizoxmits0_pcib(parent_dip, &exp_id, &xmits) == FALSE)
687 return (FALSE);
688
689 /*
690 * Make sure it is attached.
691 */
692 if (man_dip_is_attached(dip) == FALSE) {
693 MAN_DBG(MAN_DR, ("man_get_eri_dev_info: "
694 "dip 0x%p not attached\n", (void *)dip));
695 return (FALSE);
696 }
697 mdevp->mdev_exp_id = exp_id;
698 mdevp->mdev_ppa = ddi_get_instance(dip);
699 mdevp->mdev_major = ddi_driver_major(dip);
700 mdevp->mdev_state = MDEV_ASSIGNED;
701 return (TRUE);
702 }
703
704 /*
705 * MAN RIO is connected to SCHIZO/XMITS 0 and PCI_B Leaf.
706 * Incase of XMITS, it is actually connected to a PCI Bridge(21154)
707 * which is directly connected to the PCI_B leaf of XMITS0.
708 *
709 * This function verifies if the given dip is SCHIZO/XMITS 0 and
710 * PCI_B Leaf. This is done as follows:
711 *
712 * - Check the binding name to verify SCHIZO/XMITS.
713 * - Verify the Device type to be "pci".
714 * - Verify the PortID to be ending with 0x1C
715 * - Verify the the CSR base to be 0x70.0000.
716 */
717 static int
man_dip_is_schizoxmits0_pcib(dev_info_t * dip,int * exp_id,int * xmits)718 man_dip_is_schizoxmits0_pcib(dev_info_t *dip, int *exp_id, int *xmits)
719 {
720 char dtype[MAN_DDI_BUFLEN];
721 int portid;
722 uint_t pci_csr_base;
723 struct pci_phys_spec *regbuf = NULL;
724 int length = MAN_DDI_BUFLEN;
725 char *name;
726
727 ASSERT(dip != NULL);
728 *exp_id = -1;
729 if ((name = ddi_binding_name(dip)) == NULL)
730 return (FALSE);
731 if (strcmp(name, MAN_SCHIZO_BINDING_NAME) == 0) {
732 MAN_DBG(MAN_PATH, ("man_dip_is_schizoxmits0_pcib: "
733 "SCHIZO found 0x%p\n", (void *)dip));
734 } else if (strcmp(name, MAN_XMITS_BINDING_NAME) == 0) {
735 *xmits = TRUE;
736 MAN_DBG(MAN_PATH, ("man_dip_is_schizoxmits0_pcib: "
737 "XMITS found 0x%p\n", (void *)dip));
738 } else
739 return (FALSE);
740 if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, MAN_DEVTYPE_PROP,
741 (caddr_t)dtype, &length) == DDI_PROP_SUCCESS) {
742
743 MAN_DBG(MAN_PATH, ("dtype: %s\n", dtype));
744 if (strncmp(dtype, MAN_DEVTYPE_PCI, 3) != 0)
745 goto notfound;
746
747 /*
748 * Get safari ID (DDI port ID).
749 */
750 if ((portid = (int)ddi_getprop(DDI_DEV_T_ANY, dip, 0,
751 MAN_PORTID_PROP, -1)) == -1) {
752
753 MAN_DBG(MAN_PATH, ("ddi_getpropp: failed\n"));
754 goto notfound;
755 }
756
757 /*
758 * All schizo 0 safari IDs end in 0x1C.
759 */
760 if ((portid & MAN_SCHIZO_MASK) != MAN_SCHIZO_0_ID)
761 goto notfound;
762
763 /*
764 * All PCI nodes "B" are at configspace 0x70.0000
765 */
766 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
767 MAN_REG_PROP, (caddr_t)®buf,
768 &length) != DDI_PROP_SUCCESS) {
769
770 MAN_DBG(MAN_PATH, ("ddi_getlongprop_buf: failed"));
771 goto notfound;
772 }
773
774 pci_csr_base = regbuf[0].pci_phys_mid & PCI_CONF_ADDR_MASK;
775 kmem_free(regbuf, length);
776 if (pci_csr_base == MAN_PCI_B_CSR_BASE) {
777
778 MAN_DBG(MAN_PATH, ("man_dip_is_schizoxmits0_pcib:"
779 " found PCI B at dip(0x%p)\n", (void *)dip));
780
781 *exp_id = portid >> 5;
782 return (TRUE);
783 }
784 }
785
786 notfound:
787 return (FALSE);
788 }
789
790 static int
man_dip_is_eri(dev_info_t * dip,man_dev_t * ndevp)791 man_dip_is_eri(dev_info_t *dip, man_dev_t *ndevp)
792 {
793 struct pci_phys_spec *regbuf = NULL;
794 int length = 0;
795 uint_t pci_device;
796 uint_t pci_function;
797
798 MAN_DBG(MAN_PATH, ("man_dip_is_eri: dip(0x%p) ndevp(0x%p)\n",
799 (void *)dip, (void *)ndevp));
800 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
801 MAN_REG_PROP, (caddr_t)®buf,
802 &length) == DDI_PROP_SUCCESS) {
803
804 pci_device = PCI_REG_DEV_G(regbuf->pci_phys_hi);
805 pci_function = PCI_REG_FUNC_G(regbuf->pci_phys_hi);
806 kmem_free(regbuf, length);
807
808 /*
809 * The network function of the RIO ASIC will always
810 * be device 3 and function 1 ("network@3,1").
811 */
812 if (pci_device == 3 && pci_function == 1) {
813 ndevp->mdev_ppa = ddi_get_instance(dip);
814 ndevp->mdev_major = ddi_driver_major(dip);
815
816 MAN_DBG(MAN_PATH, ("man_dip_is_eri: found eri maj(%d)"
817 " ppa(%d)\n", ndevp->mdev_major, ndevp->mdev_ppa));
818
819 return (TRUE);
820 }
821 }
822
823 MAN_DBG(MAN_PATH, ("man_dip_is_eri: returns FALSE\n"));
824
825 return (FALSE);
826 }
827
828 static int
man_dip_is_attached(dev_info_t * dip)829 man_dip_is_attached(dev_info_t *dip)
830 {
831 int state;
832
833 state = ddi_get_devstate(dip);
834 if (i_ddi_devi_attached(dip) || (state == DDI_DEVSTATE_UP)) {
835 /*
836 * The instance info is more important for us,
837 * so verify.
838 */
839 if (ddi_get_instance(dip) >= 0) {
840 return (TRUE);
841 }
842 cmn_err(CE_WARN, "man_dip_is_attached: "
843 "eri 0x%p instance is not set yet", (void *)dip);
844
845 }
846 return (FALSE);
847 }
848
849 #if defined(DEBUG)
850 static void
man_print_manc(manc_t * mcp)851 man_print_manc(manc_t *mcp)
852 {
853 cmn_err(CE_CONT, "\tmcp(0x%p)\n\n", (void *)mcp);
854
855 if (mcp == NULL)
856 return;
857
858 cmn_err(CE_CONT, "\tmagic: 0x%x\n", mcp->manc_magic);
859 cmn_err(CE_CONT, "\tversion: 0x%x\n", mcp->manc_version);
860 cmn_err(CE_CONT, "\tcsum: %d\n", mcp->manc_csum);
861 cmn_err(CE_CONT, "\tdom_eaddr: %s\n",
862 ether_sprintf(&mcp->manc_dom_eaddr));
863 cmn_err(CE_CONT, "\tsc_eaddr: %s\n",
864 ether_sprintf(&mcp->manc_sc_eaddr));
865 cmn_err(CE_CONT, "\tiob_bitmap: 0x%x\n", mcp->manc_iob_bitmap);
866 cmn_err(CE_CONT, "\tgolden_iob: %d\n", mcp->manc_golden_iob);
867
868 }
869
870 #endif /* DEBUG */
871