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