xref: /illumos-gate/usr/src/uts/common/io/usbgem/usbgem.c (revision 44bf619d328827ce5eca6833fcd5c69f1592e578)
1 /*
2  * usbgem.c: General USB to Fast Ethernet mac driver framework
3  *
4  * Copyright (c) 2002-2012 Masayuki Murayama.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice,
10  *    this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  *    this list of conditions and the following disclaimer in the documentation
14  *    and/or other materials provided with the distribution.
15  *
16  * 3. Neither the name of the author nor the names of its contributors may be
17  *    used to endorse or promote products derived from this software without
18  *    specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31  * DAMAGE.
32  */
33 
34 /*
35  * Copyright 2019 Joyent, Inc.
36  */
37 
38 /*
39  * Change log
40  */
41 
42 /*
43  * TODO:
44  *	implement DELAYED_START
45  */
46 
47 /*
48  * System Header files.
49  */
50 #include <sys/types.h>
51 #include <sys/conf.h>
52 #include <sys/debug.h>
53 #include <sys/kmem.h>
54 #include <sys/vtrace.h>
55 #include <sys/ethernet.h>
56 #include <sys/modctl.h>
57 #include <sys/errno.h>
58 #include <sys/ddi.h>
59 #include <sys/sunddi.h>
60 #ifndef USBGEM_CONFIG_GLDv3
61 #include <sys/dlpi.h>
62 #include <sys/strsubr.h>
63 #endif
64 #include <sys/stream.h>		/* required for MBLK* */
65 #include <sys/strsun.h>		/* required for mionack() */
66 #include <sys/byteorder.h>
67 
68 #include <sys/usb/usba.h>
69 #ifdef USBGEM_CONFIG_GLDv3
70 #include <inet/common.h>
71 #include <inet/led.h>
72 #include <inet/mi.h>
73 #include <inet/nd.h>
74 #endif
75 
76 /* supplement definitions */
77 extern const char *usb_str_cr(usb_cr_t);
78 
79 #ifndef USBGEM_CONFIG_GLDv3
80 #pragma weak	gld_linkstate
81 #endif
82 #include <sys/note.h>
83 
84 #include "usbgem_mii.h"
85 #include "usbgem.h"
86 
87 #ifdef MODULE
88 char	ident[] = "usb general ethernet mac driver v" VERSION;
89 #else
90 extern char	ident[];
91 #endif
92 
93 /* Debugging support */
94 #ifdef USBGEM_DEBUG_LEVEL
95 static int usbgem_debug = USBGEM_DEBUG_LEVEL;
96 #define	DPRINTF(n, args)	if (usbgem_debug > (n)) cmn_err args
97 #else
98 #define	DPRINTF(n, args)
99 #endif
100 
101 /*
102  * Useful macros and typedefs
103  */
104 #define	ROUNDUP(x, a)		(((x) + (a) - 1) & ~((a) - 1))
105 #define	DEFAULT_PIPE(dp)	((dp)->reg_data->dev_default_ph)
106 #define	VTAG_SIZE	4
107 #define	BOOLEAN(x)	((x) != 0)
108 /*
109  * configuration parameters
110  */
111 #define	USBDRV_MAJOR_VER	2
112 #define	USBDRV_MINOR_VER	0
113 
114 #define	ETHERHEADERL	(sizeof (struct ether_header))
115 #define	MAXPKTLEN(dp)	((dp)->mtu + ETHERHEADERL)
116 #define	MAXPKTBUF(dp)	((dp)->mtu + ETHERHEADERL + ETHERFCSL)
117 
118 #define	WATCH_INTERVAL_FAST	drv_usectohz(100*1000)
119 
120 #define	STOP_GRACEFUL	B_TRUE
121 
122 /*
123  * Private functions
124  */
125 static int usbgem_open_pipes(struct usbgem_dev *dp);
126 static int usbgem_close_pipes(struct usbgem_dev *dp);
127 static void usbgem_intr_cb(usb_pipe_handle_t, usb_intr_req_t *);
128 static void usbgem_bulkin_cb(usb_pipe_handle_t, usb_bulk_req_t *);
129 static void usbgem_bulkout_cb(usb_pipe_handle_t, usb_bulk_req_t *);
130 
131 static int usbgem_mii_start(struct usbgem_dev *);
132 static void usbgem_mii_stop(struct usbgem_dev *);
133 
134 /* local buffer management */
135 static int usbgem_init_rx_buf(struct usbgem_dev *);
136 
137 /* internal mac interfaces */
138 static void usbgem_tx_timeout(struct usbgem_dev *);
139 static void usbgem_mii_link_watcher(struct usbgem_dev *);
140 static int usbgem_mac_init(struct usbgem_dev *);
141 static int usbgem_mac_start(struct usbgem_dev *);
142 static int usbgem_mac_stop(struct usbgem_dev *, int, boolean_t);
143 static void usbgem_mac_ioctl(struct usbgem_dev *, queue_t *, mblk_t *);
144 
145 int usbgem_speed_value[] = {10, 100, 1000};
146 
147 static int usbgem_ctrl_retry = 5;
148 
149 /* usb event support */
150 static int usbgem_disconnect_cb(dev_info_t *dip);
151 static int usbgem_reconnect_cb(dev_info_t *dip);
152 int usbgem_suspend(dev_info_t *dip);
153 int usbgem_resume(dev_info_t *dip);
154 
155 static uint8_t usbgem_bcastaddr[] = {
156 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
157 };
158 
159 #ifdef MODULE
160 extern struct mod_ops mod_miscops;
161 
162 static struct modlmisc modlmisc = {
163 	&mod_miscops,
164 	"usbgem v" VERSION,
165 };
166 
167 static struct modlinkage modlinkage = {
168 	MODREV_1, &modlmisc, NULL
169 };
170 
171 /*
172  * _init : done
173  */
174 int
175 _init(void)
176 {
177 	int	status;
178 
179 	DPRINTF(2, (CE_CONT, "!usbgem: _init: called"));
180 	status = mod_install(&modlinkage);
181 
182 	return (status);
183 }
184 
185 /*
186  * _fini : done
187  */
188 int
189 _fini(void)
190 {
191 	int	status;
192 
193 	DPRINTF(2, (CE_CONT, "!usbgem: _fini: called"));
194 	status = mod_remove(&modlinkage);
195 	return (status);
196 }
197 
198 int
199 _info(struct modinfo *modinfop)
200 {
201 	return (mod_info(&modlinkage, modinfop));
202 }
203 #endif /* MODULE */
204 
205 /* ============================================================== */
206 /*
207  * Ether CRC calculation utilities
208  */
209 /* ============================================================== */
210 /*
211  * Ether CRC calculation according to 21143 data sheet
212  */
213 #define	CRC32_POLY_LE	0xedb88320
214 uint32_t
215 usbgem_ether_crc_le(const uint8_t *addr)
216 {
217 	int		idx;
218 	int		bit;
219 	uint_t		data;
220 	uint32_t	crc = 0xffffffff;
221 
222 	crc = 0xffffffff;
223 	for (idx = 0; idx < ETHERADDRL; idx++) {
224 		for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) {
225 			crc = (crc >> 1) ^
226 			    (((crc ^ data) & 1) ? CRC32_POLY_LE : 0);
227 		}
228 	}
229 	return	(crc);
230 }
231 
232 #define	CRC32_POLY_BE	0x04c11db7
233 uint32_t
234 usbgem_ether_crc_be(const uint8_t *addr)
235 {
236 	int		idx;
237 	int		bit;
238 	uint_t		data;
239 	uint32_t	crc;
240 
241 	crc = 0xffffffff;
242 	for (idx = 0; idx < ETHERADDRL; idx++) {
243 		for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) {
244 			crc = (crc << 1) ^
245 			    ((((crc >> 31) ^ data) & 1) ? CRC32_POLY_BE : 0);
246 		}
247 	}
248 	return (crc);
249 }
250 
251 int
252 usbgem_prop_get_int(struct usbgem_dev *dp, char *prop_template, int def_val)
253 {
254 	char	propname[32];
255 
256 	(void) sprintf(propname, prop_template, dp->name);
257 
258 	return (ddi_prop_get_int(DDI_DEV_T_ANY, dp->dip,
259 	    DDI_PROP_DONTPASS, propname, def_val));
260 }
261 
262 static int
263 usbgem_population(uint32_t x)
264 {
265 	int	i;
266 	int	cnt;
267 
268 	cnt = 0;
269 	for (i = 0; i < 32; i++) {
270 		if (x & (1 << i)) {
271 			cnt++;
272 		}
273 	}
274 	return (cnt);
275 }
276 
277 static clock_t
278 usbgem_timestamp_nz()
279 {
280 	clock_t	now;
281 	now = ddi_get_lbolt();
282 	return (now ? now : (clock_t)1);
283 }
284 
285 #ifdef USBGEM_DEBUG_LEVEL
286 #ifdef USBGEM_DEBUG_VLAN
287 #ifdef notdef
288 #include <netinet/in.h>
289 #endif
290 static void
291 usbgem_dump_packet(struct usbgem_dev *dp, char *title, mblk_t *mp,
292     boolean_t check_cksum)
293 {
294 	char	msg[180];
295 	uint8_t	buf[18+20+20];
296 	uint8_t	*p;
297 	size_t	offset;
298 	uint_t	ethertype;
299 	uint_t	proto;
300 	uint_t	ipproto = 0;
301 	uint_t	iplen;
302 	uint_t	iphlen;
303 	uint_t	tcplen;
304 	uint_t	udplen;
305 	uint_t	cksum;
306 	int	rest;
307 	int	len;
308 	char	*bp;
309 	mblk_t	*tp;
310 	extern uint_t	ip_cksum(mblk_t *, int, uint32_t);
311 
312 	msg[0] = 0;
313 	bp = msg;
314 
315 	rest = sizeof (buf);
316 	offset = 0;
317 	for (tp = mp; tp; tp = tp->b_cont) {
318 		len = tp->b_wptr - tp->b_rptr;
319 		len = min(rest, len);
320 		bcopy(tp->b_rptr, &buf[offset], len);
321 		rest -= len;
322 		offset += len;
323 		if (rest == 0) {
324 			break;
325 		}
326 	}
327 
328 	offset = 0;
329 	p = &buf[offset];
330 
331 	/* ethernet address */
332 	sprintf(bp,
333 	    "ether: %02x:%02x:%02x:%02x:%02x:%02x"
334 	    " -> %02x:%02x:%02x:%02x:%02x:%02x",
335 	    p[6], p[7], p[8], p[9], p[10], p[11],
336 	    p[0], p[1], p[2], p[3], p[4], p[5]);
337 	bp = &msg[strlen(msg)];
338 
339 	/* vlag tag and etherrtype */
340 	ethertype = GET_ETHERTYPE(p);
341 	if (ethertype == VTAG_TPID) {
342 		sprintf(bp, " vtag:0x%04x", GET_NET16(&p[14]));
343 		bp = &msg[strlen(msg)];
344 
345 		offset += VTAG_SIZE;
346 		p = &buf[offset];
347 		ethertype = GET_ETHERTYPE(p);
348 	}
349 	sprintf(bp, " type:%04x", ethertype);
350 	bp = &msg[strlen(msg)];
351 
352 	/* ethernet packet length */
353 	sprintf(bp, " mblklen:%d", msgdsize(mp));
354 	bp = &msg[strlen(msg)];
355 	if (mp->b_cont) {
356 		sprintf(bp, "(");
357 		bp = &msg[strlen(msg)];
358 		for (tp = mp; tp; tp = tp->b_cont) {
359 			if (tp == mp) {
360 				sprintf(bp, "%d", tp->b_wptr - tp->b_rptr);
361 			} else {
362 				sprintf(bp, "+%d", tp->b_wptr - tp->b_rptr);
363 			}
364 			bp = &msg[strlen(msg)];
365 		}
366 		sprintf(bp, ")");
367 		bp = &msg[strlen(msg)];
368 	}
369 
370 	if (ethertype != ETHERTYPE_IP) {
371 		goto x;
372 	}
373 
374 	/* ip address */
375 	offset += sizeof (struct ether_header);
376 	p = &buf[offset];
377 	ipproto = p[9];
378 	iplen = GET_NET16(&p[2]);
379 	sprintf(bp, ", ip: %d.%d.%d.%d -> %d.%d.%d.%d proto:%d iplen:%d",
380 	    p[12], p[13], p[14], p[15],
381 	    p[16], p[17], p[18], p[19],
382 	    ipproto, iplen);
383 	bp = (void *)&msg[strlen(msg)];
384 
385 	iphlen = (p[0] & 0xf) * 4;
386 
387 	/* cksum for psuedo header */
388 	cksum = *(uint16_t *)&p[12];
389 	cksum += *(uint16_t *)&p[14];
390 	cksum += *(uint16_t *)&p[16];
391 	cksum += *(uint16_t *)&p[18];
392 	cksum += BE_16(ipproto);
393 
394 	/* tcp or udp protocol header */
395 	offset += iphlen;
396 	p = &buf[offset];
397 	if (ipproto == IPPROTO_TCP) {
398 		tcplen = iplen - iphlen;
399 		sprintf(bp, ", tcp: len:%d cksum:%x",
400 		    tcplen, GET_NET16(&p[16]));
401 		bp = (void *)&msg[strlen(msg)];
402 
403 		if (check_cksum) {
404 			cksum += BE_16(tcplen);
405 			cksum = (uint16_t)ip_cksum(mp, offset, cksum);
406 			sprintf(bp, " (%s)",
407 			    (cksum == 0 || cksum == 0xffff) ? "ok" : "ng");
408 			bp = (void *)&msg[strlen(msg)];
409 		}
410 	} else if (ipproto == IPPROTO_UDP) {
411 		udplen = GET_NET16(&p[4]);
412 		sprintf(bp, ", udp: len:%d cksum:%x",
413 		    udplen, GET_NET16(&p[6]));
414 		bp = (void *)&msg[strlen(msg)];
415 
416 		if (GET_NET16(&p[6]) && check_cksum) {
417 			cksum += *(uint16_t *)&p[4];
418 			cksum = (uint16_t)ip_cksum(mp, offset, cksum);
419 			sprintf(bp, " (%s)",
420 			    (cksum == 0 || cksum == 0xffff) ? "ok" : "ng");
421 			bp = (void *)&msg[strlen(msg)];
422 		}
423 	}
424 x:
425 	cmn_err(CE_CONT, "!%s: %s: %s", dp->name, title, msg);
426 }
427 #endif /* USBGEM_DEBUG_VLAN */
428 #endif /* USBGEM_DEBUG_LEVEL */
429 
430 #ifdef GEM_GCC_RUNTIME
431 /*
432  * gcc3 runtime routines
433  */
434 #pragma weak memcmp
435 int
436 memcmp(const void *s1, const void *s2, size_t n)
437 {
438 	int	i;
439 	int	ret;
440 
441 	ret = 0;
442 	for (i = 0; i < n; i++) {
443 		ret = (int)((uint8_t *)s1)[i] - (int)((uint8_t *)s2)[i];
444 		if (ret) {
445 			return (ret);
446 		}
447 	}
448 	return (0);
449 }
450 
451 #pragma weak memset
452 void *
453 memset(void *s, int c, size_t n)
454 {
455 	if ((c & 0xff) == 0) {
456 		bzero(s, n);
457 	} else {
458 		while (n--) {
459 			((uint8_t *)s)[n] = c;
460 		}
461 	}
462 	return (s);
463 }
464 
465 #pragma weak _memcpy = memcpy
466 #pragma weak memcpy
467 void *
468 memcpy(void *s1, const void *s2, size_t n)
469 {
470 	bcopy(s2, s1, n);
471 	return (s1);
472 }
473 #endif /* GEM_GCC_RUNTIME */
474 /* ============================================================== */
475 /*
476  * hardware operations
477  */
478 /* ============================================================== */
479 static int
480 usbgem_hal_reset_chip(struct usbgem_dev *dp)
481 {
482 	int	err;
483 
484 	sema_p(&dp->hal_op_lock);
485 	err = (*dp->ugc.usbgc_reset_chip)(dp);
486 	sema_v(&dp->hal_op_lock);
487 	return (err);
488 }
489 
490 static int
491 usbgem_hal_init_chip(struct usbgem_dev *dp)
492 {
493 	int	err;
494 
495 	sema_p(&dp->hal_op_lock);
496 	err = (*dp->ugc.usbgc_init_chip)(dp);
497 	sema_v(&dp->hal_op_lock);
498 	return (err);
499 }
500 
501 static int
502 usbgem_hal_attach_chip(struct usbgem_dev *dp)
503 {
504 	int	err;
505 
506 	sema_p(&dp->hal_op_lock);
507 	err = (*dp->ugc.usbgc_attach_chip)(dp);
508 	sema_v(&dp->hal_op_lock);
509 	return (err);
510 }
511 
512 static int
513 usbgem_hal_set_rx_filter(struct usbgem_dev *dp)
514 {
515 	int	err;
516 
517 	sema_p(&dp->hal_op_lock);
518 	err = (*dp->ugc.usbgc_set_rx_filter)(dp);
519 	sema_v(&dp->hal_op_lock);
520 	return (err);
521 }
522 
523 static int
524 usbgem_hal_set_media(struct usbgem_dev *dp)
525 {
526 	int	err;
527 
528 	sema_p(&dp->hal_op_lock);
529 	err = (*dp->ugc.usbgc_set_media)(dp);
530 	sema_v(&dp->hal_op_lock);
531 	return (err);
532 }
533 
534 static int
535 usbgem_hal_start_chip(struct usbgem_dev *dp)
536 {
537 	int	err;
538 
539 	sema_p(&dp->hal_op_lock);
540 	err = (*dp->ugc.usbgc_start_chip)(dp);
541 	sema_v(&dp->hal_op_lock);
542 	return (err);
543 }
544 
545 static int
546 usbgem_hal_stop_chip(struct usbgem_dev *dp)
547 {
548 	int	err;
549 
550 	sema_p(&dp->hal_op_lock);
551 	err = (*dp->ugc.usbgc_stop_chip)(dp);
552 	sema_v(&dp->hal_op_lock);
553 	return (err);
554 }
555 
556 static int
557 usbgem_hal_get_stats(struct usbgem_dev *dp)
558 {
559 	int	err;
560 
561 	sema_p(&dp->hal_op_lock);
562 	err = (*dp->ugc.usbgc_get_stats)(dp);
563 	sema_v(&dp->hal_op_lock);
564 	return (err);
565 }
566 
567 
568 /* ============================================================== */
569 /*
570  * USB pipe management
571  */
572 /* ============================================================== */
573 static boolean_t
574 usbgem_rx_start_unit(struct usbgem_dev *dp, usb_bulk_req_t *req)
575 {
576 	mblk_t	*mp;
577 	int	err;
578 	usb_flags_t	flags;
579 
580 	ASSERT(req);
581 
582 	mp = allocb(dp->rx_buf_len, BPRI_MED);
583 	if (mp == NULL) {
584 		cmn_err(CE_WARN, "!%s: %s: failed to allocate mblk",
585 		    dp->name, __func__);
586 		goto err;
587 	}
588 
589 	req->bulk_len = dp->rx_buf_len;
590 	req->bulk_data = mp;
591 	req->bulk_client_private = (usb_opaque_t)dp;
592 	req->bulk_timeout = 0;
593 	req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK;
594 	req->bulk_cb = usbgem_bulkin_cb;
595 	req->bulk_exc_cb = usbgem_bulkin_cb;
596 	req->bulk_completion_reason = 0;
597 	req->bulk_cb_flags = 0;
598 
599 	flags = 0;
600 	err = usb_pipe_bulk_xfer(dp->bulkin_pipe, req, flags);
601 
602 	if (err != USB_SUCCESS) {
603 		cmn_err(CE_WARN, "%s: failed to bulk_xfer for rx, err:%d",
604 		    dp->name, err);
605 
606 		/* free req and mp */
607 		usb_free_bulk_req(req);
608 		goto err;
609 	}
610 	return (B_TRUE);
611 err:
612 	return (B_FALSE);
613 }
614 
615 /* ============================================================== */
616 /*
617  * Rx/Tx buffer management
618  */
619 /* ============================================================== */
620 static int
621 usbgem_init_rx_buf(struct usbgem_dev *dp)
622 {
623 	int	i;
624 	usb_bulk_req_t	*req;
625 
626 	ASSERT(dp->mac_state == MAC_STATE_ONLINE);
627 
628 	for (i = 0; i < dp->ugc.usbgc_rx_list_max; i++) {
629 		req = usb_alloc_bulk_req(dp->dip, 0, USB_FLAGS_SLEEP);
630 		if (req == NULL) {
631 			cmn_err(CE_WARN,
632 			    "!%s: %s: failed to allocate bulkreq for rx",
633 			    dp->name, __func__);
634 			return (USB_FAILURE);
635 		}
636 		if (!usbgem_rx_start_unit(dp, req)) {
637 			return (USB_FAILURE);
638 		}
639 		mutex_enter(&dp->rxlock);
640 		dp->rx_busy_cnt++;
641 		mutex_exit(&dp->rxlock);
642 	}
643 	return (USB_SUCCESS);
644 }
645 
646 /* ============================================================== */
647 /*
648  * memory resource management
649  */
650 /* ============================================================== */
651 static int
652 usbgem_free_memory(struct usbgem_dev *dp)
653 {
654 	usb_bulk_req_t	*req;
655 
656 	/* free all tx requst structure */
657 	while ((req = dp->tx_free_list) != NULL) {
658 		dp->tx_free_list =
659 		    (usb_bulk_req_t *)req->bulk_client_private;
660 		req->bulk_data = NULL;
661 		usb_free_bulk_req(req);
662 	}
663 	return (USB_SUCCESS);
664 }
665 
666 static int
667 usbgem_alloc_memory(struct usbgem_dev *dp)
668 {
669 	int	i;
670 	usb_bulk_req_t	*req;
671 
672 	/* allocate tx requests */
673 	dp->tx_free_list = NULL;
674 	for (i = 0; i < dp->ugc.usbgc_tx_list_max; i++) {
675 		req = usb_alloc_bulk_req(dp->dip, 0, USB_FLAGS_SLEEP);
676 		if (req == NULL) {
677 			cmn_err(CE_WARN,
678 			    "%s:%s failed to allocate tx requests",
679 			    dp->name, __func__);
680 
681 			/* free partially allocated tx requests */
682 			(void) usbgem_free_memory(dp);
683 			return (USB_FAILURE);
684 		}
685 
686 		/* add the new one allocated into tx free list */
687 		req->bulk_client_private = (usb_opaque_t)dp->tx_free_list;
688 		dp->tx_free_list = req;
689 	}
690 
691 	return (USB_SUCCESS);
692 }
693 
694 /* ========================================================== */
695 /*
696  * Start transmission.
697  * Return zero on success,
698  */
699 /* ========================================================== */
700 
701 #ifdef TXTIMEOUT_TEST
702 static int usbgem_send_cnt = 0;
703 #endif
704 
705 /*
706  * usbgem_send is used only to send data packet into ethernet line.
707  */
708 static mblk_t *
709 usbgem_send_common(struct usbgem_dev *dp, mblk_t *mp, uint32_t flags)
710 {
711 	int		err;
712 	mblk_t		*new;
713 	usb_bulk_req_t	*req;
714 	int		mcast;
715 	int		bcast;
716 	int		len;
717 	boolean_t	intr;
718 	usb_flags_t	usb_flags = 0;
719 #ifdef USBGEM_DEBUG_LEVEL
720 	usb_pipe_state_t	p_state;
721 #endif
722 	DPRINTF(2, (CE_CONT, "!%s: %s: called", dp->name, __func__));
723 
724 	intr = (flags & 1) != 0;
725 	len = msgdsize(mp);
726 	bcast = 0;
727 	mcast = 0;
728 	if (mp->b_rptr[0] & 1) {
729 		if (bcmp(mp->b_rptr, &usbgem_bcastaddr, ETHERADDRL) == 0) {
730 			bcast = 1;
731 		} else {
732 			mcast = 1;
733 		}
734 	}
735 	new = (*dp->ugc.usbgc_tx_make_packet)(dp, mp);
736 	if (new == NULL) {
737 		/*
738 		 * no memory resource. we don't stop downstream,
739 		 * we just discard the packet.
740 		 */
741 		DPRINTF(0, (CE_CONT, "!%s: %s: no memory",
742 		    dp->name, __func__));
743 		freemsg(mp);
744 
745 		mutex_enter(&dp->txlock);
746 		dp->stats.noxmtbuf++;
747 		dp->stats.errxmt++;
748 		mutex_exit(&dp->txlock);
749 
750 		return (NULL);
751 	}
752 
753 	ASSERT(new->b_cont == NULL);
754 
755 	mutex_enter(&dp->txlock);
756 	if (dp->tx_free_list == NULL) {
757 		/*
758 		 * no tx free slot
759 		 */
760 		ASSERT(dp->tx_busy_cnt == dp->ugc.usbgc_tx_list_max);
761 		mutex_exit(&dp->txlock);
762 
763 		DPRINTF(4, (CE_CONT, "!%s: %s: no free slot",
764 		    dp->name, __func__));
765 		if (new && new != mp) {
766 			/* free reallocated message */
767 			freemsg(new);
768 		}
769 		return (mp);
770 	}
771 	req = dp->tx_free_list;
772 	dp->tx_free_list = (usb_bulk_req_t *)req->bulk_client_private;
773 	dp->tx_busy_cnt++;
774 
775 	if (dp->tx_free_list == NULL) {
776 		intr = B_TRUE;
777 	}
778 	if (intr) {
779 		dp->tx_intr_pended++;
780 	}
781 	DB_TCI(new) = intr;
782 #ifdef USBGEM_DEBUG_LEVEL
783 	new->b_datap->db_cksum32 = dp->tx_seq_num;
784 	dp->tx_seq_num++;
785 #endif
786 	dp->stats.obytes += len;
787 	dp->stats.opackets++;
788 	if (bcast | mcast) {
789 		dp->stats.obcast += bcast;
790 		dp->stats.omcast += mcast;
791 	}
792 	mutex_exit(&dp->txlock);
793 
794 	DPRINTF(2, (CE_CONT, "!%s: %s: sending", dp->name, __func__));
795 
796 	req->bulk_len = (long)new->b_wptr - (long)new->b_rptr;
797 	req->bulk_data = new;
798 	req->bulk_client_private = (usb_opaque_t)dp;
799 	req->bulk_timeout = dp->bulkout_timeout;	/* in second */
800 	req->bulk_attributes = 0;
801 	req->bulk_cb = usbgem_bulkout_cb;
802 	req->bulk_exc_cb = usbgem_bulkout_cb;
803 	req->bulk_completion_reason = 0;
804 	req->bulk_cb_flags = 0;
805 
806 	if (intr) {
807 		usb_flags = USB_FLAGS_SLEEP;
808 	}
809 	if ((err = usb_pipe_bulk_xfer(dp->bulkout_pipe, req, usb_flags))
810 	    != USB_SUCCESS) {
811 
812 		/* failed to transfer the packet, discard it. */
813 		freemsg(new);
814 		req->bulk_data = NULL;
815 
816 		/* recycle the request block */
817 		mutex_enter(&dp->txlock);
818 		dp->tx_busy_cnt--;
819 		req->bulk_client_private = (usb_opaque_t)dp->tx_free_list;
820 		dp->tx_free_list = req;
821 		mutex_exit(&dp->txlock);
822 
823 		cmn_err(CE_NOTE,
824 		    "%s: %s: usb_pipe_bulk_xfer: failed: err:%d",
825 		    dp->name, __func__, err);
826 
827 		/* we use another flag to indicate error state. */
828 		if (dp->fatal_error == (clock_t)0) {
829 			dp->fatal_error = usbgem_timestamp_nz();
830 		}
831 	} else {
832 		/* record the start time */
833 		dp->tx_start_time = ddi_get_lbolt();
834 	}
835 
836 	if (err == USB_SUCCESS && (usb_flags & USB_FLAGS_SLEEP)) {
837 		usbgem_bulkout_cb(dp->bulkout_pipe, req);
838 	}
839 
840 	if (new != mp) {
841 		freemsg(mp);
842 	}
843 	return (NULL);
844 }
845 
846 int
847 usbgem_restart_nic(struct usbgem_dev *dp)
848 {
849 	int	ret;
850 	int	flags = 0;
851 
852 	DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
853 
854 	ASSERT(dp->mac_state != MAC_STATE_DISCONNECTED);
855 
856 	/*
857 	 * ensure to stop the nic
858 	 */
859 	if (dp->mac_state == MAC_STATE_ONLINE) {
860 		(void) usbgem_mac_stop(dp, MAC_STATE_STOPPED, STOP_GRACEFUL);
861 	}
862 
863 	/* now the nic become quiescent, reset the chip */
864 	if (usbgem_hal_reset_chip(dp) != USB_SUCCESS) {
865 		cmn_err(CE_WARN, "%s: %s: failed to reset chip",
866 		    dp->name, __func__);
867 		goto err;
868 	}
869 
870 	/*
871 	 * restore the nic state step by step
872 	 */
873 	if (dp->nic_state < NIC_STATE_INITIALIZED) {
874 		goto done;
875 	}
876 
877 	if (usbgem_mac_init(dp) != USB_SUCCESS) {
878 		cmn_err(CE_WARN, "%s: %s: failed to initialize chip",
879 		    dp->name, __func__);
880 		goto err;
881 	}
882 
883 	/* setup mac address and enable rx filter */
884 	sema_p(&dp->rxfilter_lock);
885 	dp->rxmode |= RXMODE_ENABLE;
886 	ret = usbgem_hal_set_rx_filter(dp);
887 	sema_v(&dp->rxfilter_lock);
888 	if (ret != USB_SUCCESS) {
889 		goto err;
890 	}
891 
892 	/*
893 	 * update the link state asynchronously
894 	 */
895 	cv_signal(&dp->link_watcher_wait_cv);
896 
897 	/*
898 	 * XXX - a panic happened because of linkdown.
899 	 * We must check mii_state here, because the link can be down just
900 	 * before the restart event happen. If the link is down now,
901 	 * gem_mac_start() will be called from gem_mii_link_check() when
902 	 * the link become up later.
903 	 */
904 	if (dp->mii_state == MII_STATE_LINKUP) {
905 		if (usbgem_hal_set_media(dp) != USB_SUCCESS) {
906 			goto err;
907 		}
908 		if (dp->nic_state < NIC_STATE_ONLINE) {
909 			goto done;
910 		}
911 
912 		(void) usbgem_mac_start(dp);
913 
914 	}
915 done:
916 	return (USB_SUCCESS);
917 err:
918 #ifdef GEM_CONFIG_FMA
919 	ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
920 #endif
921 	return (USB_FAILURE);
922 }
923 
924 static void
925 usbgem_tx_timeout(struct usbgem_dev *dp)
926 {
927 	uint_t	rwlock;
928 	clock_t	now;
929 
930 	for (; ; ) {
931 		mutex_enter(&dp->tx_watcher_lock);
932 		(void) cv_timedwait(&dp->tx_watcher_cv, &dp->tx_watcher_lock,
933 		    dp->tx_watcher_interval + ddi_get_lbolt());
934 		mutex_exit(&dp->tx_watcher_lock);
935 
936 		if (dp->tx_watcher_stop) {
937 			break;
938 		}
939 
940 		now = ddi_get_lbolt();
941 
942 		rwlock = RW_READER;
943 again:
944 		rw_enter(&dp->dev_state_lock, rwlock);
945 
946 		if ((dp->mac_state != MAC_STATE_DISCONNECTED &&
947 		    dp->fatal_error &&
948 		    now - dp->fatal_error >= dp->ugc.usbgc_tx_timeout) ||
949 		    (dp->mac_state == MAC_STATE_ONLINE &&
950 		    dp->mii_state == MII_STATE_LINKUP &&
951 		    dp->tx_busy_cnt != 0 &&
952 		    now - dp->tx_start_time >= dp->ugc.usbgc_tx_timeout)) {
953 			if (rwlock == RW_READER) {
954 				/*
955 				 * Upgrade dev_state_lock from shared mode
956 				 * to exclusive mode to restart nic
957 				 */
958 				rwlock = RW_WRITER;
959 				rw_exit(&dp->dev_state_lock);
960 				goto again;
961 			}
962 			cmn_err(CE_WARN, "%s: %s: restarting the nic:"
963 			    " fatal_error:%ld nic_state:%d"
964 			    " mac_state:%d starttime:%ld",
965 			    dp->name, __func__,
966 			    dp->fatal_error ? now - dp->fatal_error: 0,
967 			    dp->nic_state, dp->mac_state,
968 			    dp->tx_busy_cnt ? now - dp->tx_start_time : 0);
969 
970 			(void) usbgem_restart_nic(dp);
971 		}
972 
973 		rw_exit(&dp->dev_state_lock);
974 	}
975 }
976 
977 static int
978 usbgem_tx_watcher_start(struct usbgem_dev *dp)
979 {
980 	int	err;
981 	kthread_t	*wdth;
982 
983 	DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
984 
985 	/* make a first call of uwgem_lw_link_check() */
986 	dp->tx_watcher_stop = 0;
987 	dp->tx_watcher_interval = drv_usectohz(1000*1000);
988 
989 	wdth = thread_create(NULL, 0, usbgem_tx_timeout, dp, 0, &p0,
990 	    TS_RUN, minclsyspri);
991 	if (wdth == NULL) {
992 		cmn_err(CE_WARN,
993 		    "!%s: %s: failed to create a tx_watcher thread",
994 		    dp->name, __func__);
995 		return (USB_FAILURE);
996 	}
997 	dp->tx_watcher_did = wdth->t_did;
998 
999 	return (USB_SUCCESS);
1000 }
1001 
1002 static void
1003 usbgem_tx_watcher_stop(struct usbgem_dev *dp)
1004 {
1005 	DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
1006 	if (dp->tx_watcher_did) {
1007 		/* Ensure timer routine stopped */
1008 		dp->tx_watcher_stop = 1;
1009 		cv_signal(&dp->tx_watcher_cv);
1010 		thread_join(dp->tx_watcher_did);
1011 		dp->tx_watcher_did = 0;
1012 	}
1013 }
1014 
1015 /* ================================================================== */
1016 /*
1017  * Callback handlers
1018  */
1019 /* ================================================================== */
1020 static void
1021 usbgem_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
1022 {
1023 	mblk_t	*newmp;
1024 	mblk_t	*mp;
1025 	mblk_t	*tp;
1026 	uint64_t	len = 0;
1027 	int	pkts = 0;
1028 	int	bcast = 0;
1029 	int	mcast = 0;
1030 	boolean_t	busy;
1031 	struct usbgem_dev	*dp;
1032 
1033 	dp = (struct usbgem_dev *)req->bulk_client_private;
1034 	mp = req->bulk_data;
1035 	req->bulk_data = NULL;
1036 
1037 	DPRINTF(2, (CE_CONT, "!%s: %s: mp:%p, cr:%s(%d)",
1038 	    dp->name, __func__, mp,
1039 	    usb_str_cr(req->bulk_completion_reason),
1040 	    req->bulk_completion_reason));
1041 
1042 	/*
1043 	 * we cannot acquire dev_state_lock because the routine
1044 	 * must be executed during usbgem_mac_stop() to avoid
1045 	 * dead lock.
1046 	 * we use a simle membar operation to get the state correctly.
1047 	 */
1048 	membar_consumer();
1049 
1050 	if (req->bulk_completion_reason == USB_CR_OK &&
1051 	    dp->nic_state == NIC_STATE_ONLINE) {
1052 		newmp = (*dp->ugc.usbgc_rx_make_packet)(dp, mp);
1053 
1054 		if (newmp != mp) {
1055 			/* the message has been reallocated, free old one */
1056 			freemsg(mp);
1057 		}
1058 
1059 		/* the message may includes one or more ethernet packets */
1060 		for (tp = newmp; tp; tp = tp->b_next) {
1061 			len += (uintptr_t)tp->b_wptr - (uintptr_t)tp->b_rptr;
1062 			pkts++;
1063 			if (tp->b_rptr[0] & 1) {
1064 				if (bcmp(tp->b_rptr, &usbgem_bcastaddr,
1065 				    ETHERADDRL) == 0) {
1066 					bcast++;
1067 				} else {
1068 					mcast++;
1069 				}
1070 			}
1071 		}
1072 
1073 		/* send up if it is a valid packet */
1074 #ifdef USBGEM_CONFIG_GLDv3
1075 		mac_rx(dp->mh, NULL, newmp);
1076 #else
1077 		while (newmp) {
1078 			tp = newmp;
1079 			newmp = newmp->b_next;
1080 			tp->b_next = NULL;
1081 			gld_recv(dp->macinfo, tp);
1082 		}
1083 #endif
1084 	} else {
1085 		freemsg(mp);
1086 		len = 0;
1087 	}
1088 
1089 	mutex_enter(&dp->rxlock);
1090 	/* update rx_active */
1091 	if (dp->rx_active) {
1092 		dp->rx_active = dp->mac_state == MAC_STATE_ONLINE;
1093 	}
1094 
1095 	dp->stats.rbytes += len;
1096 	dp->stats.rpackets += pkts;
1097 	if (bcast | mcast) {
1098 		dp->stats.rbcast += bcast;
1099 		dp->stats.rmcast += mcast;
1100 	}
1101 	mutex_exit(&dp->rxlock);
1102 
1103 	if (dp->rx_active) {
1104 		/* prepare to receive the next packets */
1105 		if (usbgem_rx_start_unit(dp, req)) {
1106 			/* we successed */
1107 			goto done;
1108 		}
1109 		cmn_err(CE_WARN,
1110 		    "!%s: %s: failed to fill next rx packet",
1111 		    dp->name, __func__);
1112 		/*
1113 		 * we use another flag to indicate error state.
1114 		 * if we acquire dev_state_lock for RW_WRITER here,
1115 		 * usbgem_mac_stop() may hang.
1116 		 */
1117 		if (dp->fatal_error == (clock_t)0) {
1118 			dp->fatal_error = usbgem_timestamp_nz();
1119 		}
1120 	} else {
1121 		/* no need to prepare the next packets */
1122 		usb_free_bulk_req(req);
1123 	}
1124 
1125 	mutex_enter(&dp->rxlock);
1126 	dp->rx_active = B_FALSE;
1127 	dp->rx_busy_cnt--;
1128 	if (dp->rx_busy_cnt == 0) {
1129 		/* wake up someone waits for me */
1130 		cv_broadcast(&dp->rx_drain_cv);
1131 	}
1132 	mutex_exit(&dp->rxlock);
1133 done:
1134 	;
1135 }
1136 
1137 static void
1138 usbgem_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
1139 {
1140 	boolean_t	intr;
1141 	boolean_t	tx_sched;
1142 	struct usbgem_dev	*dp;
1143 
1144 	dp = (struct usbgem_dev *)req->bulk_client_private;
1145 	tx_sched = B_FALSE;
1146 
1147 	DPRINTF(2, (CE_CONT,
1148 	    "!%s: %s: cr:%s(%d) cb_flags:0x%x head:%d tail:%d",
1149 	    dp->name, __func__,
1150 	    usb_str_cr(req->bulk_completion_reason),
1151 	    req->bulk_completion_reason,
1152 	    req->bulk_cb_flags,
1153 	    dp->tx_busy_cnt));
1154 
1155 	/* we have finished to transfer the packet into tx fifo */
1156 	intr = DB_TCI(req->bulk_data);
1157 	freemsg(req->bulk_data);
1158 
1159 	if (req->bulk_completion_reason != USB_CR_OK &&
1160 	    dp->fatal_error == (clock_t)0) {
1161 		dp->fatal_error = usbgem_timestamp_nz();
1162 	}
1163 
1164 	mutex_enter(&dp->txlock);
1165 
1166 	if (intr) {
1167 		ASSERT(dp->tx_intr_pended > 0);
1168 		/* find the last interrupt we have scheduled */
1169 		if (--(dp->tx_intr_pended) == 0) {
1170 			tx_sched = B_TRUE;
1171 		}
1172 	}
1173 
1174 	ASSERT(dp->tx_busy_cnt > 0);
1175 	req->bulk_client_private = (usb_opaque_t)dp->tx_free_list;
1176 	dp->tx_free_list = req;
1177 	dp->tx_busy_cnt--;
1178 
1179 #ifdef CONFIG_TX_LIMITER
1180 	if (tx_sched) {
1181 		dp->tx_max_packets =
1182 		    min(dp->tx_max_packets + 1, dp->ugc.usbgc_tx_list_max);
1183 	}
1184 #endif
1185 	if (dp->mac_state != MAC_STATE_ONLINE && dp->tx_busy_cnt == 0) {
1186 		cv_broadcast(&dp->tx_drain_cv);
1187 	}
1188 
1189 	mutex_exit(&dp->txlock);
1190 
1191 	if (tx_sched) {
1192 #ifdef USBGEM_CONFIG_GLDv3
1193 		mac_tx_update(dp->mh);
1194 #else
1195 		gld_sched(dp->macinfo);
1196 #endif
1197 	}
1198 }
1199 
1200 static void
1201 usbgem_intr_cb(usb_pipe_handle_t ph, usb_intr_req_t *req)
1202 {
1203 	struct usbgem_dev	*dp;
1204 
1205 	dp = (struct usbgem_dev *)req->intr_client_private;
1206 	dp->stats.intr++;
1207 
1208 	if (req->intr_completion_reason == USB_CR_OK) {
1209 		(*dp->ugc.usbgc_interrupt)(dp, req->intr_data);
1210 	}
1211 
1212 	/* free the request and data */
1213 	usb_free_intr_req(req);
1214 }
1215 
1216 /* ======================================================================== */
1217 /*
1218  * MII support routines
1219  */
1220 /* ======================================================================== */
1221 static void
1222 usbgem_choose_forcedmode(struct usbgem_dev *dp)
1223 {
1224 	/* choose media mode */
1225 	if (dp->anadv_1000fdx || dp->anadv_1000hdx) {
1226 		dp->speed = USBGEM_SPD_1000;
1227 		dp->full_duplex = dp->anadv_1000fdx;
1228 	} else if (dp->anadv_100fdx || dp->anadv_100t4) {
1229 		dp->speed = USBGEM_SPD_100;
1230 		dp->full_duplex = B_TRUE;
1231 	} else if (dp->anadv_100hdx) {
1232 		dp->speed = USBGEM_SPD_100;
1233 		dp->full_duplex = B_FALSE;
1234 	} else {
1235 		dp->speed = USBGEM_SPD_10;
1236 		dp->full_duplex = dp->anadv_10fdx;
1237 	}
1238 }
1239 
1240 static uint16_t
1241 usbgem_mii_read(struct usbgem_dev *dp, uint_t reg, int *errp)
1242 {
1243 	uint16_t	val;
1244 
1245 	sema_p(&dp->hal_op_lock);
1246 	val = (*dp->ugc.usbgc_mii_read)(dp, reg, errp);
1247 	sema_v(&dp->hal_op_lock);
1248 
1249 	return (val);
1250 }
1251 
1252 static void
1253 usbgem_mii_write(struct usbgem_dev *dp, uint_t reg, uint16_t val, int *errp)
1254 {
1255 	sema_p(&dp->hal_op_lock);
1256 	(*dp->ugc.usbgc_mii_write)(dp, reg, val, errp);
1257 	sema_v(&dp->hal_op_lock);
1258 }
1259 
1260 static int
1261 usbgem_mii_probe(struct usbgem_dev *dp)
1262 {
1263 	int	err;
1264 
1265 	err = (*dp->ugc.usbgc_mii_probe)(dp);
1266 	return (err);
1267 }
1268 
1269 static int
1270 usbgem_mii_init(struct usbgem_dev *dp)
1271 {
1272 	int	err;
1273 
1274 	err = (*dp->ugc.usbgc_mii_init)(dp);
1275 	return (err);
1276 }
1277 
1278 #define	fc_cap_decode(x)	\
1279 	((((x) & MII_ABILITY_PAUSE) != 0 ? 1 : 0) |	\
1280 	(((x) & MII_ABILITY_ASM_DIR) != 0 ? 2 : 0))
1281 
1282 int
1283 usbgem_mii_config_default(struct usbgem_dev *dp, int *errp)
1284 {
1285 	uint16_t	mii_stat;
1286 	uint16_t	val;
1287 
1288 	DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
1289 
1290 	/*
1291 	 * Configure bits in advertisement register
1292 	 */
1293 	mii_stat = dp->mii_status;
1294 
1295 	DPRINTF(1, (CE_CONT, "!%s: %s: MII_STATUS reg:%b",
1296 	    dp->name, __func__, mii_stat, MII_STATUS_BITS));
1297 
1298 	if ((mii_stat & MII_STATUS_ABILITY_TECH) == 0) {
1299 		/* it's funny */
1300 		cmn_err(CE_WARN, "!%s: wrong ability bits: mii_status:%b",
1301 		    dp->name, mii_stat, MII_STATUS_BITS);
1302 		return (USB_FAILURE);
1303 	}
1304 
1305 	/* Do not change the rest of ability bits in advert reg */
1306 	val = usbgem_mii_read(dp, MII_AN_ADVERT, errp) & ~MII_ABILITY_ALL;
1307 	if (*errp != USB_SUCCESS) {
1308 		goto usberr;
1309 	}
1310 
1311 	DPRINTF(0, (CE_CONT,
1312 	    "!%s: %s: 100T4:%d 100F:%d 100H:%d 10F:%d 10H:%d",
1313 	    dp->name, __func__,
1314 	    dp->anadv_100t4, dp->anadv_100fdx, dp->anadv_100hdx,
1315 	    dp->anadv_10fdx, dp->anadv_10hdx));
1316 
1317 	/* set technology bits */
1318 	if (dp->anadv_100t4) {
1319 		val |= MII_ABILITY_100BASE_T4;
1320 	}
1321 	if (dp->anadv_100fdx) {
1322 		val |= MII_ABILITY_100BASE_TX_FD;
1323 	}
1324 	if (dp->anadv_100hdx) {
1325 		val |= MII_ABILITY_100BASE_TX;
1326 	}
1327 	if (dp->anadv_10fdx) {
1328 		val |= MII_ABILITY_10BASE_T_FD;
1329 	}
1330 	if (dp->anadv_10hdx) {
1331 		val |= MII_ABILITY_10BASE_T;
1332 	}
1333 
1334 	/* set flow control capabilities */
1335 	if (dp->anadv_pause) {
1336 		val |= MII_ABILITY_PAUSE;
1337 	}
1338 	if (dp->anadv_asmpause) {
1339 		val |= MII_ABILITY_ASM_DIR;
1340 	}
1341 
1342 	DPRINTF(0, (CE_CONT,
1343 	    "!%s: %s: setting MII_AN_ADVERT reg:%b, pause:%d, asmpause:%d",
1344 	    dp->name, __func__, val, MII_ABILITY_BITS,
1345 	    dp->anadv_pause, dp->anadv_asmpause));
1346 
1347 	usbgem_mii_write(dp, MII_AN_ADVERT, val, errp);
1348 	if (*errp != USB_SUCCESS) {
1349 		goto usberr;
1350 	}
1351 
1352 	if (dp->mii_status & MII_STATUS_XSTATUS) {
1353 		/*
1354 		 * 1000Base-T GMII support
1355 		 */
1356 		if (!dp->anadv_autoneg) {
1357 			/* enable manual configuration */
1358 			val = MII_1000TC_CFG_EN;
1359 			if (dp->anadv_1000t_ms == 2) {
1360 				val |= MII_1000TC_CFG_VAL;
1361 			}
1362 		} else {
1363 			val = 0;
1364 			if (dp->anadv_1000fdx) {
1365 				val |= MII_1000TC_ADV_FULL;
1366 			}
1367 			if (dp->anadv_1000hdx) {
1368 				val |= MII_1000TC_ADV_HALF;
1369 			}
1370 			switch (dp->anadv_1000t_ms) {
1371 			case 1:
1372 				/* slave */
1373 				val |= MII_1000TC_CFG_EN;
1374 				break;
1375 
1376 			case 2:
1377 				/* master */
1378 				val |= MII_1000TC_CFG_EN | MII_1000TC_CFG_VAL;
1379 				break;
1380 
1381 			default:
1382 				/* auto: do nothing */
1383 				break;
1384 			}
1385 		}
1386 		DPRINTF(0, (CE_CONT,
1387 		    "!%s: %s: setting MII_1000TC reg:%b",
1388 		    dp->name, __func__, val, MII_1000TC_BITS));
1389 
1390 		usbgem_mii_write(dp, MII_1000TC, val, errp);
1391 		if (*errp != USB_SUCCESS) {
1392 			goto usberr;
1393 		}
1394 	}
1395 	return (USB_SUCCESS);
1396 
1397 usberr:
1398 	return (*errp);
1399 }
1400 
1401 static char *usbgem_fc_type[] = {
1402 	"without",
1403 	"with symmetric",
1404 	"with tx",
1405 	"with rx",
1406 };
1407 
1408 #ifdef USBGEM_CONFIG_GLDv3
1409 #define	USBGEM_LINKUP(dp)	mac_link_update((dp)->mh, LINK_STATE_UP)
1410 #define	USBGEM_LINKDOWN(dp)	mac_link_update((dp)->mh, LINK_STATE_DOWN)
1411 #else
1412 #define	USBGEM_LINKUP(dp)	\
1413 	if (gld_linkstate) {	\
1414 		gld_linkstate((dp)->macinfo, GLD_LINKSTATE_UP);	\
1415 	}
1416 #define	USBGEM_LINKDOWN(dp)	\
1417 	if (gld_linkstate) {	\
1418 		gld_linkstate((dp)->macinfo, GLD_LINKSTATE_DOWN);	\
1419 	}
1420 #endif
1421 
1422 static uint8_t usbgem_fc_result[4 /* my cap */][4 /* lp cap */] = {
1423 /*	 none	symm	tx	rx/symm */
1424 /* none */
1425 	{FLOW_CONTROL_NONE,
1426 		FLOW_CONTROL_NONE,
1427 			FLOW_CONTROL_NONE,
1428 				FLOW_CONTROL_NONE},
1429 /* sym */
1430 	{FLOW_CONTROL_NONE,
1431 		FLOW_CONTROL_SYMMETRIC,
1432 			FLOW_CONTROL_NONE,
1433 				FLOW_CONTROL_SYMMETRIC},
1434 /* tx */
1435 	{FLOW_CONTROL_NONE,
1436 		FLOW_CONTROL_NONE,
1437 			FLOW_CONTROL_NONE,
1438 				FLOW_CONTROL_TX_PAUSE},
1439 /* rx/symm */
1440 	{FLOW_CONTROL_NONE,
1441 		FLOW_CONTROL_SYMMETRIC,
1442 			FLOW_CONTROL_RX_PAUSE,
1443 				FLOW_CONTROL_SYMMETRIC},
1444 };
1445 
1446 static boolean_t
1447 usbgem_mii_link_check(struct usbgem_dev *dp, int *oldstatep, int *newstatep)
1448 {
1449 	boolean_t	tx_sched = B_FALSE;
1450 	uint16_t	status;
1451 	uint16_t	advert;
1452 	uint16_t	lpable;
1453 	uint16_t	exp;
1454 	uint16_t	ctl1000;
1455 	uint16_t	stat1000;
1456 	uint16_t	val;
1457 	clock_t		now;
1458 	clock_t		diff;
1459 	int		linkdown_action;
1460 	boolean_t	fix_phy = B_FALSE;
1461 	int		err;
1462 	uint_t		rwlock;
1463 
1464 	DPRINTF(4, (CE_CONT, "!%s: %s: time:%d state:%d",
1465 	    dp->name, __func__, ddi_get_lbolt(), dp->mii_state));
1466 
1467 	if (dp->mii_state != MII_STATE_LINKUP) {
1468 		rwlock = RW_WRITER;
1469 	} else {
1470 		rwlock = RW_READER;
1471 	}
1472 again:
1473 	rw_enter(&dp->dev_state_lock, rwlock);
1474 
1475 	/* save old mii state */
1476 	*oldstatep = dp->mii_state;
1477 
1478 	if (dp->mac_state == MAC_STATE_DISCONNECTED) {
1479 		/* stop periodic execution of the link watcher */
1480 		dp->mii_interval = 0;
1481 		tx_sched = B_FALSE;
1482 		goto next;
1483 	}
1484 
1485 	now = ddi_get_lbolt();
1486 	diff = now - dp->mii_last_check;
1487 	dp->mii_last_check = now;
1488 
1489 	/*
1490 	 * For NWAM, don't show linkdown state right
1491 	 * when the device is attached.
1492 	 */
1493 	if (dp->linkup_delay > 0) {
1494 		if (dp->linkup_delay > diff) {
1495 			dp->linkup_delay -= diff;
1496 		} else {
1497 			/* link up timeout */
1498 			dp->linkup_delay = -1;
1499 		}
1500 	}
1501 
1502 next_nowait:
1503 	switch (dp->mii_state) {
1504 	case MII_STATE_UNKNOWN:
1505 		goto reset_phy;
1506 
1507 	case MII_STATE_RESETTING:
1508 		dp->mii_timer -= diff;
1509 		if (dp->mii_timer > 0) {
1510 			/* don't read phy registers in resetting */
1511 			dp->mii_interval = WATCH_INTERVAL_FAST;
1512 			goto next;
1513 		}
1514 
1515 		val = usbgem_mii_read(dp, MII_CONTROL, &err);
1516 		if (err != USB_SUCCESS) {
1517 			goto usberr;
1518 		}
1519 		if (val & MII_CONTROL_RESET) {
1520 			cmn_err(CE_NOTE,
1521 			    "!%s: time:%ld resetting phy not complete."
1522 			    " mii_control:0x%b",
1523 			    dp->name, ddi_get_lbolt(),
1524 			    val, MII_CONTROL_BITS);
1525 		}
1526 
1527 		/* ensure neither isolated nor pwrdown nor auto-nego mode */
1528 		usbgem_mii_write(dp, MII_CONTROL, 0, &err);
1529 		if (err != USB_SUCCESS) {
1530 			goto usberr;
1531 		}
1532 #if USBGEM_DEBUG_LEVEL > 10
1533 		val = usbgem_mii_read(dp, MII_CONTROL, &err);
1534 		cmn_err(CE_CONT, "!%s: readback control %b",
1535 		    dp->name, val, MII_CONTROL_BITS);
1536 #endif
1537 		/* As resetting PHY has completed, configure PHY registers */
1538 		if ((*dp->ugc.usbgc_mii_config)(dp, &err) != USB_SUCCESS) {
1539 			/* we failed to configure PHY */
1540 			goto usberr;
1541 		}
1542 
1543 		/* prepare for forced mode */
1544 		usbgem_choose_forcedmode(dp);
1545 
1546 		dp->mii_lpable = 0;
1547 		dp->mii_advert = 0;
1548 		dp->mii_exp = 0;
1549 		dp->mii_ctl1000 = 0;
1550 		dp->mii_stat1000 = 0;
1551 
1552 		dp->flow_control = FLOW_CONTROL_NONE;
1553 
1554 		if (!dp->anadv_autoneg) {
1555 			/* skip auto-negotiation phase */
1556 			dp->mii_state = MII_STATE_MEDIA_SETUP;
1557 			dp->mii_timer = dp->ugc.usbgc_mii_linkdown_timeout;
1558 			goto next_nowait;
1559 		}
1560 
1561 		/* issue an auto-negotiation command */
1562 		goto autonego;
1563 
1564 	case MII_STATE_AUTONEGOTIATING:
1565 		/*
1566 		 * Autonegotiation in progress
1567 		 */
1568 		dp->mii_timer -= diff;
1569 		if (dp->mii_timer -
1570 		    (dp->ugc.usbgc_mii_an_timeout - dp->ugc.usbgc_mii_an_wait)
1571 		    > 0) {
1572 			/* wait for minimum time (2.3 - 2.5 sec) */
1573 			dp->mii_interval = WATCH_INTERVAL_FAST;
1574 			goto next;
1575 		}
1576 
1577 		/* read PHY status */
1578 		status = usbgem_mii_read(dp, MII_STATUS, &err);
1579 		if (err != USB_SUCCESS) {
1580 			goto usberr;
1581 		}
1582 		DPRINTF(4, (CE_CONT,
1583 		    "!%s: %s: called: mii_state:%d MII_STATUS reg:%b",
1584 		    dp->name, __func__, dp->mii_state,
1585 		    status, MII_STATUS_BITS));
1586 
1587 		if (status & MII_STATUS_REMFAULT) {
1588 			/*
1589 			 * The link parnert told me something wrong happend.
1590 			 * What do we do ?
1591 			 */
1592 			cmn_err(CE_CONT,
1593 			    "!%s: auto-negotiation failed: remote fault",
1594 			    dp->name);
1595 			goto autonego;
1596 		}
1597 
1598 		if ((status & MII_STATUS_ANDONE) == 0) {
1599 			if (dp->mii_timer <= 0) {
1600 				/*
1601 				 * Auto-negotiation has been timed out,
1602 				 * Reset PHY and try again.
1603 				 */
1604 				if (!dp->mii_supress_msg) {
1605 					cmn_err(CE_WARN,
1606 					    "!%s: auto-negotiation failed:"
1607 					    " timeout",
1608 					    dp->name);
1609 					dp->mii_supress_msg = B_TRUE;
1610 				}
1611 				goto autonego;
1612 			}
1613 			/*
1614 			 * Auto-negotiation is in progress. Wait for a while.
1615 			 */
1616 			dp->mii_interval = dp->ugc.usbgc_mii_an_watch_interval;
1617 			goto next;
1618 		}
1619 
1620 		/*
1621 		 * Auto-negotiation has been completed. Let's go to AN_DONE.
1622 		 */
1623 		dp->mii_state = MII_STATE_AN_DONE;
1624 		dp->mii_supress_msg = B_FALSE;
1625 		DPRINTF(0, (CE_CONT,
1626 		    "!%s: auto-negotiation completed, MII_STATUS:%b",
1627 		    dp->name, status, MII_STATUS_BITS));
1628 
1629 		if (dp->ugc.usbgc_mii_an_delay > 0) {
1630 			dp->mii_timer = dp->ugc.usbgc_mii_an_delay;
1631 			dp->mii_interval = drv_usectohz(20*1000);
1632 			goto next;
1633 		}
1634 
1635 		dp->mii_timer = 0;
1636 		diff = 0;
1637 		goto next_nowait;
1638 
1639 	case MII_STATE_AN_DONE:
1640 		/*
1641 		 * Auto-negotiation has done. Now we can set up media.
1642 		 */
1643 		dp->mii_timer -= diff;
1644 		if (dp->mii_timer > 0) {
1645 			/* wait for a while */
1646 			dp->mii_interval = WATCH_INTERVAL_FAST;
1647 			goto next;
1648 		}
1649 
1650 		/*
1651 		 * Setup speed and duplex mode according with
1652 		 * the result of auto negotiation.
1653 		 */
1654 
1655 		/*
1656 		 * Read registers required to determin current
1657 		 * duplex mode and media speed.
1658 		 */
1659 		if (dp->ugc.usbgc_mii_an_delay > 0) {
1660 			/* the 'status' variable is not initialized yet */
1661 			status = usbgem_mii_read(dp, MII_STATUS, &err);
1662 			if (err != USB_SUCCESS) {
1663 				goto usberr;
1664 			}
1665 		}
1666 		advert = usbgem_mii_read(dp, MII_AN_ADVERT, &err);
1667 		if (err != USB_SUCCESS) {
1668 			goto usberr;
1669 		}
1670 		lpable = usbgem_mii_read(dp, MII_AN_LPABLE, &err);
1671 		if (err != USB_SUCCESS) {
1672 			goto usberr;
1673 		}
1674 		exp = usbgem_mii_read(dp, MII_AN_EXPANSION, &err);
1675 		if (err != USB_SUCCESS) {
1676 			goto usberr;
1677 		}
1678 		if (exp == 0xffff) {
1679 			/* some phys don't have exp register */
1680 			exp = 0;
1681 		}
1682 
1683 		ctl1000 = 0;
1684 		stat1000 = 0;
1685 		if (dp->mii_status & MII_STATUS_XSTATUS) {
1686 			ctl1000 = usbgem_mii_read(dp, MII_1000TC, &err);
1687 			if (err != USB_SUCCESS) {
1688 				goto usberr;
1689 			}
1690 			stat1000 = usbgem_mii_read(dp, MII_1000TS, &err);
1691 			if (err != USB_SUCCESS) {
1692 				goto usberr;
1693 			}
1694 		}
1695 		dp->mii_lpable = lpable;
1696 		dp->mii_advert = advert;
1697 		dp->mii_exp = exp;
1698 		dp->mii_ctl1000 = ctl1000;
1699 		dp->mii_stat1000 = stat1000;
1700 
1701 		cmn_err(CE_CONT,
1702 		    "!%s: auto-negotiation done: "
1703 		    "status:%b, advert:%b, lpable:%b, exp:%b",
1704 		    dp->name,
1705 		    status, MII_STATUS_BITS,
1706 		    advert, MII_ABILITY_BITS,
1707 		    lpable, MII_ABILITY_BITS,
1708 		    exp, MII_AN_EXP_BITS);
1709 
1710 		DPRINTF(0, (CE_CONT, "!%s: MII_STATUS:%b",
1711 		    dp->name, status, MII_STATUS_BITS));
1712 
1713 		if (dp->mii_status & MII_STATUS_XSTATUS) {
1714 			cmn_err(CE_CONT,
1715 			    "! MII_1000TC reg:%b, MII_1000TS reg:%b",
1716 			    ctl1000, MII_1000TC_BITS,
1717 			    stat1000, MII_1000TS_BITS);
1718 		}
1719 
1720 		if (usbgem_population(lpable) <= 1 &&
1721 		    (exp & MII_AN_EXP_LPCANAN) == 0) {
1722 			if ((advert & MII_ABILITY_TECH) != lpable) {
1723 				cmn_err(CE_WARN,
1724 				    "!%s: but the link partner doesn't seem"
1725 				    " to have auto-negotiation capability."
1726 				    " please check the link configuration.",
1727 				    dp->name);
1728 			}
1729 			/*
1730 			 * it should be a result of pararell detection,
1731 			 * which cannot detect duplex mode.
1732 			 */
1733 			if ((advert & lpable) == 0 &&
1734 			    lpable & MII_ABILITY_10BASE_T) {
1735 				/* no common technology, try 10M half mode */
1736 				lpable |= advert & MII_ABILITY_10BASE_T;
1737 				fix_phy = B_TRUE;
1738 			}
1739 		} else if (lpable == 0) {
1740 			cmn_err(CE_WARN, "!%s: wrong lpable.", dp->name);
1741 			goto reset_phy;
1742 		}
1743 		/*
1744 		 * configure current link mode according to AN priority.
1745 		 */
1746 		val = advert & lpable;
1747 		if ((ctl1000 & MII_1000TC_ADV_FULL) &&
1748 		    (stat1000 & MII_1000TS_LP_FULL)) {
1749 			/* 1000BaseT & full duplex */
1750 			dp->speed = USBGEM_SPD_1000;
1751 			dp->full_duplex = B_TRUE;
1752 		} else if ((ctl1000 & MII_1000TC_ADV_HALF) &&
1753 		    (stat1000 & MII_1000TS_LP_HALF)) {
1754 			/* 1000BaseT & half duplex */
1755 			dp->speed = USBGEM_SPD_1000;
1756 			dp->full_duplex = B_FALSE;
1757 		} else if ((val & MII_ABILITY_100BASE_TX_FD)) {
1758 			/* 100BaseTx & fullduplex */
1759 			dp->speed = USBGEM_SPD_100;
1760 			dp->full_duplex = B_TRUE;
1761 		} else if ((val & MII_ABILITY_100BASE_T4)) {
1762 			/* 100BaseTx & fullduplex */
1763 			dp->speed = USBGEM_SPD_100;
1764 			dp->full_duplex = B_TRUE;
1765 		} else if ((val & MII_ABILITY_100BASE_TX)) {
1766 			/* 100BaseTx & half duplex */
1767 			dp->speed = USBGEM_SPD_100;
1768 			dp->full_duplex = B_FALSE;
1769 		} else if ((val & MII_ABILITY_10BASE_T_FD)) {
1770 			/* 10BaseT & full duplex */
1771 			dp->speed = USBGEM_SPD_10;
1772 			dp->full_duplex = B_TRUE;
1773 		} else if ((val & MII_ABILITY_10BASE_T)) {
1774 			/* 10BaseT & half duplex */
1775 			dp->speed = USBGEM_SPD_10;
1776 			dp->full_duplex = B_FALSE;
1777 		} else {
1778 			/*
1779 			 * the link partner doesn't seem to have
1780 			 * auto-negotiation capability and our PHY
1781 			 * could not report current mode correctly.
1782 			 * We guess current mode by mii_control register.
1783 			 */
1784 			val = usbgem_mii_read(dp, MII_CONTROL, &err);
1785 			if (err != USB_SUCCESS) {
1786 				goto usberr;
1787 			}
1788 
1789 			/* select 100m half or 10m half */
1790 			dp->speed = (val & MII_CONTROL_100MB) ?
1791 			    USBGEM_SPD_100 : USBGEM_SPD_10;
1792 			dp->full_duplex = B_FALSE;
1793 			fix_phy = B_TRUE;
1794 
1795 			cmn_err(CE_NOTE,
1796 			    "!%s: auto-negotiation done but "
1797 			    "common ability not found.\n"
1798 			    "PHY state: control:%b advert:%b lpable:%b\n"
1799 			    "guessing %d Mbps %s duplex mode",
1800 			    dp->name,
1801 			    val, MII_CONTROL_BITS,
1802 			    advert, MII_ABILITY_BITS,
1803 			    lpable, MII_ABILITY_BITS,
1804 			    usbgem_speed_value[dp->speed],
1805 			    dp->full_duplex ? "full" : "half");
1806 		}
1807 
1808 		if (dp->full_duplex) {
1809 			dp->flow_control =
1810 			    usbgem_fc_result[fc_cap_decode(advert)]
1811 			    [fc_cap_decode(lpable)];
1812 		} else {
1813 			dp->flow_control = FLOW_CONTROL_NONE;
1814 		}
1815 		dp->mii_state = MII_STATE_MEDIA_SETUP;
1816 		dp->mii_timer = dp->ugc.usbgc_mii_linkdown_timeout;
1817 		goto next_nowait;
1818 
1819 	case MII_STATE_MEDIA_SETUP:
1820 		DPRINTF(2, (CE_CONT, "!%s: setup midia mode", dp->name));
1821 
1822 		/* assume the link state is down */
1823 		dp->mii_state = MII_STATE_LINKDOWN;
1824 		dp->mii_supress_msg = B_FALSE;
1825 
1826 		/* use short interval */
1827 		dp->mii_interval = WATCH_INTERVAL_FAST;
1828 
1829 		if ((!dp->anadv_autoneg) ||
1830 		    dp->ugc.usbgc_mii_an_oneshot || fix_phy) {
1831 
1832 			/*
1833 			 * write the result of auto negotiation back.
1834 			 */
1835 			val = usbgem_mii_read(dp, MII_CONTROL, &err);
1836 			if (err != USB_SUCCESS) {
1837 				goto usberr;
1838 			}
1839 			val &= ~(MII_CONTROL_SPEED | MII_CONTROL_FDUPLEX |
1840 			    MII_CONTROL_ANE   | MII_CONTROL_RSAN);
1841 
1842 			if (dp->full_duplex) {
1843 				val |= MII_CONTROL_FDUPLEX;
1844 			}
1845 
1846 			switch (dp->speed) {
1847 			case USBGEM_SPD_1000:
1848 				val |= MII_CONTROL_1000MB;
1849 				break;
1850 
1851 			case USBGEM_SPD_100:
1852 				val |= MII_CONTROL_100MB;
1853 				break;
1854 
1855 			default:
1856 				cmn_err(CE_WARN, "%s: unknown speed:%d",
1857 				    dp->name, dp->speed);
1858 				/* FALLTHROUGH */
1859 
1860 			case USBGEM_SPD_10:
1861 				/* for USBGEM_SPD_10, do nothing */
1862 				break;
1863 			}
1864 
1865 			if (dp->mii_status & MII_STATUS_XSTATUS) {
1866 				usbgem_mii_write(dp,
1867 				    MII_1000TC, MII_1000TC_CFG_EN, &err);
1868 				if (err != USB_SUCCESS) {
1869 					goto usberr;
1870 				}
1871 			}
1872 			usbgem_mii_write(dp, MII_CONTROL, val, &err);
1873 			if (err != USB_SUCCESS) {
1874 				goto usberr;
1875 			}
1876 		}
1877 		/*
1878 		 * XXX -- nic state should be one of
1879 		 * NIC_STATE_DISCONNECTED
1880 		 * NIC_STATE_STOPPED
1881 		 * NIC_STATE_INITIALIZED
1882 		 * NIC_STATE_ONLINE
1883 		 */
1884 		if (dp->nic_state >= NIC_STATE_INITIALIZED) {
1885 			/* notify the result of autonegotiation to mac */
1886 			if (usbgem_hal_set_media(dp) != USB_SUCCESS) {
1887 				goto usberr;
1888 			}
1889 		}
1890 		goto next_nowait;
1891 
1892 	case MII_STATE_LINKDOWN:
1893 		status = usbgem_mii_read(dp, MII_STATUS, &err);
1894 		if (err != USB_SUCCESS) {
1895 			goto usberr;
1896 		}
1897 		if (status & MII_STATUS_LINKUP) {
1898 			/*
1899 			 * Link is going up
1900 			 */
1901 			dp->mii_state = MII_STATE_LINKUP;
1902 			dp->mii_supress_msg = B_FALSE;
1903 
1904 			DPRINTF(0, (CE_CONT,
1905 			    "!%s: link up detected: status:%b",
1906 			    dp->name, status, MII_STATUS_BITS));
1907 
1908 			/*
1909 			 * MII_CONTROL_100MB and  MII_CONTROL_FDUPLEX are
1910 			 * ignored when MII_CONTROL_ANE is set.
1911 			 */
1912 			cmn_err(CE_CONT,
1913 			    "!%s: Link up: %d Mbps %s duplex %s flow control",
1914 			    dp->name,
1915 			    usbgem_speed_value[dp->speed],
1916 			    dp->full_duplex ? "full" : "half",
1917 			    usbgem_fc_type[dp->flow_control]);
1918 
1919 			dp->mii_interval =
1920 			    dp->ugc.usbgc_mii_link_watch_interval;
1921 
1922 			if (dp->ugc.usbgc_mii_hw_link_detection &&
1923 			    dp->nic_state == NIC_STATE_ONLINE) {
1924 				dp->mii_interval = 0;
1925 			}
1926 
1927 			if (dp->nic_state == NIC_STATE_ONLINE) {
1928 				if (dp->mac_state == MAC_STATE_INITIALIZED) {
1929 					(void) usbgem_mac_start(dp);
1930 				}
1931 				tx_sched = B_TRUE;
1932 			}
1933 
1934 			goto next;
1935 		}
1936 
1937 		dp->mii_supress_msg = B_TRUE;
1938 		if (dp->anadv_autoneg) {
1939 			dp->mii_timer -= diff;
1940 			if (dp->mii_timer <= 0) {
1941 				/*
1942 				 * the link down timer expired.
1943 				 * need to restart auto-negotiation.
1944 				 */
1945 				linkdown_action =
1946 				    dp->ugc.usbgc_mii_linkdown_timeout_action;
1947 				goto restart_autonego;
1948 			}
1949 		}
1950 		/* don't change mii_state */
1951 		goto next;
1952 
1953 	case MII_STATE_LINKUP:
1954 		if (rwlock == RW_READER) {
1955 			/* first pass, read mii status */
1956 			status = usbgem_mii_read(dp, MII_STATUS, &err);
1957 			if (err != USB_SUCCESS) {
1958 				goto usberr;
1959 			}
1960 		}
1961 		if ((status & MII_STATUS_LINKUP) == 0) {
1962 			/*
1963 			 * Link is going down
1964 			 */
1965 			cmn_err(CE_NOTE,
1966 			    "!%s: link down detected: status:%b",
1967 			    dp->name, status, MII_STATUS_BITS);
1968 			/*
1969 			 * Acquire exclusive lock to change mii_state
1970 			 */
1971 			if (rwlock == RW_READER) {
1972 				rwlock = RW_WRITER;
1973 				rw_exit(&dp->dev_state_lock);
1974 				goto again;
1975 			}
1976 
1977 			dp->mii_state = MII_STATE_LINKDOWN;
1978 			dp->mii_timer = dp->ugc.usbgc_mii_linkdown_timeout;
1979 
1980 			/*
1981 			 * As we may change the state of the device,
1982 			 * let us acquire exclusive lock for the state.
1983 			 */
1984 			if (dp->nic_state == NIC_STATE_ONLINE &&
1985 			    dp->mac_state == MAC_STATE_ONLINE &&
1986 			    dp->ugc.usbgc_mii_stop_mac_on_linkdown) {
1987 				(void) usbgem_restart_nic(dp);
1988 				/* drain tx */
1989 				tx_sched = B_TRUE;
1990 			}
1991 
1992 			if (dp->anadv_autoneg) {
1993 				/* need to restart auto-negotiation */
1994 				linkdown_action =
1995 				    dp->ugc.usbgc_mii_linkdown_action;
1996 				goto restart_autonego;
1997 			}
1998 			/*
1999 			 * don't use hw link down detection until the link
2000 			 * status become stable for a while.
2001 			 */
2002 			dp->mii_interval =
2003 			    dp->ugc.usbgc_mii_link_watch_interval;
2004 
2005 			goto next;
2006 		}
2007 
2008 		/*
2009 		 * still link up, no need to change mii_state
2010 		 */
2011 		if (dp->ugc.usbgc_mii_hw_link_detection &&
2012 		    dp->nic_state == NIC_STATE_ONLINE) {
2013 			/*
2014 			 * no need to check link status periodicly
2015 			 * if nic can generate interrupts when link go down.
2016 			 */
2017 			dp->mii_interval = 0;
2018 		}
2019 		goto next;
2020 	}
2021 	/* NOTREACHED */
2022 	cmn_err(CE_PANIC, "!%s: %s: not reached", dp->name, __func__);
2023 
2024 	/*
2025 	 * Actions for new state.
2026 	 */
2027 restart_autonego:
2028 	switch (linkdown_action) {
2029 	case MII_ACTION_RESET:
2030 		if (!dp->mii_supress_msg) {
2031 			cmn_err(CE_CONT, "!%s: resetting PHY", dp->name);
2032 		}
2033 		dp->mii_supress_msg = B_TRUE;
2034 		goto reset_phy;
2035 
2036 	case MII_ACTION_NONE:
2037 		dp->mii_supress_msg = B_TRUE;
2038 		if (dp->ugc.usbgc_mii_an_oneshot) {
2039 			goto autonego;
2040 		}
2041 		/* PHY will restart autonego automatically */
2042 		dp->mii_state = MII_STATE_AUTONEGOTIATING;
2043 		dp->mii_timer = dp->ugc.usbgc_mii_an_timeout;
2044 		dp->mii_interval = dp->ugc.usbgc_mii_an_watch_interval;
2045 		goto next;
2046 
2047 	case MII_ACTION_RSA:
2048 		if (!dp->mii_supress_msg) {
2049 			cmn_err(CE_CONT, "!%s: restarting auto-negotiation",
2050 			    dp->name);
2051 		}
2052 		dp->mii_supress_msg = B_TRUE;
2053 		goto autonego;
2054 
2055 	default:
2056 		cmn_err(CE_PANIC, "!%s: unknowm linkdown action: %d",
2057 		    dp->name, dp->ugc.usbgc_mii_linkdown_action);
2058 	}
2059 	/* NOTREACHED */
2060 
2061 reset_phy:
2062 	if (!dp->mii_supress_msg) {
2063 		cmn_err(CE_CONT, "!%s: resetting PHY", dp->name);
2064 	}
2065 	dp->mii_state = MII_STATE_RESETTING;
2066 	dp->mii_timer = dp->ugc.usbgc_mii_reset_timeout;
2067 	if (!dp->ugc.usbgc_mii_dont_reset) {
2068 		usbgem_mii_write(dp, MII_CONTROL, MII_CONTROL_RESET, &err);
2069 		if (err != USB_SUCCESS) {
2070 			goto usberr;
2071 		}
2072 	}
2073 	dp->mii_interval = WATCH_INTERVAL_FAST;
2074 	goto next;
2075 
2076 autonego:
2077 	if (!dp->mii_supress_msg) {
2078 		cmn_err(CE_CONT, "!%s: auto-negotiation started", dp->name);
2079 	}
2080 	dp->mii_state = MII_STATE_AUTONEGOTIATING;
2081 	dp->mii_timer = dp->ugc.usbgc_mii_an_timeout;
2082 
2083 	/* start/restart autoneg */
2084 	val = usbgem_mii_read(dp, MII_CONTROL, &err) &
2085 	    ~(MII_CONTROL_ISOLATE | MII_CONTROL_PWRDN | MII_CONTROL_RESET);
2086 	if (err != USB_SUCCESS) {
2087 		goto usberr;
2088 	}
2089 	if (val & MII_CONTROL_ANE) {
2090 		val |= MII_CONTROL_RSAN;
2091 	}
2092 	usbgem_mii_write(dp, MII_CONTROL,
2093 	    val | dp->ugc.usbgc_mii_an_cmd | MII_CONTROL_ANE, &err);
2094 	if (err != USB_SUCCESS) {
2095 		goto usberr;
2096 	}
2097 
2098 	dp->mii_interval = dp->ugc.usbgc_mii_an_watch_interval;
2099 	goto next;
2100 
2101 usberr:
2102 	dp->mii_state = MII_STATE_UNKNOWN;
2103 	dp->mii_interval = dp->ugc.usbgc_mii_link_watch_interval;
2104 	tx_sched = B_TRUE;
2105 
2106 next:
2107 	*newstatep = dp->mii_state;
2108 	rw_exit(&dp->dev_state_lock);
2109 	return (tx_sched);
2110 }
2111 
2112 static void
2113 usbgem_mii_link_watcher(struct usbgem_dev *dp)
2114 {
2115 	int		old_mii_state;
2116 	int		new_mii_state;
2117 	boolean_t	tx_sched;
2118 
2119 	DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2120 
2121 	for (; ; ) {
2122 
2123 		mutex_enter(&dp->link_watcher_lock);
2124 		if (dp->mii_interval) {
2125 			(void) cv_timedwait(&dp->link_watcher_wait_cv,
2126 			    &dp->link_watcher_lock,
2127 			    dp->mii_interval + ddi_get_lbolt());
2128 		} else {
2129 			cv_wait(&dp->link_watcher_wait_cv,
2130 			    &dp->link_watcher_lock);
2131 		}
2132 		mutex_exit(&dp->link_watcher_lock);
2133 
2134 		if (dp->link_watcher_stop) {
2135 			break;
2136 		}
2137 
2138 		/* we block callbacks from disconnect/suspend and restart */
2139 		tx_sched = usbgem_mii_link_check(dp,
2140 		    &old_mii_state, &new_mii_state);
2141 
2142 		/*
2143 		 * gld v2 notifier functions are not able to
2144 		 * be called with any locks in this layer.
2145 		 */
2146 		if (tx_sched) {
2147 			/* kick potentially stopped downstream */
2148 #ifdef USBGEM_CONFIG_GLDv3
2149 			mac_tx_update(dp->mh);
2150 #else
2151 			gld_sched(dp->macinfo);
2152 #endif
2153 		}
2154 
2155 		if (old_mii_state != new_mii_state) {
2156 			/* notify new mii link state */
2157 			if (new_mii_state == MII_STATE_LINKUP) {
2158 				dp->linkup_delay = 0;
2159 				USBGEM_LINKUP(dp);
2160 			} else if (dp->linkup_delay <= 0) {
2161 				USBGEM_LINKDOWN(dp);
2162 			}
2163 		} else if (dp->linkup_delay < 0) {
2164 			/* first linkup timeout */
2165 			dp->linkup_delay = 0;
2166 			USBGEM_LINKDOWN(dp);
2167 		}
2168 	}
2169 
2170 	thread_exit();
2171 }
2172 
2173 void
2174 usbgem_mii_update_link(struct usbgem_dev *dp)
2175 {
2176 	cv_signal(&dp->link_watcher_wait_cv);
2177 }
2178 
2179 int
2180 usbgem_mii_probe_default(struct usbgem_dev *dp)
2181 {
2182 	int		phy;
2183 	uint16_t	status;
2184 	uint16_t	xstatus;
2185 	int		err;
2186 	uint16_t	adv;
2187 	uint16_t	adv_org;
2188 
2189 	DPRINTF(3, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2190 
2191 	/*
2192 	 * Scan PHY
2193 	 */
2194 	dp->mii_status = 0;
2195 
2196 	/* Try default phy first */
2197 	if (dp->mii_phy_addr) {
2198 		status = usbgem_mii_read(dp, MII_STATUS, &err);
2199 		if (err != USB_SUCCESS) {
2200 			goto usberr;
2201 		}
2202 		if (status != 0xffff && status != 0x0000) {
2203 			goto PHY_found;
2204 		}
2205 
2206 		if (dp->mii_phy_addr < 0) {
2207 			cmn_err(CE_NOTE,
2208 		    "!%s: failed to probe default internal and/or non-MII PHY",
2209 			    dp->name);
2210 			return (USB_FAILURE);
2211 		}
2212 
2213 		cmn_err(CE_NOTE,
2214 		    "!%s: failed to probe default MII PHY at %d",
2215 		    dp->name, dp->mii_phy_addr);
2216 	}
2217 
2218 	/* Try all possible address */
2219 	for (phy = dp->ugc.usbgc_mii_addr_min; phy < 32; phy++) {
2220 		dp->mii_phy_addr = phy;
2221 		status = usbgem_mii_read(dp, MII_STATUS, &err);
2222 		if (err != USB_SUCCESS) {
2223 			DPRINTF(0, (CE_CONT,
2224 			    "!%s: %s: mii_read(status) failed",
2225 			    dp->name, __func__));
2226 			goto usberr;
2227 		}
2228 
2229 		if (status != 0xffff && status != 0x0000) {
2230 			usbgem_mii_write(dp, MII_CONTROL, 0, &err);
2231 			if (err != USB_SUCCESS) {
2232 				DPRINTF(0, (CE_CONT,
2233 				    "!%s: %s: mii_write(control) failed",
2234 				    dp->name, __func__));
2235 				goto usberr;
2236 			}
2237 			goto PHY_found;
2238 		}
2239 	}
2240 	for (phy = dp->ugc.usbgc_mii_addr_min; phy < 32; phy++) {
2241 		dp->mii_phy_addr = phy;
2242 		usbgem_mii_write(dp, MII_CONTROL, 0, &err);
2243 		if (err != USB_SUCCESS) {
2244 			DPRINTF(0, (CE_CONT,
2245 			    "!%s: %s: mii_write(control) failed",
2246 			    dp->name, __func__));
2247 			goto usberr;
2248 		}
2249 		status = usbgem_mii_read(dp, MII_STATUS, &err);
2250 		if (err != USB_SUCCESS) {
2251 			DPRINTF(0, (CE_CONT,
2252 			    "!%s: %s: mii_read(status) failed",
2253 			    dp->name, __func__));
2254 			goto usberr;
2255 		}
2256 
2257 		if (status != 0xffff && status != 0) {
2258 			goto PHY_found;
2259 		}
2260 	}
2261 
2262 	cmn_err(CE_NOTE, "!%s: no MII PHY found", dp->name);
2263 	return (USB_FAILURE);
2264 
2265 PHY_found:
2266 	dp->mii_status = status;
2267 	dp->mii_status_ro = ~status;
2268 	dp->mii_phy_id = usbgem_mii_read(dp, MII_PHYIDH, &err) << 16;
2269 	if (err != USB_SUCCESS) {
2270 		DPRINTF(0, (CE_CONT,
2271 		    "!%s: %s: mii_read(PHYIDH) failed",
2272 		    dp->name, __func__));
2273 		goto usberr;
2274 	}
2275 	dp->mii_phy_id |= usbgem_mii_read(dp, MII_PHYIDL, &err);
2276 	if (err != USB_SUCCESS) {
2277 		DPRINTF(0, (CE_CONT,
2278 		    "!%s: %s: mii_read(PHYIDL) failed",
2279 		    dp->name, __func__));
2280 		goto usberr;
2281 	}
2282 
2283 	if (dp->mii_phy_addr < 0) {
2284 		cmn_err(CE_CONT, "!%s: using internal/non-MII PHY(0x%08x)",
2285 		    dp->name, dp->mii_phy_id);
2286 	} else {
2287 		cmn_err(CE_CONT, "!%s: MII PHY (0x%08x) found at %d",
2288 		    dp->name, dp->mii_phy_id, dp->mii_phy_addr);
2289 	}
2290 
2291 	cmn_err(CE_CONT,
2292 	    "!%s: PHY control:%b, status:%b, advert:%b, lpar:%b, exp:%b",
2293 	    dp->name,
2294 	    usbgem_mii_read(dp, MII_CONTROL, &err), MII_CONTROL_BITS,
2295 	    status, MII_STATUS_BITS,
2296 	    usbgem_mii_read(dp, MII_AN_ADVERT, &err), MII_ABILITY_BITS,
2297 	    usbgem_mii_read(dp, MII_AN_LPABLE, &err), MII_ABILITY_BITS,
2298 	    usbgem_mii_read(dp, MII_AN_EXPANSION, &err), MII_AN_EXP_BITS);
2299 
2300 	dp->mii_xstatus = 0;
2301 	if (status & MII_STATUS_XSTATUS) {
2302 		dp->mii_xstatus = usbgem_mii_read(dp, MII_XSTATUS, &err);
2303 
2304 		cmn_err(CE_CONT, "!%s: xstatus:%b",
2305 		    dp->name, dp->mii_xstatus, MII_XSTATUS_BITS);
2306 	}
2307 	dp->mii_xstatus_ro = ~dp->mii_xstatus;
2308 
2309 	/* check if the phy can advertize pause abilities */
2310 	adv_org = usbgem_mii_read(dp, MII_AN_ADVERT, &err);
2311 	if (err != USB_SUCCESS) {
2312 		goto usberr;
2313 	}
2314 
2315 	usbgem_mii_write(dp, MII_AN_ADVERT,
2316 	    MII_ABILITY_PAUSE | MII_ABILITY_ASM_DIR, &err);
2317 	if (err != USB_SUCCESS) {
2318 		goto usberr;
2319 	}
2320 
2321 	adv = usbgem_mii_read(dp, MII_AN_ADVERT, &err);
2322 	if (err != USB_SUCCESS) {
2323 		goto usberr;
2324 	}
2325 
2326 	if ((adv & MII_ABILITY_PAUSE) == 0) {
2327 		dp->ugc.usbgc_flow_control &= ~1;
2328 	}
2329 
2330 	if ((adv & MII_ABILITY_ASM_DIR) == 0) {
2331 		dp->ugc.usbgc_flow_control &= ~2;
2332 	}
2333 
2334 	usbgem_mii_write(dp, MII_AN_ADVERT, adv_org, &err);
2335 	if (err != USB_SUCCESS) {
2336 		goto usberr;
2337 	}
2338 	return (USB_SUCCESS);
2339 
2340 usberr:
2341 	return (USB_FAILURE);
2342 }
2343 
2344 int
2345 usbgem_mii_init_default(struct usbgem_dev *dp)
2346 {
2347 	/* ENPTY */
2348 	return (USB_SUCCESS);
2349 }
2350 
2351 static int
2352 usbgem_mii_start(struct usbgem_dev *dp)
2353 {
2354 	int	err;
2355 	kthread_t	*lwth;
2356 
2357 	DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2358 
2359 	/* make a first call of usbgem_mii_link_check() */
2360 	dp->link_watcher_stop = 0;
2361 	dp->mii_state = MII_STATE_UNKNOWN;
2362 	dp->mii_interval = drv_usectohz(1000*1000); /* 1sec */
2363 	dp->mii_last_check = ddi_get_lbolt();
2364 	dp->linkup_delay = 600 * drv_usectohz(1000*1000); /* 10 minutes */
2365 
2366 	lwth = thread_create(NULL, 0, usbgem_mii_link_watcher, dp, 0, &p0,
2367 	    TS_RUN, minclsyspri);
2368 	if (lwth == NULL) {
2369 		cmn_err(CE_WARN,
2370 		    "!%s: %s: failed to create a link watcher thread",
2371 		    dp->name, __func__);
2372 		return (USB_FAILURE);
2373 	}
2374 	dp->link_watcher_did = lwth->t_did;
2375 
2376 	return (USB_SUCCESS);
2377 }
2378 
2379 static void
2380 usbgem_mii_stop(struct usbgem_dev *dp)
2381 {
2382 	DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2383 
2384 	/* Ensure timer routine stopped */
2385 	dp->link_watcher_stop = 1;
2386 	cv_signal(&dp->link_watcher_wait_cv);
2387 	thread_join(dp->link_watcher_did);
2388 }
2389 
2390 /* ============================================================== */
2391 /*
2392  * internal mac register operation interface
2393  */
2394 /* ============================================================== */
2395 /*
2396  * usbgem_mac_init: cold start
2397  */
2398 static int
2399 usbgem_mac_init(struct usbgem_dev *dp)
2400 {
2401 	int	err;
2402 
2403 	DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2404 
2405 	if (dp->mac_state == MAC_STATE_DISCONNECTED) {
2406 		/* pretend we succeeded */
2407 		return (USB_SUCCESS);
2408 	}
2409 
2410 	ASSERT(dp->mac_state == MAC_STATE_STOPPED);
2411 
2412 	/* reset fatal error timestamp */
2413 	dp->fatal_error = (clock_t)0;
2414 
2415 	/* reset tx side state */
2416 	mutex_enter(&dp->txlock);
2417 	dp->tx_busy_cnt = 0;
2418 	dp->tx_max_packets = dp->ugc.usbgc_tx_list_max;
2419 	mutex_exit(&dp->txlock);
2420 
2421 	/* reset rx side state */
2422 	mutex_enter(&dp->rxlock);
2423 	dp->rx_busy_cnt = 0;
2424 	mutex_exit(&dp->rxlock);
2425 
2426 	err = usbgem_hal_init_chip(dp);
2427 	if (err == USB_SUCCESS) {
2428 		dp->mac_state = MAC_STATE_INITIALIZED;
2429 	}
2430 
2431 	return (err);
2432 }
2433 
2434 /*
2435  * usbgem_mac_start: warm start
2436  */
2437 static int
2438 usbgem_mac_start(struct usbgem_dev *dp)
2439 {
2440 	int	err;
2441 	int	i;
2442 	usb_flags_t	flags = 0;
2443 	usb_intr_req_t	*req;
2444 #ifdef USBGEM_DEBUG_LEVEL
2445 	usb_pipe_state_t	p_state;
2446 #endif
2447 	DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2448 
2449 	if (dp->mac_state == MAC_STATE_DISCONNECTED) {
2450 		/* do nothing but don't return failure */
2451 		return (USB_SUCCESS);
2452 	}
2453 
2454 	if (dp->mac_state != MAC_STATE_INITIALIZED) {
2455 		/* don't return failer */
2456 		DPRINTF(0, (CE_CONT,
2457 		    "!%s: %s: mac_state(%d) is not MAC_STATE_INITIALIZED",
2458 		    dp->name, __func__, dp->mac_state));
2459 		goto x;
2460 	}
2461 
2462 	dp->mac_state = MAC_STATE_ONLINE;
2463 
2464 	if (usbgem_hal_start_chip(dp) != USB_SUCCESS) {
2465 		cmn_err(CE_NOTE,
2466 		    "!%s: %s: usb error was detected during start_chip",
2467 		    dp->name, __func__);
2468 		goto x;
2469 	}
2470 
2471 #ifdef USBGEM_DEBUG_LEVEL
2472 	usb_pipe_get_state(dp->intr_pipe, &p_state, 0);
2473 	ASSERT(p_state == USB_PIPE_STATE_IDLE);
2474 #endif /* USBGEM_DEBUG_LEVEL */
2475 
2476 	if (dp->ugc.usbgc_interrupt && dp->intr_pipe) {
2477 
2478 		/* make a request for interrupt */
2479 
2480 		req = usb_alloc_intr_req(dp->dip, 0, USB_FLAGS_SLEEP);
2481 		if (req == NULL) {
2482 			cmn_err(CE_WARN, "!%s: %s: failed to allocate intreq",
2483 			    dp->name, __func__);
2484 			goto x;
2485 		}
2486 		req->intr_data = NULL;
2487 		req->intr_client_private = (usb_opaque_t)dp;
2488 		req->intr_timeout = 0;
2489 		req->intr_attributes =
2490 		    USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING;
2491 		req->intr_len = dp->ep_intr->wMaxPacketSize;
2492 		req->intr_cb = usbgem_intr_cb;
2493 		req->intr_exc_cb = usbgem_intr_cb;
2494 		req->intr_completion_reason = 0;
2495 		req->intr_cb_flags = 0;
2496 
2497 		err = usb_pipe_intr_xfer(dp->intr_pipe, req, flags);
2498 		if (err != USB_SUCCESS) {
2499 			cmn_err(CE_WARN,
2500 			    "%s: err:%d failed to start polling of intr pipe",
2501 			    dp->name, err);
2502 			goto x;
2503 		}
2504 	}
2505 
2506 	/* kick to receive the first packet */
2507 	if (usbgem_init_rx_buf(dp) != USB_SUCCESS) {
2508 		goto err_stop_intr;
2509 	}
2510 	dp->rx_active = B_TRUE;
2511 
2512 	return (USB_SUCCESS);
2513 
2514 err_stop_intr:
2515 	/* stop the interrupt pipe */
2516 	DPRINTF(0, (CE_CONT, "!%s: %s: FAULURE", dp->name, __func__));
2517 	if (dp->ugc.usbgc_interrupt && dp->intr_pipe) {
2518 		usb_pipe_stop_intr_polling(dp->intr_pipe, USB_FLAGS_SLEEP);
2519 	}
2520 x:
2521 	ASSERT(dp->mac_state == MAC_STATE_ONLINE);
2522 	/* we use another flag to indicate error state. */
2523 	if (dp->fatal_error == (clock_t)0) {
2524 		dp->fatal_error = usbgem_timestamp_nz();
2525 	}
2526 	return (USB_FAILURE);
2527 }
2528 
2529 static int
2530 usbgem_mac_stop(struct usbgem_dev *dp, int new_state, boolean_t graceful)
2531 {
2532 	DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2533 
2534 	/*
2535 	 * we must have writer lock for dev_state_lock
2536 	 */
2537 	ASSERT(new_state == MAC_STATE_STOPPED ||
2538 	    new_state == MAC_STATE_DISCONNECTED);
2539 
2540 	/* stop polling interrupt pipe */
2541 	if (dp->ugc.usbgc_interrupt && dp->intr_pipe) {
2542 		usb_pipe_stop_intr_polling(dp->intr_pipe, USB_FLAGS_SLEEP);
2543 	}
2544 
2545 	if (new_state == MAC_STATE_STOPPED || graceful) {
2546 		/* stop the nic hardware completely */
2547 		if (usbgem_hal_stop_chip(dp) != USB_SUCCESS) {
2548 			(void) usbgem_hal_reset_chip(dp);
2549 		}
2550 	}
2551 
2552 	/* stop preparing new rx packets and sending new packets */
2553 	dp->mac_state = new_state;
2554 
2555 	/* other processors must get mac_state correctly after here */
2556 	membar_producer();
2557 
2558 	/* cancel all requests we have sent */
2559 	usb_pipe_reset(dp->dip, dp->bulkin_pipe, USB_FLAGS_SLEEP, NULL, 0);
2560 	usb_pipe_reset(dp->dip, dp->bulkout_pipe, USB_FLAGS_SLEEP, NULL, 0);
2561 
2562 	DPRINTF(0, (CE_CONT,
2563 	    "!%s: %s: rx_busy_cnt:%d tx_busy_cnt:%d",
2564 	    dp->name, __func__, dp->rx_busy_cnt, dp->tx_busy_cnt));
2565 
2566 	/*
2567 	 * Here all rx packets has been cancelled and their call back
2568 	 * function has been exeuted, because we called usb_pipe_reset
2569 	 * synchronously.
2570 	 * So actually we just ensure rx_busy_cnt == 0.
2571 	 */
2572 	mutex_enter(&dp->rxlock);
2573 	while (dp->rx_busy_cnt > 0) {
2574 		cv_wait(&dp->rx_drain_cv, &dp->rxlock);
2575 	}
2576 	mutex_exit(&dp->rxlock);
2577 
2578 	DPRINTF(0, (CE_CONT, "!%s: %s: rx_busy_cnt is %d now",
2579 	    dp->name, __func__, dp->rx_busy_cnt));
2580 
2581 	mutex_enter(&dp->txlock);
2582 	while (dp->tx_busy_cnt > 0) {
2583 		cv_wait(&dp->tx_drain_cv, &dp->txlock);
2584 	}
2585 	mutex_exit(&dp->txlock);
2586 
2587 	DPRINTF(0, (CE_CONT, "!%s: %s: tx_busy_cnt is %d now",
2588 	    dp->name, __func__, dp->tx_busy_cnt));
2589 
2590 	return (USB_SUCCESS);
2591 }
2592 
2593 static int
2594 usbgem_add_multicast(struct usbgem_dev *dp, const uint8_t *ep)
2595 {
2596 	int	cnt;
2597 	int	err;
2598 
2599 	DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2600 
2601 	sema_p(&dp->rxfilter_lock);
2602 	if (dp->mc_count_req++ < USBGEM_MAXMC) {
2603 		/* append the new address at the end of the mclist */
2604 		cnt = dp->mc_count;
2605 		bcopy(ep, dp->mc_list[cnt].addr.ether_addr_octet,
2606 		    ETHERADDRL);
2607 		if (dp->ugc.usbgc_multicast_hash) {
2608 			dp->mc_list[cnt].hash =
2609 			    (*dp->ugc.usbgc_multicast_hash)(dp, ep);
2610 		}
2611 		dp->mc_count = cnt + 1;
2612 	}
2613 
2614 	if (dp->mc_count_req != dp->mc_count) {
2615 		/* multicast address list overflow */
2616 		dp->rxmode |= RXMODE_MULTI_OVF;
2617 	} else {
2618 		dp->rxmode &= ~RXMODE_MULTI_OVF;
2619 	}
2620 
2621 	if (dp->mac_state != MAC_STATE_DISCONNECTED) {
2622 		/* tell new multicast list to the hardware */
2623 		err = usbgem_hal_set_rx_filter(dp);
2624 	}
2625 	sema_v(&dp->rxfilter_lock);
2626 
2627 	return (err);
2628 }
2629 
2630 static int
2631 usbgem_remove_multicast(struct usbgem_dev *dp, const uint8_t *ep)
2632 {
2633 	size_t		len;
2634 	int		i;
2635 	int		cnt;
2636 	int		err;
2637 
2638 	DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2639 
2640 	sema_p(&dp->rxfilter_lock);
2641 	dp->mc_count_req--;
2642 	cnt = dp->mc_count;
2643 	for (i = 0; i < cnt; i++) {
2644 		if (bcmp(ep, &dp->mc_list[i].addr, ETHERADDRL)) {
2645 			continue;
2646 		}
2647 		/* shrink the mclist by copying forward */
2648 		len = (cnt - (i + 1)) * sizeof (*dp->mc_list);
2649 		if (len > 0) {
2650 			bcopy(&dp->mc_list[i+1], &dp->mc_list[i], len);
2651 		}
2652 		dp->mc_count--;
2653 		break;
2654 	}
2655 
2656 	if (dp->mc_count_req != dp->mc_count) {
2657 		/* multicast address list overflow */
2658 		dp->rxmode |= RXMODE_MULTI_OVF;
2659 	} else {
2660 		dp->rxmode &= ~RXMODE_MULTI_OVF;
2661 	}
2662 
2663 	if (dp->mac_state != MAC_STATE_DISCONNECTED) {
2664 		err = usbgem_hal_set_rx_filter(dp);
2665 	}
2666 	sema_v(&dp->rxfilter_lock);
2667 
2668 	return (err);
2669 }
2670 
2671 
2672 /* ============================================================== */
2673 /*
2674  * ioctl
2675  */
2676 /* ============================================================== */
2677 enum ioc_reply {
2678 	IOC_INVAL = -1,				/* bad, NAK with EINVAL	*/
2679 	IOC_DONE,				/* OK, reply sent	*/
2680 	IOC_ACK,				/* OK, just send ACK	*/
2681 	IOC_REPLY,				/* OK, just send reply	*/
2682 	IOC_RESTART_ACK,			/* OK, restart & ACK	*/
2683 	IOC_RESTART_REPLY			/* OK, restart & reply	*/
2684 };
2685 
2686 
2687 #ifdef USBGEM_CONFIG_MAC_PROP
2688 static int
2689 usbgem_get_def_val(struct usbgem_dev *dp, mac_prop_id_t pr_num,
2690     uint_t pr_valsize, void *pr_val)
2691 {
2692 	link_flowctrl_t fl;
2693 	int err = 0;
2694 
2695 	ASSERT(pr_valsize > 0);
2696 	switch (pr_num) {
2697 	case MAC_PROP_AUTONEG:
2698 		*(uint8_t *)pr_val =
2699 		    BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG);
2700 		break;
2701 
2702 	case MAC_PROP_FLOWCTRL:
2703 		if (pr_valsize < sizeof (link_flowctrl_t)) {
2704 			return (EINVAL);
2705 		}
2706 		switch (dp->ugc.usbgc_flow_control) {
2707 		case FLOW_CONTROL_NONE:
2708 			fl = LINK_FLOWCTRL_NONE;
2709 			break;
2710 		case FLOW_CONTROL_SYMMETRIC:
2711 			fl = LINK_FLOWCTRL_BI;
2712 			break;
2713 		case FLOW_CONTROL_TX_PAUSE:
2714 			fl = LINK_FLOWCTRL_TX;
2715 			break;
2716 		case FLOW_CONTROL_RX_PAUSE:
2717 			fl = LINK_FLOWCTRL_RX;
2718 			break;
2719 		}
2720 		bcopy(&fl, pr_val, sizeof (fl));
2721 		break;
2722 
2723 	case MAC_PROP_ADV_1000FDX_CAP:
2724 	case MAC_PROP_EN_1000FDX_CAP:
2725 		*(uint8_t *)pr_val =
2726 		    (dp->mii_xstatus & MII_XSTATUS_1000BASET_FD) ||
2727 		    (dp->mii_xstatus & MII_XSTATUS_1000BASEX_FD);
2728 		break;
2729 
2730 	case MAC_PROP_ADV_1000HDX_CAP:
2731 	case MAC_PROP_EN_1000HDX_CAP:
2732 		*(uint8_t *)pr_val =
2733 		    (dp->mii_xstatus & MII_XSTATUS_1000BASET) ||
2734 		    (dp->mii_xstatus & MII_XSTATUS_1000BASEX);
2735 		break;
2736 
2737 	case MAC_PROP_ADV_100T4_CAP:
2738 	case MAC_PROP_EN_100T4_CAP:
2739 		*(uint8_t *)pr_val =
2740 		    BOOLEAN(dp->mii_status & MII_STATUS_100_BASE_T4);
2741 		break;
2742 
2743 	case MAC_PROP_ADV_100FDX_CAP:
2744 	case MAC_PROP_EN_100FDX_CAP:
2745 		*(uint8_t *)pr_val =
2746 		    BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD);
2747 		break;
2748 
2749 	case MAC_PROP_ADV_100HDX_CAP:
2750 	case MAC_PROP_EN_100HDX_CAP:
2751 		*(uint8_t *)pr_val =
2752 		    BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX);
2753 		break;
2754 
2755 	case MAC_PROP_ADV_10FDX_CAP:
2756 	case MAC_PROP_EN_10FDX_CAP:
2757 		*(uint8_t *)pr_val =
2758 		    BOOLEAN(dp->mii_status & MII_STATUS_10_FD);
2759 		break;
2760 
2761 	case MAC_PROP_ADV_10HDX_CAP:
2762 	case MAC_PROP_EN_10HDX_CAP:
2763 		*(uint8_t *)pr_val =
2764 		    BOOLEAN(dp->mii_status & MII_STATUS_10);
2765 		break;
2766 
2767 	default:
2768 		err = ENOTSUP;
2769 		break;
2770 	}
2771 	return (err);
2772 }
2773 
2774 #ifdef MAC_VERSION_V1
2775 static void
2776 usbgem_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num,
2777     mac_prop_info_handle_t prh)
2778 {
2779 	struct usbgem_dev *dp = arg;
2780 	link_flowctrl_t fl;
2781 
2782 	/*
2783 	 * By default permissions are read/write unless specified
2784 	 * otherwise by the driver.
2785 	 */
2786 
2787 	switch (pr_num) {
2788 	case MAC_PROP_DUPLEX:
2789 	case MAC_PROP_SPEED:
2790 	case MAC_PROP_STATUS:
2791 	case MAC_PROP_ADV_1000FDX_CAP:
2792 	case MAC_PROP_ADV_1000HDX_CAP:
2793 	case MAC_PROP_ADV_100FDX_CAP:
2794 	case MAC_PROP_ADV_100HDX_CAP:
2795 	case MAC_PROP_ADV_10FDX_CAP:
2796 	case MAC_PROP_ADV_10HDX_CAP:
2797 	case MAC_PROP_ADV_100T4_CAP:
2798 	case MAC_PROP_EN_100T4_CAP:
2799 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2800 		break;
2801 
2802 	case MAC_PROP_EN_1000FDX_CAP:
2803 		if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET_FD) == 0) {
2804 			mac_prop_info_set_default_uint8(prh,
2805 			    BOOLEAN(
2806 			    dp->mii_xstatus & MII_XSTATUS_1000BASET_FD));
2807 		} else if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX_FD)
2808 		    == 0) {
2809 			mac_prop_info_set_default_uint8(prh,
2810 			    BOOLEAN(
2811 			    dp->mii_xstatus & MII_XSTATUS_1000BASEX_FD));
2812 		} else {
2813 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2814 		}
2815 		break;
2816 
2817 	case MAC_PROP_EN_1000HDX_CAP:
2818 		if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET) == 0) {
2819 			mac_prop_info_set_default_uint8(prh,
2820 			    BOOLEAN(
2821 			    dp->mii_xstatus & MII_XSTATUS_1000BASET));
2822 		} else if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX) == 0) {
2823 			mac_prop_info_set_default_uint8(prh,
2824 			    BOOLEAN(
2825 			    dp->mii_xstatus & MII_XSTATUS_1000BASEX));
2826 		} else {
2827 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2828 		}
2829 		break;
2830 
2831 	case MAC_PROP_EN_100FDX_CAP:
2832 		if ((dp->mii_status_ro & MII_STATUS_100_BASEX_FD) == 0) {
2833 			mac_prop_info_set_default_uint8(prh,
2834 			    BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD));
2835 		} else {
2836 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2837 		}
2838 		break;
2839 
2840 	case MAC_PROP_EN_100HDX_CAP:
2841 		if ((dp->mii_status_ro & MII_STATUS_100_BASEX) == 0) {
2842 			mac_prop_info_set_default_uint8(prh,
2843 			    BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX));
2844 		} else {
2845 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2846 		}
2847 		break;
2848 
2849 	case MAC_PROP_EN_10FDX_CAP:
2850 		if ((dp->mii_status_ro & MII_STATUS_10_FD) == 0) {
2851 			mac_prop_info_set_default_uint8(prh,
2852 			    BOOLEAN(dp->mii_status & MII_STATUS_10_FD));
2853 		} else {
2854 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2855 		}
2856 		break;
2857 
2858 	case MAC_PROP_EN_10HDX_CAP:
2859 		if ((dp->mii_status_ro & MII_STATUS_10) == 0) {
2860 			mac_prop_info_set_default_uint8(prh,
2861 			    BOOLEAN(dp->mii_status & MII_STATUS_10));
2862 		} else {
2863 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2864 		}
2865 		break;
2866 
2867 	case MAC_PROP_AUTONEG:
2868 		if ((dp->mii_status_ro & MII_STATUS_CANAUTONEG) == 0) {
2869 			mac_prop_info_set_default_uint8(prh,
2870 			    BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG));
2871 		} else {
2872 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2873 		}
2874 		break;
2875 
2876 	case MAC_PROP_FLOWCTRL:
2877 		switch (dp->ugc.usbgc_flow_control) {
2878 		case FLOW_CONTROL_NONE:
2879 			fl = LINK_FLOWCTRL_NONE;
2880 			break;
2881 		case FLOW_CONTROL_SYMMETRIC:
2882 			fl = LINK_FLOWCTRL_BI;
2883 			break;
2884 		case FLOW_CONTROL_TX_PAUSE:
2885 			fl = LINK_FLOWCTRL_TX;
2886 			break;
2887 		case FLOW_CONTROL_RX_PAUSE:
2888 			fl = LINK_FLOWCTRL_RX;
2889 			break;
2890 		}
2891 		mac_prop_info_set_default_link_flowctrl(prh, fl);
2892 		break;
2893 
2894 	case MAC_PROP_MTU:
2895 		mac_prop_info_set_range_uint32(prh,
2896 		    dp->ugc.usbgc_min_mtu, dp->ugc.usbgc_max_mtu);
2897 		break;
2898 
2899 	case MAC_PROP_PRIVATE:
2900 		break;
2901 	}
2902 }
2903 #endif
2904 
2905 static int
2906 usbgem_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
2907     uint_t pr_valsize, const void *pr_val)
2908 {
2909 	struct usbgem_dev *dp = arg;
2910 	int err = 0;
2911 	boolean_t	update = B_FALSE;
2912 	link_flowctrl_t flowctrl;
2913 	uint32_t cur_mtu, new_mtu;
2914 
2915 	rw_enter(&dp->dev_state_lock, RW_WRITER);
2916 	switch (pr_num) {
2917 	case MAC_PROP_EN_1000FDX_CAP:
2918 		if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET_FD) == 0 ||
2919 		    (dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX_FD) == 0) {
2920 			if (dp->anadv_1000fdx != *(uint8_t *)pr_val) {
2921 				dp->anadv_1000fdx = *(uint8_t *)pr_val;
2922 				update = B_TRUE;
2923 			}
2924 		} else {
2925 			err = ENOTSUP;
2926 		}
2927 		break;
2928 
2929 	case MAC_PROP_EN_1000HDX_CAP:
2930 		if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET) == 0 ||
2931 		    (dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX) == 0) {
2932 			if (dp->anadv_1000hdx != *(uint8_t *)pr_val) {
2933 				dp->anadv_1000hdx = *(uint8_t *)pr_val;
2934 				update = B_TRUE;
2935 			}
2936 		} else {
2937 			err = ENOTSUP;
2938 		}
2939 		break;
2940 
2941 	case MAC_PROP_EN_100FDX_CAP:
2942 		if ((dp->mii_status_ro & MII_STATUS_100_BASEX_FD) == 0) {
2943 			if (dp->anadv_100fdx != *(uint8_t *)pr_val) {
2944 				dp->anadv_100fdx = *(uint8_t *)pr_val;
2945 				update = B_TRUE;
2946 			}
2947 		} else {
2948 			err = ENOTSUP;
2949 		}
2950 		break;
2951 
2952 	case MAC_PROP_EN_100HDX_CAP:
2953 		if ((dp->mii_status_ro & MII_STATUS_100_BASEX) == 0) {
2954 			if (dp->anadv_100hdx != *(uint8_t *)pr_val) {
2955 				dp->anadv_100hdx = *(uint8_t *)pr_val;
2956 				update = B_TRUE;
2957 			}
2958 		} else {
2959 			err = ENOTSUP;
2960 		}
2961 		break;
2962 
2963 	case MAC_PROP_EN_10FDX_CAP:
2964 		if ((dp->mii_status_ro & MII_STATUS_10_FD) == 0) {
2965 			if (dp->anadv_10fdx != *(uint8_t *)pr_val) {
2966 				dp->anadv_10fdx = *(uint8_t *)pr_val;
2967 				update = B_TRUE;
2968 			}
2969 		} else {
2970 			err = ENOTSUP;
2971 		}
2972 		break;
2973 
2974 	case MAC_PROP_EN_10HDX_CAP:
2975 		if ((dp->mii_status_ro & MII_STATUS_10_FD) == 0) {
2976 			if (dp->anadv_10hdx != *(uint8_t *)pr_val) {
2977 				dp->anadv_10hdx = *(uint8_t *)pr_val;
2978 				update = B_TRUE;
2979 			}
2980 		} else {
2981 			err = ENOTSUP;
2982 		}
2983 		break;
2984 
2985 	case MAC_PROP_AUTONEG:
2986 		if ((dp->mii_status_ro & MII_STATUS_CANAUTONEG) == 0) {
2987 			if (dp->anadv_autoneg != *(uint8_t *)pr_val) {
2988 				dp->anadv_autoneg = *(uint8_t *)pr_val;
2989 				update = B_TRUE;
2990 			}
2991 		} else {
2992 			err = ENOTSUP;
2993 		}
2994 		break;
2995 
2996 	case MAC_PROP_FLOWCTRL:
2997 		bcopy(pr_val, &flowctrl, sizeof (flowctrl));
2998 
2999 		switch (flowctrl) {
3000 		default:
3001 			err = EINVAL;
3002 			break;
3003 
3004 		case LINK_FLOWCTRL_NONE:
3005 			if (dp->flow_control != FLOW_CONTROL_NONE) {
3006 				dp->flow_control = FLOW_CONTROL_NONE;
3007 				update = B_TRUE;
3008 			}
3009 			break;
3010 
3011 		case LINK_FLOWCTRL_RX:
3012 			if (dp->flow_control != FLOW_CONTROL_RX_PAUSE) {
3013 				dp->flow_control = FLOW_CONTROL_RX_PAUSE;
3014 				update = B_TRUE;
3015 			}
3016 			break;
3017 
3018 		case LINK_FLOWCTRL_TX:
3019 			if (dp->flow_control != FLOW_CONTROL_TX_PAUSE) {
3020 				dp->flow_control = FLOW_CONTROL_TX_PAUSE;
3021 				update = B_TRUE;
3022 			}
3023 			break;
3024 
3025 		case LINK_FLOWCTRL_BI:
3026 			if (dp->flow_control != FLOW_CONTROL_SYMMETRIC) {
3027 				dp->flow_control = FLOW_CONTROL_SYMMETRIC;
3028 				update = B_TRUE;
3029 			}
3030 			break;
3031 		}
3032 		break;
3033 
3034 	case MAC_PROP_ADV_1000FDX_CAP:
3035 	case MAC_PROP_ADV_1000HDX_CAP:
3036 	case MAC_PROP_ADV_100FDX_CAP:
3037 	case MAC_PROP_ADV_100HDX_CAP:
3038 	case MAC_PROP_ADV_10FDX_CAP:
3039 	case MAC_PROP_ADV_10HDX_CAP:
3040 	case MAC_PROP_STATUS:
3041 	case MAC_PROP_SPEED:
3042 	case MAC_PROP_DUPLEX:
3043 		err = ENOTSUP; /* read-only prop. Can't set this. */
3044 		break;
3045 
3046 	case MAC_PROP_MTU:
3047 		bcopy(pr_val, &new_mtu, sizeof (new_mtu));
3048 		if (new_mtu != dp->mtu) {
3049 			err = EINVAL;
3050 		}
3051 		break;
3052 
3053 	case MAC_PROP_PRIVATE:
3054 		err = ENOTSUP;
3055 		break;
3056 
3057 	default:
3058 		err = ENOTSUP;
3059 		break;
3060 	}
3061 
3062 	if (update) {
3063 		/* sync with PHY */
3064 		usbgem_choose_forcedmode(dp);
3065 		dp->mii_state = MII_STATE_UNKNOWN;
3066 		cv_signal(&dp->link_watcher_wait_cv);
3067 	}
3068 	rw_exit(&dp->dev_state_lock);
3069 	return (err);
3070 }
3071 
3072 static int
3073 #ifdef MAC_VERSION_V1
3074 usbgem_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
3075     uint_t pr_valsize, void *pr_val)
3076 #else
3077 usbgem_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
3078     uint_t pr_flags, uint_t pr_valsize, void *pr_val, uint_t *perm)
3079 #endif
3080 {
3081 	struct usbgem_dev *dp = arg;
3082 	int err = 0;
3083 	link_flowctrl_t flowctrl;
3084 	uint64_t tmp = 0;
3085 
3086 	if (pr_valsize == 0) {
3087 		return (EINVAL);
3088 	}
3089 #ifndef MAC_VERSION_V1
3090 	*perm = MAC_PROP_PERM_RW;
3091 #endif
3092 	bzero(pr_val, pr_valsize);
3093 #ifndef MAC_VERSION_V1
3094 	if ((pr_flags & MAC_PROP_DEFAULT) && (pr_num != MAC_PROP_PRIVATE)) {
3095 		return (usbgem_get_def_val(dp, pr_num, pr_valsize, pr_val));
3096 	}
3097 #endif
3098 	rw_enter(&dp->dev_state_lock, RW_READER);
3099 	switch (pr_num) {
3100 	case MAC_PROP_DUPLEX:
3101 #ifndef MAC_VERSION_V1
3102 		*perm = MAC_PROP_PERM_READ;
3103 #endif
3104 		if (pr_valsize >= sizeof (link_duplex_t)) {
3105 			if (dp->mii_state != MII_STATE_LINKUP) {
3106 				*(link_duplex_t *)pr_val = LINK_DUPLEX_UNKNOWN;
3107 			} else if (dp->full_duplex) {
3108 				*(link_duplex_t *)pr_val = LINK_DUPLEX_FULL;
3109 			} else {
3110 				*(link_duplex_t *)pr_val = LINK_DUPLEX_HALF;
3111 			}
3112 		} else {
3113 			err = EINVAL;
3114 		}
3115 		break;
3116 	case MAC_PROP_SPEED:
3117 #ifndef MAC_VERSION_V1
3118 		*perm = MAC_PROP_PERM_READ;
3119 #endif
3120 		if (pr_valsize >= sizeof (uint64_t)) {
3121 			switch (dp->speed) {
3122 			case USBGEM_SPD_1000:
3123 				tmp = 1000000000;
3124 				break;
3125 			case USBGEM_SPD_100:
3126 				tmp = 100000000;
3127 				break;
3128 			case USBGEM_SPD_10:
3129 				tmp = 10000000;
3130 				break;
3131 			default:
3132 				tmp = 0;
3133 			}
3134 			bcopy(&tmp, pr_val, sizeof (tmp));
3135 		} else {
3136 			err = EINVAL;
3137 		}
3138 		break;
3139 
3140 	case MAC_PROP_AUTONEG:
3141 #ifndef MAC_VERSION_V1
3142 		if (dp->mii_status_ro & MII_STATUS_CANAUTONEG) {
3143 			*perm = MAC_PROP_PERM_READ;
3144 		}
3145 #endif
3146 		*(uint8_t *)pr_val = dp->anadv_autoneg;
3147 		break;
3148 
3149 	case MAC_PROP_FLOWCTRL:
3150 		if (pr_valsize >= sizeof (link_flowctrl_t)) {
3151 			switch (dp->flow_control) {
3152 			case FLOW_CONTROL_NONE:
3153 				flowctrl = LINK_FLOWCTRL_NONE;
3154 				break;
3155 			case FLOW_CONTROL_RX_PAUSE:
3156 				flowctrl = LINK_FLOWCTRL_RX;
3157 				break;
3158 			case FLOW_CONTROL_TX_PAUSE:
3159 				flowctrl = LINK_FLOWCTRL_TX;
3160 				break;
3161 			case FLOW_CONTROL_SYMMETRIC:
3162 				flowctrl = LINK_FLOWCTRL_BI;
3163 				break;
3164 			}
3165 			bcopy(&flowctrl, pr_val, sizeof (flowctrl));
3166 		} else {
3167 			err = EINVAL;
3168 		}
3169 		break;
3170 
3171 	case MAC_PROP_ADV_1000FDX_CAP:
3172 	case MAC_PROP_ADV_1000HDX_CAP:
3173 	case MAC_PROP_ADV_100FDX_CAP:
3174 	case MAC_PROP_ADV_100HDX_CAP:
3175 	case MAC_PROP_ADV_10FDX_CAP:
3176 	case MAC_PROP_ADV_10HDX_CAP:
3177 	case MAC_PROP_ADV_100T4_CAP:
3178 		usbgem_get_def_val(dp, pr_num, pr_valsize, pr_val);
3179 		break;
3180 
3181 	case MAC_PROP_EN_1000FDX_CAP:
3182 #ifndef MAC_VERSION_V1
3183 		if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET_FD) &&
3184 		    (dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX_FD)) {
3185 			*perm = MAC_PROP_PERM_READ;
3186 		}
3187 #endif
3188 		*(uint8_t *)pr_val = dp->anadv_1000fdx;
3189 		break;
3190 
3191 	case MAC_PROP_EN_1000HDX_CAP:
3192 #ifndef MAC_VERSION_V1
3193 		if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET) &&
3194 		    (dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX)) {
3195 			*perm = MAC_PROP_PERM_READ;
3196 		}
3197 #endif
3198 		*(uint8_t *)pr_val = dp->anadv_1000hdx;
3199 		break;
3200 
3201 	case MAC_PROP_EN_100FDX_CAP:
3202 #ifndef MAC_VERSION_V1
3203 		if (dp->mii_status_ro & MII_STATUS_100_BASEX_FD) {
3204 			*perm = MAC_PROP_PERM_READ;
3205 		}
3206 #endif
3207 		*(uint8_t *)pr_val = dp->anadv_100fdx;
3208 		break;
3209 
3210 	case MAC_PROP_EN_100HDX_CAP:
3211 #ifndef MAC_VERSION_V1
3212 		if (dp->mii_status_ro & MII_STATUS_100_BASEX) {
3213 			*perm = MAC_PROP_PERM_READ;
3214 		}
3215 #endif
3216 		*(uint8_t *)pr_val = dp->anadv_100hdx;
3217 		break;
3218 
3219 	case MAC_PROP_EN_10FDX_CAP:
3220 #ifndef MAC_VERSION_V1
3221 		if (dp->mii_status_ro & MII_STATUS_10_FD) {
3222 			*perm = MAC_PROP_PERM_READ;
3223 		}
3224 #endif
3225 		*(uint8_t *)pr_val = dp->anadv_10fdx;
3226 		break;
3227 
3228 	case MAC_PROP_EN_10HDX_CAP:
3229 #ifndef MAC_VERSION_V1
3230 		if (dp->mii_status_ro & MII_STATUS_10) {
3231 			*perm = MAC_PROP_PERM_READ;
3232 		}
3233 #endif
3234 		*(uint8_t *)pr_val = dp->anadv_10hdx;
3235 		break;
3236 
3237 	case MAC_PROP_EN_100T4_CAP:
3238 #ifndef MAC_VERSION_V1
3239 		if (dp->mii_status_ro & MII_STATUS_100_BASE_T4) {
3240 			*perm = MAC_PROP_PERM_READ;
3241 		}
3242 #endif
3243 		*(uint8_t *)pr_val = dp->anadv_100t4;
3244 		break;
3245 
3246 	case MAC_PROP_PRIVATE:
3247 		err = ENOTSUP;
3248 		break;
3249 
3250 #ifndef MAC_VERSION_V1
3251 	case MAC_PROP_MTU: {
3252 		mac_propval_range_t range;
3253 		if (!(pr_flags & MAC_PROP_POSSIBLE)) {
3254 			err = ENOTSUP;
3255 			break;
3256 		}
3257 		if (pr_valsize < sizeof (mac_propval_range_t)) {
3258 			err = EINVAL;
3259 			break;
3260 		}
3261 		range.mpr_count = 1;
3262 		range.mpr_type = MAC_PROPVAL_UINT32;
3263 		range.range_uint32[0].mpur_min = ETHERMTU;
3264 		range.range_uint32[0].mpur_max = dp->mtu;
3265 		bcopy(&range, pr_val, sizeof (range));
3266 		break;
3267 	}
3268 #endif
3269 	default:
3270 		err = ENOTSUP;
3271 		break;
3272 	}
3273 
3274 	rw_exit(&dp->dev_state_lock);
3275 	return (err);
3276 }
3277 #endif /* USBGEM_CONFIG_MAC_PROP */
3278 
3279 #ifdef USBGEM_CONFIG_ND
3280 /* ============================================================== */
3281 /*
3282  * ND interface
3283  */
3284 /* ============================================================== */
3285 enum {
3286 	PARAM_AUTONEG_CAP,
3287 	PARAM_PAUSE_CAP,
3288 	PARAM_ASYM_PAUSE_CAP,
3289 	PARAM_1000FDX_CAP,
3290 	PARAM_1000HDX_CAP,
3291 	PARAM_100T4_CAP,
3292 	PARAM_100FDX_CAP,
3293 	PARAM_100HDX_CAP,
3294 	PARAM_10FDX_CAP,
3295 	PARAM_10HDX_CAP,
3296 
3297 	PARAM_ADV_AUTONEG_CAP,
3298 	PARAM_ADV_PAUSE_CAP,
3299 	PARAM_ADV_ASYM_PAUSE_CAP,
3300 	PARAM_ADV_1000FDX_CAP,
3301 	PARAM_ADV_1000HDX_CAP,
3302 	PARAM_ADV_100T4_CAP,
3303 	PARAM_ADV_100FDX_CAP,
3304 	PARAM_ADV_100HDX_CAP,
3305 	PARAM_ADV_10FDX_CAP,
3306 	PARAM_ADV_10HDX_CAP,
3307 	PARAM_ADV_1000T_MS,
3308 
3309 	PARAM_LP_AUTONEG_CAP,
3310 	PARAM_LP_PAUSE_CAP,
3311 	PARAM_LP_ASYM_PAUSE_CAP,
3312 	PARAM_LP_1000FDX_CAP,
3313 	PARAM_LP_1000HDX_CAP,
3314 	PARAM_LP_100T4_CAP,
3315 	PARAM_LP_100FDX_CAP,
3316 	PARAM_LP_100HDX_CAP,
3317 	PARAM_LP_10FDX_CAP,
3318 	PARAM_LP_10HDX_CAP,
3319 
3320 	PARAM_LINK_STATUS,
3321 	PARAM_LINK_SPEED,
3322 	PARAM_LINK_DUPLEX,
3323 
3324 	PARAM_LINK_AUTONEG,
3325 	PARAM_LINK_RX_PAUSE,
3326 	PARAM_LINK_TX_PAUSE,
3327 
3328 	PARAM_LOOP_MODE,
3329 	PARAM_MSI_CNT,
3330 #ifdef DEBUG_RESUME
3331 	PARAM_RESUME_TEST,
3332 #endif
3333 
3334 	PARAM_COUNT
3335 };
3336 
3337 struct usbgem_nd_arg {
3338 	struct usbgem_dev	*dp;
3339 	int		item;
3340 };
3341 
3342 static int
3343 usbgem_param_get(queue_t *q, mblk_t *mp, caddr_t arg, cred_t *credp)
3344 {
3345 	struct usbgem_dev	*dp = ((struct usbgem_nd_arg *)(void *)arg)->dp;
3346 	int		item = ((struct usbgem_nd_arg *)(void *)arg)->item;
3347 	long		val;
3348 
3349 	DPRINTF(1, (CE_CONT, "!%s: %s: called, item:%d",
3350 	    dp->name, __func__, item));
3351 
3352 	switch (item) {
3353 	case PARAM_AUTONEG_CAP:
3354 		val = BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG);
3355 		DPRINTF(1, (CE_CONT, "autoneg_cap:%d", val));
3356 		break;
3357 
3358 	case PARAM_PAUSE_CAP:
3359 		val = dp->ugc.usbgc_flow_control != FLOW_CONTROL_NONE;
3360 		break;
3361 
3362 	case PARAM_ASYM_PAUSE_CAP:
3363 		val = dp->ugc.usbgc_flow_control > FLOW_CONTROL_SYMMETRIC;
3364 		break;
3365 
3366 	case PARAM_1000FDX_CAP:
3367 		val = (dp->mii_xstatus & MII_XSTATUS_1000BASET_FD) ||
3368 		    (dp->mii_xstatus & MII_XSTATUS_1000BASEX_FD);
3369 		break;
3370 
3371 	case PARAM_1000HDX_CAP:
3372 		val = (dp->mii_xstatus & MII_XSTATUS_1000BASET) ||
3373 		    (dp->mii_xstatus & MII_XSTATUS_1000BASEX);
3374 		break;
3375 
3376 	case PARAM_100T4_CAP:
3377 		val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASE_T4);
3378 		break;
3379 
3380 	case PARAM_100FDX_CAP:
3381 		val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD);
3382 		break;
3383 
3384 	case PARAM_100HDX_CAP:
3385 		val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX);
3386 		break;
3387 
3388 	case PARAM_10FDX_CAP:
3389 		val = BOOLEAN(dp->mii_status & MII_STATUS_10_FD);
3390 		break;
3391 
3392 	case PARAM_10HDX_CAP:
3393 		val = BOOLEAN(dp->mii_status & MII_STATUS_10);
3394 		break;
3395 
3396 	case PARAM_ADV_AUTONEG_CAP:
3397 		val = dp->anadv_autoneg;
3398 		break;
3399 
3400 	case PARAM_ADV_PAUSE_CAP:
3401 		val = dp->anadv_pause;
3402 		break;
3403 
3404 	case PARAM_ADV_ASYM_PAUSE_CAP:
3405 		val = dp->anadv_asmpause;
3406 		break;
3407 
3408 	case PARAM_ADV_1000FDX_CAP:
3409 		val = dp->anadv_1000fdx;
3410 		break;
3411 
3412 	case PARAM_ADV_1000HDX_CAP:
3413 		val = dp->anadv_1000hdx;
3414 		break;
3415 
3416 	case PARAM_ADV_100T4_CAP:
3417 		val = dp->anadv_100t4;
3418 		break;
3419 
3420 	case PARAM_ADV_100FDX_CAP:
3421 		val = dp->anadv_100fdx;
3422 		break;
3423 
3424 	case PARAM_ADV_100HDX_CAP:
3425 		val = dp->anadv_100hdx;
3426 		break;
3427 
3428 	case PARAM_ADV_10FDX_CAP:
3429 		val = dp->anadv_10fdx;
3430 		break;
3431 
3432 	case PARAM_ADV_10HDX_CAP:
3433 		val = dp->anadv_10hdx;
3434 		break;
3435 
3436 	case PARAM_ADV_1000T_MS:
3437 		val = dp->anadv_1000t_ms;
3438 		break;
3439 
3440 	case PARAM_LP_AUTONEG_CAP:
3441 		val = BOOLEAN(dp->mii_exp & MII_AN_EXP_LPCANAN);
3442 		break;
3443 
3444 	case PARAM_LP_PAUSE_CAP:
3445 		val = BOOLEAN(dp->mii_lpable & MII_ABILITY_PAUSE);
3446 		break;
3447 
3448 	case PARAM_LP_ASYM_PAUSE_CAP:
3449 		val = BOOLEAN(dp->mii_lpable & MII_ABILITY_ASM_DIR);
3450 		break;
3451 
3452 	case PARAM_LP_1000FDX_CAP:
3453 		val = BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_FULL);
3454 		break;
3455 
3456 	case PARAM_LP_1000HDX_CAP:
3457 		val = BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_HALF);
3458 		break;
3459 
3460 	case PARAM_LP_100T4_CAP:
3461 		val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_T4);
3462 		break;
3463 
3464 	case PARAM_LP_100FDX_CAP:
3465 		val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX_FD);
3466 		break;
3467 
3468 	case PARAM_LP_100HDX_CAP:
3469 		val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX);
3470 		break;
3471 
3472 	case PARAM_LP_10FDX_CAP:
3473 		val = BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T_FD);
3474 		break;
3475 
3476 	case PARAM_LP_10HDX_CAP:
3477 		val = BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T);
3478 		break;
3479 
3480 	case PARAM_LINK_STATUS:
3481 		val = (dp->mii_state == MII_STATE_LINKUP);
3482 		break;
3483 
3484 	case PARAM_LINK_SPEED:
3485 		val = usbgem_speed_value[dp->speed];
3486 		break;
3487 
3488 	case PARAM_LINK_DUPLEX:
3489 		val = 0;
3490 		if (dp->mii_state == MII_STATE_LINKUP) {
3491 			val = dp->full_duplex ? 2 : 1;
3492 		}
3493 		break;
3494 
3495 	case PARAM_LINK_AUTONEG:
3496 		val = BOOLEAN(dp->mii_exp & MII_AN_EXP_LPCANAN);
3497 		break;
3498 
3499 	case PARAM_LINK_RX_PAUSE:
3500 		val = (dp->flow_control == FLOW_CONTROL_SYMMETRIC) ||
3501 		    (dp->flow_control == FLOW_CONTROL_RX_PAUSE);
3502 		break;
3503 
3504 	case PARAM_LINK_TX_PAUSE:
3505 		val = (dp->flow_control == FLOW_CONTROL_SYMMETRIC) ||
3506 		    (dp->flow_control == FLOW_CONTROL_TX_PAUSE);
3507 		break;
3508 
3509 #ifdef DEBUG_RESUME
3510 	case PARAM_RESUME_TEST:
3511 		val = 0;
3512 		break;
3513 #endif
3514 	default:
3515 		cmn_err(CE_WARN, "%s: unimplemented ndd control (%d)",
3516 		    dp->name, item);
3517 		break;
3518 	}
3519 
3520 	(void) mi_mpprintf(mp, "%ld", val);
3521 
3522 	return (0);
3523 }
3524 
3525 static int
3526 usbgem_param_set(queue_t *q,
3527     mblk_t *mp, char *value, caddr_t arg, cred_t *credp)
3528 {
3529 	struct usbgem_dev	*dp = ((struct usbgem_nd_arg *)(void *)arg)->dp;
3530 	int		item = ((struct usbgem_nd_arg *)(void *)arg)->item;
3531 	long		val;
3532 	char		*end;
3533 
3534 	DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3535 	if (ddi_strtol(value, &end, 10, &val)) {
3536 		return (EINVAL);
3537 	}
3538 	if (end == value) {
3539 		return (EINVAL);
3540 	}
3541 
3542 	switch (item) {
3543 	case PARAM_ADV_AUTONEG_CAP:
3544 		if (val != 0 && val != 1) {
3545 			goto err;
3546 		}
3547 		if (val && (dp->mii_status & MII_STATUS_CANAUTONEG) == 0) {
3548 			goto err;
3549 		}
3550 		dp->anadv_autoneg = (int)val;
3551 		break;
3552 
3553 	case PARAM_ADV_PAUSE_CAP:
3554 		if (val != 0 && val != 1) {
3555 			goto err;
3556 		}
3557 		if (val && dp->ugc.usbgc_flow_control == FLOW_CONTROL_NONE) {
3558 			goto err;
3559 		}
3560 		dp->anadv_pause = (int)val;
3561 		break;
3562 
3563 	case PARAM_ADV_ASYM_PAUSE_CAP:
3564 		if (val != 0 && val != 1) {
3565 			goto err;
3566 		}
3567 		if (val &&
3568 		    dp->ugc.usbgc_flow_control <= FLOW_CONTROL_SYMMETRIC) {
3569 			goto err;
3570 		}
3571 		dp->anadv_asmpause = (int)val;
3572 		break;
3573 
3574 	case PARAM_ADV_1000FDX_CAP:
3575 		if (val != 0 && val != 1) {
3576 			goto err;
3577 		}
3578 		if (val && (dp->mii_xstatus &
3579 		    (MII_XSTATUS_1000BASET_FD |
3580 		    MII_XSTATUS_1000BASEX_FD)) == 0) {
3581 			goto err;
3582 		}
3583 		dp->anadv_1000fdx = (int)val;
3584 		break;
3585 
3586 	case PARAM_ADV_1000HDX_CAP:
3587 		if (val != 0 && val != 1) {
3588 			goto err;
3589 		}
3590 		if (val && (dp->mii_xstatus &
3591 		    (MII_XSTATUS_1000BASET | MII_XSTATUS_1000BASEX)) == 0) {
3592 			goto err;
3593 		}
3594 		dp->anadv_1000hdx = (int)val;
3595 		break;
3596 
3597 	case PARAM_ADV_100T4_CAP:
3598 		if (val != 0 && val != 1) {
3599 			goto err;
3600 		}
3601 		if (val && (dp->mii_status & MII_STATUS_100_BASE_T4) == 0) {
3602 			goto err;
3603 		}
3604 		dp->anadv_100t4 = (int)val;
3605 		break;
3606 
3607 	case PARAM_ADV_100FDX_CAP:
3608 		if (val != 0 && val != 1) {
3609 			goto err;
3610 		}
3611 		if (val && (dp->mii_status & MII_STATUS_100_BASEX_FD) == 0) {
3612 			goto err;
3613 		}
3614 		dp->anadv_100fdx = (int)val;
3615 		break;
3616 
3617 	case PARAM_ADV_100HDX_CAP:
3618 		if (val != 0 && val != 1) {
3619 			goto err;
3620 		}
3621 		if (val && (dp->mii_status & MII_STATUS_100_BASEX) == 0) {
3622 			goto err;
3623 		}
3624 		dp->anadv_100hdx = (int)val;
3625 		break;
3626 
3627 	case PARAM_ADV_10FDX_CAP:
3628 		if (val != 0 && val != 1) {
3629 			goto err;
3630 		}
3631 		if (val && (dp->mii_status & MII_STATUS_10_FD) == 0) {
3632 			goto err;
3633 		}
3634 		dp->anadv_10fdx = (int)val;
3635 		break;
3636 
3637 	case PARAM_ADV_10HDX_CAP:
3638 		if (val != 0 && val != 1) {
3639 			goto err;
3640 		}
3641 		if (val && (dp->mii_status & MII_STATUS_10) == 0) {
3642 			goto err;
3643 		}
3644 		dp->anadv_10hdx = (int)val;
3645 		break;
3646 
3647 	case PARAM_ADV_1000T_MS:
3648 		if (val != 0 && val != 1 && val != 2) {
3649 			goto err;
3650 		}
3651 		if (val && (dp->mii_xstatus &
3652 		    (MII_XSTATUS_1000BASET | MII_XSTATUS_1000BASET_FD)) == 0) {
3653 			goto err;
3654 		}
3655 		dp->anadv_1000t_ms = (int)val;
3656 		break;
3657 
3658 #ifdef DEBUG_RESUME
3659 	case PARAM_RESUME_TEST:
3660 		mutex_exit(&dp->xmitlock);
3661 		mutex_exit(&dp->intrlock);
3662 		gem_suspend(dp->dip);
3663 		gem_resume(dp->dip);
3664 		mutex_enter(&dp->intrlock);
3665 		mutex_enter(&dp->xmitlock);
3666 		break;
3667 #endif
3668 	}
3669 
3670 	/* sync with PHY */
3671 	usbgem_choose_forcedmode(dp);
3672 
3673 	dp->mii_state = MII_STATE_UNKNOWN;
3674 	if (dp->ugc.usbgc_mii_hw_link_detection) {
3675 		/* wake up link watcher possiblely sleeps */
3676 		cv_signal(&dp->link_watcher_wait_cv);
3677 	}
3678 
3679 	return (0);
3680 err:
3681 	return (EINVAL);
3682 }
3683 
3684 static void
3685 usbgem_nd_load(struct usbgem_dev *dp,
3686     char *name, ndgetf_t gf, ndsetf_t sf, int item)
3687 {
3688 	struct usbgem_nd_arg	*arg;
3689 
3690 	ASSERT(item >= 0);
3691 	ASSERT(item < PARAM_COUNT);
3692 
3693 	arg = &((struct usbgem_nd_arg *)(void *)dp->nd_arg_p)[item];
3694 	arg->dp = dp;
3695 	arg->item = item;
3696 
3697 	DPRINTF(2, (CE_CONT, "!%s: %s: name:%s, item:%d",
3698 	    dp->name, __func__, name, item));
3699 	(void) nd_load(&dp->nd_data_p, name, gf, sf, (caddr_t)arg);
3700 }
3701 
3702 static void
3703 usbgem_nd_setup(struct usbgem_dev *dp)
3704 {
3705 	DPRINTF(1, (CE_CONT, "!%s: %s: called, mii_status:0x%b",
3706 	    dp->name, __func__, dp->mii_status, MII_STATUS_BITS));
3707 
3708 	ASSERT(dp->nd_arg_p == NULL);
3709 
3710 	dp->nd_arg_p =
3711 	    kmem_zalloc(sizeof (struct usbgem_nd_arg) * PARAM_COUNT, KM_SLEEP);
3712 
3713 #define	SETFUNC(x)	((x) ? usbgem_param_set : NULL)
3714 
3715 	usbgem_nd_load(dp, "autoneg_cap",
3716 	    usbgem_param_get, NULL, PARAM_AUTONEG_CAP);
3717 	usbgem_nd_load(dp, "pause_cap",
3718 	    usbgem_param_get, NULL, PARAM_PAUSE_CAP);
3719 	usbgem_nd_load(dp, "asym_pause_cap",
3720 	    usbgem_param_get, NULL, PARAM_ASYM_PAUSE_CAP);
3721 	usbgem_nd_load(dp, "1000fdx_cap",
3722 	    usbgem_param_get, NULL, PARAM_1000FDX_CAP);
3723 	usbgem_nd_load(dp, "1000hdx_cap",
3724 	    usbgem_param_get, NULL, PARAM_1000HDX_CAP);
3725 	usbgem_nd_load(dp, "100T4_cap",
3726 	    usbgem_param_get, NULL, PARAM_100T4_CAP);
3727 	usbgem_nd_load(dp, "100fdx_cap",
3728 	    usbgem_param_get, NULL, PARAM_100FDX_CAP);
3729 	usbgem_nd_load(dp, "100hdx_cap",
3730 	    usbgem_param_get, NULL, PARAM_100HDX_CAP);
3731 	usbgem_nd_load(dp, "10fdx_cap",
3732 	    usbgem_param_get, NULL, PARAM_10FDX_CAP);
3733 	usbgem_nd_load(dp, "10hdx_cap",
3734 	    usbgem_param_get, NULL, PARAM_10HDX_CAP);
3735 
3736 	/* Our advertised capabilities */
3737 	usbgem_nd_load(dp, "adv_autoneg_cap", usbgem_param_get,
3738 	    SETFUNC(dp->mii_status & MII_STATUS_CANAUTONEG),
3739 	    PARAM_ADV_AUTONEG_CAP);
3740 	usbgem_nd_load(dp, "adv_pause_cap", usbgem_param_get,
3741 	    SETFUNC(dp->ugc.usbgc_flow_control & 1),
3742 	    PARAM_ADV_PAUSE_CAP);
3743 	usbgem_nd_load(dp, "adv_asym_pause_cap", usbgem_param_get,
3744 	    SETFUNC(dp->ugc.usbgc_flow_control & 2),
3745 	    PARAM_ADV_ASYM_PAUSE_CAP);
3746 	usbgem_nd_load(dp, "adv_1000fdx_cap", usbgem_param_get,
3747 	    SETFUNC(dp->mii_xstatus &
3748 	    (MII_XSTATUS_1000BASEX_FD | MII_XSTATUS_1000BASET_FD)),
3749 	    PARAM_ADV_1000FDX_CAP);
3750 	usbgem_nd_load(dp, "adv_1000hdx_cap", usbgem_param_get,
3751 	    SETFUNC(dp->mii_xstatus &
3752 	    (MII_XSTATUS_1000BASEX | MII_XSTATUS_1000BASET)),
3753 	    PARAM_ADV_1000HDX_CAP);
3754 	usbgem_nd_load(dp, "adv_100T4_cap", usbgem_param_get,
3755 	    SETFUNC((dp->mii_status & MII_STATUS_100_BASE_T4) &&
3756 	    !dp->mii_advert_ro),
3757 	    PARAM_ADV_100T4_CAP);
3758 	usbgem_nd_load(dp, "adv_100fdx_cap", usbgem_param_get,
3759 	    SETFUNC((dp->mii_status & MII_STATUS_100_BASEX_FD) &&
3760 	    !dp->mii_advert_ro),
3761 	    PARAM_ADV_100FDX_CAP);
3762 	usbgem_nd_load(dp, "adv_100hdx_cap", usbgem_param_get,
3763 	    SETFUNC((dp->mii_status & MII_STATUS_100_BASEX) &&
3764 	    !dp->mii_advert_ro),
3765 	    PARAM_ADV_100HDX_CAP);
3766 	usbgem_nd_load(dp, "adv_10fdx_cap", usbgem_param_get,
3767 	    SETFUNC((dp->mii_status & MII_STATUS_10_FD) &&
3768 	    !dp->mii_advert_ro),
3769 	    PARAM_ADV_10FDX_CAP);
3770 	usbgem_nd_load(dp, "adv_10hdx_cap", usbgem_param_get,
3771 	    SETFUNC((dp->mii_status & MII_STATUS_10) &&
3772 	    !dp->mii_advert_ro),
3773 	    PARAM_ADV_10HDX_CAP);
3774 	usbgem_nd_load(dp, "adv_1000t_ms", usbgem_param_get,
3775 	    SETFUNC(dp->mii_xstatus &
3776 	    (MII_XSTATUS_1000BASET_FD | MII_XSTATUS_1000BASET)),
3777 	    PARAM_ADV_1000T_MS);
3778 
3779 
3780 	/* Partner's advertised capabilities */
3781 	usbgem_nd_load(dp, "lp_autoneg_cap",
3782 	    usbgem_param_get, NULL, PARAM_LP_AUTONEG_CAP);
3783 	usbgem_nd_load(dp, "lp_pause_cap",
3784 	    usbgem_param_get, NULL, PARAM_LP_PAUSE_CAP);
3785 	usbgem_nd_load(dp, "lp_asym_pause_cap",
3786 	    usbgem_param_get, NULL, PARAM_LP_ASYM_PAUSE_CAP);
3787 	usbgem_nd_load(dp, "lp_1000fdx_cap",
3788 	    usbgem_param_get, NULL, PARAM_LP_1000FDX_CAP);
3789 	usbgem_nd_load(dp, "lp_1000hdx_cap",
3790 	    usbgem_param_get, NULL, PARAM_LP_1000HDX_CAP);
3791 	usbgem_nd_load(dp, "lp_100T4_cap",
3792 	    usbgem_param_get, NULL, PARAM_LP_100T4_CAP);
3793 	usbgem_nd_load(dp, "lp_100fdx_cap",
3794 	    usbgem_param_get, NULL, PARAM_LP_100FDX_CAP);
3795 	usbgem_nd_load(dp, "lp_100hdx_cap",
3796 	    usbgem_param_get, NULL, PARAM_LP_100HDX_CAP);
3797 	usbgem_nd_load(dp, "lp_10fdx_cap",
3798 	    usbgem_param_get, NULL, PARAM_LP_10FDX_CAP);
3799 	usbgem_nd_load(dp, "lp_10hdx_cap",
3800 	    usbgem_param_get, NULL, PARAM_LP_10HDX_CAP);
3801 
3802 	/* Current operating modes */
3803 	usbgem_nd_load(dp, "link_status",
3804 	    usbgem_param_get, NULL, PARAM_LINK_STATUS);
3805 	usbgem_nd_load(dp, "link_speed",
3806 	    usbgem_param_get, NULL, PARAM_LINK_SPEED);
3807 	usbgem_nd_load(dp, "link_duplex",
3808 	    usbgem_param_get, NULL, PARAM_LINK_DUPLEX);
3809 	usbgem_nd_load(dp, "link_autoneg",
3810 	    usbgem_param_get, NULL, PARAM_LINK_AUTONEG);
3811 	usbgem_nd_load(dp, "link_rx_pause",
3812 	    usbgem_param_get, NULL, PARAM_LINK_RX_PAUSE);
3813 	usbgem_nd_load(dp, "link_tx_pause",
3814 	    usbgem_param_get, NULL, PARAM_LINK_TX_PAUSE);
3815 #ifdef DEBUG_RESUME
3816 	usbgem_nd_load(dp, "resume_test",
3817 	    usbgem_param_get, usbgem_param_set, PARAM_RESUME_TEST);
3818 #endif
3819 #undef	SETFUNC
3820 }
3821 
3822 static
3823 enum ioc_reply
3824 usbgem_nd_ioctl(struct usbgem_dev *dp,
3825     queue_t *wq, mblk_t *mp, struct iocblk *iocp)
3826 {
3827 	boolean_t	ok;
3828 
3829 	DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3830 
3831 	switch (iocp->ioc_cmd) {
3832 	case ND_GET:
3833 		ok = nd_getset(wq, dp->nd_data_p, mp);
3834 		DPRINTF(1, (CE_CONT,
3835 		    "%s: get %s", dp->name, ok ? "OK" : "FAIL"));
3836 		return (ok ? IOC_REPLY : IOC_INVAL);
3837 
3838 	case ND_SET:
3839 		ok = nd_getset(wq, dp->nd_data_p, mp);
3840 
3841 		DPRINTF(1, (CE_CONT, "%s: set %s err %d",
3842 		    dp->name, ok ? "OK" : "FAIL", iocp->ioc_error));
3843 
3844 		if (!ok) {
3845 			return (IOC_INVAL);
3846 		}
3847 
3848 		if (iocp->ioc_error) {
3849 			return (IOC_REPLY);
3850 		}
3851 
3852 		return (IOC_RESTART_REPLY);
3853 	}
3854 
3855 	cmn_err(CE_WARN, "%s: invalid cmd 0x%x", dp->name, iocp->ioc_cmd);
3856 
3857 	return (IOC_INVAL);
3858 }
3859 
3860 static void
3861 usbgem_nd_cleanup(struct usbgem_dev *dp)
3862 {
3863 	ASSERT(dp->nd_data_p != NULL);
3864 	ASSERT(dp->nd_arg_p != NULL);
3865 
3866 	nd_free(&dp->nd_data_p);
3867 
3868 	kmem_free(dp->nd_arg_p, sizeof (struct usbgem_nd_arg) * PARAM_COUNT);
3869 	dp->nd_arg_p = NULL;
3870 }
3871 #endif /* USBGEM_CONFIG_ND */
3872 
3873 static void
3874 usbgem_mac_ioctl(struct usbgem_dev *dp, queue_t *wq, mblk_t *mp)
3875 {
3876 	struct iocblk	*iocp;
3877 	enum ioc_reply	status;
3878 
3879 	DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3880 
3881 	/*
3882 	 * Validate the command before bothering with the mutex ...
3883 	 */
3884 	iocp = (void *)mp->b_rptr;
3885 	iocp->ioc_error = 0;
3886 
3887 	DPRINTF(1, (CE_CONT, "%s: %s cmd:0x%x", dp->name, __func__,
3888 	    iocp->ioc_cmd));
3889 
3890 #ifdef USBGEM_CONFIG_ND
3891 	switch (iocp->ioc_cmd) {
3892 	default:
3893 		_NOTE(NOTREACHED)
3894 		status = IOC_INVAL;
3895 		break;
3896 
3897 	case ND_GET:
3898 	case ND_SET:
3899 		status = usbgem_nd_ioctl(dp, wq, mp, iocp);
3900 		break;
3901 	}
3902 
3903 	/*
3904 	 * Finally, decide how to reply
3905 	 */
3906 	switch (status) {
3907 	default:
3908 	case IOC_INVAL:
3909 		/*
3910 		 * Error, reply with a NAK and EINVAL or the specified error
3911 		 */
3912 		miocnak(wq, mp, 0, iocp->ioc_error == 0 ?
3913 		    EINVAL : iocp->ioc_error);
3914 		break;
3915 
3916 	case IOC_DONE:
3917 		/*
3918 		 * OK, reply already sent
3919 		 */
3920 		break;
3921 
3922 	case IOC_RESTART_ACK:
3923 	case IOC_ACK:
3924 		/*
3925 		 * OK, reply with an ACK
3926 		 */
3927 		miocack(wq, mp, 0, 0);
3928 		break;
3929 
3930 	case IOC_RESTART_REPLY:
3931 	case IOC_REPLY:
3932 		/*
3933 		 * OK, send prepared reply as ACK or NAK
3934 		 */
3935 		mp->b_datap->db_type =
3936 		    iocp->ioc_error == 0 ? M_IOCACK : M_IOCNAK;
3937 		qreply(wq, mp);
3938 		break;
3939 	}
3940 #else
3941 	miocnak(wq, mp, 0, EINVAL);
3942 	return;
3943 #endif /* USBGEM_CONFIG_GLDv3 */
3944 }
3945 
3946 #ifndef SYS_MAC_H
3947 #define	XCVR_UNDEFINED	0
3948 #define	XCVR_NONE	1
3949 #define	XCVR_10		2
3950 #define	XCVR_100T4	3
3951 #define	XCVR_100X	4
3952 #define	XCVR_100T2	5
3953 #define	XCVR_1000X	6
3954 #define	XCVR_1000T	7
3955 #endif
3956 static int
3957 usbgem_mac_xcvr_inuse(struct usbgem_dev *dp)
3958 {
3959 	int	val = XCVR_UNDEFINED;
3960 
3961 	if ((dp->mii_status & MII_STATUS_XSTATUS) == 0) {
3962 		if (dp->mii_status & MII_STATUS_100_BASE_T4) {
3963 			val = XCVR_100T4;
3964 		} else if (dp->mii_status &
3965 		    (MII_STATUS_100_BASEX_FD |
3966 		    MII_STATUS_100_BASEX)) {
3967 			val = XCVR_100X;
3968 		} else if (dp->mii_status &
3969 		    (MII_STATUS_100_BASE_T2_FD |
3970 		    MII_STATUS_100_BASE_T2)) {
3971 			val = XCVR_100T2;
3972 		} else if (dp->mii_status &
3973 		    (MII_STATUS_10_FD | MII_STATUS_10)) {
3974 			val = XCVR_10;
3975 		}
3976 	} else if (dp->mii_xstatus &
3977 	    (MII_XSTATUS_1000BASET_FD | MII_XSTATUS_1000BASET)) {
3978 		val = XCVR_1000T;
3979 	} else if (dp->mii_xstatus &
3980 	    (MII_XSTATUS_1000BASEX_FD | MII_XSTATUS_1000BASEX)) {
3981 		val = XCVR_1000X;
3982 	}
3983 
3984 	return (val);
3985 }
3986 
3987 #ifdef USBGEM_CONFIG_GLDv3
3988 /* ============================================================== */
3989 /*
3990  * GLDv3 interface
3991  */
3992 /* ============================================================== */
3993 static int	usbgem_m_getstat(void *, uint_t, uint64_t *);
3994 static int	usbgem_m_start(void *);
3995 static void	usbgem_m_stop(void *);
3996 static int	usbgem_m_setpromisc(void *, boolean_t);
3997 static int	usbgem_m_multicst(void *, boolean_t, const uint8_t *);
3998 static int	usbgem_m_unicst(void *, const uint8_t *);
3999 static mblk_t	*usbgem_m_tx(void *, mblk_t *);
4000 static void	usbgem_m_ioctl(void *, queue_t *, mblk_t *);
4001 #ifdef GEM_CONFIG_MAC_PROP
4002 static int	usbgem_m_setprop(void *, const char *, mac_prop_id_t,
4003     uint_t, const void *);
4004 #ifdef MAC_VERSION_V1
4005 static int	usbgem_m_getprop(void *, const char *, mac_prop_id_t,
4006     uint_t, void *);
4007 #else
4008 static int	usbgem_m_getprop(void *, const char *, mac_prop_id_t,
4009     uint_t, uint_t, void *, uint_t *);
4010 #endif
4011 #endif
4012 
4013 #ifdef _SYS_MAC_PROVIDER_H
4014 #define	GEM_M_CALLBACK_FLAGS	(MC_IOCTL)
4015 #else
4016 #define	GEM_M_CALLBACK_FLAGS	(MC_IOCTL)
4017 #endif
4018 
4019 static mac_callbacks_t gem_m_callbacks = {
4020 #ifdef USBGEM_CONFIG_MAC_PROP
4021 #ifdef MAC_VERSION_V1
4022 	GEM_M_CALLBACK_FLAGS | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
4023 #else
4024 	GEM_M_CALLBACK_FLAGS | MC_SETPROP | MC_GETPROP,
4025 #endif
4026 #else
4027 	GEM_M_CALLBACK_FLAGS,
4028 #endif
4029 	usbgem_m_getstat,
4030 	usbgem_m_start,
4031 	usbgem_m_stop,
4032 	usbgem_m_setpromisc,
4033 	usbgem_m_multicst,
4034 	usbgem_m_unicst,
4035 	usbgem_m_tx,
4036 #ifdef _SYS_MAC_PROVIDER_H
4037 #ifdef MAC_VERSION_V1
4038 	NULL,
4039 #endif
4040 #else
4041 	NULL,	/* m_resources */
4042 #endif
4043 	usbgem_m_ioctl,
4044 	NULL, /* m_getcapab */
4045 #ifdef USBGEM_CONFIG_MAC_PROP
4046 	NULL,
4047 	NULL,
4048 	usbgem_m_setprop,
4049 	usbgem_m_getprop,
4050 #endif
4051 #ifdef MAC_VERSION_V1
4052 	usbgem_m_propinfo,
4053 #endif
4054 };
4055 
4056 static int
4057 usbgem_m_start(void *arg)
4058 {
4059 	int	ret;
4060 	int	err;
4061 	struct usbgem_dev *dp = arg;
4062 
4063 	DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4064 
4065 	err = EIO;
4066 
4067 	rw_enter(&dp->dev_state_lock, RW_WRITER);
4068 	dp->nic_state = NIC_STATE_ONLINE;
4069 
4070 	if (dp->mac_state == MAC_STATE_DISCONNECTED) {
4071 		err = 0;
4072 		goto x;
4073 	}
4074 	if (usbgem_mac_init(dp) != USB_SUCCESS) {
4075 		goto x;
4076 	}
4077 
4078 	/* initialize rx filter state */
4079 	sema_p(&dp->rxfilter_lock);
4080 	dp->mc_count = 0;
4081 	dp->mc_count_req = 0;
4082 
4083 	bcopy(dp->dev_addr.ether_addr_octet,
4084 	    dp->cur_addr.ether_addr_octet, ETHERADDRL);
4085 	dp->rxmode |= RXMODE_ENABLE;
4086 
4087 	ret = usbgem_hal_set_rx_filter(dp);
4088 	sema_v(&dp->rxfilter_lock);
4089 
4090 	if (ret != USB_SUCCESS) {
4091 		goto x;
4092 	}
4093 
4094 	if (dp->mii_state == MII_STATE_LINKUP) {
4095 		/* setup media mode if the link have been up */
4096 		if (usbgem_hal_set_media(dp) != USB_SUCCESS) {
4097 			goto x;
4098 		}
4099 		if (usbgem_mac_start(dp) != USB_SUCCESS) {
4100 			goto x;
4101 		}
4102 	}
4103 
4104 	err = 0;
4105 x:
4106 	rw_exit(&dp->dev_state_lock);
4107 	return (err);
4108 }
4109 
4110 static void
4111 usbgem_m_stop(void *arg)
4112 {
4113 	struct usbgem_dev	*dp = arg;
4114 
4115 	DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4116 
4117 	/* stop rx gracefully */
4118 	rw_enter(&dp->dev_state_lock, RW_READER);
4119 	sema_p(&dp->rxfilter_lock);
4120 	dp->rxmode &= ~RXMODE_ENABLE;
4121 
4122 	if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4123 		(void) usbgem_hal_set_rx_filter(dp);
4124 	}
4125 	sema_v(&dp->rxfilter_lock);
4126 	rw_exit(&dp->dev_state_lock);
4127 
4128 	/* make the nic state inactive */
4129 	rw_enter(&dp->dev_state_lock, RW_WRITER);
4130 	dp->nic_state = NIC_STATE_STOPPED;
4131 
4132 	/* stop mac completely */
4133 	if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4134 		(void) usbgem_mac_stop(dp, MAC_STATE_STOPPED, STOP_GRACEFUL);
4135 	}
4136 	rw_exit(&dp->dev_state_lock);
4137 }
4138 
4139 static int
4140 usbgem_m_multicst(void *arg, boolean_t add, const uint8_t *ep)
4141 {
4142 	int	err;
4143 	int	ret;
4144 	struct usbgem_dev	*dp = arg;
4145 
4146 	DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4147 
4148 	rw_enter(&dp->dev_state_lock, RW_READER);
4149 	if (add) {
4150 		ret = usbgem_add_multicast(dp, ep);
4151 	} else {
4152 		ret = usbgem_remove_multicast(dp, ep);
4153 	}
4154 	rw_exit(&dp->dev_state_lock);
4155 
4156 	err = 0;
4157 	if (ret != USB_SUCCESS) {
4158 #ifdef GEM_CONFIG_FMA
4159 		ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4160 #endif
4161 		err = EIO;
4162 	}
4163 
4164 	return (err);
4165 }
4166 
4167 static int
4168 usbgem_m_setpromisc(void *arg, boolean_t on)
4169 {
4170 	int	err;
4171 	struct usbgem_dev	*dp = arg;
4172 
4173 	DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4174 
4175 	rw_enter(&dp->dev_state_lock, RW_READER);
4176 
4177 	sema_p(&dp->rxfilter_lock);
4178 	if (on) {
4179 		dp->rxmode |= RXMODE_PROMISC;
4180 	} else {
4181 		dp->rxmode &= ~RXMODE_PROMISC;
4182 	}
4183 
4184 	err = 0;
4185 	if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4186 		if (usbgem_hal_set_rx_filter(dp) != USB_SUCCESS) {
4187 			err = EIO;
4188 		}
4189 	}
4190 	sema_v(&dp->rxfilter_lock);
4191 
4192 	rw_exit(&dp->dev_state_lock);
4193 
4194 #ifdef GEM_CONFIG_FMA
4195 	if (err != 0) {
4196 		ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4197 	}
4198 #endif
4199 	return (err);
4200 }
4201 
4202 int
4203 usbgem_m_getstat(void *arg, uint_t stat, uint64_t *valp)
4204 {
4205 	uint64_t	val;
4206 	struct usbgem_dev	*dp = arg;
4207 	struct usbgem_stats	*gstp = &dp->stats;
4208 
4209 	DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4210 
4211 	rw_enter(&dp->dev_state_lock, RW_READER);
4212 	if (dp->mac_state == MAC_STATE_DISCONNECTED) {
4213 		rw_exit(&dp->dev_state_lock);
4214 		return (0);
4215 	}
4216 
4217 	/* LINTED */
4218 	if (usbgem_hal_get_stats(dp) != USB_SUCCESS) {
4219 #ifdef GEM_CONFIG_FMA
4220 		rw_exit(&dp->dev_state_lock);
4221 		ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4222 		return (EIO);
4223 #endif
4224 	}
4225 	rw_exit(&dp->dev_state_lock);
4226 
4227 	switch (stat) {
4228 	case MAC_STAT_IFSPEED:
4229 		val = usbgem_speed_value[dp->speed] *1000000ull;
4230 		break;
4231 
4232 	case MAC_STAT_MULTIRCV:
4233 		val = gstp->rmcast;
4234 		break;
4235 
4236 	case MAC_STAT_BRDCSTRCV:
4237 		val = gstp->rbcast;
4238 		break;
4239 
4240 	case MAC_STAT_MULTIXMT:
4241 		val = gstp->omcast;
4242 		break;
4243 
4244 	case MAC_STAT_BRDCSTXMT:
4245 		val = gstp->obcast;
4246 		break;
4247 
4248 	case MAC_STAT_NORCVBUF:
4249 		val = gstp->norcvbuf + gstp->missed;
4250 		break;
4251 
4252 	case MAC_STAT_IERRORS:
4253 		val = gstp->errrcv;
4254 		break;
4255 
4256 	case MAC_STAT_NOXMTBUF:
4257 		val = gstp->noxmtbuf;
4258 		break;
4259 
4260 	case MAC_STAT_OERRORS:
4261 		val = gstp->errxmt;
4262 		break;
4263 
4264 	case MAC_STAT_COLLISIONS:
4265 		val = gstp->collisions;
4266 		break;
4267 
4268 	case MAC_STAT_RBYTES:
4269 		val = gstp->rbytes;
4270 		break;
4271 
4272 	case MAC_STAT_IPACKETS:
4273 		val = gstp->rpackets;
4274 		break;
4275 
4276 	case MAC_STAT_OBYTES:
4277 		val = gstp->obytes;
4278 		break;
4279 
4280 	case MAC_STAT_OPACKETS:
4281 		val = gstp->opackets;
4282 		break;
4283 
4284 	case MAC_STAT_UNDERFLOWS:
4285 		val = gstp->underflow;
4286 		break;
4287 
4288 	case MAC_STAT_OVERFLOWS:
4289 		val = gstp->overflow;
4290 		break;
4291 
4292 	case ETHER_STAT_ALIGN_ERRORS:
4293 		val = gstp->frame;
4294 		break;
4295 
4296 	case ETHER_STAT_FCS_ERRORS:
4297 		val = gstp->crc;
4298 		break;
4299 
4300 	case ETHER_STAT_FIRST_COLLISIONS:
4301 		val = gstp->first_coll;
4302 		break;
4303 
4304 	case ETHER_STAT_MULTI_COLLISIONS:
4305 		val = gstp->multi_coll;
4306 		break;
4307 
4308 	case ETHER_STAT_SQE_ERRORS:
4309 		val = gstp->sqe;
4310 		break;
4311 
4312 	case ETHER_STAT_DEFER_XMTS:
4313 		val = gstp->defer;
4314 		break;
4315 
4316 	case ETHER_STAT_TX_LATE_COLLISIONS:
4317 		val = gstp->xmtlatecoll;
4318 		break;
4319 
4320 	case ETHER_STAT_EX_COLLISIONS:
4321 		val = gstp->excoll;
4322 		break;
4323 
4324 	case ETHER_STAT_MACXMT_ERRORS:
4325 		val = gstp->xmit_internal_err;
4326 		break;
4327 
4328 	case ETHER_STAT_CARRIER_ERRORS:
4329 		val = gstp->nocarrier;
4330 		break;
4331 
4332 	case ETHER_STAT_TOOLONG_ERRORS:
4333 		val = gstp->frame_too_long;
4334 		break;
4335 
4336 	case ETHER_STAT_MACRCV_ERRORS:
4337 		val = gstp->rcv_internal_err;
4338 		break;
4339 
4340 	case ETHER_STAT_XCVR_ADDR:
4341 		val = dp->mii_phy_addr;
4342 		break;
4343 
4344 	case ETHER_STAT_XCVR_ID:
4345 		val = dp->mii_phy_id;
4346 		break;
4347 
4348 	case ETHER_STAT_XCVR_INUSE:
4349 		val = usbgem_mac_xcvr_inuse(dp);
4350 		break;
4351 
4352 	case ETHER_STAT_CAP_1000FDX:
4353 		val = (dp->mii_xstatus & MII_XSTATUS_1000BASET_FD) ||
4354 		    (dp->mii_xstatus & MII_XSTATUS_1000BASEX_FD);
4355 		break;
4356 
4357 	case ETHER_STAT_CAP_1000HDX:
4358 		val = (dp->mii_xstatus & MII_XSTATUS_1000BASET) ||
4359 		    (dp->mii_xstatus & MII_XSTATUS_1000BASEX);
4360 		break;
4361 
4362 	case ETHER_STAT_CAP_100FDX:
4363 		val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD);
4364 		break;
4365 
4366 	case ETHER_STAT_CAP_100HDX:
4367 		val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX);
4368 		break;
4369 
4370 	case ETHER_STAT_CAP_10FDX:
4371 		val = BOOLEAN(dp->mii_status & MII_STATUS_10_FD);
4372 		break;
4373 
4374 	case ETHER_STAT_CAP_10HDX:
4375 		val = BOOLEAN(dp->mii_status & MII_STATUS_10);
4376 		break;
4377 
4378 	case ETHER_STAT_CAP_ASMPAUSE:
4379 		val = dp->ugc.usbgc_flow_control > FLOW_CONTROL_SYMMETRIC;
4380 		break;
4381 
4382 	case ETHER_STAT_CAP_PAUSE:
4383 		val = dp->ugc.usbgc_flow_control != FLOW_CONTROL_NONE;
4384 		break;
4385 
4386 	case ETHER_STAT_CAP_AUTONEG:
4387 		val = BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG);
4388 		break;
4389 
4390 	case ETHER_STAT_ADV_CAP_1000FDX:
4391 		val = dp->anadv_1000fdx;
4392 		break;
4393 
4394 	case ETHER_STAT_ADV_CAP_1000HDX:
4395 		val = dp->anadv_1000hdx;
4396 		break;
4397 
4398 	case ETHER_STAT_ADV_CAP_100FDX:
4399 		val = dp->anadv_100fdx;
4400 		break;
4401 
4402 	case ETHER_STAT_ADV_CAP_100HDX:
4403 		val = dp->anadv_100hdx;
4404 		break;
4405 
4406 	case ETHER_STAT_ADV_CAP_10FDX:
4407 		val = dp->anadv_10fdx;
4408 		break;
4409 
4410 	case ETHER_STAT_ADV_CAP_10HDX:
4411 		val = dp->anadv_10hdx;
4412 		break;
4413 
4414 	case ETHER_STAT_ADV_CAP_ASMPAUSE:
4415 		val = dp->anadv_asmpause;
4416 		break;
4417 
4418 	case ETHER_STAT_ADV_CAP_PAUSE:
4419 		val = dp->anadv_pause;
4420 		break;
4421 
4422 	case ETHER_STAT_ADV_CAP_AUTONEG:
4423 		val = dp->anadv_autoneg;
4424 		break;
4425 
4426 	case ETHER_STAT_LP_CAP_1000FDX:
4427 		val = BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_FULL);
4428 		break;
4429 
4430 	case ETHER_STAT_LP_CAP_1000HDX:
4431 		val = BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_HALF);
4432 		break;
4433 
4434 	case ETHER_STAT_LP_CAP_100FDX:
4435 		val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX_FD);
4436 		break;
4437 
4438 	case ETHER_STAT_LP_CAP_100HDX:
4439 		val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX);
4440 		break;
4441 
4442 	case ETHER_STAT_LP_CAP_10FDX:
4443 		val = BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T_FD);
4444 		break;
4445 
4446 	case ETHER_STAT_LP_CAP_10HDX:
4447 		val = BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T);
4448 		break;
4449 
4450 	case ETHER_STAT_LP_CAP_ASMPAUSE:
4451 		val = BOOLEAN(dp->mii_lpable & MII_ABILITY_ASM_DIR);
4452 		break;
4453 
4454 	case ETHER_STAT_LP_CAP_PAUSE:
4455 		val = BOOLEAN(dp->mii_lpable & MII_ABILITY_PAUSE);
4456 		break;
4457 
4458 	case ETHER_STAT_LP_CAP_AUTONEG:
4459 		val = BOOLEAN(dp->mii_exp & MII_AN_EXP_LPCANAN);
4460 		break;
4461 
4462 	case ETHER_STAT_LINK_ASMPAUSE:
4463 		val = BOOLEAN(dp->flow_control & 2);
4464 		break;
4465 
4466 	case ETHER_STAT_LINK_PAUSE:
4467 		val = BOOLEAN(dp->flow_control & 1);
4468 		break;
4469 
4470 	case ETHER_STAT_LINK_AUTONEG:
4471 		val = dp->anadv_autoneg &&
4472 		    BOOLEAN(dp->mii_exp & MII_AN_EXP_LPCANAN);
4473 		break;
4474 
4475 	case ETHER_STAT_LINK_DUPLEX:
4476 		val = (dp->mii_state == MII_STATE_LINKUP) ?
4477 		    (dp->full_duplex ? 2 : 1) : 0;
4478 		break;
4479 
4480 	case ETHER_STAT_TOOSHORT_ERRORS:
4481 		val = gstp->runt;
4482 		break;
4483 #ifdef NEVER	/* it doesn't make sense */
4484 	case ETHER_STAT_CAP_REMFAULT:
4485 		val = B_TRUE;
4486 		break;
4487 
4488 	case ETHER_STAT_ADV_REMFAULT:
4489 		val = dp->anadv_remfault;
4490 		break;
4491 #endif
4492 	case ETHER_STAT_LP_REMFAULT:
4493 		val = BOOLEAN(dp->mii_lpable & MII_AN_ADVERT_REMFAULT);
4494 		break;
4495 
4496 	case ETHER_STAT_JABBER_ERRORS:
4497 		val = gstp->jabber;
4498 		break;
4499 
4500 	case ETHER_STAT_CAP_100T4:
4501 		val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASE_T4);
4502 		break;
4503 
4504 	case ETHER_STAT_ADV_CAP_100T4:
4505 		val = dp->anadv_100t4;
4506 		break;
4507 
4508 	case ETHER_STAT_LP_CAP_100T4:
4509 		val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_T4);
4510 		break;
4511 
4512 	default:
4513 #if GEM_DEBUG_LEVEL > 2
4514 		cmn_err(CE_WARN,
4515 		    "%s: unrecognized parameter value = %d",
4516 		    __func__, stat);
4517 #endif
4518 		*valp = 0;
4519 		return (ENOTSUP);
4520 	}
4521 
4522 	*valp = val;
4523 
4524 	return (0);
4525 }
4526 
4527 static int
4528 usbgem_m_unicst(void *arg, const uint8_t *mac)
4529 {
4530 	int	err;
4531 	struct usbgem_dev	*dp = arg;
4532 
4533 	DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4534 
4535 	rw_enter(&dp->dev_state_lock, RW_READER);
4536 
4537 	sema_p(&dp->rxfilter_lock);
4538 	bcopy(mac, dp->cur_addr.ether_addr_octet, ETHERADDRL);
4539 	dp->rxmode |= RXMODE_ENABLE;
4540 
4541 	err = 0;
4542 	if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4543 		if (usbgem_hal_set_rx_filter(dp) != USB_SUCCESS) {
4544 			err = EIO;
4545 		}
4546 	}
4547 	sema_v(&dp->rxfilter_lock);
4548 	rw_exit(&dp->dev_state_lock);
4549 
4550 #ifdef GEM_CONFIG_FMA
4551 	if (err != 0) {
4552 		ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4553 	}
4554 #endif
4555 	return (err);
4556 }
4557 
4558 /*
4559  * usbgem_m_tx is used only for sending data packets into ethernet wire.
4560  */
4561 static mblk_t *
4562 usbgem_m_tx(void *arg, mblk_t *mp_head)
4563 {
4564 	int	limit;
4565 	mblk_t	*mp;
4566 	mblk_t	*nmp;
4567 	struct usbgem_dev	*dp = arg;
4568 
4569 	DPRINTF(4, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4570 
4571 	mp = mp_head;
4572 
4573 	rw_enter(&dp->dev_state_lock, RW_READER);
4574 
4575 	if (dp->mii_state != MII_STATE_LINKUP ||
4576 	    dp->mac_state != MAC_STATE_ONLINE) {
4577 		/* some nics hate to send packets during the link is down */
4578 		for (; mp; mp = nmp) {
4579 			nmp = mp->b_next;
4580 			mp->b_next = NULL;
4581 			freemsg(mp);
4582 		}
4583 		goto x;
4584 	}
4585 
4586 	ASSERT(dp->nic_state == NIC_STATE_ONLINE);
4587 
4588 	limit = dp->tx_max_packets;
4589 	for (; limit-- && mp; mp = nmp) {
4590 		nmp = mp->b_next;
4591 		mp->b_next = NULL;
4592 		if (usbgem_send_common(dp, mp,
4593 		    (limit == 0 && nmp) ? 1 : 0)) {
4594 			mp->b_next = nmp;
4595 			break;
4596 		}
4597 	}
4598 #ifdef CONFIG_TX_LIMITER
4599 	if (mp == mp_head) {
4600 		/* no packets were sent, descrease allocation limit */
4601 		mutex_enter(&dp->txlock);
4602 		dp->tx_max_packets = max(dp->tx_max_packets - 1, 1);
4603 		mutex_exit(&dp->txlock);
4604 	}
4605 #endif
4606 x:
4607 	rw_exit(&dp->dev_state_lock);
4608 
4609 	return (mp);
4610 }
4611 
4612 static void
4613 usbgem_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
4614 {
4615 	struct usbgem_dev	*dp = arg;
4616 
4617 	DPRINTF(1, (CE_CONT, "!%s: %s: called",
4618 	    ((struct usbgem_dev *)arg)->name, __func__));
4619 
4620 	rw_enter(&dp->dev_state_lock, RW_READER);
4621 	usbgem_mac_ioctl((struct usbgem_dev *)arg, wq, mp);
4622 	rw_exit(&dp->dev_state_lock);
4623 }
4624 
4625 static void
4626 usbgem_gld3_init(struct usbgem_dev *dp, mac_register_t *macp)
4627 {
4628 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
4629 	macp->m_driver = dp;
4630 	macp->m_dip = dp->dip;
4631 	macp->m_src_addr = dp->dev_addr.ether_addr_octet;
4632 	macp->m_callbacks = &gem_m_callbacks;
4633 	macp->m_min_sdu = 0;
4634 	macp->m_max_sdu = dp->mtu;
4635 
4636 	if (dp->misc_flag & USBGEM_VLAN) {
4637 		macp->m_margin = VTAG_SIZE;
4638 	}
4639 }
4640 #else
4641 /* ============================================================== */
4642 /*
4643  * GLDv2 interface
4644  */
4645 /* ============================================================== */
4646 static int usbgem_gld_reset(gld_mac_info_t *);
4647 static int usbgem_gld_start(gld_mac_info_t *);
4648 static int usbgem_gld_stop(gld_mac_info_t *);
4649 static int usbgem_gld_set_mac_address(gld_mac_info_t *, uint8_t *);
4650 static int usbgem_gld_set_multicast(gld_mac_info_t *, uint8_t *, int);
4651 static int usbgem_gld_set_promiscuous(gld_mac_info_t *, int);
4652 static int usbgem_gld_get_stats(gld_mac_info_t *, struct gld_stats *);
4653 static int usbgem_gld_send(gld_mac_info_t *, mblk_t *);
4654 static int usbgem_gld_send_tagged(gld_mac_info_t *, mblk_t *, uint32_t);
4655 
4656 static int
4657 usbgem_gld_reset(gld_mac_info_t *macinfo)
4658 {
4659 	int	err;
4660 	struct usbgem_dev	*dp;
4661 
4662 	err = GLD_SUCCESS;
4663 	dp = (struct usbgem_dev *)macinfo->gldm_private;
4664 
4665 	DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4666 
4667 	rw_enter(&dp->dev_state_lock, RW_WRITER);
4668 	if (usbgem_mac_init(dp) != USB_SUCCESS) {
4669 		err = GLD_FAILURE;
4670 		goto x;
4671 	}
4672 
4673 	dp->nic_state = NIC_STATE_INITIALIZED;
4674 
4675 	/* setup media mode if the link have been up */
4676 	if (dp->mii_state == MII_STATE_LINKUP) {
4677 		if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4678 			(void) usbgem_hal_set_media(dp);
4679 		}
4680 	}
4681 x:
4682 	rw_exit(&dp->dev_state_lock);
4683 	return (err);
4684 }
4685 
4686 static int
4687 usbgem_gld_start(gld_mac_info_t *macinfo)
4688 {
4689 	int	err;
4690 	struct usbgem_dev *dp;
4691 
4692 	dp = (struct usbgem_dev *)macinfo->gldm_private;
4693 
4694 	DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4695 
4696 	rw_enter(&dp->dev_state_lock, RW_WRITER);
4697 
4698 	dp->nic_state = NIC_STATE_ONLINE;
4699 
4700 	if (dp->mii_state == MII_STATE_LINKUP) {
4701 		if (usbgem_mac_start(dp) != USB_SUCCESS) {
4702 			/* sema_v(&dp->mii_lock); */
4703 			err = GLD_FAILURE;
4704 			goto x;
4705 		}
4706 	}
4707 
4708 	/*
4709 	 * XXX - don't call gld_linkstate() here,
4710 	 * otherwise it cause recursive mutex call.
4711 	 */
4712 	err = GLD_SUCCESS;
4713 x:
4714 	rw_exit(&dp->dev_state_lock);
4715 
4716 	return (err);
4717 }
4718 
4719 static int
4720 usbgem_gld_stop(gld_mac_info_t *macinfo)
4721 {
4722 	int	err = GLD_SUCCESS;
4723 	struct usbgem_dev	*dp;
4724 
4725 	dp = (struct usbgem_dev *)macinfo->gldm_private;
4726 
4727 	DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4728 
4729 	/* try to stop rx gracefully */
4730 	rw_enter(&dp->dev_state_lock, RW_READER);
4731 	sema_p(&dp->rxfilter_lock);
4732 	dp->rxmode &= ~RXMODE_ENABLE;
4733 
4734 	if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4735 		(void) usbgem_hal_set_rx_filter(dp);
4736 	}
4737 	sema_v(&dp->rxfilter_lock);
4738 	rw_exit(&dp->dev_state_lock);
4739 
4740 	/* make the nic state inactive */
4741 	rw_enter(&dp->dev_state_lock, RW_WRITER);
4742 	dp->nic_state = NIC_STATE_STOPPED;
4743 
4744 	if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4745 		if (usbgem_mac_stop(dp, MAC_STATE_STOPPED, STOP_GRACEFUL)
4746 		    != USB_SUCCESS) {
4747 			err = GLD_FAILURE;
4748 		}
4749 	}
4750 	rw_exit(&dp->dev_state_lock);
4751 
4752 	return (err);
4753 }
4754 
4755 static int
4756 usbgem_gld_set_multicast(gld_mac_info_t *macinfo, uint8_t *ep, int flag)
4757 {
4758 	int		err;
4759 	int		ret;
4760 	struct usbgem_dev	*dp;
4761 
4762 	dp = (struct usbgem_dev *)macinfo->gldm_private;
4763 
4764 	DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4765 
4766 	rw_enter(&dp->dev_state_lock, RW_READER);
4767 	if (flag == GLD_MULTI_ENABLE) {
4768 		ret = usbgem_add_multicast(dp, ep);
4769 	} else {
4770 		ret = usbgem_remove_multicast(dp, ep);
4771 	}
4772 	rw_exit(&dp->dev_state_lock);
4773 
4774 	err = GLD_SUCCESS;
4775 	if (ret != USB_SUCCESS) {
4776 #ifdef GEM_CONFIG_FMA
4777 		ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4778 #endif
4779 		err = GLD_FAILURE;
4780 	}
4781 	return (err);
4782 }
4783 
4784 static int
4785 usbgem_gld_set_promiscuous(gld_mac_info_t *macinfo, int flag)
4786 {
4787 	boolean_t	need_to_change = B_TRUE;
4788 	struct usbgem_dev	*dp;
4789 
4790 	dp = (struct usbgem_dev *)macinfo->gldm_private;
4791 
4792 	DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4793 
4794 	sema_p(&dp->rxfilter_lock);
4795 	if (flag == GLD_MAC_PROMISC_NONE) {
4796 		dp->rxmode &= ~(RXMODE_PROMISC | RXMODE_ALLMULTI_REQ);
4797 	} else if (flag == GLD_MAC_PROMISC_MULTI) {
4798 		dp->rxmode |= RXMODE_ALLMULTI_REQ;
4799 	} else if (flag == GLD_MAC_PROMISC_PHYS) {
4800 		dp->rxmode |= RXMODE_PROMISC;
4801 	} else {
4802 		/* mode unchanged */
4803 		need_to_change = B_FALSE;
4804 	}
4805 
4806 	if (need_to_change) {
4807 		if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4808 			(void) usbgem_hal_set_rx_filter(dp);
4809 		}
4810 	}
4811 	sema_v(&dp->rxfilter_lock);
4812 
4813 	return (GLD_SUCCESS);
4814 }
4815 
4816 static int
4817 usbgem_gld_set_mac_address(gld_mac_info_t *macinfo, uint8_t *mac)
4818 {
4819 	struct usbgem_dev	*dp;
4820 	dp = (struct usbgem_dev *)macinfo->gldm_private;
4821 
4822 	DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4823 
4824 	sema_p(&dp->rxfilter_lock);
4825 	bcopy(mac, dp->cur_addr.ether_addr_octet, ETHERADDRL);
4826 	dp->rxmode |= RXMODE_ENABLE;
4827 
4828 	if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4829 		(void) usbgem_hal_set_rx_filter(dp);
4830 	}
4831 	sema_v(&dp->rxfilter_lock);
4832 
4833 	return (GLD_SUCCESS);
4834 }
4835 
4836 static	int
4837 usbgem_gld_get_stats(gld_mac_info_t *macinfo, struct gld_stats *gs)
4838 {
4839 	struct usbgem_dev	*dp;
4840 	struct usbgem_stats	*vs;
4841 
4842 	dp = (struct usbgem_dev *)macinfo->gldm_private;
4843 
4844 	if ((*dp->ugc.usbgc_get_stats)(dp) != USB_SUCCESS) {
4845 #ifdef GEM_CONFIG_FMA
4846 		ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4847 #endif
4848 		return (USB_FAILURE);
4849 	}
4850 
4851 	vs = &dp->stats;
4852 
4853 	gs->glds_errxmt = vs->errxmt;
4854 	gs->glds_errrcv = vs->errrcv;
4855 	gs->glds_collisions = vs->collisions;
4856 
4857 	gs->glds_excoll = vs->excoll;
4858 	gs->glds_defer = vs->defer;
4859 	gs->glds_frame = vs->frame;
4860 	gs->glds_crc = vs->crc;
4861 
4862 	gs->glds_overflow = vs->overflow; /* fifo err,underrun,rbufovf */
4863 	gs->glds_underflow = vs->underflow;
4864 	gs->glds_short = vs->runt;
4865 	gs->glds_missed = vs->missed; /* missed pkts while rbuf ovf */
4866 	gs->glds_xmtlatecoll = vs->xmtlatecoll;
4867 	gs->glds_nocarrier = vs->nocarrier;
4868 	gs->glds_norcvbuf = vs->norcvbuf;	/* OS resource exaust */
4869 	gs->glds_intr = vs->intr;
4870 
4871 	/* all before here must be kept in place for v0 compatibility */
4872 	gs->glds_speed = usbgem_speed_value[dp->speed] * 1000000;
4873 	gs->glds_media = GLDM_PHYMII;
4874 	gs->glds_duplex = dp->full_duplex ? GLD_DUPLEX_FULL : GLD_DUPLEX_HALF;
4875 
4876 	/* gs->glds_media_specific */
4877 	gs->glds_dot3_first_coll = vs->first_coll;
4878 	gs->glds_dot3_multi_coll = vs->multi_coll;
4879 	gs->glds_dot3_sqe_error = 0;
4880 	gs->glds_dot3_mac_xmt_error = 0;
4881 	gs->glds_dot3_mac_rcv_error = 0;
4882 	gs->glds_dot3_frame_too_long = vs->frame_too_long;
4883 
4884 	return (GLD_SUCCESS);
4885 }
4886 
4887 static int
4888 usbgem_gld_ioctl(gld_mac_info_t *macinfo, queue_t *wq, mblk_t *mp)
4889 {
4890 	struct usbgem_dev	*dp;
4891 
4892 	dp = (struct usbgem_dev *)macinfo->gldm_private;
4893 	usbgem_mac_ioctl(dp, wq, mp);
4894 
4895 	return (GLD_SUCCESS);
4896 }
4897 
4898 /*
4899  * gem_gld_send is used only for sending data packets into ethernet wire.
4900  */
4901 static int
4902 usbgem_gld_send(gld_mac_info_t *macinfo, mblk_t *mp)
4903 {
4904 	int		ret;
4905 	uint32_t	flags = 0;
4906 	struct usbgem_dev	*dp;
4907 
4908 	dp = (struct usbgem_dev *)macinfo->gldm_private;
4909 
4910 	/* nic state must be online of suspended */
4911 	rw_enter(&dp->dev_state_lock, RW_READER);
4912 
4913 	ASSERT(dp->nic_state == NIC_STATE_ONLINE);
4914 	ASSERT(mp->b_next == NULL);
4915 
4916 	if (dp->mii_state != MII_STATE_LINKUP) {
4917 		/* Some nics hate to send packets while the link is down. */
4918 		/* we discard the untransmitted packets silently */
4919 		rw_exit(&dp->dev_state_lock);
4920 
4921 		freemsg(mp);
4922 #ifdef GEM_CONFIG_FMA
4923 		/* FIXME - should we ignore the error? */
4924 		ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4925 #endif
4926 		return (GLD_SUCCESS);
4927 	}
4928 
4929 	ret = (usbgem_send_common(dp, mp, flags) == NULL)
4930 	    ? GLD_SUCCESS : GLD_NORESOURCES;
4931 	rw_exit(&dp->dev_state_lock);
4932 
4933 	return (ret);
4934 }
4935 
4936 /*
4937  * usbgem_gld_send is used only for sending data packets into ethernet wire.
4938  */
4939 static int
4940 usbgem_gld_send_tagged(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t vtag)
4941 {
4942 	uint32_t	flags;
4943 	struct usbgem_dev	*dp;
4944 
4945 	dp = (struct usbgem_dev *)macinfo->gldm_private;
4946 
4947 	/*
4948 	 * Some nics hate to send packets while the link is down.
4949 	 */
4950 	if (dp->mii_state != MII_STATE_LINKUP) {
4951 		/* we dicard the untransmitted packets silently */
4952 		freemsg(mp);
4953 #ifdef GEM_CONFIG_FMA
4954 		/* FIXME - should we ignore the error? */
4955 		ddi_fm_service_impact(dp->dip, DDI_SERVICE_UNAFFECTED);
4956 #endif
4957 		return (GLD_SUCCESS);
4958 	}
4959 #ifdef notyet
4960 	flags = GLD_VTAG_TCI(vtag) << GEM_SEND_VTAG_SHIFT;
4961 #endif
4962 	return ((usbgem_send_common(dp, mp, 0) == NULL) ?
4963 	    GLD_SUCCESS : GLD_NORESOURCES);
4964 }
4965 
4966 static void
4967 usbgem_gld_init(struct usbgem_dev *dp, gld_mac_info_t *macinfo, char *ident)
4968 {
4969 	/*
4970 	 * configure GLD
4971 	 */
4972 	macinfo->gldm_devinfo = dp->dip;
4973 	macinfo->gldm_private = (caddr_t)dp;
4974 
4975 	macinfo->gldm_reset = usbgem_gld_reset;
4976 	macinfo->gldm_start = usbgem_gld_start;
4977 	macinfo->gldm_stop = usbgem_gld_stop;
4978 	macinfo->gldm_set_mac_addr = usbgem_gld_set_mac_address;
4979 	macinfo->gldm_send = usbgem_gld_send;
4980 	macinfo->gldm_set_promiscuous = usbgem_gld_set_promiscuous;
4981 	macinfo->gldm_get_stats = usbgem_gld_get_stats;
4982 	macinfo->gldm_ioctl = usbgem_gld_ioctl;
4983 	macinfo->gldm_set_multicast = usbgem_gld_set_multicast;
4984 	macinfo->gldm_intr = NULL;
4985 	macinfo->gldm_mctl = NULL;
4986 
4987 	macinfo->gldm_ident = ident;
4988 	macinfo->gldm_type = DL_ETHER;
4989 	macinfo->gldm_minpkt = 0;
4990 	macinfo->gldm_maxpkt = dp->mtu;
4991 	macinfo->gldm_addrlen = ETHERADDRL;
4992 	macinfo->gldm_saplen = -2;
4993 	macinfo->gldm_ppa = ddi_get_instance(dp->dip);
4994 #ifdef GLD_CAP_LINKSTATE
4995 	macinfo->gldm_capabilities = GLD_CAP_LINKSTATE;
4996 #endif
4997 	macinfo->gldm_vendor_addr = dp->dev_addr.ether_addr_octet;
4998 	macinfo->gldm_broadcast_addr = usbgem_bcastaddr;
4999 }
5000 #endif /* USBGEM_CONFIG_GLDv3 */
5001 
5002 
5003 /* ======================================================================== */
5004 /*
5005  * .conf interface
5006  */
5007 /* ======================================================================== */
5008 void
5009 usbgem_generate_macaddr(struct usbgem_dev *dp, uint8_t *mac)
5010 {
5011 	extern char	hw_serial[];
5012 	char		*hw_serial_p;
5013 	int		i;
5014 	uint64_t	val;
5015 	uint64_t	key;
5016 
5017 	cmn_err(CE_NOTE,
5018 	    "!%s: using temp ether address,"
5019 	    " do not use this for long time",
5020 	    dp->name);
5021 
5022 	/* prefer a fixed address for DHCP */
5023 	hw_serial_p = &hw_serial[0];
5024 	val = stoi(&hw_serial_p);
5025 
5026 	key = 0;
5027 	for (i = 0; i < USBGEM_NAME_LEN; i++) {
5028 		if (dp->name[i] == 0) {
5029 			break;
5030 		}
5031 		key ^= dp->name[i];
5032 	}
5033 	key ^= ddi_get_instance(dp->dip);
5034 	val ^= key << 32;
5035 
5036 	/* generate a local address */
5037 	mac[0] = 0x02;
5038 	mac[1] = (uint8_t)(val >> 32);
5039 	mac[2] = (uint8_t)(val >> 24);
5040 	mac[3] = (uint8_t)(val >> 16);
5041 	mac[4] = (uint8_t)(val >> 8);
5042 	mac[5] = (uint8_t)val;
5043 }
5044 
5045 boolean_t
5046 usbgem_get_mac_addr_conf(struct usbgem_dev *dp)
5047 {
5048 	char		propname[32];
5049 	char		*valstr;
5050 	uint8_t		mac[ETHERADDRL];
5051 	char		*cp;
5052 	int		c;
5053 	int		i;
5054 	int		j;
5055 	uint8_t		v;
5056 	uint8_t		d;
5057 	uint8_t		ored;
5058 
5059 	DPRINTF(3, (CE_CONT, "!%s: %s: called", dp->name, __func__));
5060 	/*
5061 	 * Get ethernet address from .conf file
5062 	 */
5063 	(void) sprintf(propname, "mac-addr");
5064 	if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, dp->dip,
5065 	    DDI_PROP_DONTPASS, propname, &valstr)) != DDI_PROP_SUCCESS) {
5066 		return (B_FALSE);
5067 	}
5068 
5069 	if (strlen(valstr) != ETHERADDRL*3-1) {
5070 		goto syntax_err;
5071 	}
5072 
5073 	cp = valstr;
5074 	j = 0;
5075 	ored = 0;
5076 	for (;;) {
5077 		v = 0;
5078 		for (i = 0; i < 2; i++) {
5079 			c = *cp++;
5080 
5081 			if (c >= 'a' && c <= 'f') {
5082 				d = c - 'a' + 10;
5083 			} else if (c >= 'A' && c <= 'F') {
5084 				d = c - 'A' + 10;
5085 			} else if (c >= '0' && c <= '9') {
5086 				d = c - '0';
5087 			} else {
5088 				goto syntax_err;
5089 			}
5090 			v = (v << 4) | d;
5091 		}
5092 
5093 		mac[j++] = v;
5094 		ored |= v;
5095 		if (j == ETHERADDRL) {
5096 			/* done */
5097 			break;
5098 		}
5099 
5100 		c = *cp++;
5101 		if (c != ':') {
5102 			goto syntax_err;
5103 		}
5104 	}
5105 
5106 	if (ored == 0) {
5107 		usbgem_generate_macaddr(dp, mac);
5108 	}
5109 	for (i = 0; i < ETHERADDRL; i++) {
5110 		dp->dev_addr.ether_addr_octet[i] = mac[i];
5111 	}
5112 	ddi_prop_free(valstr);
5113 	return (B_TRUE);
5114 
5115 syntax_err:
5116 	cmn_err(CE_CONT,
5117 	    "!%s: read mac addr: trying .conf: syntax err %s",
5118 	    dp->name, valstr);
5119 	ddi_prop_free(valstr);
5120 
5121 	return (B_FALSE);
5122 }
5123 
5124 static void
5125 usbgem_read_conf(struct usbgem_dev *dp)
5126 {
5127 	int	val;
5128 
5129 	DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
5130 
5131 	/*
5132 	 * Get media mode infomation from .conf file
5133 	 */
5134 	dp->anadv_autoneg = usbgem_prop_get_int(dp, "adv_autoneg_cap", 1) != 0;
5135 	dp->anadv_1000fdx = usbgem_prop_get_int(dp, "adv_1000fdx_cap", 1) != 0;
5136 	dp->anadv_1000hdx = usbgem_prop_get_int(dp, "adv_1000hdx_cap", 1) != 0;
5137 	dp->anadv_100t4 = usbgem_prop_get_int(dp, "adv_100T4_cap", 1) != 0;
5138 	dp->anadv_100fdx = usbgem_prop_get_int(dp, "adv_100fdx_cap", 1) != 0;
5139 	dp->anadv_100hdx = usbgem_prop_get_int(dp, "adv_100hdx_cap", 1) != 0;
5140 	dp->anadv_10fdx = usbgem_prop_get_int(dp, "adv_10fdx_cap", 1) != 0;
5141 	dp->anadv_10hdx = usbgem_prop_get_int(dp, "adv_10hdx_cap", 1) != 0;
5142 	dp->anadv_1000t_ms = usbgem_prop_get_int(dp, "adv_1000t_ms", 0);
5143 
5144 	if ((ddi_prop_exists(DDI_DEV_T_ANY, dp->dip,
5145 	    DDI_PROP_DONTPASS, "full-duplex"))) {
5146 		dp->full_duplex =
5147 		    usbgem_prop_get_int(dp, "full-duplex", 1) != 0;
5148 		dp->anadv_autoneg = B_FALSE;
5149 		if (dp->full_duplex) {
5150 			dp->anadv_1000hdx = B_FALSE;
5151 			dp->anadv_100hdx = B_FALSE;
5152 			dp->anadv_10hdx = B_FALSE;
5153 		} else {
5154 			dp->anadv_1000fdx = B_FALSE;
5155 			dp->anadv_100fdx = B_FALSE;
5156 			dp->anadv_10fdx = B_FALSE;
5157 		}
5158 	}
5159 
5160 	if ((val = usbgem_prop_get_int(dp, "speed", 0)) > 0) {
5161 		dp->anadv_autoneg = B_FALSE;
5162 		switch (val) {
5163 		case 1000:
5164 			dp->speed = USBGEM_SPD_1000;
5165 			dp->anadv_100t4 = B_FALSE;
5166 			dp->anadv_100fdx = B_FALSE;
5167 			dp->anadv_100hdx = B_FALSE;
5168 			dp->anadv_10fdx = B_FALSE;
5169 			dp->anadv_10hdx = B_FALSE;
5170 			break;
5171 		case 100:
5172 			dp->speed = USBGEM_SPD_100;
5173 			dp->anadv_1000fdx = B_FALSE;
5174 			dp->anadv_1000hdx = B_FALSE;
5175 			dp->anadv_10fdx = B_FALSE;
5176 			dp->anadv_10hdx = B_FALSE;
5177 			break;
5178 		case 10:
5179 			dp->speed = USBGEM_SPD_10;
5180 			dp->anadv_1000fdx = B_FALSE;
5181 			dp->anadv_1000hdx = B_FALSE;
5182 			dp->anadv_100t4 = B_FALSE;
5183 			dp->anadv_100fdx = B_FALSE;
5184 			dp->anadv_100hdx = B_FALSE;
5185 			break;
5186 		default:
5187 			cmn_err(CE_WARN,
5188 			    "!%s: property %s: illegal value:%d",
5189 			    dp->name, "speed", val);
5190 			dp->anadv_autoneg = B_TRUE;
5191 			break;
5192 		}
5193 	}
5194 	val = usbgem_prop_get_int(dp,
5195 	    "adv_pause", dp->ugc.usbgc_flow_control & 1);
5196 	val |= usbgem_prop_get_int(dp,
5197 	    "adv_asmpause", BOOLEAN(dp->ugc.usbgc_flow_control & 2)) << 1;
5198 	if (val > FLOW_CONTROL_RX_PAUSE || val < FLOW_CONTROL_NONE) {
5199 		cmn_err(CE_WARN,
5200 		    "!%s: property %s: illegal value:%d",
5201 		    dp->name, "flow-control", val);
5202 	} else {
5203 		val = min(val, dp->ugc.usbgc_flow_control);
5204 	}
5205 	dp->anadv_pause = BOOLEAN(val & 1);
5206 	dp->anadv_asmpause = BOOLEAN(val & 2);
5207 
5208 	dp->mtu = usbgem_prop_get_int(dp, "mtu", dp->mtu);
5209 	dp->txthr = usbgem_prop_get_int(dp, "txthr", dp->txthr);
5210 	dp->rxthr = usbgem_prop_get_int(dp, "rxthr", dp->rxthr);
5211 	dp->txmaxdma = usbgem_prop_get_int(dp, "txmaxdma", dp->txmaxdma);
5212 	dp->rxmaxdma = usbgem_prop_get_int(dp, "rxmaxdma", dp->rxmaxdma);
5213 #ifdef GEM_CONFIG_POLLING
5214 	dp->poll_pkt_delay =
5215 	    usbgem_prop_get_int(dp, "pkt_delay", dp->poll_pkt_delay);
5216 
5217 	dp->max_poll_interval[GEM_SPD_10] =
5218 	    usbgem_prop_get_int(dp, "max_poll_interval_10",
5219 	    dp->max_poll_interval[GEM_SPD_10]);
5220 	dp->max_poll_interval[GEM_SPD_100] =
5221 	    usbgem_prop_get_int(dp, "max_poll_interval_100",
5222 	    dp->max_poll_interval[GEM_SPD_100]);
5223 	dp->max_poll_interval[GEM_SPD_1000] =
5224 	    usbgem_prop_get_int(dp, "max_poll_interval_1000",
5225 	    dp->max_poll_interval[GEM_SPD_1000]);
5226 
5227 	dp->min_poll_interval[GEM_SPD_10] =
5228 	    usbgem_prop_get_int(dp, "min_poll_interval_10",
5229 	    dp->min_poll_interval[GEM_SPD_10]);
5230 	dp->min_poll_interval[GEM_SPD_100] =
5231 	    usbgem_prop_get_int(dp, "min_poll_interval_100",
5232 	    dp->min_poll_interval[GEM_SPD_100]);
5233 	dp->min_poll_interval[GEM_SPD_1000] =
5234 	    usbgem_prop_get_int(dp, "min_poll_interval_1000",
5235 	    dp->min_poll_interval[GEM_SPD_1000]);
5236 #endif
5237 }
5238 
5239 /*
5240  * usbem kstat support
5241  */
5242 #ifndef GEM_CONFIG_GLDv3
5243 /* kstat items based from dmfe driver */
5244 
5245 struct usbgem_kstat_named {
5246 	struct kstat_named	ks_xcvr_addr;
5247 	struct kstat_named	ks_xcvr_id;
5248 	struct kstat_named	ks_xcvr_inuse;
5249 	struct kstat_named	ks_link_up;
5250 	struct kstat_named	ks_link_duplex;	/* 0:unknwon, 1:half, 2:full */
5251 	struct kstat_named	ks_cap_1000fdx;
5252 	struct kstat_named	ks_cap_1000hdx;
5253 	struct kstat_named	ks_cap_100fdx;
5254 	struct kstat_named	ks_cap_100hdx;
5255 	struct kstat_named	ks_cap_10fdx;
5256 	struct kstat_named	ks_cap_10hdx;
5257 #ifdef NEVER
5258 	struct kstat_named	ks_cap_remfault;
5259 #endif
5260 	struct kstat_named	ks_cap_autoneg;
5261 
5262 	struct kstat_named	ks_adv_cap_1000fdx;
5263 	struct kstat_named	ks_adv_cap_1000hdx;
5264 	struct kstat_named	ks_adv_cap_100fdx;
5265 	struct kstat_named	ks_adv_cap_100hdx;
5266 	struct kstat_named	ks_adv_cap_10fdx;
5267 	struct kstat_named	ks_adv_cap_10hdx;
5268 #ifdef NEVER
5269 	struct kstat_named	ks_adv_cap_remfault;
5270 #endif
5271 	struct kstat_named	ks_adv_cap_autoneg;
5272 	struct kstat_named	ks_lp_cap_1000fdx;
5273 	struct kstat_named	ks_lp_cap_1000hdx;
5274 	struct kstat_named	ks_lp_cap_100fdx;
5275 	struct kstat_named	ks_lp_cap_100hdx;
5276 	struct kstat_named	ks_lp_cap_10fdx;
5277 	struct kstat_named	ks_lp_cap_10hdx;
5278 	struct kstat_named	ks_lp_cap_remfault;
5279 	struct kstat_named	ks_lp_cap_autoneg;
5280 };
5281 
5282 static int
5283 usbgem_kstat_update(kstat_t *ksp, int rw)
5284 {
5285 	struct usbgem_kstat_named *knp;
5286 	struct usbgem_dev *dp = (struct usbgem_dev *)ksp->ks_private;
5287 
5288 	if (rw != KSTAT_READ) {
5289 		return (0);
5290 	}
5291 
5292 	knp = (struct usbgem_kstat_named *)ksp->ks_data;
5293 
5294 	knp->ks_xcvr_addr.value.ul = dp->mii_phy_addr;
5295 	knp->ks_xcvr_id.value.ul = dp->mii_phy_id;
5296 	knp->ks_xcvr_inuse.value.ul = usbgem_mac_xcvr_inuse(dp);
5297 	knp->ks_link_up.value.ul = dp->mii_state == MII_STATE_LINKUP;
5298 	knp->ks_link_duplex.value.ul =
5299 	    (dp->mii_state == MII_STATE_LINKUP) ?
5300 	    (dp->full_duplex ? 2 : 1) : 0;
5301 
5302 	knp->ks_cap_1000fdx.value.ul =
5303 	    (dp->mii_xstatus & MII_XSTATUS_1000BASET_FD) ||
5304 	    (dp->mii_xstatus & MII_XSTATUS_1000BASEX_FD);
5305 	knp->ks_cap_1000hdx.value.ul =
5306 	    (dp->mii_xstatus & MII_XSTATUS_1000BASET) ||
5307 	    (dp->mii_xstatus & MII_XSTATUS_1000BASEX);
5308 	knp->ks_cap_100fdx.value.ul =
5309 	    BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD);
5310 	knp->ks_cap_100hdx.value.ul =
5311 	    BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX);
5312 	knp->ks_cap_10fdx.value.ul =
5313 	    BOOLEAN(dp->mii_status & MII_STATUS_10_FD);
5314 	knp->ks_cap_10hdx.value.ul =
5315 	    BOOLEAN(dp->mii_status & MII_STATUS_10);
5316 #ifdef NEVER
5317 	knp->ks_cap_remfault.value.ul = B_TRUE;
5318 #endif
5319 	knp->ks_cap_autoneg.value.ul =
5320 	    BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG);
5321 
5322 	knp->ks_adv_cap_1000fdx.value.ul = dp->anadv_1000fdx;
5323 	knp->ks_adv_cap_1000hdx.value.ul = dp->anadv_1000hdx;
5324 	knp->ks_adv_cap_100fdx.value.ul	= dp->anadv_100fdx;
5325 	knp->ks_adv_cap_100hdx.value.ul	= dp->anadv_100hdx;
5326 	knp->ks_adv_cap_10fdx.value.ul	= dp->anadv_10fdx;
5327 	knp->ks_adv_cap_10hdx.value.ul	= dp->anadv_10hdx;
5328 #ifdef NEVER
5329 	knp->ks_adv_cap_remfault.value.ul = 0;
5330 #endif
5331 	knp->ks_adv_cap_autoneg.value.ul = dp->anadv_autoneg;
5332 
5333 	knp->ks_lp_cap_1000fdx.value.ul =
5334 	    BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_FULL);
5335 	knp->ks_lp_cap_1000hdx.value.ul =
5336 	    BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_HALF);
5337 	knp->ks_lp_cap_100fdx.value.ul =
5338 	    BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX_FD);
5339 	knp->ks_lp_cap_100hdx.value.ul =
5340 	    BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX);
5341 	knp->ks_lp_cap_10fdx.value.ul =
5342 	    BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T_FD);
5343 	knp->ks_lp_cap_10hdx.value.ul =
5344 	    BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T);
5345 	knp->ks_lp_cap_remfault.value.ul =
5346 	    BOOLEAN(dp->mii_exp & MII_AN_EXP_PARFAULT);
5347 	knp->ks_lp_cap_autoneg.value.ul =
5348 	    BOOLEAN(dp->mii_exp & MII_AN_EXP_LPCANAN);
5349 
5350 	return (0);
5351 }
5352 
5353 
5354 static int
5355 usbgem_kstat_init(struct usbgem_dev *dp)
5356 {
5357 	int			i;
5358 	kstat_t			*ksp;
5359 	struct usbgem_kstat_named	*knp;
5360 
5361 	ksp = kstat_create(
5362 	    (char *)ddi_driver_name(dp->dip), ddi_get_instance(dp->dip),
5363 	    "mii", "net", KSTAT_TYPE_NAMED,
5364 	    sizeof (*knp) / sizeof (knp->ks_xcvr_addr), 0);
5365 
5366 	if (ksp == NULL) {
5367 		cmn_err(CE_WARN, "%s: %s() for mii failed",
5368 		    dp->name, __func__);
5369 		return (USB_FAILURE);
5370 	}
5371 
5372 	knp = (struct usbgem_kstat_named *)ksp->ks_data;
5373 
5374 	kstat_named_init(&knp->ks_xcvr_addr, "xcvr_addr",
5375 	    KSTAT_DATA_INT32);
5376 	kstat_named_init(&knp->ks_xcvr_id, "xcvr_id",
5377 	    KSTAT_DATA_UINT32);
5378 	kstat_named_init(&knp->ks_xcvr_inuse, "xcvr_inuse",
5379 	    KSTAT_DATA_UINT32);
5380 	kstat_named_init(&knp->ks_link_up, "link_up",
5381 	    KSTAT_DATA_UINT32);
5382 	kstat_named_init(&knp->ks_link_duplex, "link_duplex",
5383 	    KSTAT_DATA_UINT32);
5384 	kstat_named_init(&knp->ks_cap_1000fdx, "cap_1000fdx",
5385 	    KSTAT_DATA_UINT32);
5386 	kstat_named_init(&knp->ks_cap_1000hdx, "cap_1000hdx",
5387 	    KSTAT_DATA_UINT32);
5388 	kstat_named_init(&knp->ks_cap_100fdx, "cap_100fdx",
5389 	    KSTAT_DATA_UINT32);
5390 	kstat_named_init(&knp->ks_cap_100hdx, "cap_100hdx",
5391 	    KSTAT_DATA_UINT32);
5392 	kstat_named_init(&knp->ks_cap_10fdx, "cap_10fdx",
5393 	    KSTAT_DATA_UINT32);
5394 	kstat_named_init(&knp->ks_cap_10hdx, "cap_10hdx",
5395 	    KSTAT_DATA_UINT32);
5396 #ifdef NEVER
5397 	kstat_named_init(&knp->ks_cap_remfault, "cap_rem_fault",
5398 	    KSTAT_DATA_UINT32);
5399 #endif
5400 	kstat_named_init(&knp->ks_cap_autoneg, "cap_autoneg",
5401 	    KSTAT_DATA_UINT32);
5402 	kstat_named_init(&knp->ks_adv_cap_1000fdx, "adv_cap_1000fdx",
5403 	    KSTAT_DATA_UINT32);
5404 	kstat_named_init(&knp->ks_adv_cap_1000hdx, "adv_cap_1000hdx",
5405 	    KSTAT_DATA_UINT32);
5406 	kstat_named_init(&knp->ks_adv_cap_100fdx, "adv_cap_100fdx",
5407 	    KSTAT_DATA_UINT32);
5408 	kstat_named_init(&knp->ks_adv_cap_100hdx, "adv_cap_100hdx",
5409 	    KSTAT_DATA_UINT32);
5410 	kstat_named_init(&knp->ks_adv_cap_10fdx, "adv_cap_10fdx",
5411 	    KSTAT_DATA_UINT32);
5412 	kstat_named_init(&knp->ks_adv_cap_10hdx, "adv_cap_10hdx",
5413 	    KSTAT_DATA_UINT32);
5414 #ifdef NEVER
5415 	kstat_named_init(&knp->ks_adv_cap_remfault, "adv_rem_fault",
5416 	    KSTAT_DATA_UINT32);
5417 #endif
5418 	kstat_named_init(&knp->ks_adv_cap_autoneg, "adv_cap_autoneg",
5419 	    KSTAT_DATA_UINT32);
5420 
5421 	kstat_named_init(&knp->ks_lp_cap_1000fdx, "lp_cap_1000fdx",
5422 	    KSTAT_DATA_UINT32);
5423 	kstat_named_init(&knp->ks_lp_cap_1000hdx, "lp_cap_1000hdx",
5424 	    KSTAT_DATA_UINT32);
5425 	kstat_named_init(&knp->ks_lp_cap_100fdx, "lp_cap_100fdx",
5426 	    KSTAT_DATA_UINT32);
5427 	kstat_named_init(&knp->ks_lp_cap_100hdx, "lp_cap_100hdx",
5428 	    KSTAT_DATA_UINT32);
5429 	kstat_named_init(&knp->ks_lp_cap_10fdx, "lp_cap_10fdx",
5430 	    KSTAT_DATA_UINT32);
5431 	kstat_named_init(&knp->ks_lp_cap_10hdx, "lp_cap_10hdx",
5432 	    KSTAT_DATA_UINT32);
5433 	kstat_named_init(&knp->ks_lp_cap_remfault, "lp_cap_rem_fault",
5434 	    KSTAT_DATA_UINT32);
5435 	kstat_named_init(&knp->ks_lp_cap_autoneg, "lp_cap_autoneg",
5436 	    KSTAT_DATA_UINT32);
5437 
5438 	ksp->ks_private = (void *) dp;
5439 	ksp->ks_update = usbgem_kstat_update;
5440 	dp->ksp = ksp;
5441 
5442 	kstat_install(ksp);
5443 
5444 	return (USB_SUCCESS);
5445 }
5446 #endif /* GEM_CONFIG_GLDv3 */
5447 /* ======================================================================== */
5448 /*
5449  * attach/detatch/usb support
5450  */
5451 /* ======================================================================== */
5452 int
5453 usbgem_ctrl_out(struct usbgem_dev *dp,
5454     uint8_t reqt, uint8_t req, uint16_t val, uint16_t ix, uint16_t len,
5455     void *bp, int size)
5456 {
5457 	mblk_t			*data;
5458 	usb_ctrl_setup_t	setup;
5459 	usb_cr_t		completion_reason;
5460 	usb_cb_flags_t		cb_flags;
5461 	usb_flags_t		flags;
5462 	int			i;
5463 	int			ret;
5464 
5465 	DPRINTF(4, (CE_CONT, "!%s: %s "
5466 	    "reqt:0x%02x req:0x%02x val:0x%04x ix:0x%04x len:0x%02x "
5467 	    "bp:0x%p nic_state:%d",
5468 	    dp->name, __func__, reqt, req, val, ix, len, bp, dp->nic_state));
5469 
5470 	if (dp->mac_state == MAC_STATE_DISCONNECTED) {
5471 		return (USB_PIPE_ERROR);
5472 	}
5473 
5474 	data = NULL;
5475 	if (size > 0) {
5476 		if ((data = allocb(size, 0)) == NULL) {
5477 			return (USB_FAILURE);
5478 		}
5479 
5480 		bcopy(bp, data->b_rptr, size);
5481 		data->b_wptr = data->b_rptr + size;
5482 	}
5483 
5484 	setup.bmRequestType = reqt;
5485 	setup.bRequest = req;
5486 	setup.wValue = val;
5487 	setup.wIndex = ix;
5488 	setup.wLength = len;
5489 	setup.attrs = 0;	/* attributes */
5490 
5491 	for (i = usbgem_ctrl_retry; i > 0; i--) {
5492 		completion_reason = 0;
5493 		cb_flags = 0;
5494 
5495 		ret = usb_pipe_ctrl_xfer_wait(DEFAULT_PIPE(dp),
5496 		    &setup, &data, &completion_reason, &cb_flags, 0);
5497 
5498 		if (ret == USB_SUCCESS) {
5499 			break;
5500 		}
5501 		if (i == 1) {
5502 			cmn_err(CE_WARN,
5503 			    "!%s: %s failed: "
5504 			    "reqt:0x%x req:0x%x val:0x%x ix:0x%x len:0x%x "
5505 			    "ret:%d cr:%s(%d), cb_flags:0x%x %s",
5506 			    dp->name, __func__, reqt, req, val, ix, len,
5507 			    ret, usb_str_cr(completion_reason),
5508 			    completion_reason,
5509 			    cb_flags,
5510 			    (i > 1) ? "retrying..." : "fatal");
5511 		}
5512 	}
5513 
5514 	if (data != NULL) {
5515 		freemsg(data);
5516 	}
5517 
5518 	return (ret);
5519 }
5520 
5521 int
5522 usbgem_ctrl_in(struct usbgem_dev *dp,
5523     uint8_t reqt, uint8_t req, uint16_t val, uint16_t ix, uint16_t len,
5524     void *bp, int size)
5525 {
5526 	mblk_t			*data;
5527 	usb_ctrl_setup_t	setup;
5528 	usb_cr_t		completion_reason;
5529 	usb_cb_flags_t		cb_flags;
5530 	int			i;
5531 	int			ret;
5532 	int			reclen;
5533 
5534 	DPRINTF(4, (CE_CONT,
5535 	    "!%s: %s:"
5536 	    " reqt:0x%02x req:0x%02x val:0x%04x ix:0x%04x len:0x%02x"
5537 	    " bp:x%p mac_state:%d",
5538 	    dp->name, __func__, reqt, req, val, ix, len, bp, dp->mac_state));
5539 
5540 	if (dp->mac_state == MAC_STATE_DISCONNECTED) {
5541 		return (USB_PIPE_ERROR);
5542 	}
5543 
5544 	data = NULL;
5545 
5546 	setup.bmRequestType = reqt;
5547 	setup.bRequest = req;
5548 	setup.wValue = val;
5549 	setup.wIndex = ix;
5550 	setup.wLength = len;
5551 	setup.attrs = USB_ATTRS_AUTOCLEARING;	/* XXX */
5552 
5553 	for (i = usbgem_ctrl_retry; i > 0; i--) {
5554 		completion_reason = 0;
5555 		cb_flags = 0;
5556 		ret = usb_pipe_ctrl_xfer_wait(DEFAULT_PIPE(dp), &setup, &data,
5557 		    &completion_reason, &cb_flags, 0);
5558 
5559 		if (ret == USB_SUCCESS) {
5560 			reclen = msgdsize(data);
5561 			bcopy(data->b_rptr, bp, min(reclen, size));
5562 			break;
5563 		}
5564 		if (i == 1) {
5565 			cmn_err(CE_WARN,
5566 			    "!%s: %s failed: "
5567 			    "reqt:0x%x req:0x%x val:0x%x ix:0x%x len:0x%x "
5568 			    "ret:%d cr:%s(%d) cb_flags:0x%x %s",
5569 			    dp->name, __func__,
5570 			    reqt, req, val, ix, len,
5571 			    ret, usb_str_cr(completion_reason),
5572 			    completion_reason,
5573 			    cb_flags,
5574 			    (i > 1) ? "retrying..." : "fatal");
5575 		}
5576 	}
5577 
5578 	if (data) {
5579 		freemsg(data);
5580 	}
5581 
5582 	return (ret);
5583 }
5584 
5585 int
5586 usbgem_ctrl_out_val(struct usbgem_dev *dp,
5587     uint8_t reqt, uint8_t req, uint16_t val, uint16_t ix, uint16_t len,
5588     uint32_t v)
5589 {
5590 	uint8_t	buf[4];
5591 
5592 	/* convert to little endian from native byte order */
5593 	switch (len) {
5594 	case 4:
5595 		buf[3] = v >> 24;
5596 		buf[2] = v >> 16;
5597 		/* FALLTHROUGH */
5598 	case 2:
5599 		buf[1] = v >> 8;
5600 		/* FALLTHROUGH */
5601 	case 1:
5602 		buf[0] = v;
5603 	}
5604 
5605 	return (usbgem_ctrl_out(dp, reqt, req, val, ix, len, buf, len));
5606 }
5607 
5608 int
5609 usbgem_ctrl_in_val(struct usbgem_dev *dp,
5610     uint8_t reqt, uint8_t req, uint16_t val, uint16_t ix, uint16_t len,
5611     void *valp)
5612 {
5613 	uint8_t		buf[4];
5614 	uint_t		v;
5615 	int		err;
5616 
5617 #ifdef SANITY
5618 	bzero(buf, sizeof (buf));
5619 #endif
5620 	err = usbgem_ctrl_in(dp, reqt, req, val, ix, len, buf, len);
5621 	if (err == USB_SUCCESS) {
5622 		v = 0;
5623 		switch (len) {
5624 		case 4:
5625 			v |= buf[3] << 24;
5626 			v |= buf[2] << 16;
5627 			/* FALLTHROUGH */
5628 		case 2:
5629 			v |= buf[1] << 8;
5630 			/* FALLTHROUGH */
5631 		case 1:
5632 			v |= buf[0];
5633 		}
5634 
5635 		switch (len) {
5636 		case 4:
5637 			*(uint32_t *)valp = v;
5638 			break;
5639 		case 2:
5640 			*(uint16_t *)valp = v;
5641 			break;
5642 		case 1:
5643 			*(uint8_t *)valp = v;
5644 			break;
5645 		}
5646 	}
5647 	return (err);
5648 }
5649 
5650 /*
5651  * Attach / detach / disconnect / reconnect management
5652  */
5653 static int
5654 usbgem_open_pipes(struct usbgem_dev *dp)
5655 {
5656 	int			i;
5657 	int			ret;
5658 	int			ifnum;
5659 	int			alt;
5660 	usb_client_dev_data_t	*reg_data;
5661 	usb_ep_data_t		*ep_tree_node;
5662 
5663 	DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
5664 
5665 	ifnum = dp->ugc.usbgc_ifnum;
5666 	alt = dp->ugc.usbgc_alt;
5667 
5668 	ep_tree_node = usb_lookup_ep_data(dp->dip, dp->reg_data, ifnum, alt,
5669 	    0, USB_EP_ATTR_BULK, USB_EP_DIR_IN);
5670 	if (ep_tree_node == NULL) {
5671 		cmn_err(CE_WARN, "!%s: %s: ep_bulkin is NULL",
5672 		    dp->name, __func__);
5673 		goto err;
5674 	}
5675 	dp->ep_bulkin = &ep_tree_node->ep_descr;
5676 
5677 	ep_tree_node = usb_lookup_ep_data(dp->dip, dp->reg_data, ifnum, alt,
5678 	    0, USB_EP_ATTR_BULK, USB_EP_DIR_OUT);
5679 	if (ep_tree_node == NULL) {
5680 		cmn_err(CE_WARN, "!%s: %s: ep_bulkout is NULL",
5681 		    dp->name, __func__);
5682 		goto err;
5683 	}
5684 	dp->ep_bulkout = &ep_tree_node->ep_descr;
5685 
5686 	ep_tree_node = usb_lookup_ep_data(dp->dip, dp->reg_data, ifnum, alt,
5687 	    0, USB_EP_ATTR_INTR, USB_EP_DIR_IN);
5688 	if (ep_tree_node) {
5689 		dp->ep_intr = &ep_tree_node->ep_descr;
5690 	} else {
5691 		/* don't care */
5692 		DPRINTF(1, (CE_CONT, "!%s: %s: ep_intr is NULL",
5693 		    dp->name, __func__));
5694 		dp->ep_intr = NULL;
5695 	}
5696 
5697 	/* XXX -- no need to open default pipe */
5698 
5699 	/* open bulk out pipe */
5700 	bzero(&dp->policy_bulkout, sizeof (usb_pipe_policy_t));
5701 	dp->policy_bulkout.pp_max_async_reqs = 1;
5702 
5703 	if ((ret = usb_pipe_open(dp->dip,
5704 	    dp->ep_bulkout, &dp->policy_bulkout, USB_FLAGS_SLEEP,
5705 	    &dp->bulkout_pipe)) != USB_SUCCESS) {
5706 		cmn_err(CE_WARN,
5707 		    "!%s: %s: err:%x: failed to open bulk-out pipe",
5708 		    dp->name, __func__, ret);
5709 		dp->bulkout_pipe = NULL;
5710 		goto err;
5711 	}
5712 	DPRINTF(1, (CE_CONT, "!%s: %s: bulkout_pipe opened successfully",
5713 	    dp->name, __func__));
5714 
5715 	/* open bulk in pipe */
5716 	bzero(&dp->policy_bulkin, sizeof (usb_pipe_policy_t));
5717 	dp->policy_bulkin.pp_max_async_reqs = 1;
5718 	if ((ret = usb_pipe_open(dp->dip,
5719 	    dp->ep_bulkin, &dp->policy_bulkin, USB_FLAGS_SLEEP,
5720 	    &dp->bulkin_pipe)) != USB_SUCCESS) {
5721 		cmn_err(CE_WARN,
5722 		    "!%s: %s: ret:%x failed to open bulk-in pipe",
5723 		    dp->name, __func__, ret);
5724 		dp->bulkin_pipe = NULL;
5725 		goto err;
5726 	}
5727 	DPRINTF(1, (CE_CONT, "!%s: %s: bulkin_pipe opened successfully",
5728 	    dp->name, __func__));
5729 
5730 	if (dp->ep_intr) {
5731 		/* open interrupt pipe */
5732 		bzero(&dp->policy_interrupt, sizeof (usb_pipe_policy_t));
5733 		dp->policy_interrupt.pp_max_async_reqs = 1;
5734 		if ((ret = usb_pipe_open(dp->dip, dp->ep_intr,
5735 		    &dp->policy_interrupt, USB_FLAGS_SLEEP,
5736 		    &dp->intr_pipe)) != USB_SUCCESS) {
5737 			cmn_err(CE_WARN,
5738 			    "!%s: %s: ret:%x failed to open interrupt pipe",
5739 			    dp->name, __func__, ret);
5740 			dp->intr_pipe = NULL;
5741 			goto err;
5742 		}
5743 	}
5744 	DPRINTF(1, (CE_CONT, "!%s: %s: intr_pipe opened successfully",
5745 	    dp->name, __func__));
5746 
5747 	return (USB_SUCCESS);
5748 
5749 err:
5750 	if (dp->bulkin_pipe) {
5751 		usb_pipe_close(dp->dip,
5752 		    dp->bulkin_pipe, USB_FLAGS_SLEEP, NULL, 0);
5753 		dp->bulkin_pipe = NULL;
5754 	}
5755 	if (dp->bulkout_pipe) {
5756 		usb_pipe_close(dp->dip,
5757 		    dp->bulkout_pipe, USB_FLAGS_SLEEP, NULL, 0);
5758 		dp->bulkout_pipe = NULL;
5759 	}
5760 	if (dp->intr_pipe) {
5761 		usb_pipe_close(dp->dip,
5762 		    dp->intr_pipe, USB_FLAGS_SLEEP, NULL, 0);
5763 		dp->intr_pipe = NULL;
5764 	}
5765 
5766 	return (USB_FAILURE);
5767 }
5768 
5769 static int
5770 usbgem_close_pipes(struct usbgem_dev *dp)
5771 {
5772 	DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
5773 
5774 	if (dp->intr_pipe) {
5775 		usb_pipe_close(dp->dip,
5776 		    dp->intr_pipe, USB_FLAGS_SLEEP, NULL, 0);
5777 		dp->intr_pipe = NULL;
5778 	}
5779 	DPRINTF(1, (CE_CONT, "!%s: %s: 1", dp->name, __func__));
5780 
5781 	ASSERT(dp->bulkin_pipe);
5782 	usb_pipe_close(dp->dip, dp->bulkin_pipe, USB_FLAGS_SLEEP, NULL, 0);
5783 	dp->bulkin_pipe = NULL;
5784 	DPRINTF(1, (CE_CONT, "!%s: %s: 2", dp->name, __func__));
5785 
5786 	ASSERT(dp->bulkout_pipe);
5787 	usb_pipe_close(dp->dip, dp->bulkout_pipe, USB_FLAGS_SLEEP, NULL, 0);
5788 	dp->bulkout_pipe = NULL;
5789 	DPRINTF(1, (CE_CONT, "!%s: %s: 3", dp->name, __func__));
5790 
5791 	return (USB_SUCCESS);
5792 }
5793 
5794 #define	FREEZE_GRACEFUL		(B_TRUE)
5795 #define	FREEZE_NO_GRACEFUL	(B_FALSE)
5796 static int
5797 usbgem_freeze_device(struct usbgem_dev *dp, boolean_t graceful)
5798 {
5799 	DPRINTF(0, (CE_NOTE, "!%s: %s: called", dp->name, __func__));
5800 
5801 	/* stop nic activity */
5802 	(void) usbgem_mac_stop(dp, MAC_STATE_DISCONNECTED, graceful);
5803 
5804 	/*
5805 	 * Here we free all memory resource allocated, because it will
5806 	 * cause to panic the system that we free usb_bulk_req objects
5807 	 * during the usb device is disconnected.
5808 	 */
5809 	(void) usbgem_free_memory(dp);
5810 
5811 	return (USB_SUCCESS);
5812 }
5813 
5814 static int
5815 usbgem_disconnect_cb(dev_info_t *dip)
5816 {
5817 	int	ret;
5818 	struct usbgem_dev	*dp;
5819 
5820 	dp = USBGEM_GET_DEV(dip);
5821 
5822 	cmn_err(CE_NOTE, "!%s: the usb device was disconnected (dp=%p)",
5823 	    dp->name, (void *)dp);
5824 
5825 	/* start serialize */
5826 	rw_enter(&dp->dev_state_lock, RW_WRITER);
5827 
5828 	ret = usbgem_freeze_device(dp, 0);
5829 
5830 	/* end of serialize */
5831 	rw_exit(&dp->dev_state_lock);
5832 
5833 	return (ret);
5834 }
5835 
5836 static int
5837 usbgem_recover_device(struct usbgem_dev	*dp)
5838 {
5839 	int	err;
5840 
5841 	DPRINTF(0, (CE_NOTE, "!%s: %s: called", dp->name, __func__));
5842 
5843 	err = USB_SUCCESS;
5844 
5845 	/* reinitialize the usb connection */
5846 	usbgem_close_pipes(dp);
5847 	if ((err = usbgem_open_pipes(dp)) != USB_SUCCESS) {
5848 		goto x;
5849 	}
5850 
5851 	/* initialize nic state */
5852 	dp->mac_state = MAC_STATE_STOPPED;
5853 	dp->mii_state = MII_STATE_UNKNOWN;
5854 
5855 	/* allocate memory resources again */
5856 	if ((err = usbgem_alloc_memory(dp)) != USB_SUCCESS) {
5857 		goto x;
5858 	}
5859 
5860 	/* restart nic and recover state */
5861 	(void) usbgem_restart_nic(dp);
5862 
5863 	usbgem_mii_init(dp);
5864 
5865 	/* kick potentially stopped house keeping thread */
5866 	cv_signal(&dp->link_watcher_wait_cv);
5867 x:
5868 	return (err);
5869 }
5870 
5871 static int
5872 usbgem_reconnect_cb(dev_info_t *dip)
5873 {
5874 	int	err = USB_SUCCESS;
5875 	struct usbgem_dev	*dp;
5876 
5877 	dp = USBGEM_GET_DEV(dip);
5878 	DPRINTF(0, (CE_CONT, "!%s: dp=%p", ddi_get_name(dip), dp));
5879 #ifdef notdef
5880 	/* check device changes after disconnect */
5881 	if (usb_check_same_device(dp->dip, NULL, USB_LOG_L2, -1,
5882 	    USB_CHK_BASIC | USB_CHK_CFG, NULL) != USB_SUCCESS) {
5883 		cmn_err(CE_CONT,
5884 		    "!%s: no or different device installed", dp->name);
5885 		return (DDI_SUCCESS);
5886 	}
5887 #endif
5888 	cmn_err(CE_NOTE, "%s: the usb device was reconnected", dp->name);
5889 
5890 	/* start serialize */
5891 	rw_enter(&dp->dev_state_lock, RW_WRITER);
5892 
5893 	if (dp->mac_state == MAC_STATE_DISCONNECTED) {
5894 		err = usbgem_recover_device(dp);
5895 	}
5896 
5897 	/* end of serialize */
5898 	rw_exit(&dp->dev_state_lock);
5899 
5900 	return (err == USB_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
5901 }
5902 
5903 int
5904 usbgem_suspend(dev_info_t *dip)
5905 {
5906 	int	err = USB_SUCCESS;
5907 	struct usbgem_dev	*dp;
5908 
5909 	dp = USBGEM_GET_DEV(dip);
5910 
5911 	DPRINTF(0, (CE_CONT, "!%s: %s: callded", dp->name, __func__));
5912 
5913 	/* start serialize */
5914 	rw_enter(&dp->dev_state_lock, RW_WRITER);
5915 
5916 	if (dp->mac_state == MAC_STATE_DISCONNECTED) {
5917 		err = usbgem_freeze_device(dp, STOP_GRACEFUL);
5918 	}
5919 
5920 	/* end of serialize */
5921 	rw_exit(&dp->dev_state_lock);
5922 
5923 	return (err == USB_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
5924 }
5925 
5926 int
5927 usbgem_resume(dev_info_t *dip)
5928 {
5929 	int	err = USB_SUCCESS;
5930 	struct usbgem_dev	*dp;
5931 
5932 	dp = USBGEM_GET_DEV(dip);
5933 
5934 	DPRINTF(0, (CE_CONT, "!%s: %s: callded", dp->name, __func__));
5935 #ifdef notdef
5936 	/* check device changes after disconnect */
5937 	if (usb_check_same_device(dp->dip, NULL, USB_LOG_L2, -1,
5938 	    USB_CHK_BASIC | USB_CHK_CFG, NULL) != USB_SUCCESS) {
5939 		cmn_err(CE_CONT,
5940 		    "!%s: no or different device installed", dp->name);
5941 		return (DDI_SUCCESS);
5942 	}
5943 #endif
5944 	/* start serialize */
5945 	rw_enter(&dp->dev_state_lock, RW_WRITER);
5946 
5947 	if (dp->mac_state == MAC_STATE_DISCONNECTED) {
5948 		err = usbgem_recover_device(dp);
5949 	}
5950 
5951 	/* end of serialize */
5952 	rw_exit(&dp->dev_state_lock);
5953 
5954 	return (err == USB_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
5955 }
5956 
5957 #define	USBGEM_LOCAL_DATA_SIZE(gc)	\
5958 	(sizeof (struct usbgem_dev) + USBGEM_MCALLOC)
5959 
5960 struct usbgem_dev *
5961 usbgem_do_attach(dev_info_t *dip,
5962     struct usbgem_conf *gc, void *lp, int lmsize)
5963 {
5964 	struct usbgem_dev	*dp;
5965 	int			i;
5966 #ifdef USBGEM_CONFIG_GLDv3
5967 	mac_register_t		*macp = NULL;
5968 #else
5969 	gld_mac_info_t		*macinfo;
5970 	void			*tmp;
5971 #endif
5972 	int			ret;
5973 	int			unit;
5974 	int			err;
5975 
5976 	unit = ddi_get_instance(dip);
5977 
5978 	DPRINTF(2, (CE_CONT, "!usbgem%d: %s: called", unit, __func__));
5979 
5980 	/*
5981 	 * Allocate soft data structure
5982 	 */
5983 	dp = kmem_zalloc(USBGEM_LOCAL_DATA_SIZE(gc), KM_SLEEP);
5984 	if (dp == NULL) {
5985 #ifndef USBGEM_CONFIG_GLDv3
5986 		gld_mac_free(macinfo);
5987 #endif
5988 		return (NULL);
5989 	}
5990 #ifdef USBGEM_CONFIG_GLDv3
5991 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
5992 		cmn_err(CE_WARN, "!gem%d: %s: mac_alloc failed",
5993 		    unit, __func__);
5994 		return (NULL);
5995 	}
5996 #else
5997 	macinfo = gld_mac_alloc(dip);
5998 	dp->macinfo = macinfo;
5999 #endif
6000 
6001 	/* link to private area */
6002 	dp->private = lp;
6003 	dp->priv_size = lmsize;
6004 	dp->mc_list = (struct mcast_addr *)&dp[1];
6005 
6006 	dp->dip = dip;
6007 	bcopy(gc->usbgc_name, dp->name, USBGEM_NAME_LEN);
6008 
6009 	/*
6010 	 * register with usb service
6011 	 */
6012 	if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
6013 		cmn_err(CE_WARN,
6014 		    "%s: %s: usb_client_attach failed",
6015 		    dp->name, __func__);
6016 		goto err_free_private;
6017 	}
6018 
6019 	if (usb_get_dev_data(dip, &dp->reg_data,
6020 	    USB_PARSE_LVL_ALL, 0) != USB_SUCCESS) {
6021 		dp->reg_data = NULL;
6022 		goto err_unregister_client;
6023 	}
6024 #ifdef USBGEM_DEBUG_LEVEL
6025 	usb_print_descr_tree(dp->dip, dp->reg_data);
6026 #endif
6027 
6028 	if (usbgem_open_pipes(dp) != USB_SUCCESS) {
6029 		/* failed to open pipes */
6030 		cmn_err(CE_WARN, "!%s: %s: failed to open pipes",
6031 		    dp->name, __func__);
6032 		goto err_unregister_client;
6033 	}
6034 
6035 	/*
6036 	 * Initialize mutexs and condition variables
6037 	 */
6038 	mutex_init(&dp->rxlock, NULL, MUTEX_DRIVER, NULL);
6039 	mutex_init(&dp->txlock, NULL, MUTEX_DRIVER, NULL);
6040 	cv_init(&dp->rx_drain_cv, NULL, CV_DRIVER, NULL);
6041 	cv_init(&dp->tx_drain_cv, NULL, CV_DRIVER, NULL);
6042 	rw_init(&dp->dev_state_lock, NULL, RW_DRIVER, NULL);
6043 	mutex_init(&dp->link_watcher_lock, NULL, MUTEX_DRIVER, NULL);
6044 	cv_init(&dp->link_watcher_wait_cv, NULL, CV_DRIVER, NULL);
6045 	sema_init(&dp->hal_op_lock, 1, NULL, SEMA_DRIVER, NULL);
6046 	sema_init(&dp->rxfilter_lock, 1, NULL, SEMA_DRIVER, NULL);
6047 
6048 	/*
6049 	 * Initialize configuration
6050 	 */
6051 	dp->ugc = *gc;
6052 
6053 	dp->mtu = ETHERMTU;
6054 	dp->rxmode = 0;
6055 	dp->speed = USBGEM_SPD_10;	/* default is 10Mbps */
6056 	dp->full_duplex = B_FALSE;	/* default is half */
6057 	dp->flow_control = FLOW_CONTROL_NONE;
6058 
6059 	dp->nic_state = NIC_STATE_STOPPED;
6060 	dp->mac_state = MAC_STATE_STOPPED;
6061 	dp->mii_state = MII_STATE_UNKNOWN;
6062 
6063 	/* performance tuning parameters */
6064 	dp->txthr = ETHERMAX;		/* tx fifo threshoold */
6065 	dp->txmaxdma = 16*4;		/* tx max dma burst size */
6066 	dp->rxthr = 128;		/* rx fifo threshoold */
6067 	dp->rxmaxdma = 16*4;		/* rx max dma burst size */
6068 
6069 	/*
6070 	 * Get media mode infomation from .conf file
6071 	 */
6072 	usbgem_read_conf(dp);
6073 
6074 	/* rx_buf_len depend on MTU */
6075 	dp->rx_buf_len = MAXPKTBUF(dp) + dp->ugc.usbgc_rx_header_len;
6076 
6077 	/*
6078 	 * Reset the chip
6079 	 */
6080 	if (usbgem_hal_reset_chip(dp) != USB_SUCCESS) {
6081 		cmn_err(CE_WARN,
6082 		    "!%s: %s: failed to reset the usb device",
6083 		    dp->name, __func__);
6084 		goto err_destroy_locks;
6085 	}
6086 
6087 	/*
6088 	 * HW dependant paremeter initialization
6089 	 */
6090 	if (usbgem_hal_attach_chip(dp) != USB_SUCCESS) {
6091 		cmn_err(CE_WARN,
6092 		    "!%s: %s: failed to attach the usb device",
6093 		    dp->name, __func__);
6094 		goto err_destroy_locks;
6095 	}
6096 
6097 	/* allocate resources */
6098 	if (usbgem_alloc_memory(dp) != USB_SUCCESS) {
6099 		goto err_destroy_locks;
6100 	}
6101 
6102 	DPRINTF(0, (CE_CONT,
6103 	    "!%s: %02x:%02x:%02x:%02x:%02x:%02x",
6104 	    dp->name,
6105 	    dp->dev_addr.ether_addr_octet[0],
6106 	    dp->dev_addr.ether_addr_octet[1],
6107 	    dp->dev_addr.ether_addr_octet[2],
6108 	    dp->dev_addr.ether_addr_octet[3],
6109 	    dp->dev_addr.ether_addr_octet[4],
6110 	    dp->dev_addr.ether_addr_octet[5]));
6111 
6112 	/* copy mac address */
6113 	dp->cur_addr = dp->dev_addr;
6114 
6115 	/* pre-calculated tx timeout in second for performance */
6116 	dp->bulkout_timeout =
6117 	    dp->ugc.usbgc_tx_timeout / drv_usectohz(1000*1000);
6118 
6119 #ifdef USBGEM_CONFIG_GLDv3
6120 	usbgem_gld3_init(dp, macp);
6121 #else
6122 	usbgem_gld_init(dp, macinfo, ident);
6123 #endif
6124 
6125 	/* Probe MII phy (scan phy) */
6126 	dp->mii_lpable = 0;
6127 	dp->mii_advert = 0;
6128 	dp->mii_exp = 0;
6129 	dp->mii_ctl1000 = 0;
6130 	dp->mii_stat1000 = 0;
6131 
6132 	dp->mii_status_ro = 0;
6133 	dp->mii_xstatus_ro = 0;
6134 
6135 	if (usbgem_mii_probe(dp) != USB_SUCCESS) {
6136 		cmn_err(CE_WARN, "!%s: %s: mii_probe failed",
6137 		    dp->name, __func__);
6138 		goto err_free_memory;
6139 	}
6140 
6141 	/* mask unsupported abilities */
6142 	dp->anadv_autoneg &= BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG);
6143 	dp->anadv_1000fdx &=
6144 	    BOOLEAN(dp->mii_xstatus &
6145 	    (MII_XSTATUS_1000BASEX_FD | MII_XSTATUS_1000BASET_FD));
6146 	dp->anadv_1000hdx &=
6147 	    BOOLEAN(dp->mii_xstatus &
6148 	    (MII_XSTATUS_1000BASEX | MII_XSTATUS_1000BASET));
6149 	dp->anadv_100t4 &= BOOLEAN(dp->mii_status & MII_STATUS_100_BASE_T4);
6150 	dp->anadv_100fdx &= BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD);
6151 	dp->anadv_100hdx &= BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX);
6152 	dp->anadv_10fdx &= BOOLEAN(dp->mii_status & MII_STATUS_10_FD);
6153 	dp->anadv_10hdx &= BOOLEAN(dp->mii_status & MII_STATUS_10);
6154 
6155 	if (usbgem_mii_init(dp) != USB_SUCCESS) {
6156 		cmn_err(CE_WARN, "!%s: %s: mii_init failed",
6157 		    dp->name, __func__);
6158 		goto err_free_memory;
6159 	}
6160 
6161 	/*
6162 	 * initialize kstats including mii statistics
6163 	 */
6164 #ifdef USBGEM_CONFIG_GLDv3
6165 #ifdef USBGEM_CONFIG_ND
6166 	usbgem_nd_setup(dp);
6167 #endif
6168 #else
6169 	if (usbgem_kstat_init(dp) != USB_SUCCESS) {
6170 		goto err_free_memory;
6171 	}
6172 #endif
6173 
6174 	/*
6175 	 * Add interrupt to system.
6176 	 */
6177 #ifdef USBGEM_CONFIG_GLDv3
6178 	if (ret = mac_register(macp, &dp->mh)) {
6179 		cmn_err(CE_WARN, "!%s: mac_register failed, error:%d",
6180 		    dp->name, ret);
6181 		goto err_release_stats;
6182 	}
6183 	mac_free(macp);
6184 	macp = NULL;
6185 #else
6186 	/* gld_register will corrupts driver_private */
6187 	tmp = ddi_get_driver_private(dip);
6188 	if (gld_register(dip,
6189 	    (char *)ddi_driver_name(dip), macinfo) != DDI_SUCCESS) {
6190 		cmn_err(CE_WARN, "!%s: %s: gld_register failed",
6191 		    dp->name, __func__);
6192 		ddi_set_driver_private(dip, tmp);
6193 		goto err_release_stats;
6194 	}
6195 	/* restore driver private */
6196 	ddi_set_driver_private(dip, tmp);
6197 #endif /* USBGEM_CONFIG_GLDv3 */
6198 	if (usb_register_hotplug_cbs(dip,
6199 	    usbgem_suspend, usbgem_resume) != USB_SUCCESS) {
6200 		cmn_err(CE_WARN,
6201 		    "!%s: %s: failed to register hotplug cbs",
6202 		    dp->name, __func__);
6203 		goto err_unregister_gld;
6204 	}
6205 
6206 	/* reset mii and start mii link watcher */
6207 	if (usbgem_mii_start(dp) != USB_SUCCESS) {
6208 		goto err_unregister_hotplug;
6209 	}
6210 
6211 	/* start tx watchdow watcher */
6212 	if (usbgem_tx_watcher_start(dp)) {
6213 		goto err_usbgem_mii_stop;
6214 	}
6215 
6216 	ddi_set_driver_private(dip, (caddr_t)dp);
6217 
6218 	DPRINTF(2, (CE_CONT, "!%s: %s: return: success", dp->name, __func__));
6219 
6220 	return (dp);
6221 
6222 err_usbgem_mii_stop:
6223 	usbgem_mii_stop(dp);
6224 
6225 err_unregister_hotplug:
6226 	usb_unregister_hotplug_cbs(dip);
6227 
6228 err_unregister_gld:
6229 #ifdef USBGEM_CONFIG_GLDv3
6230 	mac_unregister(dp->mh);
6231 #else
6232 	gld_unregister(macinfo);
6233 #endif
6234 
6235 err_release_stats:
6236 #ifdef USBGEM_CONFIG_GLDv3
6237 #ifdef USBGEM_CONFIG_ND
6238 	/* release NDD resources */
6239 	usbgem_nd_cleanup(dp);
6240 #endif
6241 #else
6242 	kstat_delete(dp->ksp);
6243 #endif
6244 
6245 err_free_memory:
6246 	usbgem_free_memory(dp);
6247 
6248 err_destroy_locks:
6249 	cv_destroy(&dp->tx_drain_cv);
6250 	cv_destroy(&dp->rx_drain_cv);
6251 	mutex_destroy(&dp->txlock);
6252 	mutex_destroy(&dp->rxlock);
6253 	rw_destroy(&dp->dev_state_lock);
6254 	mutex_destroy(&dp->link_watcher_lock);
6255 	cv_destroy(&dp->link_watcher_wait_cv);
6256 	sema_destroy(&dp->hal_op_lock);
6257 	sema_destroy(&dp->rxfilter_lock);
6258 
6259 err_close_pipes:
6260 	(void) usbgem_close_pipes(dp);
6261 
6262 err_unregister_client:
6263 	usb_client_detach(dp->dip, dp->reg_data);
6264 
6265 err_free_private:
6266 #ifdef USBGEM_CONFIG_GLDv3
6267 	if (macp) {
6268 		mac_free(macp);
6269 	}
6270 #else
6271 	gld_mac_free(macinfo);
6272 #endif
6273 	kmem_free((caddr_t)dp, USBGEM_LOCAL_DATA_SIZE(gc));
6274 
6275 	return (NULL);
6276 }
6277 
6278 int
6279 usbgem_do_detach(dev_info_t *dip)
6280 {
6281 	struct usbgem_dev	*dp;
6282 
6283 	dp = USBGEM_GET_DEV(dip);
6284 
6285 #ifdef USBGEM_CONFIG_GLDv3
6286 	/* unregister with gld v3 */
6287 	if (mac_unregister(dp->mh) != DDI_SUCCESS) {
6288 		return (DDI_FAILURE);
6289 	}
6290 #else
6291 	/* unregister with gld v2 */
6292 	if (gld_unregister(dp->macinfo) != DDI_SUCCESS) {
6293 		return (DDI_FAILURE);
6294 	}
6295 #endif
6296 	/* unregister with hotplug service */
6297 	usb_unregister_hotplug_cbs(dip);
6298 
6299 	/* stop tx watchdog watcher */
6300 	usbgem_tx_watcher_stop(dp);
6301 
6302 	/* stop the link manager */
6303 	usbgem_mii_stop(dp);
6304 
6305 	/* unregister with usb service */
6306 	(void) usbgem_free_memory(dp);
6307 	(void) usbgem_close_pipes(dp);
6308 	usb_client_detach(dp->dip, dp->reg_data);
6309 	dp->reg_data = NULL;
6310 
6311 	/* unregister with kernel statistics */
6312 #ifdef USBGEM_CONFIG_GLDv3
6313 #ifdef USBGEM_CONFIG_ND
6314 	/* release ndd resources */
6315 	usbgem_nd_cleanup(dp);
6316 #endif
6317 #else
6318 	/* destroy kstat objects */
6319 	kstat_delete(dp->ksp);
6320 #endif
6321 
6322 	/* release locks and condition variables */
6323 	mutex_destroy(&dp->txlock);
6324 	mutex_destroy(&dp->rxlock);
6325 	cv_destroy(&dp->tx_drain_cv);
6326 	cv_destroy(&dp->rx_drain_cv);
6327 	rw_destroy(&dp->dev_state_lock);
6328 	mutex_destroy(&dp->link_watcher_lock);
6329 	cv_destroy(&dp->link_watcher_wait_cv);
6330 	sema_destroy(&dp->hal_op_lock);
6331 	sema_destroy(&dp->rxfilter_lock);
6332 
6333 	/* release basic memory resources */
6334 #ifndef USBGEM_CONFIG_GLDv3
6335 	gld_mac_free(dp->macinfo);
6336 #endif
6337 	kmem_free((caddr_t)(dp->private), dp->priv_size);
6338 	kmem_free((caddr_t)dp, USBGEM_LOCAL_DATA_SIZE(&dp->ugc));
6339 
6340 	DPRINTF(2, (CE_CONT, "!%s: %s: return: success",
6341 	    ddi_driver_name(dip), __func__));
6342 
6343 	return (DDI_SUCCESS);
6344 }
6345 
6346 int
6347 usbgem_mod_init(struct dev_ops *dop, char *name)
6348 {
6349 #ifdef USBGEM_CONFIG_GLDv3
6350 	major_t	major;
6351 	major = ddi_name_to_major(name);
6352 	if (major == DDI_MAJOR_T_NONE) {
6353 		return (DDI_FAILURE);
6354 	}
6355 	mac_init_ops(dop, name);
6356 #endif
6357 	return (DDI_SUCCESS);
6358 }
6359 
6360 void
6361 usbgem_mod_fini(struct dev_ops *dop)
6362 {
6363 #ifdef USBGEM_CONFIG_GLDv3
6364 	mac_fini_ops(dop);
6365 #endif
6366 }
6367 
6368 int
6369 usbgem_quiesce(dev_info_t *dip)
6370 {
6371 	struct usbgem_dev	*dp;
6372 
6373 	dp = USBGEM_GET_DEV(dip);
6374 
6375 	ASSERT(dp != NULL);
6376 
6377 	if (dp->mac_state != MAC_STATE_DISCONNECTED &&
6378 	    dp->mac_state != MAC_STATE_STOPPED) {
6379 		if (usbgem_hal_stop_chip(dp) != USB_SUCCESS) {
6380 			(void) usbgem_hal_reset_chip(dp);
6381 		}
6382 	}
6383 
6384 	/* devo_quiesce() must return DDI_SUCCESS always */
6385 	return (DDI_SUCCESS);
6386 }
6387