xref: /illumos-gate/usr/src/uts/common/io/ixgbe/ixgbe_gld.c (revision f27d3025d908422c3f6e682964b4f1e2b4834e4a)
1 /*
2  * CDDL HEADER START
3  *
4  * Copyright(c) 2007-2008 Intel Corporation. All rights reserved.
5  * The contents of this file are subject to the terms of the
6  * Common Development and Distribution License (the "License").
7  * You may not use this file except in compliance with the License.
8  *
9  * You can obtain a copy of the license at:
10  *      http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When using or redistributing this file, you may do so under the
15  * License only. No other modification of this header is permitted.
16  *
17  * If applicable, add the following below this CDDL HEADER, with the
18  * fields enclosed by brackets "[]" replaced with your own identifying
19  * information: Portions Copyright [yyyy] [name of copyright owner]
20  *
21  * CDDL HEADER END
22  */
23 
24 /*
25  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
26  * Use is subject to license terms of the CDDL.
27  */
28 
29 #pragma ident	"%Z%%M%	%I%	%E% SMI"
30 
31 #include "ixgbe_sw.h"
32 
33 /*
34  * Retrieve a value for one of the statistics.
35  */
36 int
37 ixgbe_m_stat(void *arg, uint_t stat, uint64_t *val)
38 {
39 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
40 	struct ixgbe_hw *hw = &ixgbe->hw;
41 	ixgbe_stat_t *ixgbe_ks;
42 	int i;
43 
44 	ixgbe_ks = (ixgbe_stat_t *)ixgbe->ixgbe_ks->ks_data;
45 
46 	mutex_enter(&ixgbe->gen_lock);
47 
48 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
49 		mutex_exit(&ixgbe->gen_lock);
50 		return (ECANCELED);
51 	}
52 
53 	switch (stat) {
54 	case MAC_STAT_IFSPEED:
55 		*val = ixgbe->link_speed * 1000000ull;
56 		break;
57 
58 	case MAC_STAT_MULTIRCV:
59 		ixgbe_ks->mprc.value.ui64 +=
60 		    IXGBE_READ_REG(hw, IXGBE_MPRC);
61 		*val = ixgbe_ks->mprc.value.ui64;
62 		break;
63 
64 	case MAC_STAT_BRDCSTRCV:
65 		ixgbe_ks->bprc.value.ui64 +=
66 		    IXGBE_READ_REG(hw, IXGBE_BPRC);
67 		*val = ixgbe_ks->bprc.value.ui64;
68 		break;
69 
70 	case MAC_STAT_MULTIXMT:
71 		ixgbe_ks->mptc.value.ui64 +=
72 		    IXGBE_READ_REG(hw, IXGBE_MPTC);
73 		*val = ixgbe_ks->mptc.value.ui64;
74 		break;
75 
76 	case MAC_STAT_BRDCSTXMT:
77 		ixgbe_ks->bptc.value.ui64 +=
78 		    IXGBE_READ_REG(hw, IXGBE_BPTC);
79 		*val = ixgbe_ks->bptc.value.ui64;
80 		break;
81 
82 	case MAC_STAT_NORCVBUF:
83 		for (i = 0; i < 8; i++) {
84 			ixgbe_ks->rnbc.value.ui64 +=
85 			    IXGBE_READ_REG(hw, IXGBE_RNBC(i));
86 		}
87 		*val = ixgbe_ks->rnbc.value.ui64;
88 		break;
89 
90 	case MAC_STAT_IERRORS:
91 		ixgbe_ks->crcerrs.value.ui64 +=
92 		    IXGBE_READ_REG(hw, IXGBE_CRCERRS);
93 		ixgbe_ks->illerrc.value.ui64 +=
94 		    IXGBE_READ_REG(hw, IXGBE_ILLERRC);
95 		ixgbe_ks->errbc.value.ui64 +=
96 		    IXGBE_READ_REG(hw, IXGBE_ERRBC);
97 		ixgbe_ks->rlec.value.ui64 +=
98 		    IXGBE_READ_REG(hw, IXGBE_RLEC);
99 		*val = ixgbe_ks->crcerrs.value.ui64 +
100 		    ixgbe_ks->illerrc.value.ui64 +
101 		    ixgbe_ks->errbc.value.ui64 +
102 		    ixgbe_ks->rlec.value.ui64;
103 		break;
104 
105 	case MAC_STAT_RBYTES:
106 		for (i = 0; i < 16; i++)
107 			ixgbe_ks->tor.value.ui64 +=
108 			    IXGBE_READ_REG(hw, IXGBE_QBRC(i));
109 		*val = ixgbe_ks->tor.value.ui64;
110 		break;
111 
112 	case MAC_STAT_OBYTES:
113 		for (i = 0; i < 16; i++)
114 			ixgbe_ks->tot.value.ui64 +=
115 			    IXGBE_READ_REG(hw, IXGBE_QBTC(i));
116 		*val = ixgbe_ks->tot.value.ui64;
117 		break;
118 
119 	case MAC_STAT_IPACKETS:
120 		ixgbe_ks->tpr.value.ui64 +=
121 		    IXGBE_READ_REG(hw, IXGBE_TPR);
122 		*val = ixgbe_ks->tpr.value.ui64;
123 		break;
124 
125 	case MAC_STAT_OPACKETS:
126 		ixgbe_ks->tpt.value.ui64 +=
127 		    IXGBE_READ_REG(hw, IXGBE_TPT);
128 		*val = ixgbe_ks->tpt.value.ui64;
129 		break;
130 
131 	/* RFC 1643 stats */
132 	case ETHER_STAT_FCS_ERRORS:
133 		ixgbe_ks->crcerrs.value.ui64 +=
134 		    IXGBE_READ_REG(hw, IXGBE_CRCERRS);
135 		*val = ixgbe_ks->crcerrs.value.ui64;
136 		break;
137 
138 	case ETHER_STAT_TOOLONG_ERRORS:
139 		ixgbe_ks->roc.value.ui64 +=
140 		    IXGBE_READ_REG(hw, IXGBE_ROC);
141 		*val = ixgbe_ks->roc.value.ui64;
142 		break;
143 
144 	case ETHER_STAT_MACRCV_ERRORS:
145 		ixgbe_ks->crcerrs.value.ui64 +=
146 		    IXGBE_READ_REG(hw, IXGBE_CRCERRS);
147 		ixgbe_ks->illerrc.value.ui64 +=
148 		    IXGBE_READ_REG(hw, IXGBE_ILLERRC);
149 		ixgbe_ks->errbc.value.ui64 +=
150 		    IXGBE_READ_REG(hw, IXGBE_ERRBC);
151 		ixgbe_ks->rlec.value.ui64 +=
152 		    IXGBE_READ_REG(hw, IXGBE_RLEC);
153 		*val = ixgbe_ks->crcerrs.value.ui64 +
154 		    ixgbe_ks->illerrc.value.ui64 +
155 		    ixgbe_ks->errbc.value.ui64 +
156 		    ixgbe_ks->rlec.value.ui64;
157 		break;
158 
159 	/* MII/GMII stats */
160 	case ETHER_STAT_XCVR_ADDR:
161 		/* The Internal PHY's MDI address for each MAC is 1 */
162 		*val = 1;
163 		break;
164 
165 	case ETHER_STAT_XCVR_ID:
166 		*val = hw->phy.id;
167 		break;
168 
169 	case ETHER_STAT_XCVR_INUSE:
170 		switch (ixgbe->link_speed) {
171 		case IXGBE_LINK_SPEED_1GB_FULL:
172 			*val =
173 			    (hw->phy.media_type == ixgbe_media_type_copper) ?
174 			    XCVR_1000T : XCVR_1000X;
175 			break;
176 		case IXGBE_LINK_SPEED_100_FULL:
177 			*val = (hw->phy.media_type == ixgbe_media_type_copper) ?
178 			    XCVR_100T2 : XCVR_100X;
179 			break;
180 		default:
181 			*val = XCVR_NONE;
182 			break;
183 		}
184 		break;
185 
186 	case ETHER_STAT_CAP_1000FDX:
187 		*val = ixgbe->param_1000fdx_cap;
188 		break;
189 
190 	case ETHER_STAT_CAP_100FDX:
191 		*val = ixgbe->param_100fdx_cap;
192 		break;
193 
194 	case ETHER_STAT_CAP_ASMPAUSE:
195 		*val = ixgbe->param_asym_pause_cap;
196 		break;
197 
198 	case ETHER_STAT_CAP_PAUSE:
199 		*val = ixgbe->param_pause_cap;
200 		break;
201 
202 	case ETHER_STAT_CAP_AUTONEG:
203 		*val = ixgbe->param_autoneg_cap;
204 		break;
205 
206 	case ETHER_STAT_ADV_CAP_1000FDX:
207 		*val = ixgbe->param_adv_1000fdx_cap;
208 		break;
209 
210 	case ETHER_STAT_ADV_CAP_100FDX:
211 		*val = ixgbe->param_adv_100fdx_cap;
212 		break;
213 
214 	case ETHER_STAT_ADV_CAP_ASMPAUSE:
215 		*val = ixgbe->param_adv_asym_pause_cap;
216 		break;
217 
218 	case ETHER_STAT_ADV_CAP_PAUSE:
219 		*val = ixgbe->param_adv_pause_cap;
220 		break;
221 
222 	case ETHER_STAT_ADV_CAP_AUTONEG:
223 		*val = hw->mac.autoneg;
224 		break;
225 
226 	case ETHER_STAT_LP_CAP_1000FDX:
227 		*val = ixgbe->param_lp_1000fdx_cap;
228 		break;
229 
230 	case ETHER_STAT_LP_CAP_100FDX:
231 		*val = ixgbe->param_lp_100fdx_cap;
232 		break;
233 
234 	case ETHER_STAT_LP_CAP_ASMPAUSE:
235 		*val = ixgbe->param_lp_asym_pause_cap;
236 		break;
237 
238 	case ETHER_STAT_LP_CAP_PAUSE:
239 		*val = ixgbe->param_lp_pause_cap;
240 		break;
241 
242 	case ETHER_STAT_LP_CAP_AUTONEG:
243 		*val = ixgbe->param_lp_autoneg_cap;
244 		break;
245 
246 	case ETHER_STAT_LINK_ASMPAUSE:
247 		*val = ixgbe->param_asym_pause_cap;
248 		break;
249 
250 	case ETHER_STAT_LINK_PAUSE:
251 		*val = ixgbe->param_pause_cap;
252 		break;
253 
254 	case ETHER_STAT_LINK_AUTONEG:
255 		*val = hw->mac.autoneg;
256 		break;
257 	case ETHER_STAT_LINK_DUPLEX:
258 		*val = LINK_DUPLEX_FULL;
259 		break;
260 
261 	case ETHER_STAT_TOOSHORT_ERRORS:
262 		ixgbe_ks->ruc.value.ui64 +=
263 		    IXGBE_READ_REG(hw, IXGBE_RUC);
264 		*val = ixgbe_ks->ruc.value.ui64;
265 		break;
266 
267 	case ETHER_STAT_CAP_REMFAULT:
268 		*val = ixgbe->param_rem_fault;
269 		break;
270 
271 	case ETHER_STAT_ADV_REMFAULT:
272 		*val = ixgbe->param_adv_rem_fault;
273 		break;
274 
275 	case ETHER_STAT_LP_REMFAULT:
276 		*val = ixgbe->param_lp_rem_fault;
277 		break;
278 
279 	case ETHER_STAT_JABBER_ERRORS:
280 		ixgbe_ks->rjc.value.ui64 +=
281 		    IXGBE_READ_REG(hw, IXGBE_RJC);
282 		*val = ixgbe_ks->rjc.value.ui64;
283 		break;
284 
285 	default:
286 		mutex_exit(&ixgbe->gen_lock);
287 		return (ENOTSUP);
288 	}
289 
290 	mutex_exit(&ixgbe->gen_lock);
291 
292 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK)
293 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_UNAFFECTED);
294 
295 	return (0);
296 }
297 
298 /*
299  * Bring the device out of the reset/quiesced state that it
300  * was in when the interface was registered.
301  */
302 int
303 ixgbe_m_start(void *arg)
304 {
305 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
306 
307 	mutex_enter(&ixgbe->gen_lock);
308 
309 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
310 		mutex_exit(&ixgbe->gen_lock);
311 		return (ECANCELED);
312 	}
313 
314 	if (ixgbe_start(ixgbe) != IXGBE_SUCCESS) {
315 		mutex_exit(&ixgbe->gen_lock);
316 		return (EIO);
317 	}
318 
319 	ixgbe->ixgbe_state |= IXGBE_STARTED;
320 
321 	mutex_exit(&ixgbe->gen_lock);
322 
323 	/*
324 	 * Enable and start the watchdog timer
325 	 */
326 	ixgbe_enable_watchdog_timer(ixgbe);
327 
328 	return (0);
329 }
330 
331 /*
332  * Stop the device and put it in a reset/quiesced state such
333  * that the interface can be unregistered.
334  */
335 void
336 ixgbe_m_stop(void *arg)
337 {
338 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
339 
340 	mutex_enter(&ixgbe->gen_lock);
341 
342 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
343 		mutex_exit(&ixgbe->gen_lock);
344 		return;
345 	}
346 
347 	ixgbe->ixgbe_state &= ~IXGBE_STARTED;
348 
349 	ixgbe_stop(ixgbe);
350 
351 	mutex_exit(&ixgbe->gen_lock);
352 
353 	/*
354 	 * Disable and stop the watchdog timer
355 	 */
356 	ixgbe_disable_watchdog_timer(ixgbe);
357 }
358 
359 /*
360  * Set the promiscuity of the device.
361  */
362 int
363 ixgbe_m_promisc(void *arg, boolean_t on)
364 {
365 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
366 	uint32_t reg_val;
367 	struct ixgbe_hw *hw = &ixgbe->hw;
368 
369 	mutex_enter(&ixgbe->gen_lock);
370 
371 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
372 		mutex_exit(&ixgbe->gen_lock);
373 		return (ECANCELED);
374 	}
375 	reg_val = IXGBE_READ_REG(hw, IXGBE_FCTRL);
376 
377 	if (on)
378 		reg_val |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
379 	else
380 		reg_val &= (~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE));
381 
382 	IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_FCTRL, reg_val);
383 
384 	mutex_exit(&ixgbe->gen_lock);
385 
386 	return (0);
387 }
388 
389 /*
390  * Add/remove the addresses to/from the set of multicast
391  * addresses for which the device will receive packets.
392  */
393 int
394 ixgbe_m_multicst(void *arg, boolean_t add, const uint8_t *mcst_addr)
395 {
396 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
397 	int result;
398 
399 	mutex_enter(&ixgbe->gen_lock);
400 
401 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
402 		mutex_exit(&ixgbe->gen_lock);
403 		return (ECANCELED);
404 	}
405 
406 	result = (add) ? ixgbe_multicst_add(ixgbe, mcst_addr)
407 	    : ixgbe_multicst_remove(ixgbe, mcst_addr);
408 
409 	mutex_exit(&ixgbe->gen_lock);
410 
411 	return (result);
412 }
413 
414 /*
415  * Set a new device unicast address.
416  */
417 int
418 ixgbe_m_unicst(void *arg, const uint8_t *mac_addr)
419 {
420 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
421 	int result;
422 
423 	mutex_enter(&ixgbe->gen_lock);
424 
425 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
426 		mutex_exit(&ixgbe->gen_lock);
427 		return (ECANCELED);
428 	}
429 
430 	/*
431 	 * Store the new MAC address.
432 	 */
433 	bcopy(mac_addr, ixgbe->hw.mac.addr, ETHERADDRL);
434 
435 	/*
436 	 * Set MAC address in address slot 0, which is the default address.
437 	 */
438 	result = ixgbe_unicst_set(ixgbe, mac_addr, 0);
439 
440 	mutex_exit(&ixgbe->gen_lock);
441 
442 	return (result);
443 }
444 
445 /*
446  * Pass on M_IOCTL messages passed to the DLD, and support
447  * private IOCTLs for debugging and ndd.
448  */
449 void
450 ixgbe_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
451 {
452 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
453 	struct iocblk *iocp;
454 	enum ioc_reply status;
455 
456 	iocp = (struct iocblk *)(uintptr_t)mp->b_rptr;
457 	iocp->ioc_error = 0;
458 
459 	switch (iocp->ioc_cmd) {
460 	case LB_GET_INFO_SIZE:
461 	case LB_GET_INFO:
462 	case LB_GET_MODE:
463 	case LB_SET_MODE:
464 		status = ixgbe_loopback_ioctl(ixgbe, iocp, mp);
465 		break;
466 
467 	case ND_GET:
468 	case ND_SET:
469 		status = ixgbe_nd_ioctl(ixgbe, q, mp, iocp);
470 		break;
471 
472 	default:
473 		status = IOC_INVAL;
474 		break;
475 	}
476 
477 	/*
478 	 * Decide how to reply
479 	 */
480 	switch (status) {
481 	default:
482 	case IOC_INVAL:
483 		/*
484 		 * Error, reply with a NAK and EINVAL or the specified error
485 		 */
486 		miocnak(q, mp, 0, iocp->ioc_error == 0 ?
487 		    EINVAL : iocp->ioc_error);
488 		break;
489 
490 	case IOC_DONE:
491 		/*
492 		 * OK, reply already sent
493 		 */
494 		break;
495 
496 	case IOC_ACK:
497 		/*
498 		 * OK, reply with an ACK
499 		 */
500 		miocack(q, mp, 0, 0);
501 		break;
502 
503 	case IOC_REPLY:
504 		/*
505 		 * OK, send prepared reply as ACK or NAK
506 		 */
507 		mp->b_datap->db_type = iocp->ioc_error == 0 ?
508 		    M_IOCACK : M_IOCNAK;
509 		qreply(q, mp);
510 		break;
511 	}
512 }
513 
514 
515 /*
516  * Find an unused address slot, set the address to it, reserve
517  * this slot and enable the device to start filtering on the
518  * new address.
519  */
520 int
521 ixgbe_m_unicst_add(void *arg, mac_multi_addr_t *maddr)
522 {
523 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
524 	mac_addr_slot_t slot;
525 	int err;
526 
527 	mutex_enter(&ixgbe->gen_lock);
528 
529 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
530 		mutex_exit(&ixgbe->gen_lock);
531 		return (ECANCELED);
532 	}
533 
534 	if (mac_unicst_verify(ixgbe->mac_hdl,
535 	    maddr->mma_addr, maddr->mma_addrlen) == B_FALSE) {
536 		mutex_exit(&ixgbe->gen_lock);
537 		return (EINVAL);
538 	}
539 
540 	if (ixgbe->unicst_avail == 0) {
541 		/* no slots available */
542 		mutex_exit(&ixgbe->gen_lock);
543 		return (ENOSPC);
544 	}
545 
546 	/*
547 	 * Primary/default address is in slot 0. The next addresses
548 	 * are the multiple MAC addresses. So multiple MAC address 0
549 	 * is in slot 1, 1 in slot 2, and so on. So the first multiple
550 	 * MAC address resides in slot 1.
551 	 */
552 	for (slot = 1; slot < ixgbe->unicst_total; slot++) {
553 		if (ixgbe->unicst_addr[slot].mac.set == 0)
554 			break;
555 	}
556 
557 	ASSERT((slot > 0) && (slot < ixgbe->unicst_total));
558 
559 	maddr->mma_slot = slot;
560 
561 	if ((err = ixgbe_unicst_set(ixgbe, maddr->mma_addr, slot)) == 0) {
562 		ixgbe->unicst_addr[slot].mac.set = 1;
563 		ixgbe->unicst_avail--;
564 	}
565 
566 	mutex_exit(&ixgbe->gen_lock);
567 
568 	return (err);
569 }
570 
571 /*
572  * Removes a MAC address that was added before.
573  */
574 int
575 ixgbe_m_unicst_remove(void *arg, mac_addr_slot_t slot)
576 {
577 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
578 	int err;
579 
580 	mutex_enter(&ixgbe->gen_lock);
581 
582 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
583 		mutex_exit(&ixgbe->gen_lock);
584 		return (ECANCELED);
585 	}
586 
587 	if ((slot <= 0) || (slot >= ixgbe->unicst_total)) {
588 		mutex_exit(&ixgbe->gen_lock);
589 		return (EINVAL);
590 	}
591 
592 	if (ixgbe->unicst_addr[slot].mac.set == 1) {
593 		/*
594 		 * Copy the default address to the passed slot
595 		 */
596 		if ((err = ixgbe_unicst_set(ixgbe,
597 		    ixgbe->unicst_addr[0].mac.addr, slot)) == 0) {
598 			ixgbe->unicst_addr[slot].mac.set = 0;
599 			ixgbe->unicst_avail++;
600 		}
601 
602 		mutex_exit(&ixgbe->gen_lock);
603 
604 		return (err);
605 	}
606 
607 	mutex_exit(&ixgbe->gen_lock);
608 
609 	return (EINVAL);
610 }
611 
612 /*
613  * Modifies the value of an address that has been added before.
614  * The new address length and the slot number that was returned
615  * in the call to add should be passed in. mma_flags should be
616  * set to 0.
617  * Returns 0 on success.
618  */
619 int
620 ixgbe_m_unicst_modify(void *arg, mac_multi_addr_t *maddr)
621 {
622 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
623 	mac_addr_slot_t slot;
624 	int err;
625 
626 	mutex_enter(&ixgbe->gen_lock);
627 
628 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
629 		mutex_exit(&ixgbe->gen_lock);
630 		return (ECANCELED);
631 	}
632 
633 	if (mac_unicst_verify(ixgbe->mac_hdl,
634 	    maddr->mma_addr, maddr->mma_addrlen) == B_FALSE) {
635 		mutex_exit(&ixgbe->gen_lock);
636 		return (EINVAL);
637 	}
638 
639 	slot = maddr->mma_slot;
640 
641 	if ((slot <= 0) || (slot >= ixgbe->unicst_total)) {
642 		mutex_exit(&ixgbe->gen_lock);
643 		return (EINVAL);
644 	}
645 
646 	if (ixgbe->unicst_addr[slot].mac.set == 1) {
647 		err = ixgbe_unicst_set(ixgbe, maddr->mma_addr, slot);
648 		mutex_exit(&ixgbe->gen_lock);
649 		return (err);
650 	}
651 
652 	mutex_exit(&ixgbe->gen_lock);
653 
654 	return (EINVAL);
655 }
656 
657 /*
658  * Get the MAC address and all other information related to
659  * the address slot passed in mac_multi_addr_t.
660  * mma_flags should be set to 0 in the call.
661  * On return, mma_flags can take the following values:
662  * 1) MMAC_SLOT_UNUSED
663  * 2) MMAC_SLOT_USED | MMAC_VENDOR_ADDR
664  * 3) MMAC_SLOT_UNUSED | MMAC_VENDOR_ADDR
665  * 4) MMAC_SLOT_USED
666  */
667 int
668 ixgbe_m_unicst_get(void *arg, mac_multi_addr_t *maddr)
669 {
670 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
671 	mac_addr_slot_t slot;
672 
673 	mutex_enter(&ixgbe->gen_lock);
674 
675 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
676 		mutex_exit(&ixgbe->gen_lock);
677 		return (ECANCELED);
678 	}
679 
680 	slot = maddr->mma_slot;
681 
682 	if ((slot <= 0) || (slot >= ixgbe->unicst_total)) {
683 		mutex_exit(&ixgbe->gen_lock);
684 		return (EINVAL);
685 	}
686 	if (ixgbe->unicst_addr[slot].mac.set == 1) {
687 		bcopy(ixgbe->unicst_addr[slot].mac.addr,
688 		    maddr->mma_addr, ETHERADDRL);
689 		maddr->mma_flags = MMAC_SLOT_USED;
690 	} else {
691 		maddr->mma_flags = MMAC_SLOT_UNUSED;
692 	}
693 
694 	mutex_exit(&ixgbe->gen_lock);
695 
696 	return (0);
697 }
698 
699 /*
700  * Obtain the MAC's capabilities and associated data from
701  * the driver.
702  */
703 boolean_t
704 ixgbe_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
705 {
706 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
707 
708 	switch (cap) {
709 	case MAC_CAPAB_HCKSUM: {
710 		uint32_t *tx_hcksum_flags = cap_data;
711 
712 		/*
713 		 * We advertise our capabilities only if tx hcksum offload is
714 		 * enabled.  On receive, the stack will accept checksummed
715 		 * packets anyway, even if we haven't said we can deliver
716 		 * them.
717 		 */
718 		if (!ixgbe->tx_hcksum_enable)
719 			return (B_FALSE);
720 
721 		*tx_hcksum_flags = HCKSUM_INET_PARTIAL | HCKSUM_IPHDRCKSUM;
722 		break;
723 	}
724 	case MAC_CAPAB_LSO: {
725 		mac_capab_lso_t *cap_lso = cap_data;
726 
727 		if (ixgbe->lso_enable) {
728 			cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4;
729 			cap_lso->lso_basic_tcp_ipv4.lso_max = IXGBE_LSO_MAXLEN;
730 			break;
731 		} else {
732 			return (B_FALSE);
733 		}
734 	}
735 	case MAC_CAPAB_MULTIADDRESS: {
736 		multiaddress_capab_t *mmacp = cap_data;
737 
738 		/*
739 		 * The number of MAC addresses made available by
740 		 * this capability is one less than the total as
741 		 * the primary address in slot 0 is counted in
742 		 * the total.
743 		 */
744 		mmacp->maddr_naddr = ixgbe->unicst_total - 1;
745 		mmacp->maddr_naddrfree = ixgbe->unicst_avail;
746 		/* No multiple factory addresses, set mma_flag to 0 */
747 		mmacp->maddr_flag = 0;
748 		mmacp->maddr_handle = ixgbe;
749 		mmacp->maddr_add = ixgbe_m_unicst_add;
750 		mmacp->maddr_remove = ixgbe_m_unicst_remove;
751 		mmacp->maddr_modify = ixgbe_m_unicst_modify;
752 		mmacp->maddr_get = ixgbe_m_unicst_get;
753 		mmacp->maddr_reserve = NULL;
754 		break;
755 	}
756 	default:
757 		return (B_FALSE);
758 	}
759 	return (B_TRUE);
760 }
761