xref: /illumos-gate/usr/src/uts/common/io/elxl/elxl.c (revision 4d9fdb46b215739778ebc12079842c9905586999)
1 /*
2  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  * Copyright 2018 Joyent, Inc.
5  */
6 
7 /*
8  * Copyright (c) 1998 The NetBSD Foundation, Inc.
9  * All rights reserved.
10  *
11  * This code is derived from software contributed to The NetBSD Foundation
12  * by Frank van der Linden.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions and the following disclaimer.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the
21  *    documentation and/or other materials provided with the distribution.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
24  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
27  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 #include <sys/varargs.h>
37 #include <sys/types.h>
38 #include <sys/modctl.h>
39 #include <sys/conf.h>
40 #include <sys/devops.h>
41 #include <sys/stream.h>
42 #include <sys/strsun.h>
43 #include <sys/cmn_err.h>
44 #include <sys/ethernet.h>
45 #include <sys/pci.h>
46 #include <sys/kmem.h>
47 #include <sys/time.h>
48 #include <sys/mii.h>
49 #include <sys/miiregs.h>
50 #include <sys/mac_ether.h>
51 #include <sys/mac_provider.h>
52 #include <sys/strsubr.h>
53 #include <sys/pattr.h>
54 #include <sys/dlpi.h>
55 #include <sys/ddi.h>
56 #include <sys/sunddi.h>
57 
58 #include <sys/vlan.h>
59 
60 #include "elxl.h"
61 
62 static boolean_t elxl_add_intr(elxl_t *);
63 static void elxl_probe_media(elxl_t *);
64 static void elxl_set_rxfilter(elxl_t *);
65 static void elxl_set_media(elxl_t *);
66 static uint16_t elxl_read_eeprom(elxl_t *, int);
67 static void elxl_init(elxl_t *);
68 static void elxl_stop(elxl_t *);
69 static void elxl_reset(elxl_t *);
70 static void elxl_getstats(elxl_t *);
71 
72 static int elxl_eeprom_busy(elxl_t *);
73 
74 static void elxl_setup_tx(elxl_t *);
75 
76 static uint16_t elxl_mii_read(void *, uint8_t, uint8_t);
77 static void elxl_mii_write(void *, uint8_t, uint8_t, uint16_t);
78 static void elxl_mii_notify(void *, link_state_t);
79 
80 static int elxl_m_stat(void *, uint_t, uint64_t *);
81 static int elxl_m_start(void *);
82 static void elxl_m_stop(void *);
83 static mblk_t *elxl_m_tx(void *, mblk_t *);
84 static int elxl_m_promisc(void *, boolean_t);
85 static int elxl_m_multicst(void *, boolean_t, const uint8_t *);
86 static int elxl_m_unicst(void *, const uint8_t *);
87 static int elxl_m_getprop(void *, const char *, mac_prop_id_t, uint_t,
88     void *);
89 static int elxl_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
90     const void *);
91 static void elxl_m_propinfo(void *, const char *, mac_prop_id_t,
92     mac_prop_info_handle_t);
93 static boolean_t elxl_m_getcapab(void *, mac_capab_t cap, void *);
94 static uint_t elxl_intr(caddr_t, caddr_t);
95 static void elxl_error(elxl_t *, char *, ...);
96 static void elxl_linkcheck(void *);
97 static int elxl_attach(dev_info_t *);
98 static void elxl_detach(elxl_t *);
99 static void elxl_suspend(elxl_t *);
100 static void elxl_resume(dev_info_t *);
101 static int elxl_ddi_attach(dev_info_t *, ddi_attach_cmd_t);
102 static int elxl_ddi_detach(dev_info_t *, ddi_detach_cmd_t);
103 static int elxl_ddi_quiesce(dev_info_t *);
104 
105 static ddi_device_acc_attr_t ex_dev_acc_attr = {
106 	DDI_DEVICE_ATTR_V0,
107 	DDI_STRUCTURE_LE_ACC,
108 	DDI_STRICTORDER_ACC
109 };
110 
111 static ddi_device_acc_attr_t ex_buf_acc_attr = {
112 	DDI_DEVICE_ATTR_V0,
113 	DDI_NEVERSWAP_ACC,
114 	DDI_STORECACHING_OK_ACC
115 };
116 
117 /*
118  * In theory buffers can have more flexible DMA attributes, but since
119  * we're just using a preallocated region with bcopy, there is little
120  * reason to allow for rougher alignment.  (Further, the 8-byte
121  * alignment can allow for more efficient bcopy and similar operations
122  * from the buffer.)
123  */
124 static ddi_dma_attr_t ex_dma_attr = {
125 	DMA_ATTR_V0,		/* dma_attr_version */
126 	0,			/* dma_attr_addr_lo */
127 	0xFFFFFFFFU,		/* dma_attr_addr_hi */
128 	0x00FFFFFFU,		/* dma_attr_count_max */
129 	8,			/* dma_attr_align */
130 	0x7F,			/* dma_attr_burstsizes */
131 	1,			/* dma_attr_minxfer */
132 	0xFFFFFFFFU,		/* dma_attr_maxxfer */
133 	0xFFFFFFFFU,		/* dma_attr_seg */
134 	1,			/* dma_attr_sgllen */
135 	1,			/* dma_attr_granular */
136 	0			/* dma_attr_flags */
137 };
138 
139 static uint8_t ex_broadcast[6] = {
140 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
141 };
142 
143 /*
144  * Structure to map media-present bits in boards to ifmedia codes and
145  * printable media names.  Used for table-driven ifmedia initialization.
146  */
147 typedef struct ex_media {
148 	int	exm_mpbit;		/* media present bit */
149 	int	exm_xcvr;		/* XCVR_SEL_* constant */
150 } ex_media_t;
151 
152 /*
153  * Media table for 3c90x chips.  Note that chips with MII have no
154  * `native' media.  This is sorted in "reverse preference".
155  */
156 static ex_media_t ex_native_media[] = {
157 	{ MEDIAOPT_AUI,		XCVR_SEL_AUI },
158 	{ MEDIAOPT_BNC,		XCVR_SEL_BNC },
159 	{ MEDIAOPT_10T,		XCVR_SEL_10T },
160 	{ MEDIAOPT_100TX,	XCVR_SEL_AUTO },	/* only 90XB */
161 	{ MEDIAOPT_100FX,	XCVR_SEL_100FX },
162 	{ MEDIAOPT_MII,		XCVR_SEL_MII },
163 	{ MEDIAOPT_100T4,	XCVR_SEL_MII },
164 	{ 0,			0 },
165 };
166 
167 
168 /*
169  * NB: There are lots of other models that *could* be supported.
170  * Specifically there are cardbus and miniPCI variants that could be
171  * easily added here, but they require special hacks and I have no
172  * access to the hardware required to verify them.  Especially they
173  * seem to require some extra work in another register window, and I
174  * have no supporting documentation.
175  */
176 static const struct ex_product {
177 	uint16_t	epp_prodid;	/* PCI product ID */
178 	const char	*epp_name;	/* device name */
179 	unsigned	epp_flags;	/* initial softc flags */
180 } ex_products[] = {
181 	{ 0x4500, "3c450-TX",		0 },
182 	{ 0x7646, "3cSOHO100-TX",	0 },
183 	{ 0x9000, "3c900-TPO",		0 },
184 	{ 0x9001, "3c900-COMBO",	0 },
185 	{ 0x9004, "3c900B-TPO",		0 },
186 	{ 0x9005, "3c900B-COMBO",	0 },
187 	{ 0x9006, "3c900B-TPC",		0 },
188 	{ 0x900a, "3c900B-FL",		0 },
189 	{ 0x9050, "3c905-TX",		0 },
190 	{ 0x9051, "3c905-T4",		0 },
191 	{ 0x9055, "3c905B-TX",		0 },
192 	{ 0x9056, "3c905B-T4",		0 },
193 	{ 0x9058, "3c905B-COMBO",	0 },
194 	{ 0x905a, "3c905B-FX",		0 },
195 	{ 0x9200, "3c905C-TX",		0 },
196 	{ 0x9201, "3c920B-EMB",		0 },
197 	{ 0x9202, "3c920B-EMB-WNM",	0 },
198 	{ 0x9800, "3c980",		0 },
199 	{ 0x9805, "3c980C-TXM",		0 },
200 
201 	{ 0, NULL, 0 },
202 };
203 
204 static char *ex_priv_prop[] = {
205 	"_media",
206 	"_available_media",
207 	NULL
208 };
209 
210 static mii_ops_t ex_mii_ops = {
211 	MII_OPS_VERSION,
212 	elxl_mii_read,
213 	elxl_mii_write,
214 	elxl_mii_notify,
215 };
216 
217 static mac_callbacks_t elxl_m_callbacks = {
218 	MC_GETCAPAB | MC_PROPERTIES,
219 	elxl_m_stat,
220 	elxl_m_start,
221 	elxl_m_stop,
222 	elxl_m_promisc,
223 	elxl_m_multicst,
224 	elxl_m_unicst,
225 	elxl_m_tx,
226 	NULL,
227 	NULL,
228 	elxl_m_getcapab,
229 	NULL,
230 	NULL,
231 	elxl_m_setprop,
232 	elxl_m_getprop,
233 	elxl_m_propinfo
234 };
235 
236 /*
237  * Stream information
238  */
239 DDI_DEFINE_STREAM_OPS(ex_devops, nulldev, nulldev,
240     elxl_ddi_attach, elxl_ddi_detach,
241     nodev, NULL, D_MP, NULL, elxl_ddi_quiesce);
242 
243 /*
244  * Module linkage information.
245  */
246 
247 static struct modldrv ex_modldrv = {
248 	&mod_driverops,			/* drv_modops */
249 	"3Com EtherLink XL",		/* drv_linkinfo */
250 	&ex_devops			/* drv_dev_ops */
251 };
252 
253 static struct modlinkage ex_modlinkage = {
254 	MODREV_1,		/* ml_rev */
255 	{ &ex_modldrv, NULL }	/* ml_linkage */
256 };
257 
258 int
259 _init(void)
260 {
261 	int	rv;
262 	mac_init_ops(&ex_devops, "elxl");
263 	if ((rv = mod_install(&ex_modlinkage)) != DDI_SUCCESS) {
264 		mac_fini_ops(&ex_devops);
265 	}
266 	return (rv);
267 }
268 
269 int
270 _fini(void)
271 {
272 	int	rv;
273 	if ((rv = mod_remove(&ex_modlinkage)) == DDI_SUCCESS) {
274 		mac_fini_ops(&ex_devops);
275 	}
276 	return (rv);
277 }
278 
279 int
280 _info(struct modinfo *modinfop)
281 {
282 	return (mod_info(&ex_modlinkage, modinfop));
283 }
284 
285 static void
286 ex_free_ring(ex_ring_t *r)
287 {
288 	for (int i = 0; i < r->r_count; i++) {
289 		ex_desc_t *ed = &r->r_desc[i];
290 		if (ed->ed_bufaddr)
291 			(void) ddi_dma_unbind_handle(ed->ed_dmah);
292 		if (ed->ed_acch)
293 			ddi_dma_mem_free(&ed->ed_acch);
294 		if (ed->ed_dmah)
295 			ddi_dma_free_handle(&ed->ed_dmah);
296 	}
297 
298 	if (r->r_paddr)
299 		(void) ddi_dma_unbind_handle(r->r_dmah);
300 	if (r->r_acch)
301 		ddi_dma_mem_free(&r->r_acch);
302 	if (r->r_dmah)
303 		ddi_dma_free_handle(&r->r_dmah);
304 
305 	kmem_free(r->r_desc, sizeof (ex_desc_t) * r->r_count);
306 	r->r_desc = NULL;
307 }
308 
309 static void
310 elxl_reset_ring(ex_ring_t *r, uint_t dir)
311 {
312 	ex_desc_t	*ed;
313 	ex_pd_t		*pd;
314 
315 	if (dir == DDI_DMA_WRITE) {
316 		/* transmit ring, not linked yet */
317 		for (int i = 0; i < r->r_count; i++) {
318 			ed = &r->r_desc[i];
319 			pd = ed->ed_pd;
320 			PUT_PD(r, pd->pd_link, 0);
321 			PUT_PD(r, pd->pd_fsh, 0);
322 			PUT_PD(r, pd->pd_len, EX_FR_LAST);
323 			PUT_PD(r, pd->pd_addr, ed->ed_bufaddr);
324 		}
325 		r->r_head = NULL;
326 		r->r_tail = NULL;
327 		r->r_avail = r->r_count;
328 	} else {
329 		/* receive is linked into a list */
330 		for (int i = 0; i < r->r_count; i++) {
331 			ed = &r->r_desc[i];
332 			pd = ed->ed_pd;
333 			PUT_PD(r, pd->pd_link, ed->ed_next->ed_descaddr);
334 			PUT_PD(r, pd->pd_status, 0);
335 			PUT_PD(r, pd->pd_len, EX_BUFSZ | EX_FR_LAST);
336 			PUT_PD(r, pd->pd_addr, ed->ed_bufaddr);
337 		}
338 		r->r_head = &r->r_desc[0];
339 		r->r_tail = NULL;
340 		r->r_avail = 0;
341 	}
342 	(void) ddi_dma_sync(r->r_dmah, 0, 0, DDI_DMA_SYNC_FORDEV);
343 }
344 
345 static boolean_t
346 ex_alloc_ring(elxl_t *sc, int count, ex_ring_t *r, uint_t dir)
347 {
348 	dev_info_t		*dip = sc->ex_dip;
349 	int			i;
350 	int			rv;
351 	size_t			len;
352 	ddi_dma_cookie_t	dmac;
353 	unsigned		ndmac;
354 
355 	r->r_count = count;
356 	r->r_desc = kmem_zalloc(sizeof (ex_desc_t) * count, KM_SLEEP);
357 
358 	rv = ddi_dma_alloc_handle(dip, &ex_dma_attr, DDI_DMA_DONTWAIT,
359 	    NULL, &r->r_dmah);
360 	if (rv != DDI_SUCCESS) {
361 		elxl_error(sc, "unable to allocate descriptor dma handle");
362 		return (B_FALSE);
363 	}
364 
365 	rv = ddi_dma_mem_alloc(r->r_dmah, count * sizeof (struct ex_pd),
366 	    &ex_dev_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
367 	    (caddr_t *)&r->r_pd, &len, &r->r_acch);
368 	if (rv != DDI_SUCCESS) {
369 		elxl_error(sc, "unable to allocate descriptor memory");
370 		return (B_FALSE);
371 	}
372 	bzero(r->r_pd, len);
373 
374 	rv = ddi_dma_addr_bind_handle(r->r_dmah, NULL,
375 	    (caddr_t)r->r_pd, len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
376 	    DDI_DMA_DONTWAIT, NULL, &dmac, &ndmac);
377 	if (rv != DDI_DMA_MAPPED) {
378 		elxl_error(sc, "unable to map descriptor memory");
379 		return (B_FALSE);
380 	}
381 	r->r_paddr = dmac.dmac_address;
382 
383 	for (i = 0; i < count; i++) {
384 		ex_desc_t	*ed = &r->r_desc[i];
385 		ex_pd_t		*pd = &r->r_pd[i];
386 
387 		ed->ed_pd = pd;
388 		ed->ed_off = (i * sizeof (ex_pd_t));
389 		ed->ed_descaddr = r->r_paddr + (i * sizeof (ex_pd_t));
390 
391 		/* Link the high level descriptors into a ring. */
392 		ed->ed_next = &r->r_desc[(i + 1) % count];
393 		ed->ed_next->ed_prev = ed;
394 
395 		rv = ddi_dma_alloc_handle(dip, &ex_dma_attr,
396 		    DDI_DMA_DONTWAIT, NULL, &ed->ed_dmah);
397 		if (rv != 0) {
398 			elxl_error(sc, "can't allocate buf dma handle");
399 			return (B_FALSE);
400 		}
401 		rv = ddi_dma_mem_alloc(ed->ed_dmah, EX_BUFSZ, &ex_buf_acc_attr,
402 		    DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, NULL, &ed->ed_buf,
403 		    &len, &ed->ed_acch);
404 		if (rv != DDI_SUCCESS) {
405 			elxl_error(sc, "unable to allocate buf memory");
406 			return (B_FALSE);
407 		}
408 		bzero(ed->ed_buf, len);
409 
410 		rv = ddi_dma_addr_bind_handle(ed->ed_dmah, NULL,
411 		    ed->ed_buf, len, dir | DDI_DMA_STREAMING,
412 		    DDI_DMA_DONTWAIT, NULL, &dmac, &ndmac);
413 		if (rv != DDI_DMA_MAPPED) {
414 			elxl_error(sc, "unable to map buf memory");
415 			return (B_FALSE);
416 		}
417 		ed->ed_bufaddr = dmac.dmac_address;
418 	}
419 
420 	elxl_reset_ring(r, dir);
421 
422 	return (B_TRUE);
423 }
424 
425 static boolean_t
426 elxl_add_intr(elxl_t *sc)
427 {
428 	dev_info_t		*dip;
429 	int			actual;
430 	uint_t			ipri;
431 
432 	int			rv;
433 
434 	dip = sc->ex_dip;
435 
436 	rv = ddi_intr_alloc(dip, &sc->ex_intrh, DDI_INTR_TYPE_FIXED,
437 	    0, 1, &actual, DDI_INTR_ALLOC_STRICT);
438 	if ((rv != DDI_SUCCESS) || (actual != 1)) {
439 		elxl_error(sc, "Unable to allocate interrupt, %d, count %d",
440 		    rv, actual);
441 		return (B_FALSE);
442 	}
443 
444 	if (ddi_intr_get_pri(sc->ex_intrh, &ipri) != DDI_SUCCESS) {
445 		elxl_error(sc, "Unable to get interrupt priority");
446 		return (B_FALSE);
447 	}
448 
449 	if (ddi_intr_add_handler(sc->ex_intrh, elxl_intr, sc, NULL) !=
450 	    DDI_SUCCESS) {
451 		elxl_error(sc, "Can't add interrupt handler");
452 		(void) ddi_intr_free(sc->ex_intrh);
453 		sc->ex_intrh = NULL;
454 		return (B_FALSE);
455 	}
456 	mutex_init(&sc->ex_intrlock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri));
457 	mutex_init(&sc->ex_txlock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri));
458 
459 	return (B_TRUE);
460 }
461 
462 static int
463 elxl_attach(dev_info_t *dip)
464 {
465 	elxl_t		*sc;
466 	mac_register_t	*macp;
467 	uint16_t	val;
468 	uint16_t	venid;
469 	uint16_t	devid;
470 	int		i;
471 
472 	sc = kmem_zalloc(sizeof (*sc), KM_SLEEP);
473 	ddi_set_driver_private(dip, sc);
474 	sc->ex_dip = dip;
475 
476 	if (pci_config_setup(dip, &sc->ex_pcih) != DDI_SUCCESS) {
477 		elxl_error(sc, "unable to setup PCI config handle");
478 		goto fail;
479 	}
480 	venid = pci_config_get16(sc->ex_pcih, PCI_CONF_VENID);
481 	devid = pci_config_get16(sc->ex_pcih, PCI_CONF_DEVID);
482 
483 	if (venid != 0x10b7) {
484 		/* Not a 3Com part! */
485 		elxl_error(sc, "Unsupported vendor id (0x%x)", venid);
486 		goto fail;
487 	}
488 	for (i = 0; ex_products[i].epp_name; i++) {
489 		if (devid == ex_products[i].epp_prodid) {
490 			cmn_err(CE_CONT, "?%s%d: 3Com %s",
491 			    ddi_driver_name(dip),
492 			    ddi_get_instance(dip),
493 			    ex_products[i].epp_name);
494 			sc->ex_conf = ex_products[i].epp_flags;
495 			break;
496 		}
497 	}
498 	if (ex_products[i].epp_name == NULL) {
499 		/* Not a produce we know how to support */
500 		elxl_error(sc, "Unsupported device id (0x%x)", devid);
501 		elxl_error(sc, "Driver may or may not function.");
502 	}
503 
504 	pci_config_put16(sc->ex_pcih, PCI_CONF_COMM,
505 	    pci_config_get16(sc->ex_pcih, PCI_CONF_COMM) |
506 	    PCI_COMM_IO | PCI_COMM_MAE | PCI_COMM_ME);
507 
508 	if (ddi_regs_map_setup(dip, 1, &sc->ex_regsva, 0, 0, &ex_dev_acc_attr,
509 	    &sc->ex_regsh) != DDI_SUCCESS) {
510 		elxl_error(sc, "Unable to map device registers");
511 		goto fail;
512 	}
513 
514 	if (!elxl_add_intr(sc)) {
515 		goto fail;
516 	}
517 
518 	elxl_reset(sc);
519 
520 	val = elxl_read_eeprom(sc, EE_OEM_ADDR_0);
521 	sc->ex_factaddr[0] = val >> 8;
522 	sc->ex_factaddr[1] = val & 0xff;
523 	val = elxl_read_eeprom(sc, EE_OEM_ADDR_1);
524 	sc->ex_factaddr[2] = val >> 8;
525 	sc->ex_factaddr[3] = val & 0xff;
526 	val = elxl_read_eeprom(sc, EE_OEM_ADDR_2);
527 	sc->ex_factaddr[4] = val >> 8;
528 	sc->ex_factaddr[5] = val & 0xff;
529 	bcopy(sc->ex_factaddr, sc->ex_curraddr, 6);
530 
531 	sc->ex_capab = elxl_read_eeprom(sc, EE_CAPABILITIES);
532 
533 	/*
534 	 * Is this a 90XB?  If bit 2 (supportsLargePackets) is set, or
535 	 * bit (supportsNoTxLength) is clear, then its a 90X.
536 	 * Otherwise its a 90XB.
537 	 */
538 	if ((sc->ex_capab & (1 << 2)) || !(sc->ex_capab & (1 << 9))) {
539 		sc->ex_conf &= ~CONF_90XB;
540 	} else {
541 		sc->ex_conf |= CONF_90XB;
542 	}
543 
544 	if (!ex_alloc_ring(sc, EX_NRX, &sc->ex_rxring, DDI_DMA_READ)) {
545 		goto fail;
546 	}
547 
548 	if (!ex_alloc_ring(sc, EX_NTX, &sc->ex_txring, DDI_DMA_WRITE)) {
549 		goto fail;
550 	}
551 
552 	elxl_probe_media(sc);
553 
554 	/*
555 	 * The probe may have indicated MII!
556 	 */
557 	if (sc->ex_mediaopt & (MEDIAOPT_MII | MEDIAOPT_100TX)) {
558 		sc->ex_miih = mii_alloc(sc, sc->ex_dip, &ex_mii_ops);
559 		if (sc->ex_miih == NULL) {
560 			goto fail;
561 		}
562 		/*
563 		 * Note: The 90XB models can in theory support pause,
564 		 * but we're not enabling now due to lack of units for
565 		 * testing with.  If this is changed, make sure to
566 		 * update the code in elxl_mii_notify to set the flow
567 		 * control field in the W3_MAC_CONTROL register.
568 		 */
569 		mii_set_pauseable(sc->ex_miih, B_FALSE, B_FALSE);
570 	}
571 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
572 		elxl_error(sc, "MAC register allocation failed");
573 		goto fail;
574 	}
575 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
576 	macp->m_driver = sc;
577 	macp->m_dip = dip;
578 	macp->m_src_addr = sc->ex_curraddr;
579 	macp->m_callbacks = &elxl_m_callbacks;
580 	macp->m_min_sdu = 0;
581 	macp->m_max_sdu = ETHERMTU;
582 	macp->m_margin = VLAN_TAGSZ;
583 	macp->m_priv_props = ex_priv_prop;
584 
585 	(void) ddi_intr_enable(sc->ex_intrh);
586 
587 	if (mac_register(macp, &sc->ex_mach) == DDI_SUCCESS) {
588 
589 			/*
590 			 * Note: we don't want to start link checking
591 			 * until *after* we have added the MAC handle.
592 			 */
593 		if (sc->ex_mediaopt &
594 		    (MEDIAOPT_MASK & ~(MEDIAOPT_MII | MEDIAOPT_100TX))) {
595 
596 			/* Check non-MII link state once per second. */
597 			sc->ex_linkcheck =
598 			    ddi_periodic_add(elxl_linkcheck, sc, 10000000, 0);
599 		}
600 
601 		mac_free(macp);
602 		return (DDI_SUCCESS);
603 	}
604 
605 	mac_free(macp);
606 
607 fail:
608 	elxl_detach(sc);
609 	return (DDI_FAILURE);
610 }
611 
612 /*
613  * Find the media present on non-MII chips, and select the one to use.
614  */
615 static void
616 elxl_probe_media(elxl_t *sc)
617 {
618 	ex_media_t	*exm;
619 	uint32_t	config;
620 	uint32_t	default_media;
621 	uint16_t	media_options;
622 
623 	SET_WIN(3);
624 	config = GET32(W3_INTERNAL_CONFIG);
625 	media_options = GET16(W3_MEDIAOPT);
626 
627 	/*
628 	 * We modify the media_options field so that we have a
629 	 * consistent view of the media available, without worrying
630 	 * about the version of ASIC, etc.
631 	 */
632 
633 	/*
634 	 * 100BASE-TX is handled differently on 90XB from 90X.  Older
635 	 * parts use the external MII to provide this support.
636 	 */
637 	if (sc->ex_conf & CONF_90XB) {
638 		if (media_options & MEDIAOPT_100TX) {
639 			/*
640 			 * 3Com advises that we should only ever use the
641 			 * auto mode.  Notably, it seems that there should
642 			 * never be a 90XB board with the MEDIAOPT_10T bit set
643 			 * without this bit.  If it happens, the driver will
644 			 * run in compatible 10BASE-T only mode.
645 			 */
646 			media_options &= ~MEDIAOPT_10T;
647 		}
648 	} else {
649 		if (media_options & MEDIAOPT_100TX) {
650 			/*
651 			 * If this occurs, we really want to use it like
652 			 * an MII device.  Generally in this situation we
653 			 * want to use the MII exclusively, and there ought
654 			 * not be a 10bT transceiver.
655 			 */
656 			media_options |= MEDIAOPT_MII;
657 			media_options &= ~MEDIAOPT_100TX;
658 			media_options &= ~MEDIAOPT_10T;
659 
660 			/*
661 			 * Additionally, some of these devices map all
662 			 * internal PHY register at *every* address, not
663 			 * just the "allowed" address 24.
664 			 */
665 			sc->ex_conf |= CONF_INTPHY;
666 		}
667 		/*
668 		 * Early versions didn't have 10FL models, and used this
669 		 * bit for something else (VCO).
670 		 */
671 		media_options &= ~MEDIAOPT_10FL;
672 	}
673 	if (media_options & MEDIAOPT_100T4) {
674 		/* 100BASE-T4 units all use the MII bus. */
675 		media_options |= MEDIAOPT_MII;
676 		media_options &= ~MEDIAOPT_100T4;
677 	}
678 
679 	/* Save our media options. */
680 	sc->ex_mediaopt = media_options;
681 
682 #define	APPEND_MEDIA(str, bit, name)					\
683 	if (media_options & (bit)) {					\
684 		(void) strlcat(str, *str ? "," : "", sizeof (str));	\
685 		(void) strlcat(str, name, sizeof (str));		\
686 	}
687 
688 	APPEND_MEDIA(sc->ex_medias, (MEDIAOPT_MII|MEDIAOPT_100TX), "mii");
689 	APPEND_MEDIA(sc->ex_medias, MEDIAOPT_10T, "tp-hdx,tp-fdx");
690 	APPEND_MEDIA(sc->ex_medias, MEDIAOPT_100FX, "fx-hdx,fx-fdx");
691 	APPEND_MEDIA(sc->ex_medias, MEDIAOPT_BNC, "bnc");
692 	APPEND_MEDIA(sc->ex_medias, MEDIAOPT_AUI, "aui");
693 	APPEND_MEDIA(sc->ex_medias, MEDIAOPT_10FL, "fl-hdx,fl-fdx");
694 
695 	if (config & XCVR_SEL_100TX) {
696 		/* Only found on 90XB.  Don't use this, use AUTO instead! */
697 		config |= XCVR_SEL_AUTO;
698 		config &= ~XCVR_SEL_100TX;
699 	}
700 
701 	default_media = (config & XCVR_SEL_MASK);
702 
703 	/* Sanity check that there are any media! */
704 	if ((media_options & MEDIAOPT_MASK) == 0) {
705 		elxl_error(sc,
706 		    "No media present?  Attempting to use default.");
707 		/*
708 		 * This "default" may be non-sensical.  At worst it should
709 		 * cause a busted link.
710 		 */
711 		sc->ex_xcvr = default_media;
712 	}
713 
714 	for (exm = ex_native_media; exm->exm_mpbit != 0; exm++) {
715 		if (media_options & exm->exm_mpbit) {
716 			if (exm->exm_xcvr == default_media) {
717 				/* preferred default is present, just use it */
718 				sc->ex_xcvr = default_media;
719 				return;
720 			}
721 
722 			sc->ex_xcvr = exm->exm_xcvr;
723 			/* but keep trying for other more preferred options */
724 		}
725 	}
726 }
727 
728 /*
729  * Setup transmitter parameters.
730  */
731 static void
732 elxl_setup_tx(elxl_t *sc)
733 {
734 	/*
735 	 * Disable reclaim threshold for 90xB, set free threshold to
736 	 * 6 * 256 = 1536 for 90x.
737 	 */
738 	if (sc->ex_conf & CONF_90XB)
739 		PUT_CMD(CMD_SET_TXRECLAIM | 255);
740 	else
741 		PUT8(REG_TXFREETHRESH, 6);
742 
743 	/*
744 	 * We've seen underflows at the root cause of NIC hangs on
745 	 * older cards.  Use a store-and-forward model to prevent that.
746 	 */
747 	PUT_CMD(CMD_SET_TXSTART | EX_BUFSZ >> 2);
748 }
749 
750 /*
751  * Bring device up.
752  */
753 static void
754 elxl_init(elxl_t *sc)
755 {
756 	if (sc->ex_suspended)
757 		return;
758 
759 	WAIT_CMD(sc);
760 	elxl_stop(sc);
761 
762 	PUT_CMD(CMD_RX_RESET);
763 	WAIT_CMD(sc);
764 	PUT_CMD(CMD_TX_RESET);
765 	WAIT_CMD(sc);
766 
767 	/* Load Tx parameters. */
768 	elxl_setup_tx(sc);
769 
770 	PUT32(REG_DMACTRL, GET32(REG_DMACTRL) | DMACTRL_UPRXEAREN);
771 
772 	PUT_CMD(CMD_IND_ENABLE | INT_WATCHED);
773 	PUT_CMD(CMD_INT_ENABLE | INT_WATCHED);
774 
775 	PUT_CMD(CMD_INT_ACK | 0xff);
776 
777 	elxl_set_media(sc);
778 	elxl_set_rxfilter(sc);
779 
780 	/* Configure for VLAN tag sizing. */
781 	SET_WIN(3);
782 	if (sc->ex_conf & CONF_90XB) {
783 		PUT16(W3_MAX_PKT_SIZE, EX_BUFSZ);
784 	} else {
785 		PUT16(W3_MAC_CONTROL, GET16(W3_MAC_CONTROL) |
786 		    MAC_CONTROL_ALLOW_LARGE);
787 	}
788 
789 	PUT_CMD(CMD_SET_RXEARLY | (EX_BUFSZ >> 2));
790 
791 	PUT_CMD(CMD_STATS_ENABLE);
792 	PUT_CMD(CMD_TX_ENABLE);
793 	PUT32(REG_UPLISTPTR, sc->ex_rxring.r_paddr);
794 	PUT_CMD(CMD_RX_ENABLE);
795 	PUT_CMD(CMD_UP_UNSTALL);
796 }
797 
798 /*
799  * Set multicast receive filter. Also take care of promiscuous mode.
800  * Note that *some* of this hardware is fully capable of either a 256
801  * or 64 bit multicast hash.  However, we can't determine what the
802  * size of the hash table is easily, and so we are expected to be able
803  * to resubmit the entire list of addresses each time.  This puts an
804  * onerous burden on the driver to maintain its list of multicast
805  * addresses.  Since multicast stuff is usually not that performance
806  * sensitive, and since we don't usually have much of it, we are just
807  * going to skip it.  We allow the upper layers to filter it, as
808  * needed, by setting the all-multicast bit if the hardware can do it.
809  * This also reduces our test burden.
810  */
811 static void
812 elxl_set_rxfilter(elxl_t *sc)
813 {
814 	uint16_t mask = FILTER_UNICAST | FILTER_ALLBCAST;
815 
816 	if (sc->ex_suspended)
817 		return;
818 
819 	/*
820 	 * Set the station address and clear the station mask. The latter
821 	 * is needed for 90x cards, 0 is the default for 90xB cards.
822 	 */
823 	SET_WIN(2);
824 	for (int i = 0; i < ETHERADDRL; i++) {
825 		PUT8(W2_STATION_ADDRESS + i, sc->ex_curraddr[i]);
826 		PUT8(W2_STATION_MASK + i, 0);
827 	}
828 
829 	if (sc->ex_mccount) {
830 		mask |= FILTER_ALLMULTI;
831 	}
832 	if (sc->ex_promisc) {
833 		mask |= FILTER_PROMISC;
834 	}
835 	PUT_CMD(CMD_SET_FILTER | mask);
836 }
837 
838 static void
839 elxl_set_media(elxl_t *sc)
840 {
841 	uint32_t configreg;
842 
843 	SET_WIN(4);
844 	PUT16(W4_MEDIASTAT, 0);
845 	PUT_CMD(CMD_BNC_DISABLE);
846 	drv_usecwait(800);
847 
848 	/*
849 	 * Now turn on the selected media/transceiver.
850 	 */
851 	switch (sc->ex_xcvr) {
852 	case XCVR_SEL_10T:
853 		sc->ex_mii_active = B_FALSE;
854 		PUT16(W4_MEDIASTAT,
855 		    MEDIASTAT_JABGUARD_EN | MEDIASTAT_LINKBEAT_EN);
856 		drv_usecwait(800);
857 		break;
858 
859 	case XCVR_SEL_BNC:
860 		sc->ex_mii_active = B_FALSE;
861 		PUT_CMD(CMD_BNC_ENABLE);
862 		drv_usecwait(800);
863 		break;
864 
865 	case XCVR_SEL_100FX:
866 		sc->ex_mii_active = B_FALSE;	/* Is this really true? */
867 		PUT16(W4_MEDIASTAT, MEDIASTAT_LINKBEAT_EN);
868 		drv_usecwait(800);
869 		break;
870 
871 	case XCVR_SEL_AUI:
872 		sc->ex_mii_active = B_FALSE;
873 		PUT16(W4_MEDIASTAT, MEDIASTAT_SQE_EN);
874 		drv_usecwait(800);
875 		break;
876 
877 	case XCVR_SEL_AUTO:
878 	case XCVR_SEL_MII:
879 		/*
880 		 * This is due to paranoia.  If a card claims
881 		 * to default to MII, but doesn't have it set in
882 		 * media options, then we don't want to leave
883 		 * the MII active or we'll have problems derferencing
884 		 * the "mii handle".
885 		 */
886 		if (sc->ex_miih) {
887 			sc->ex_mii_active = B_TRUE;
888 		} else {
889 			sc->ex_mii_active = B_FALSE;
890 		}
891 		break;
892 
893 	default:
894 		sc->ex_mii_active = B_FALSE;
895 		elxl_error(sc, "Impossible media setting!");
896 		break;
897 	}
898 
899 	SET_WIN(3);
900 	configreg = GET32(W3_INTERNAL_CONFIG);
901 
902 	configreg &= ~(XCVR_SEL_MASK);
903 	configreg |= (sc->ex_xcvr);
904 
905 	PUT32(W3_INTERNAL_CONFIG, configreg);
906 
907 	/*
908 	 * If we're not using MII, force the full-duplex setting.  MII
909 	 * based modes handle the full-duplex setting via the MII
910 	 * notify callback.
911 	 */
912 	if (!sc->ex_mii_active) {
913 		uint16_t mctl;
914 		mctl = GET16(W3_MAC_CONTROL);
915 		if (sc->ex_fdx) {
916 			mctl |= MAC_CONTROL_FDX;
917 		} else {
918 			mctl &= ~MAC_CONTROL_FDX;
919 		}
920 		PUT16(W3_MAC_CONTROL, mctl);
921 	}
922 }
923 
924 /*
925  * Get currently-selected media from card.
926  * (if_media callback, may be called before interface is brought up).
927  */
928 static void
929 elxl_linkcheck(void *arg)
930 {
931 	elxl_t		*sc = arg;
932 	uint16_t	stat;
933 	link_state_t	link;
934 
935 	mutex_enter(&sc->ex_txlock);
936 	if (sc->ex_mii_active) {
937 		mutex_exit(&sc->ex_txlock);
938 		return;
939 	}
940 	if (sc->ex_running && !sc->ex_suspended) {
941 		switch (sc->ex_xcvr) {
942 		case XCVR_SEL_100FX:
943 			/* these media we can detect link on */
944 			SET_WIN(4);
945 			stat = GET16(W4_MEDIASTAT);
946 			if (stat & MEDIASTAT_LINKDETECT) {
947 				sc->ex_link = LINK_STATE_UP;
948 				sc->ex_speed = 100000000;
949 			} else {
950 				sc->ex_link = LINK_STATE_DOWN;
951 				sc->ex_speed = 0;
952 			}
953 			break;
954 
955 		case XCVR_SEL_10T:
956 			/* these media we can detect link on */
957 			SET_WIN(4);
958 			stat = GET16(W4_MEDIASTAT);
959 			if (stat & MEDIASTAT_LINKDETECT) {
960 				sc->ex_link = LINK_STATE_UP;
961 				sc->ex_speed = 10000000;
962 			} else {
963 				sc->ex_link = LINK_STATE_DOWN;
964 				sc->ex_speed = 0;
965 			}
966 			break;
967 
968 		case XCVR_SEL_BNC:
969 		case XCVR_SEL_AUI:
970 		default:
971 			/*
972 			 * For these we don't really know the answer,
973 			 * but if we lie then at least it won't cause
974 			 * ifconfig to turn off the RUNNING flag.
975 			 * This is necessary because we might
976 			 * transition from LINK_STATE_DOWN when
977 			 * switching media.
978 			 */
979 			sc->ex_speed = 10000000;
980 			sc->ex_link = LINK_STATE_UP;
981 			break;
982 		}
983 		SET_WIN(3);
984 		sc->ex_duplex = GET16(W3_MAC_CONTROL) & MAC_CONTROL_FDX ?
985 		    LINK_DUPLEX_FULL : LINK_DUPLEX_HALF;
986 	} else {
987 		sc->ex_speed = 0;
988 		sc->ex_duplex = LINK_DUPLEX_UNKNOWN;
989 		sc->ex_link = LINK_STATE_UNKNOWN;
990 	}
991 	link = sc->ex_link;
992 	mutex_exit(&sc->ex_txlock);
993 
994 	mac_link_update(sc->ex_mach, link);
995 }
996 
997 static int
998 elxl_m_promisc(void *arg, boolean_t on)
999 {
1000 	elxl_t	*sc = arg;
1001 
1002 	mutex_enter(&sc->ex_intrlock);
1003 	mutex_enter(&sc->ex_txlock);
1004 	sc->ex_promisc = on;
1005 	elxl_set_rxfilter(sc);
1006 	mutex_exit(&sc->ex_txlock);
1007 	mutex_exit(&sc->ex_intrlock);
1008 	return (0);
1009 }
1010 
1011 static int
1012 elxl_m_multicst(void *arg, boolean_t add, const uint8_t *addr)
1013 {
1014 	elxl_t	*sc = arg;
1015 
1016 	_NOTE(ARGUNUSED(addr));
1017 
1018 	mutex_enter(&sc->ex_intrlock);
1019 	mutex_enter(&sc->ex_txlock);
1020 	if (add) {
1021 		sc->ex_mccount++;
1022 		if (sc->ex_mccount == 1) {
1023 			elxl_set_rxfilter(sc);
1024 		}
1025 	} else {
1026 		sc->ex_mccount--;
1027 		if (sc->ex_mccount == 0) {
1028 			elxl_set_rxfilter(sc);
1029 		}
1030 	}
1031 	mutex_exit(&sc->ex_txlock);
1032 	mutex_exit(&sc->ex_intrlock);
1033 	return (0);
1034 }
1035 
1036 static int
1037 elxl_m_unicst(void *arg, const uint8_t *addr)
1038 {
1039 	elxl_t	*sc = arg;
1040 
1041 	mutex_enter(&sc->ex_intrlock);
1042 	mutex_enter(&sc->ex_txlock);
1043 	bcopy(addr, sc->ex_curraddr, ETHERADDRL);
1044 	elxl_set_rxfilter(sc);
1045 	mutex_exit(&sc->ex_txlock);
1046 	mutex_exit(&sc->ex_intrlock);
1047 
1048 	return (0);
1049 }
1050 
1051 static mblk_t *
1052 elxl_m_tx(void *arg, mblk_t *mp)
1053 {
1054 	elxl_t		*sc = arg;
1055 	ex_desc_t	*txd;
1056 	ex_desc_t	*first;
1057 	ex_desc_t	*tail;
1058 	size_t		len;
1059 	ex_ring_t	*r;
1060 	ex_pd_t		*pd;
1061 	uint32_t	cflags;
1062 	mblk_t		*nmp;
1063 	boolean_t	reenable = B_FALSE;
1064 	boolean_t	reset = B_FALSE;
1065 	uint32_t	paddr;
1066 
1067 	r = &sc->ex_txring;
1068 	mutex_enter(&sc->ex_txlock);
1069 	if (sc->ex_suspended) {
1070 		while (mp != NULL) {
1071 			sc->ex_nocarrier++;
1072 			nmp = mp->b_next;
1073 			freemsg(mp);
1074 			mp = nmp;
1075 		}
1076 		mutex_exit(&sc->ex_txlock);
1077 		return (NULL);
1078 	}
1079 
1080 	for (int limit = (EX_NTX * 2); limit; limit--) {
1081 		uint8_t stat = GET8(REG_TXSTATUS);
1082 		if ((stat & TXSTATUS_COMPLETE) == 0) {
1083 			break;
1084 		}
1085 		if (stat & TXSTATUS_MAXCOLLISIONS) {
1086 			reenable = B_TRUE;
1087 			sc->ex_excoll++;
1088 		}
1089 		if ((stat & TXSTATUS_ERRS) != 0) {
1090 			reset = B_TRUE;
1091 			if (stat & TXSTATUS_JABBER) {
1092 				sc->ex_jabber++;
1093 			}
1094 			if (stat & TXSTATUS_RECLAIM_ERR) {
1095 				sc->ex_txerr++;
1096 			}
1097 			if (stat & TXSTATUS_UNDERRUN) {
1098 				sc->ex_uflo++;
1099 			}
1100 		}
1101 		PUT8(REG_TXSTATUS, 0);
1102 	}
1103 
1104 	if (reset || reenable) {
1105 		paddr = GET32(REG_DNLISTPTR);
1106 		if (reset) {
1107 			WAIT_CMD(sc);
1108 			PUT_CMD(CMD_TX_RESET);
1109 			WAIT_CMD(sc);
1110 			elxl_setup_tx(sc);
1111 		}
1112 		PUT_CMD(CMD_TX_ENABLE);
1113 		if (paddr) {
1114 			PUT32(REG_DNLISTPTR, paddr);
1115 		}
1116 	}
1117 
1118 	/* first reclaim any free descriptors */
1119 	while (r->r_avail < r->r_count) {
1120 
1121 		paddr = GET32(REG_DNLISTPTR);
1122 		txd = r->r_head;
1123 		if (paddr == txd->ed_descaddr) {
1124 			/* still processing this one, we're done */
1125 			break;
1126 		}
1127 		if (paddr == 0) {
1128 			/* done processing the entire list! */
1129 			r->r_head = NULL;
1130 			r->r_tail = NULL;
1131 			r->r_avail = r->r_count;
1132 			break;
1133 		}
1134 		r->r_avail++;
1135 		r->r_head = txd->ed_next;
1136 	}
1137 
1138 	if ((r->r_avail < r->r_count) && (GET32(REG_DNLISTPTR) != 0)) {
1139 		PUT_CMD(CMD_DN_STALL);
1140 		WAIT_CMD(sc);
1141 	}
1142 
1143 	first = NULL;
1144 	tail = r->r_tail;
1145 
1146 	/*
1147 	 * If there is already a tx list, select the next desc on the list.
1148 	 * Otherwise, just pick the first descriptor.
1149 	 */
1150 	txd = tail ? tail->ed_next : &r->r_desc[0];
1151 
1152 	while ((mp != NULL) && (r->r_avail)) {
1153 
1154 		nmp = mp->b_next;
1155 
1156 		len = msgsize(mp);
1157 		if (len > (ETHERMAX + VLAN_TAGSZ)) {
1158 			sc->ex_txerr++;
1159 			freemsg(mp);
1160 			mp = nmp;
1161 			continue;
1162 		}
1163 
1164 		cflags = 0;
1165 		if ((sc->ex_conf & CONF_90XB) != 0) {
1166 			uint32_t	pflags;
1167 			mac_hcksum_get(mp, NULL, NULL, NULL, NULL, &pflags);
1168 			if (pflags & HCK_IPV4_HDRCKSUM) {
1169 				cflags |= EX_DPD_IPCKSUM;
1170 			}
1171 			if (pflags & HCK_FULLCKSUM) {
1172 				cflags |= (EX_DPD_TCPCKSUM | EX_DPD_UDPCKSUM);
1173 			}
1174 		}
1175 
1176 		/* Mark this descriptor is in use.  We're committed now. */
1177 		mcopymsg(mp, txd->ed_buf);	/* frees the mblk! */
1178 		r->r_avail--;
1179 		mp = nmp;
1180 
1181 		/* Accounting stuff. */
1182 		sc->ex_opackets++;
1183 		sc->ex_obytes += len;
1184 		if (txd->ed_buf[0] & 0x1) {
1185 			if (bcmp(txd->ed_buf, ex_broadcast, ETHERADDRL) != 0) {
1186 				sc->ex_multixmt++;
1187 			} else {
1188 				sc->ex_brdcstxmt++;
1189 			}
1190 		}
1191 
1192 		pd = txd->ed_pd;
1193 
1194 
1195 		/*
1196 		 * Zero pad the frame if its too short.  This
1197 		 * also avoids a checksum offload bug.
1198 		 */
1199 		if (len < 30) {
1200 			bzero(txd->ed_buf + len, ETHERMIN - len);
1201 			len = ETHERMIN;
1202 		}
1203 
1204 		/*
1205 		 * If this our first packet so far, record the head
1206 		 * of the list.
1207 		 */
1208 		if (first == NULL) {
1209 			first = txd;
1210 		}
1211 
1212 		(void) ddi_dma_sync(txd->ed_dmah, 0, 0, DDI_DMA_SYNC_FORDEV);
1213 
1214 		PUT_PD(r, pd->pd_link, 0);
1215 		PUT_PD(r, pd->pd_fsh, len | cflags);
1216 		PUT_PD(r, pd->pd_addr, txd->ed_bufaddr);
1217 		PUT_PD(r, pd->pd_len, len | EX_FR_LAST);
1218 
1219 		/*
1220 		 * Write the link into the previous descriptor.  Note that
1221 		 * if this is the first packet (so no previous queued), this
1222 		 * will be benign because the previous descriptor won't be
1223 		 * on any tx list.  (Furthermore, we'll clear its link field
1224 		 * when we do later use it.)
1225 		 */
1226 		PUT_PD(r, txd->ed_prev->ed_pd->pd_link, txd->ed_descaddr);
1227 	}
1228 
1229 	/*
1230 	 * Are we submitting any packets?
1231 	 */
1232 	if (first != NULL) {
1233 		/* Interrupt on the last packet. */
1234 		PUT_PD(r, pd->pd_fsh, len | cflags | EX_DPD_DNIND);
1235 
1236 		if (tail == NULL) {
1237 			/* No packets pending, so its a new list head! */
1238 			r->r_head = first;
1239 		} else {
1240 			pd = tail->ed_pd;
1241 			/* We've added frames, so don't interrupt mid-list. */
1242 			PUT_PD(r, pd->pd_fsh,
1243 			    GET_PD(r, pd->pd_fsh) & ~(EX_DPD_DNIND));
1244 		}
1245 		/* Record the last descriptor. */
1246 		r->r_tail = txd;
1247 
1248 		/* flush the entire ring - we're stopped so its safe */
1249 		(void) ddi_dma_sync(r->r_dmah, 0, 0, DDI_DMA_SYNC_FORDEV);
1250 	}
1251 
1252 	/* Restart transmitter. */
1253 	if (sc->ex_txring.r_head) {
1254 		PUT32(REG_DNLISTPTR, sc->ex_txring.r_head->ed_descaddr);
1255 	}
1256 	PUT_CMD(CMD_DN_UNSTALL);
1257 
1258 	mutex_exit(&sc->ex_txlock);
1259 
1260 	return (mp);
1261 }
1262 
1263 static mblk_t *
1264 elxl_recv(elxl_t *sc, ex_desc_t *rxd, uint32_t stat)
1265 {
1266 	mblk_t		*mp = NULL;
1267 	uint32_t	len;
1268 
1269 	len = stat & EX_UPD_PKTLENMASK;
1270 	if (stat & (EX_UPD_ERR_VLAN | EX_UPD_OVERFLOW)) {
1271 		if (stat & EX_UPD_RUNT) {
1272 			sc->ex_runt++;
1273 		}
1274 		if (stat & EX_UPD_OVERRUN) {
1275 			sc->ex_oflo++;
1276 		}
1277 		if (stat & EX_UPD_CRCERR) {
1278 			sc->ex_fcs++;
1279 		}
1280 		if (stat & EX_UPD_ALIGNERR) {
1281 			sc->ex_align++;
1282 		}
1283 		if (stat & EX_UPD_OVERFLOW) {
1284 			sc->ex_toolong++;
1285 		}
1286 		return (NULL);
1287 	}
1288 	if (len < sizeof (struct ether_header)) {
1289 		sc->ex_runt++;
1290 		return (NULL);
1291 	}
1292 	if (len > (ETHERMAX + VLAN_TAGSZ)) {
1293 		/* Allow four bytes for the VLAN header */
1294 		sc->ex_toolong++;
1295 		return (NULL);
1296 	}
1297 	if ((mp = allocb(len + 14, BPRI_HI)) == NULL) {
1298 		sc->ex_allocbfail++;
1299 		return (NULL);
1300 	}
1301 
1302 	(void) ddi_dma_sync(rxd->ed_dmah, 0, 0, DDI_DMA_SYNC_FORKERNEL);
1303 	mp->b_rptr += 14;
1304 	mp->b_wptr = mp->b_rptr + len;
1305 	bcopy(rxd->ed_buf, mp->b_rptr, len);
1306 
1307 	sc->ex_ipackets++;
1308 	sc->ex_ibytes += len;
1309 	if (rxd->ed_buf[0] & 0x1) {
1310 		if (bcmp(rxd->ed_buf, ex_broadcast, ETHERADDRL) != 0) {
1311 			sc->ex_multircv++;
1312 		} else {
1313 			sc->ex_brdcstrcv++;
1314 		}
1315 	}
1316 
1317 	/*
1318 	 * Set the incoming checksum information for the packet.
1319 	 */
1320 	if (((sc->ex_conf & CONF_90XB) != 0) &&
1321 	    ((stat & EX_UPD_IPCHECKED) != 0) &&
1322 	    ((stat & (EX_UPD_CKSUMERR)) == 0)) {
1323 		uint32_t	pflags = 0;
1324 		if (stat & EX_UPD_IPCHECKED) {
1325 			pflags |= HCK_IPV4_HDRCKSUM;
1326 		}
1327 		if (stat & (EX_UPD_TCPCHECKED | EX_UPD_UDPCHECKED)) {
1328 			pflags |= (HCK_FULLCKSUM | HCK_FULLCKSUM_OK);
1329 		}
1330 		mac_hcksum_set(mp, 0, 0, 0, 0, pflags);
1331 	}
1332 
1333 	return (mp);
1334 }
1335 
1336 static int
1337 elxl_m_start(void *arg)
1338 {
1339 	elxl_t	*sc = arg;
1340 
1341 	mutex_enter(&sc->ex_intrlock);
1342 	mutex_enter(&sc->ex_txlock);
1343 
1344 	elxl_init(sc);
1345 	sc->ex_running = B_TRUE;
1346 
1347 	mutex_exit(&sc->ex_txlock);
1348 	mutex_exit(&sc->ex_intrlock);
1349 
1350 	if (sc->ex_miih) {
1351 		mii_start(sc->ex_miih);
1352 	}
1353 	return (0);
1354 }
1355 
1356 static void
1357 elxl_m_stop(void *arg)
1358 {
1359 	elxl_t	*sc = arg;
1360 
1361 	if (sc->ex_miih) {
1362 		mii_stop(sc->ex_miih);
1363 	}
1364 
1365 	mutex_enter(&sc->ex_intrlock);
1366 	mutex_enter(&sc->ex_txlock);
1367 
1368 	elxl_stop(sc);
1369 	sc->ex_running = B_FALSE;
1370 
1371 	mutex_exit(&sc->ex_txlock);
1372 	mutex_exit(&sc->ex_intrlock);
1373 }
1374 
1375 static boolean_t
1376 elxl_m_getcapab(void *arg, mac_capab_t cap, void *data)
1377 {
1378 	elxl_t		*sc = arg;
1379 	switch (cap) {
1380 	case MAC_CAPAB_HCKSUM: {
1381 		uint32_t	*flags = data;
1382 		if (sc->ex_conf & CONF_90XB) {
1383 			*flags = HCKSUM_IPHDRCKSUM | HCKSUM_INET_FULL_V4;
1384 			return (B_TRUE);
1385 		}
1386 		return (B_FALSE);
1387 	}
1388 	default:
1389 		return (B_FALSE);
1390 	}
1391 }
1392 
1393 static int
1394 elxl_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
1395     void *val)
1396 {
1397 	elxl_t		*sc = arg;
1398 	int		rv;
1399 
1400 	if (sc->ex_mii_active) {
1401 		rv = mii_m_getprop(sc->ex_miih, name, num, sz, val);
1402 		if (rv != ENOTSUP)
1403 			return (rv);
1404 	}
1405 
1406 	switch (num) {
1407 	case MAC_PROP_DUPLEX:
1408 		*(uint8_t *)val = sc->ex_duplex;
1409 		break;
1410 	case MAC_PROP_SPEED:
1411 		*(uint8_t *)val = sc->ex_speed;
1412 		break;
1413 	case MAC_PROP_STATUS:
1414 		bcopy(&sc->ex_link, val, sizeof (link_state_t));
1415 		break;
1416 
1417 	case MAC_PROP_PRIVATE:
1418 		if (strcmp(name, "_media") == 0) {
1419 			char *str;
1420 
1421 			switch (sc->ex_xcvr) {
1422 			case XCVR_SEL_AUTO:
1423 			case XCVR_SEL_MII:
1424 				str = "mii";
1425 				break;
1426 			case XCVR_SEL_10T:
1427 				str = sc->ex_fdx ? "tp-fdx" : "tp-hdx";
1428 				break;
1429 			case XCVR_SEL_BNC:
1430 				str = "bnc";
1431 				break;
1432 			case XCVR_SEL_AUI:
1433 				if (sc->ex_mediaopt & MEDIAOPT_10FL) {
1434 					str = sc->ex_fdx ? "fl-fdx" : "fl-hdx";
1435 				} else {
1436 					str = "aui";
1437 				}
1438 				break;
1439 			case XCVR_SEL_100FX:
1440 				str = sc->ex_fdx ? "fx-fdx" : "fx-hdx";
1441 				break;
1442 			default:
1443 				str = "unknown";
1444 				break;
1445 			}
1446 			(void) snprintf(val, sz, "%s", str);
1447 			return (0);
1448 		}
1449 		/*
1450 		 * This available media property is a hack, and should
1451 		 * be removed when we can provide proper support for
1452 		 * querying it as proposed in PSARC 2009/235.  (At the
1453 		 * moment the implementation lacks support for using
1454 		 * MAC_PROP_POSSIBLE with private properties.)
1455 		 */
1456 		if (strcmp(name, "_available_media") == 0) {
1457 			(void) snprintf(val, sz, "%s", sc->ex_medias);
1458 			return (0);
1459 		}
1460 		break;
1461 	}
1462 	return (ENOTSUP);
1463 }
1464 
1465 static int
1466 elxl_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz,
1467     const void *val)
1468 {
1469 	elxl_t		*sc = arg;
1470 	int		rv;
1471 
1472 	if (sc->ex_mii_active) {
1473 		rv = mii_m_setprop(sc->ex_miih, name, num, sz, val);
1474 		if (rv != ENOTSUP) {
1475 			return (rv);
1476 		}
1477 	}
1478 	switch (num) {
1479 
1480 	case MAC_PROP_PRIVATE:
1481 		if (strcmp(name, "_media") == 0) {
1482 			uint32_t mopt = sc->ex_mediaopt;
1483 
1484 			if (strcmp(val, "mii") == 0) {
1485 				if (mopt & MEDIAOPT_100TX) {
1486 					sc->ex_xcvr = XCVR_SEL_AUTO;
1487 				} else if (mopt & MEDIAOPT_MII)  {
1488 					sc->ex_xcvr = XCVR_SEL_MII;
1489 				} else {
1490 					return (EINVAL);
1491 				}
1492 			} else if (strcmp(val, "tp-fdx") == 0) {
1493 				/* select media option */
1494 				if (mopt & MEDIAOPT_10T) {
1495 					sc->ex_xcvr = XCVR_SEL_10T;
1496 					sc->ex_fdx = B_TRUE;
1497 				} else {
1498 					return (EINVAL);
1499 				}
1500 			} else if (strcmp(val, "tp-hdx") == 0) {
1501 				/* select media option */
1502 				if (mopt & MEDIAOPT_10T) {
1503 					sc->ex_xcvr = XCVR_SEL_10T;
1504 					sc->ex_fdx = B_FALSE;
1505 				} else {
1506 					return (EINVAL);
1507 				}
1508 			} else if (strcmp(val, "fx-fdx") == 0) {
1509 				if (mopt & MEDIAOPT_100FX) {
1510 					sc->ex_xcvr = XCVR_SEL_100FX;
1511 					sc->ex_fdx = B_TRUE;
1512 				} else {
1513 					return (EINVAL);
1514 				}
1515 			} else if (strcmp(val, "fx-hdx") == 0) {
1516 				if (mopt & MEDIAOPT_100FX) {
1517 					sc->ex_xcvr = XCVR_SEL_100FX;
1518 					sc->ex_fdx = B_FALSE;
1519 				} else {
1520 					return (EINVAL);
1521 				}
1522 			} else if (strcmp(val, "bnc") == 0) {
1523 				if (mopt & MEDIAOPT_BNC) {
1524 					sc->ex_xcvr = XCVR_SEL_BNC;
1525 					sc->ex_fdx = B_FALSE;
1526 				} else {
1527 					return (EINVAL);
1528 				}
1529 			} else if (strcmp(val, "aui") == 0) {
1530 				if (mopt & MEDIAOPT_AUI) {
1531 					sc->ex_xcvr = XCVR_SEL_AUI;
1532 					sc->ex_fdx = B_FALSE;
1533 				} else {
1534 					return (EINVAL);
1535 				}
1536 			} else if (strcmp(val, "fl-fdx") == 0) {
1537 				if (mopt & MEDIAOPT_10FL) {
1538 					sc->ex_xcvr = XCVR_SEL_AUI;
1539 					sc->ex_fdx = B_TRUE;
1540 				} else {
1541 					return (EINVAL);
1542 				}
1543 			} else if (strcmp(val, "fl-hdx") == 0) {
1544 				if (mopt & MEDIAOPT_10FL) {
1545 					sc->ex_xcvr = XCVR_SEL_AUI;
1546 					sc->ex_fdx = B_FALSE;
1547 				} else {
1548 					return (EINVAL);
1549 				}
1550 
1551 			} else {
1552 				return (EINVAL);
1553 			}
1554 			goto reset;
1555 		}
1556 		break;
1557 	default:
1558 		break;
1559 	}
1560 
1561 	return (ENOTSUP);
1562 
1563 reset:
1564 	mutex_enter(&sc->ex_intrlock);
1565 	mutex_enter(&sc->ex_txlock);
1566 	if (!sc->ex_suspended) {
1567 		elxl_reset(sc);
1568 		if (sc->ex_running) {
1569 			elxl_init(sc);
1570 		}
1571 	}
1572 	mutex_exit(&sc->ex_txlock);
1573 	mutex_exit(&sc->ex_intrlock);
1574 	return (0);
1575 }
1576 
1577 static void
1578 elxl_m_propinfo(void *arg, const char *name, mac_prop_id_t num,
1579     mac_prop_info_handle_t prh)
1580 {
1581 	elxl_t		*sc = arg;
1582 
1583 	if (sc->ex_mii_active)
1584 		mii_m_propinfo(sc->ex_miih, name, num, prh);
1585 
1586 	switch (num) {
1587 	case MAC_PROP_DUPLEX:
1588 	case MAC_PROP_SPEED:
1589 	case MAC_PROP_STATUS:
1590 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1591 		break;
1592 
1593 	case MAC_PROP_PRIVATE:
1594 		if (strcmp(name, "_available_media") == 0)
1595 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1596 		break;
1597 	}
1598 }
1599 
1600 static int
1601 elxl_m_stat(void *arg, uint_t stat, uint64_t *val)
1602 {
1603 	elxl_t	*sc = arg;
1604 
1605 	if (stat == MAC_STAT_IFSPEED) {
1606 		elxl_getstats(sc);
1607 	}
1608 
1609 	if ((sc->ex_mii_active) &&
1610 	    (mii_m_getstat(sc->ex_miih, stat, val) == 0)) {
1611 		return (0);
1612 	}
1613 
1614 	switch (stat) {
1615 	case MAC_STAT_IFSPEED:
1616 		*val = sc->ex_speed;
1617 		break;
1618 
1619 	case ETHER_STAT_LINK_DUPLEX:
1620 		*val = sc->ex_duplex;
1621 		break;
1622 
1623 	case MAC_STAT_MULTIRCV:
1624 		*val = sc->ex_multircv;
1625 		break;
1626 
1627 	case MAC_STAT_BRDCSTRCV:
1628 		*val = sc->ex_brdcstrcv;
1629 		break;
1630 
1631 	case MAC_STAT_MULTIXMT:
1632 		*val = sc->ex_multixmt;
1633 		break;
1634 
1635 	case MAC_STAT_BRDCSTXMT:
1636 		*val = sc->ex_brdcstxmt;
1637 		break;
1638 
1639 	case MAC_STAT_IPACKETS:
1640 		*val = sc->ex_ipackets;
1641 		break;
1642 
1643 	case MAC_STAT_OPACKETS:
1644 		*val = sc->ex_opackets;
1645 		break;
1646 
1647 	case MAC_STAT_RBYTES:
1648 		*val = sc->ex_ibytes;
1649 		break;
1650 	case MAC_STAT_OBYTES:
1651 		*val = sc->ex_obytes;
1652 		break;
1653 
1654 	case MAC_STAT_COLLISIONS:
1655 	case ETHER_STAT_FIRST_COLLISIONS:
1656 		*val = sc->ex_singlecol + sc->ex_multcol;
1657 		break;
1658 
1659 	case ETHER_STAT_MULTI_COLLISIONS:
1660 		*val = sc->ex_multcol;
1661 		break;
1662 
1663 	case ETHER_STAT_TX_LATE_COLLISIONS:
1664 		*val = sc->ex_latecol;
1665 		break;
1666 
1667 	case ETHER_STAT_ALIGN_ERRORS:
1668 		*val = sc->ex_align;
1669 		break;
1670 
1671 	case ETHER_STAT_FCS_ERRORS:
1672 		*val = sc->ex_fcs;
1673 		break;
1674 
1675 	case ETHER_STAT_SQE_ERRORS:
1676 		*val = sc->ex_sqe;
1677 		break;
1678 
1679 	case ETHER_STAT_DEFER_XMTS:
1680 		*val = sc->ex_defer;
1681 		break;
1682 
1683 	case ETHER_STAT_CARRIER_ERRORS:
1684 		*val = sc->ex_nocarrier;
1685 		break;
1686 
1687 	case ETHER_STAT_TOOLONG_ERRORS:
1688 		*val = sc->ex_toolong;
1689 		break;
1690 
1691 	case ETHER_STAT_EX_COLLISIONS:
1692 		*val = sc->ex_excoll;
1693 		break;
1694 
1695 	case MAC_STAT_OVERFLOWS:
1696 		*val = sc->ex_oflo;
1697 		break;
1698 
1699 	case MAC_STAT_UNDERFLOWS:
1700 		*val = sc->ex_uflo;
1701 		break;
1702 
1703 	case ETHER_STAT_TOOSHORT_ERRORS:
1704 		*val = sc->ex_runt;
1705 		break;
1706 
1707 	case ETHER_STAT_JABBER_ERRORS:
1708 		*val = sc->ex_jabber;
1709 		break;
1710 
1711 	case MAC_STAT_NORCVBUF:
1712 		*val = sc->ex_allocbfail;
1713 		break;
1714 
1715 	case MAC_STAT_OERRORS:
1716 		*val = sc->ex_jabber + sc->ex_latecol + sc->ex_uflo;
1717 		break;
1718 
1719 	case MAC_STAT_IERRORS:
1720 		*val = sc->ex_align + sc->ex_fcs + sc->ex_runt +
1721 		    sc->ex_toolong + sc->ex_oflo + sc->ex_allocbfail;
1722 		break;
1723 
1724 	default:
1725 		return (ENOTSUP);
1726 	}
1727 	return (0);
1728 }
1729 
1730 static uint_t
1731 elxl_intr(caddr_t arg, caddr_t dontcare)
1732 {
1733 	elxl_t		*sc = (void *)arg;
1734 	uint16_t	stat;
1735 	mblk_t		*mphead = NULL;
1736 	mblk_t		**mpp = &mphead;
1737 
1738 	_NOTE(ARGUNUSED(dontcare));
1739 
1740 	mutex_enter(&sc->ex_intrlock);
1741 	if (sc->ex_suspended) {
1742 		mutex_exit(&sc->ex_intrlock);
1743 		return (DDI_INTR_UNCLAIMED);
1744 	}
1745 
1746 	stat = GET16(REG_CMD_STAT);
1747 
1748 	if ((stat & INT_LATCH) == 0)  {
1749 		mutex_exit(&sc->ex_intrlock);
1750 		return (DDI_INTR_UNCLAIMED);
1751 	}
1752 
1753 	/*
1754 	 * Acknowledge interrupts.
1755 	 */
1756 	PUT_CMD(CMD_INT_ACK | (stat & INT_WATCHED) | INT_LATCH);
1757 
1758 	if (stat & INT_HOST_ERROR) {
1759 		/* XXX: Potentially a good spot for FMA */
1760 		elxl_error(sc, "Adapter failure (%x)", stat);
1761 		mutex_enter(&sc->ex_txlock);
1762 		elxl_reset(sc);
1763 		if (sc->ex_running)
1764 			elxl_init(sc);
1765 		mutex_exit(&sc->ex_txlock);
1766 		mutex_exit(&sc->ex_intrlock);
1767 		return (DDI_INTR_CLAIMED);
1768 	}
1769 	if (stat & INT_UP_COMPLETE) {
1770 		ex_ring_t		*r;
1771 		ex_desc_t		*rxd;
1772 		ex_pd_t			*pd;
1773 		mblk_t			*mp;
1774 		uint32_t		pktstat;
1775 
1776 		r = &sc->ex_rxring;
1777 
1778 		for (;;) {
1779 			rxd = r->r_head;
1780 			pd = rxd->ed_pd;
1781 
1782 			(void) ddi_dma_sync(r->r_dmah, rxd->ed_off,
1783 			    sizeof (ex_pd_t), DDI_DMA_SYNC_FORKERNEL);
1784 
1785 			pktstat = GET_PD(r, pd->pd_status);
1786 
1787 			if ((pktstat & EX_UPD_COMPLETE) == 0) {
1788 				break;
1789 			}
1790 
1791 			/* Advance head to next packet. */
1792 			r->r_head = r->r_head->ed_next;
1793 
1794 			if ((mp = elxl_recv(sc, rxd, pktstat)) != NULL) {
1795 				*mpp = mp;
1796 				mpp = &mp->b_next;
1797 			}
1798 
1799 			/* clear the upComplete status, reset other fields */
1800 			PUT_PD(r, pd->pd_status, 0);
1801 			PUT_PD(r, pd->pd_len, EX_BUFSZ | EX_FR_LAST);
1802 			PUT_PD(r, pd->pd_addr, rxd->ed_bufaddr);
1803 			(void) ddi_dma_sync(r->r_dmah, rxd->ed_off,
1804 			    sizeof (ex_pd_t), DDI_DMA_SYNC_FORDEV);
1805 		}
1806 
1807 		/*
1808 		 * If the engine stalled processing (due to
1809 		 * insufficient UPDs usually), restart it.
1810 		 */
1811 		if (GET32(REG_UPLISTPTR) == 0) {
1812 			/*
1813 			 * This seems that it can happen in an RX overrun
1814 			 * situation.
1815 			 */
1816 			mutex_enter(&sc->ex_txlock);
1817 			if (sc->ex_running)
1818 				elxl_init(sc);
1819 			mutex_exit(&sc->ex_txlock);
1820 		}
1821 		PUT_CMD(CMD_UP_UNSTALL);
1822 	}
1823 
1824 	mutex_exit(&sc->ex_intrlock);
1825 
1826 	if (mphead) {
1827 		mac_rx(sc->ex_mach, NULL, mphead);
1828 	}
1829 	if (stat & INT_STATS) {
1830 		elxl_getstats(sc);
1831 	}
1832 	if (stat & INT_DN_COMPLETE) {
1833 		mac_tx_update(sc->ex_mach);
1834 	}
1835 
1836 	return (DDI_INTR_CLAIMED);
1837 }
1838 
1839 static void
1840 elxl_getstats(elxl_t *sc)
1841 {
1842 	mutex_enter(&sc->ex_txlock);
1843 	if (sc->ex_suspended) {
1844 		mutex_exit(&sc->ex_txlock);
1845 		return;
1846 	}
1847 
1848 	SET_WIN(6);
1849 	/*
1850 	 * We count the packets and bytes elsewhere, but we need to
1851 	 * read the registers to clear them.
1852 	 */
1853 	(void) GET8(W6_RX_FRAMES);
1854 	(void) GET8(W6_TX_FRAMES);
1855 	(void) GET8(W6_UPPER_FRAMES);
1856 	(void) GET8(W6_RX_OVERRUNS);	/* counted by elxl_recv */
1857 	(void) GET16(W6_RX_BYTES);
1858 	(void) GET16(W6_TX_BYTES);
1859 
1860 	sc->ex_defer += GET8(W6_DEFER);
1861 	sc->ex_latecol += GET8(W6_TX_LATE_COL);
1862 	sc->ex_singlecol += GET8(W6_SINGLE_COL);
1863 	sc->ex_multcol += GET8(W6_MULT_COL);
1864 	sc->ex_sqe += GET8(W6_SQE_ERRORS);
1865 	sc->ex_nocarrier += GET8(W6_NO_CARRIER);
1866 
1867 	SET_WIN(4);
1868 	/* Note: we ought to report this somewhere... */
1869 	(void) GET8(W4_BADSSD);
1870 
1871 	mutex_exit(&sc->ex_txlock);
1872 }
1873 
1874 static void
1875 elxl_reset(elxl_t *sc)
1876 {
1877 	PUT_CMD(CMD_GLOBAL_RESET);
1878 	/*
1879 	 * Some ASICs need a longer time (20 ms) to come properly out
1880 	 * of reset.  Do not reduce this value.
1881 	 *
1882 	 * Note that this occurs only during attach and failure recovery,
1883 	 * so it should be mostly harmless.
1884 	 */
1885 	drv_usecwait(20000);
1886 	WAIT_CMD(sc);
1887 }
1888 
1889 static void
1890 elxl_stop(elxl_t *sc)
1891 {
1892 	ASSERT(mutex_owned(&sc->ex_intrlock));
1893 	ASSERT(mutex_owned(&sc->ex_txlock));
1894 
1895 	if (sc->ex_suspended)
1896 		return;
1897 
1898 	PUT_CMD(CMD_RX_DISABLE);
1899 	PUT_CMD(CMD_TX_DISABLE);
1900 	PUT_CMD(CMD_BNC_DISABLE);
1901 
1902 	elxl_reset_ring(&sc->ex_rxring, DDI_DMA_READ);
1903 	elxl_reset_ring(&sc->ex_txring, DDI_DMA_WRITE);
1904 
1905 	PUT_CMD(CMD_INT_ACK | INT_LATCH);
1906 	/* Disable all interrupts. (0 means "none".) */
1907 	PUT_CMD(CMD_INT_ENABLE | 0);
1908 }
1909 
1910 static void
1911 elxl_suspend(elxl_t *sc)
1912 {
1913 	if (sc->ex_miih) {
1914 		mii_suspend(sc->ex_miih);
1915 	}
1916 
1917 	mutex_enter(&sc->ex_intrlock);
1918 	mutex_enter(&sc->ex_txlock);
1919 	elxl_stop(sc);
1920 	sc->ex_suspended = B_TRUE;
1921 	mutex_exit(&sc->ex_txlock);
1922 	mutex_exit(&sc->ex_intrlock);
1923 }
1924 
1925 static void
1926 elxl_resume(dev_info_t *dip)
1927 {
1928 	elxl_t	*sc;
1929 
1930 	/* This should always succeed. */
1931 	sc = ddi_get_driver_private(dip);
1932 	ASSERT(sc);
1933 
1934 	mutex_enter(&sc->ex_intrlock);
1935 	mutex_enter(&sc->ex_txlock);
1936 	sc->ex_suspended = B_FALSE;
1937 	elxl_reset(sc);
1938 	if (sc->ex_running)
1939 		elxl_init(sc);
1940 	mutex_exit(&sc->ex_txlock);
1941 	mutex_exit(&sc->ex_intrlock);
1942 
1943 	if (sc->ex_miih) {
1944 		mii_resume(sc->ex_miih);
1945 	}
1946 }
1947 
1948 static void
1949 elxl_detach(elxl_t *sc)
1950 {
1951 	if (sc->ex_miih) {
1952 		/* Detach all PHYs */
1953 		mii_free(sc->ex_miih);
1954 	}
1955 	if (sc->ex_linkcheck) {
1956 		ddi_periodic_delete(sc->ex_linkcheck);
1957 	}
1958 
1959 	if (sc->ex_intrh != NULL) {
1960 		(void) ddi_intr_disable(sc->ex_intrh);
1961 		(void) ddi_intr_remove_handler(sc->ex_intrh);
1962 		(void) ddi_intr_free(sc->ex_intrh);
1963 		mutex_destroy(&sc->ex_intrlock);
1964 		mutex_destroy(&sc->ex_txlock);
1965 	}
1966 
1967 	if (sc->ex_pcih) {
1968 		pci_config_teardown(&sc->ex_pcih);
1969 	}
1970 	if (sc->ex_regsh) {
1971 		ddi_regs_map_free(&sc->ex_regsh);
1972 	}
1973 	ex_free_ring(&sc->ex_txring);
1974 	ex_free_ring(&sc->ex_rxring);
1975 
1976 	kmem_free(sc, sizeof (*sc));
1977 }
1978 
1979 /*
1980  * Read EEPROM data.  If we can't unbusy the EEPROM, then zero will be
1981  * returned.  This will probably result in a bogus node address.
1982  */
1983 static uint16_t
1984 elxl_read_eeprom(elxl_t *sc, int offset)
1985 {
1986 	uint16_t data = 0;
1987 
1988 	SET_WIN(0);
1989 	if (elxl_eeprom_busy(sc))
1990 		goto out;
1991 
1992 	PUT16(W0_EE_CMD, EE_CMD_READ | (offset & 0x3f));
1993 	if (elxl_eeprom_busy(sc))
1994 		goto out;
1995 	data = GET16(W0_EE_DATA);
1996 out:
1997 	return (data);
1998 }
1999 
2000 static int
2001 elxl_eeprom_busy(elxl_t *sc)
2002 {
2003 	int i = 2000;
2004 
2005 	while (i--) {
2006 		if (!(GET16(W0_EE_CMD) & EE_CMD_BUSY))
2007 			return (0);
2008 		drv_usecwait(100);
2009 	}
2010 	elxl_error(sc, "Eeprom stays busy.");
2011 	return (1);
2012 }
2013 
2014 static void
2015 ex_mii_send_bits(struct ex_softc *sc, uint16_t bits, int cnt)
2016 {
2017 	uint16_t val;
2018 	ASSERT(cnt > 0);
2019 
2020 	PUT16(W4_PHYSMGMT, PHYSMGMT_DIR);
2021 	drv_usecwait(1);
2022 
2023 	for (int i = (1 << (cnt - 1)); i; i >>= 1) {
2024 		if (bits & i) {
2025 			val = PHYSMGMT_DIR | PHYSMGMT_DATA;
2026 		} else {
2027 			val = PHYSMGMT_DIR;
2028 		}
2029 		PUT16(W4_PHYSMGMT, val);
2030 		drv_usecwait(1);
2031 		PUT16(W4_PHYSMGMT, val | PHYSMGMT_CLK);
2032 		drv_usecwait(1);
2033 		PUT16(W4_PHYSMGMT, val);
2034 		drv_usecwait(1);
2035 	}
2036 }
2037 
2038 static void
2039 ex_mii_sync(struct ex_softc *sc)
2040 {
2041 	/*
2042 	 * We set the data bit output, and strobe the clock 32 times.
2043 	 */
2044 	PUT16(W4_PHYSMGMT, PHYSMGMT_DATA | PHYSMGMT_DIR);
2045 	drv_usecwait(1);
2046 
2047 	for (int i = 0; i < 32; i++) {
2048 		PUT16(W4_PHYSMGMT, PHYSMGMT_DATA | PHYSMGMT_DIR | PHYSMGMT_CLK);
2049 		drv_usecwait(1);
2050 		PUT16(W4_PHYSMGMT, PHYSMGMT_DATA | PHYSMGMT_DIR);
2051 		drv_usecwait(1);
2052 	}
2053 }
2054 
2055 static uint16_t
2056 elxl_mii_read(void *arg, uint8_t phy, uint8_t reg)
2057 {
2058 	elxl_t		*sc = arg;
2059 	uint16_t	data;
2060 	int		val;
2061 
2062 	if ((sc->ex_conf & CONF_INTPHY) && phy != INTPHY_ID)
2063 		return (0xffff);
2064 
2065 	mutex_enter(&sc->ex_txlock);
2066 	SET_WIN(4);
2067 
2068 	ex_mii_sync(sc);
2069 
2070 	ex_mii_send_bits(sc, 1, 2);	/* start */
2071 	ex_mii_send_bits(sc, 2, 2);	/* read command */
2072 	ex_mii_send_bits(sc, phy, 5);
2073 	ex_mii_send_bits(sc, reg, 5);
2074 
2075 	PUT16(W4_PHYSMGMT, 0);			/* switch to input */
2076 	drv_usecwait(1);
2077 	PUT16(W4_PHYSMGMT, PHYSMGMT_CLK);	/* turnaround time */
2078 	drv_usecwait(1);
2079 	PUT16(W4_PHYSMGMT, 0);
2080 	drv_usecwait(1);
2081 
2082 	PUT16(W4_PHYSMGMT, PHYSMGMT_CLK);	/* idle time */
2083 	drv_usecwait(1);
2084 	PUT16(W4_PHYSMGMT, 0);
2085 	drv_usecwait(1);
2086 
2087 	for (data = 0, val = 0x8000; val; val >>= 1) {
2088 		if (GET16(W4_PHYSMGMT) & PHYSMGMT_DATA) {
2089 			data |= val;
2090 		}
2091 		/* strobe the clock */
2092 		PUT16(W4_PHYSMGMT, PHYSMGMT_CLK);
2093 		drv_usecwait(1);
2094 		PUT16(W4_PHYSMGMT, 0);
2095 		drv_usecwait(1);
2096 	}
2097 
2098 	/* return to output mode */
2099 	PUT16(W4_PHYSMGMT, PHYSMGMT_DIR);
2100 	drv_usecwait(1);
2101 
2102 	mutex_exit(&sc->ex_txlock);
2103 
2104 	return (data);
2105 }
2106 
2107 static void
2108 elxl_mii_write(void *arg, uint8_t phy, uint8_t reg, uint16_t data)
2109 {
2110 	elxl_t *sc = arg;
2111 
2112 	if ((sc->ex_conf & CONF_INTPHY) && phy != INTPHY_ID)
2113 		return;
2114 
2115 	mutex_enter(&sc->ex_txlock);
2116 	SET_WIN(4);
2117 
2118 	ex_mii_sync(sc);
2119 	ex_mii_send_bits(sc, 1, 2);	/* start */
2120 	ex_mii_send_bits(sc, 1, 2);	/* write */
2121 	ex_mii_send_bits(sc, phy, 5);
2122 	ex_mii_send_bits(sc, reg, 5);
2123 	ex_mii_send_bits(sc, 2, 2);	/* ack/turnaround */
2124 	ex_mii_send_bits(sc, data, 16);
2125 
2126 	/* return to output mode */
2127 	PUT16(W4_PHYSMGMT, PHYSMGMT_DIR);
2128 	drv_usecwait(1);
2129 
2130 	mutex_exit(&sc->ex_txlock);
2131 }
2132 
2133 static void
2134 elxl_mii_notify(void *arg, link_state_t link)
2135 {
2136 	elxl_t		*sc = arg;
2137 	int		mctl;
2138 	link_duplex_t	duplex;
2139 
2140 	duplex = mii_get_duplex(sc->ex_miih);
2141 
2142 	mutex_enter(&sc->ex_txlock);
2143 	if (!sc->ex_mii_active) {
2144 		/* If we're using some other legacy media, bail out now */
2145 		mutex_exit(&sc->ex_txlock);
2146 		return;
2147 	}
2148 	if (!sc->ex_suspended) {
2149 		SET_WIN(3);
2150 		mctl = GET16(W3_MAC_CONTROL);
2151 		if (duplex == LINK_DUPLEX_FULL)
2152 			mctl |= MAC_CONTROL_FDX;
2153 		else
2154 			mctl &= ~MAC_CONTROL_FDX;
2155 		PUT16(W3_MAC_CONTROL, mctl);
2156 	}
2157 	mutex_exit(&sc->ex_txlock);
2158 
2159 	mac_link_update(sc->ex_mach, link);
2160 }
2161 
2162 static int
2163 elxl_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2164 {
2165 	switch (cmd) {
2166 	case DDI_ATTACH:
2167 		return (elxl_attach(dip));
2168 
2169 	case DDI_RESUME:
2170 		elxl_resume(dip);
2171 		return (DDI_SUCCESS);
2172 
2173 	default:
2174 		return (DDI_FAILURE);
2175 	}
2176 }
2177 
2178 static int
2179 elxl_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2180 {
2181 	elxl_t	*sc;
2182 
2183 	sc = ddi_get_driver_private(dip);
2184 	ASSERT(sc);
2185 
2186 	switch (cmd) {
2187 	case DDI_DETACH:
2188 		if (mac_disable(sc->ex_mach) != 0) {
2189 			return (DDI_FAILURE);
2190 		}
2191 		(void) mac_unregister(sc->ex_mach);
2192 		elxl_detach(sc);
2193 		return (DDI_SUCCESS);
2194 
2195 	case DDI_SUSPEND:
2196 		elxl_suspend(sc);
2197 		return (DDI_SUCCESS);
2198 
2199 	default:
2200 		return (DDI_FAILURE);
2201 	}
2202 }
2203 
2204 static int
2205 elxl_ddi_quiesce(dev_info_t *dip)
2206 {
2207 	elxl_t	*sc;
2208 
2209 	sc = ddi_get_driver_private(dip);
2210 	ASSERT(sc);
2211 
2212 	if (!sc->ex_suspended)
2213 		elxl_reset(sc);
2214 	return (DDI_SUCCESS);
2215 }
2216 
2217 static void
2218 elxl_error(elxl_t *sc, char *fmt, ...)
2219 {
2220 	va_list	ap;
2221 	char	buf[256];
2222 
2223 	va_start(ap, fmt);
2224 	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
2225 	va_end(ap);
2226 
2227 	cmn_err(CE_WARN, "%s%d: %s",
2228 	    ddi_driver_name(sc->ex_dip), ddi_get_instance(sc->ex_dip), buf);
2229 }
2230