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