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