1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 QLogic Corporation. All rights reserved.
24  */
25 
26 #include <qlge.h>
27 #include <sys/strsubr.h>
28 #include <netinet/in.h>
29 #include <netinet/ip.h>
30 #include <netinet/ip6.h>
31 #include <inet/ip.h>
32 
33 /*
34  * GLDv3 functions prototypes
35  */
36 static int	ql_m_getstat(void *, uint_t, uint64_t *);
37 static int	ql_m_start(void *);
38 static void	ql_m_stop(void *);
39 static int	ql_m_setpromiscuous(void *, boolean_t);
40 static int	ql_m_multicst(void *, boolean_t, const uint8_t *);
41 static int	ql_m_unicst(void *, const uint8_t *);
42 static mblk_t	*ql_m_tx(void *, mblk_t *);
43 static void	ql_m_ioctl(void *, queue_t *, mblk_t *);
44 static boolean_t ql_m_getcapab(void *, mac_capab_t, void *);
45 static int	ql_unicst_set(qlge_t *qlge, const uint8_t *macaddr, int slot);
46 
47 static int ql_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
48     const void *);
49 static int ql_m_getprop(void *, const char *, mac_prop_id_t, uint_t, uint_t,
50     void *, uint_t *);
51 #define	QL_M_CALLBACK_FLAGS (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP)
52 static mac_callbacks_t ql_m_callbacks = {
53 	QL_M_CALLBACK_FLAGS,
54 	ql_m_getstat,
55 	ql_m_start,
56 	ql_m_stop,
57 	ql_m_setpromiscuous,
58 	ql_m_multicst,
59 	NULL,
60 	NULL,
61 	ql_m_ioctl,
62 	ql_m_getcapab,
63 	NULL,
64 	NULL,
65 	ql_m_setprop,
66 	ql_m_getprop
67 };
68 mac_priv_prop_t qlge_priv_prop[] = {
69 	{"_adv_pause_mode", MAC_PROP_PERM_RW}
70 };
71 
72 #define	QLGE_MAX_PRIV_PROPS \
73 	(sizeof (qlge_priv_prop) / sizeof (mac_priv_prop_t))
74 
75 /*
76  * This function starts the driver
77  */
78 static int
79 ql_m_start(void *arg)
80 {
81 	qlge_t *qlge = (qlge_t *)arg;
82 
83 	/*
84 	 * reset chip, re-initialize everything but do not
85 	 * re-allocate memory
86 	 */
87 	mutex_enter(&qlge->gen_mutex);
88 	if (qlge->mac_flags == QL_MAC_SUSPENDED) {
89 		mutex_exit(&qlge->gen_mutex);
90 		return (ECANCELED);
91 	}
92 	mutex_enter(&qlge->hw_mutex);
93 	qlge->mac_flags = QL_MAC_INIT;
94 	/*
95 	 * Write default ethernet address to chip register Mac
96 	 * Address slot 0 and Enable Primary Mac Function.
97 	 */
98 	ql_unicst_set(qlge,
99 	    (uint8_t *)qlge->unicst_addr[0].addr.ether_addr_octet, 0);
100 	qlge->stats.rpackets = 0;
101 	qlge->stats.rbytes = 0;
102 	qlge->stats.opackets = 0;
103 	qlge->stats.obytes = 0;
104 	mutex_exit(&qlge->hw_mutex);
105 
106 	ql_do_start(qlge);
107 	mutex_exit(&qlge->gen_mutex);
108 
109 	mutex_enter(&qlge->mbx_mutex);
110 	ql_get_firmware_version(qlge, NULL);
111 	mutex_exit(&qlge->mbx_mutex);
112 
113 	return (0);
114 }
115 
116 /*
117  * This function stops the driver
118  */
119 static void
120 ql_m_stop(void *arg)
121 {
122 	qlge_t *qlge = (qlge_t *)arg;
123 
124 	mutex_enter(&qlge->gen_mutex);
125 	if (qlge->mac_flags == QL_MAC_SUSPENDED) {
126 		mutex_exit(&qlge->gen_mutex);
127 		return;
128 	}
129 	ql_do_stop(qlge);
130 	mutex_exit(&qlge->gen_mutex);
131 	qlge->mac_flags = QL_MAC_STOPPED;
132 }
133 
134 /*
135  * Add or remove a multicast address
136  */
137 static int
138 ql_m_multicst(void *arg, boolean_t add, const uint8_t *ep)
139 {
140 	qlge_t *qlge = (qlge_t *)arg;
141 	int ret = DDI_SUCCESS;
142 
143 	mutex_enter(&qlge->gen_mutex);
144 	if (qlge->mac_flags == QL_MAC_SUSPENDED) {
145 		mutex_exit(&qlge->gen_mutex);
146 		return (ECANCELED);
147 	}
148 
149 	if (qlge->mac_flags == QL_MAC_DETACH) {
150 		mutex_exit(&qlge->gen_mutex);
151 		return (ECANCELED);
152 	}
153 	if (add) {
154 		QL_DUMP(DBG_GLD, "add to multicast list:\n",
155 		    (uint8_t *)ep, 8, ETHERADDRL);
156 		ret = ql_add_to_multicast_list(qlge, (uint8_t *)ep);
157 	} else {
158 		QL_DUMP(DBG_GLD, "remove from multicast list:\n",
159 		    (uint8_t *)ep, 8, ETHERADDRL);
160 		ret = ql_remove_from_multicast_list(qlge, (uint8_t *)ep);
161 	}
162 	mutex_exit(&qlge->gen_mutex);
163 
164 	return ((ret == DDI_SUCCESS) ? 0 : EIO);
165 }
166 
167 /*
168  * Enable or disable promiscuous mode
169  */
170 static int
171 ql_m_setpromiscuous(void* arg, boolean_t on)
172 {
173 	qlge_t *qlge = (qlge_t *)arg;
174 	int mode;
175 
176 	mutex_enter(&qlge->gen_mutex);
177 	if (qlge->mac_flags == QL_MAC_SUSPENDED) {
178 		mutex_exit(&qlge->gen_mutex);
179 		return (ECANCELED);
180 	}
181 
182 	/* enable reception of all packets on the medium, */
183 	if (on) {
184 		mode = 1;
185 		QL_PRINT(DBG_GLD, ("%s(%d) enable promiscuous mode\n",
186 		    __func__, qlge->instance));
187 	} else {
188 		mode = 0;
189 		QL_PRINT(DBG_GLD, ("%s(%d) disable promiscuous mode\n",
190 		    __func__, qlge->instance));
191 	}
192 
193 	mutex_enter(&qlge->hw_mutex);
194 	ql_set_promiscuous(qlge, mode);
195 	mutex_exit(&qlge->hw_mutex);
196 	mutex_exit(&qlge->gen_mutex);
197 	return (DDI_SUCCESS);
198 }
199 
200 
201 static int
202 ql_m_getstat(void *arg, uint_t stat, uint64_t *valp)
203 {
204 	qlge_t *qlge = (qlge_t *)arg;
205 	struct ql_stats *cur_stats;
206 	uint64_t val = 0;
207 	int i;
208 	uint32_t val32;
209 	struct rx_ring *rx_ring;
210 	struct tx_ring *tx_ring;
211 
212 	ASSERT(qlge != NULL);
213 	mutex_enter(&qlge->gen_mutex);
214 	if (qlge->mac_flags == QL_MAC_SUSPENDED) {
215 		mutex_exit(&qlge->gen_mutex);
216 		return (ECANCELED);
217 	}
218 
219 	cur_stats = &qlge->stats;
220 	/* these stats are maintained in software */
221 	switch (stat) {
222 
223 	case MAC_STAT_IFSPEED /* 1000 */ :
224 		if (CFG_IST(qlge, CFG_CHIP_8100) != 0) {
225 			qlge->speed = SPEED_10G;
226 		}
227 		val = qlge->speed * 1000000ull;
228 		break;
229 
230 	case MAC_STAT_MULTIRCV:
231 		val = cur_stats->multircv;
232 		break;
233 
234 	case MAC_STAT_BRDCSTRCV:
235 		val = cur_stats->brdcstrcv;
236 		break;
237 
238 	case MAC_STAT_MULTIXMT:
239 		cur_stats->multixmt = 0;
240 		for (i = 0; i < qlge->tx_ring_count; i++) {
241 			tx_ring = &qlge->tx_ring[i];
242 			cur_stats->multixmt += tx_ring->multixmt;
243 		}
244 		val = cur_stats->multixmt;
245 		break;
246 
247 	case MAC_STAT_BRDCSTXMT:
248 		cur_stats->brdcstxmt = 0;
249 		for (i = 0; i < qlge->tx_ring_count; i++) {
250 			tx_ring = &qlge->tx_ring[i];
251 			cur_stats->brdcstxmt += tx_ring->brdcstxmt;
252 		}
253 		val = cur_stats->brdcstxmt;
254 		break;
255 
256 	case MAC_STAT_NORCVBUF:
257 		val = cur_stats->norcvbuf;
258 		break;
259 
260 	case MAC_STAT_IERRORS:
261 		val = cur_stats->errrcv;
262 		break;
263 
264 	case MAC_STAT_OBYTES:
265 		cur_stats->obytes = 0;
266 		for (i = 0; i < qlge->tx_ring_count; i++) {
267 			tx_ring = &qlge->tx_ring[i];
268 			cur_stats->obytes += tx_ring->obytes;
269 		}
270 		val = cur_stats->obytes;
271 		break;
272 
273 	case MAC_STAT_OPACKETS:
274 		cur_stats->opackets = 0;
275 		for (i = 0; i < qlge->tx_ring_count; i++) {
276 			tx_ring = &qlge->tx_ring[i];
277 			cur_stats->opackets += tx_ring->opackets;
278 		}
279 		val = cur_stats->opackets;
280 		break;
281 
282 	case ETHER_STAT_DEFER_XMTS:
283 		cur_stats->defer = 0;
284 		for (i = 0; i < qlge->tx_ring_count; i++) {
285 			tx_ring = &qlge->tx_ring[i];
286 			cur_stats->defer += (tx_ring->defer);
287 		}
288 		val = cur_stats->defer;
289 		break;
290 
291 	case MAC_STAT_OERRORS:
292 		cur_stats->errxmt = 0;
293 		for (i = 0; i < qlge->tx_ring_count; i++) {
294 			tx_ring = &qlge->tx_ring[i];
295 			cur_stats->errxmt += tx_ring->errxmt;
296 		}
297 		val = cur_stats->errxmt;
298 		break;
299 
300 	case MAC_STAT_RBYTES:
301 		cur_stats->rbytes = 0;
302 		for (i = 0; i < qlge->rx_ring_count; i++) {
303 			rx_ring = &qlge->rx_ring[i];
304 			cur_stats->rbytes += rx_ring->rx_bytes;
305 		}
306 		val = cur_stats->rbytes;
307 		break;
308 
309 	case MAC_STAT_IPACKETS:
310 		cur_stats->rpackets = 0;
311 		for (i = 0; i < qlge->rx_ring_count; i++) {
312 			rx_ring = &qlge->rx_ring[i];
313 			cur_stats->rpackets += rx_ring->rx_packets;
314 		}
315 		val = cur_stats->rpackets;
316 		break;
317 
318 	case ETHER_STAT_FCS_ERRORS:
319 		cur_stats->crc = 0;
320 		for (i = 0; i < qlge->rx_ring_count; i++) {
321 			rx_ring = &qlge->rx_ring[i];
322 			cur_stats->crc += rx_ring->fcs_err;
323 		}
324 		val = cur_stats->crc;
325 		break;
326 
327 	case ETHER_STAT_TOOLONG_ERRORS:
328 		cur_stats->frame_too_long = 0;
329 		for (i = 0; i < qlge->rx_ring_count; i++) {
330 			rx_ring = &qlge->rx_ring[i];
331 			cur_stats->frame_too_long +=
332 			    rx_ring->frame_too_long;
333 		}
334 		val = cur_stats->frame_too_long;
335 		break;
336 
337 	case ETHER_STAT_XCVR_INUSE:
338 		val = XCVR_1000X;
339 		break;
340 	case ETHER_STAT_JABBER_ERRORS:
341 		if (ql_sem_spinlock(qlge, qlge->xgmac_sem_mask) !=
342 		    DDI_SUCCESS) {
343 			break;
344 		}
345 		ql_read_xgmac_reg(qlge, REG_XGMAC_MAC_RX_JABBER_PKTS,
346 		    &val32);
347 		val = val32;
348 		ql_sem_unlock(qlge, qlge->xgmac_sem_mask);
349 		QL_PRINT(DBG_STATS, ("%s(%d) MAC_STAT_JABBER_ERRORS "
350 		    "status %d\n", __func__, qlge->instance, val));
351 		break;
352 	case ETHER_STAT_LINK_DUPLEX:
353 		if (qlge->duplex == 1)
354 			val = LINK_DUPLEX_FULL;
355 		else
356 			val = LINK_DUPLEX_HALF;
357 		break;
358 
359 	/* statics saved in hw */
360 	case ETHER_STAT_MACRCV_ERRORS:
361 		val = 0;
362 		if (ql_sem_spinlock(qlge, qlge->xgmac_sem_mask) !=
363 		    DDI_SUCCESS) {
364 			break;
365 		}
366 		ql_read_xgmac_reg(qlge, REG_XGMAC_MAC_ALIGN_ERR,
367 		    &val32);
368 		val += val32;
369 		ql_read_xgmac_reg(qlge, REG_XGMAC_MAC_FCS_ERR, &val32);
370 		val += val32;
371 		ql_read_xgmac_reg(qlge, REG_XGMAC_MAC_RX_JABBER_PKTS,
372 		    &val32);
373 		val += val32;
374 		ql_read_xgmac_reg(qlge, REG_XGMAC_MAC_RX_SYM_ERR,
375 		    &val32);
376 		val += val32;
377 		ql_read_xgmac_reg(qlge, REG_XGMAC_MAC_RX_INT_ERR,
378 		    &val32);
379 		val += val32;
380 		ql_sem_unlock(qlge, qlge->xgmac_sem_mask);
381 		break;
382 
383 	default:
384 		mutex_exit(&qlge->gen_mutex);
385 		return (ENOTSUP);
386 	}
387 	*valp = val;
388 	mutex_exit(&qlge->gen_mutex);
389 
390 	return (0);
391 
392 }
393 
394 /*
395  * Set the physical network address
396  */
397 static int
398 ql_unicst_set(qlge_t *qlge, const uint8_t *macaddr, int slot)
399 {
400 	int status;
401 
402 	status = ql_sem_spinlock(qlge, SEM_MAC_ADDR_MASK);
403 	if (status != DDI_SUCCESS)
404 		return (EIO);
405 	status = ql_set_mac_addr_reg(qlge, (uint8_t *)macaddr,
406 	    MAC_ADDR_TYPE_CAM_MAC,
407 	    (uint16_t)(qlge->func_number * MAX_CQ + slot));
408 	ql_sem_unlock(qlge, SEM_MAC_ADDR_MASK);
409 
410 	return ((status == DDI_SUCCESS) ? 0 : EIO);
411 }
412 
413 /*
414  * Set default MAC address
415  * Each function has a total of 128 mac address, function0: 0~127,
416  * function1 128~254 etc or func_number *128 + n (0~127), but
417  * we only support one MAC address, so its address is
418  * func_number*128+0
419  */
420 static int
421 ql_m_unicst(void *arg, const uint8_t *mac)
422 {
423 	qlge_t *qlge = (qlge_t *)arg;
424 	int status;
425 
426 	ASSERT(qlge->mac_flags != QL_MAC_DETACH);
427 	mutex_enter(&qlge->gen_mutex);
428 	if (qlge->mac_flags == QL_MAC_SUSPENDED) {
429 		mutex_exit(&qlge->gen_mutex);
430 		return (ECANCELED);
431 	}
432 
433 	mutex_enter(&qlge->hw_mutex);
434 	bcopy(mac, qlge->unicst_addr[0].addr.ether_addr_octet, ETHERADDRL);
435 	/* Set Mac Address to slot 0 and Enable Primary Mac Function */
436 	status = ql_unicst_set(qlge, mac, 0);
437 	mutex_exit(&qlge->hw_mutex);
438 	mutex_exit(&qlge->gen_mutex);
439 
440 	return (status);
441 }
442 
443 /*
444  * ql_m_tx is used only for sending data packets into ethernet wire.
445  */
446 static mblk_t *
447 ql_m_tx(void *arg, mblk_t *mp)
448 {
449 	qlge_t *qlge = (qlge_t *)arg;
450 	struct tx_ring *tx_ring;
451 	mblk_t *next;
452 	int rval;
453 	uint32_t tx_count = 0;
454 
455 	if (qlge->port_link_state == LS_DOWN) {
456 		cmn_err(CE_WARN, "%s(%d): exit due to link down",
457 		    __func__, qlge->instance);
458 		freemsgchain(mp);
459 		mp = NULL;
460 		goto tx_exit;
461 	}
462 
463 	/*
464 	 * Always send this packet through tx ring 0 for now.
465 	 * Will use multiple tx rings when Crossbow is supported
466 	 */
467 	tx_ring = &qlge->tx_ring[0];
468 	mutex_enter(&tx_ring->tx_lock);
469 	if (tx_ring->mac_flags != QL_MAC_STARTED) {
470 		mutex_exit(&tx_ring->tx_lock);
471 		goto tx_exit;
472 	}
473 
474 	/* we must try to send all */
475 	while (mp != NULL) {
476 		/*
477 		 * if number of available slots is less than a threshold,
478 		 * then quit
479 		 */
480 		if (tx_ring->tx_free_count <= TX_STOP_THRESHOLD) {
481 			tx_ring->queue_stopped = 1;
482 			rval = DDI_FAILURE;
483 			/*
484 			 * If we return the buffer back we are expected to
485 			 * call mac_tx_ring_update() when
486 			 * resources are available
487 			 */
488 			tx_ring->defer++;
489 			break;
490 		}
491 		next = mp->b_next;
492 		mp->b_next = NULL;
493 
494 		rval = ql_send_common(tx_ring, mp);
495 
496 		if (rval != DDI_SUCCESS) {
497 			mp->b_next = next;
498 			break;
499 		}
500 		tx_count++;
501 		mp = next;
502 	}
503 	/*
504 	 * After all msg blocks are mapped or copied to tx buffer,
505 	 * trigger the hardware to send the msg!
506 	 */
507 	if (tx_count > 0) {
508 		ql_write_doorbell_reg(tx_ring->qlge, tx_ring->prod_idx_db_reg,
509 		    tx_ring->prod_idx);
510 	}
511 	mutex_exit(&tx_ring->tx_lock);
512 tx_exit:
513 	return (mp);
514 }
515 
516 static void
517 ql_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
518 {
519 	qlge_t *qlge = (qlge_t *)arg;
520 	struct iocblk *iocp;
521 	boolean_t need_privilege = B_TRUE;
522 	int err, cmd;
523 	enum ioc_reply status;
524 
525 	/*
526 	 * Validate the command before bothering with the mutex...
527 	 */
528 	iocp = (struct iocblk *)(void *)mp->b_rptr;
529 	iocp->ioc_error = 0;
530 	cmd = iocp->ioc_cmd;
531 
532 	mutex_enter(&qlge->gen_mutex);
533 	if (qlge->mac_flags == QL_MAC_SUSPENDED) {
534 		mutex_exit(&qlge->gen_mutex);
535 		miocnak(wq, mp, 0, EINVAL);
536 		return;
537 	}
538 	switch (cmd) {
539 		default:
540 			QL_PRINT(DBG_GLD, ("unknown ioctl cmd \n"));
541 			miocnak(wq, mp, 0, EINVAL);
542 			mutex_exit(&qlge->gen_mutex);
543 			return;
544 		case QLA_PCI_STATUS:
545 		case QLA_WRITE_REG:
546 		case QLA_READ_PCI_REG:
547 		case QLA_WRITE_PCI_REG:
548 		case QLA_GET_DBGLEAVEL:
549 		case QLA_SET_DBGLEAVEL:
550 		case QLA_READ_CONTRL_REGISTERS:
551 		case QLA_MANUAL_READ_FLASH:
552 		case QLA_MANUAL_WRITE_FLASH:
553 		case QLA_GET_BINARY_CORE_DUMP:
554 		case QLA_SUPPORTED_DUMP_TYPES:
555 		case QLA_TRIGGER_SYS_ERROR_EVENT:
556 		case QLA_READ_FLASH:
557 		case QLA_WRITE_FLASH:
558 		case QLA_READ_VPD:
559 		case QLA_GET_PROP:
560 		case QLA_SHOW_REGION:
561 		case QLA_LIST_ADAPTER_INFO:
562 		case QLA_READ_FW_IMAGE:
563 		case QLA_WRITE_FW_IMAGE_HEADERS:
564 		case QLA_CONTINUE_COPY_IN:
565 		case QLA_CONTINUE_COPY_OUT:
566 		case QLA_SOFT_RESET:
567 			break;
568 		case LB_GET_INFO_SIZE:
569 		case LB_GET_INFO:
570 		case LB_GET_MODE:
571 			need_privilege = B_FALSE;
572 		/* FALLTHRU */
573 		case LB_SET_MODE:
574 			break;
575 	}
576 
577 	if (need_privilege) {
578 		/*
579 		 * Check for specific net_config privilege
580 		 */
581 		err = secpolicy_net_config(iocp->ioc_cr, B_FALSE);
582 		if (err != 0) {
583 			miocnak(wq, mp, 0, err);
584 			mutex_exit(&qlge->gen_mutex);
585 			return;
586 		}
587 	}
588 	/*
589 	 * Implement ioctl
590 	 */
591 	switch (cmd) {
592 		case QLA_PCI_STATUS:
593 		case QLA_WRITE_REG:
594 		case QLA_READ_PCI_REG:
595 		case QLA_WRITE_PCI_REG:
596 		case QLA_GET_DBGLEAVEL:
597 		case QLA_SET_DBGLEAVEL:
598 		case QLA_READ_CONTRL_REGISTERS:
599 		case QLA_MANUAL_READ_FLASH:
600 		case QLA_MANUAL_WRITE_FLASH:
601 		case QLA_GET_BINARY_CORE_DUMP:
602 		case QLA_SUPPORTED_DUMP_TYPES:
603 		case QLA_TRIGGER_SYS_ERROR_EVENT:
604 		case QLA_READ_FLASH:
605 		case QLA_WRITE_FLASH:
606 		case QLA_READ_VPD:
607 		case QLA_GET_PROP:
608 		case QLA_SHOW_REGION:
609 		case QLA_LIST_ADAPTER_INFO:
610 		case QLA_READ_FW_IMAGE:
611 		case QLA_WRITE_FW_IMAGE_HEADERS:
612 		case QLA_CONTINUE_COPY_IN:
613 		case QLA_CONTINUE_COPY_OUT:
614 		case QLA_SOFT_RESET:
615 			status = ql_chip_ioctl(qlge, wq, mp);
616 			break;
617 		case LB_GET_INFO_SIZE:
618 		case LB_GET_INFO:
619 		case LB_GET_MODE:
620 		case LB_SET_MODE:
621 			status = ql_loop_ioctl(qlge, wq, mp, iocp);
622 			break;
623 		default:
624 			status = IOC_INVAL;
625 			break;
626 	}
627 
628 	/*
629 	 * Decide how to reply
630 	 */
631 	switch (status) {
632 	default:
633 	case IOC_INVAL:
634 		/*
635 		 * Error, reply with a NAK and EINVAL or the specified error
636 		 */
637 		miocnak(wq, mp, 0, iocp->ioc_error == 0 ?
638 		    EINVAL : iocp->ioc_error);
639 		break;
640 
641 	case IOC_DONE:
642 		/*
643 		 * OK, reply already sent
644 		 */
645 		break;
646 
647 	case IOC_ACK:
648 		/*
649 		 * OK, reply with an ACK
650 		 */
651 		miocack(wq, mp, 0, 0);
652 		break;
653 
654 	case IOC_REPLY:
655 		/*
656 		 * OK, send prepared reply as ACK or NAK
657 		 */
658 		mp->b_datap->db_type = (uint8_t)(iocp->ioc_error == 0 ?
659 		    M_IOCACK : M_IOCNAK);
660 		qreply(wq, mp);
661 		break;
662 	}
663 	mutex_exit(&qlge->gen_mutex);
664 }
665 /* ARGSUSED */
666 static int
667 qlge_set_priv_prop(qlge_t *qlge, const char *pr_name, uint_t pr_valsize,
668     const void *pr_val)
669 {
670 	int err = 0;
671 	long result;
672 
673 	if (strcmp(pr_name, "_adv_pause_mode") == 0) {
674 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
675 		if (result > PAUSE_MODE_PER_PRIORITY ||
676 		    result < PAUSE_MODE_DISABLED) {
677 			err = EINVAL;
678 		} else if (qlge->pause != (uint32_t)result) {
679 			qlge->pause = (uint32_t)result;
680 			if (qlge->flags & INTERRUPTS_ENABLED) {
681 				mutex_enter(&qlge->mbx_mutex);
682 				if (ql_set_port_cfg(qlge) == DDI_FAILURE)
683 					err = EINVAL;
684 				mutex_exit(&qlge->mbx_mutex);
685 			}
686 		}
687 		return (err);
688 	}
689 	return (ENOTSUP);
690 }
691 
692 static int
693 qlge_get_priv_prop(qlge_t *qlge, const char *pr_name, uint_t pr_flags,
694     uint_t pr_valsize, void *pr_val)
695 {
696 	int err = ENOTSUP;
697 	boolean_t is_default = (boolean_t)(pr_flags & MAC_PROP_DEFAULT);
698 	uint32_t value;
699 
700 	if (strcmp(pr_name, "_adv_pause_mode") == 0) {
701 		value = (is_default? 2 : qlge->pause);
702 		err = 0;
703 		goto done;
704 	}
705 
706 done:
707 	if (err == 0) {
708 		(void) snprintf(pr_val, pr_valsize, "%d", value);
709 	}
710 	return (err);
711 }
712 
713 /*
714  * callback functions for set/get of properties
715  */
716 /* ARGSUSED */
717 static int
718 ql_m_setprop(void *barg, const char *pr_name, mac_prop_id_t pr_num,
719     uint_t pr_valsize, const void *pr_val)
720 {
721 	qlge_t *qlge = barg;
722 	int err = 0;
723 	uint32_t cur_mtu, new_mtu;
724 
725 	mutex_enter(&qlge->gen_mutex);
726 	if (qlge->mac_flags == QL_MAC_SUSPENDED) {
727 		mutex_exit(&qlge->gen_mutex);
728 		return (ECANCELED);
729 	}
730 
731 	switch (pr_num) {
732 	case MAC_PROP_MTU:
733 		cur_mtu = qlge->mtu;
734 		bcopy(pr_val, &new_mtu, sizeof (new_mtu));
735 
736 		QL_PRINT(DBG_GLD, ("%s(%d) new mtu %d \n",
737 		    __func__, qlge->instance, new_mtu));
738 		if (new_mtu == cur_mtu) {
739 			err = 0;
740 			break;
741 		}
742 		if ((new_mtu != ETHERMTU) && (new_mtu != JUMBO_MTU)) {
743 			err = EINVAL;
744 			break;
745 		}
746 		/*
747 		 * do not change on the fly, allow only before
748 		 * driver is started or stopped
749 		 */
750 		if ((qlge->mac_flags == QL_MAC_STARTED) ||
751 		    (qlge->mac_flags == QL_MAC_DETACH)) {
752 			err = EBUSY;
753 			cmn_err(CE_WARN, "%s(%d) new mtu %d ignored, "
754 			    "driver busy, mac_flags %d", __func__,
755 			    qlge->instance, new_mtu, qlge->mac_flags);
756 			break;
757 		}
758 		qlge->mtu = new_mtu;
759 		err = mac_maxsdu_update(qlge->mh, qlge->mtu);
760 		if (err == 0) {
761 			/* EMPTY */
762 			QL_PRINT(DBG_GLD, ("%s(%d) new mtu %d set success\n",
763 			    __func__, qlge->instance,
764 			    new_mtu));
765 		}
766 		break;
767 	case MAC_PROP_PRIVATE:
768 		mutex_exit(&qlge->gen_mutex);
769 		err = qlge_set_priv_prop(qlge, pr_name, pr_valsize,
770 		    pr_val);
771 		mutex_enter(&qlge->gen_mutex);
772 		break;
773 	default:
774 		err = ENOTSUP;
775 		break;
776 	}
777 	mutex_exit(&qlge->gen_mutex);
778 	return (err);
779 }
780 
781 /* ARGSUSED */
782 static int
783 ql_m_getprop(void *barg, const char *pr_name, mac_prop_id_t pr_num,
784     uint_t pr_flags, uint_t pr_valsize, void *pr_val, uint_t *perm)
785 {
786 	qlge_t *qlge = barg;
787 	uint64_t speed;
788 	link_state_t link_state;
789 	link_duplex_t link_duplex;
790 	int err = 0;
791 
792 	mutex_enter(&qlge->gen_mutex);
793 	if (qlge->mac_flags == QL_MAC_SUSPENDED) {
794 		err = ECANCELED;
795 		goto out;
796 	}
797 
798 	if (pr_valsize == 0) {
799 		err = EINVAL;
800 		goto out;
801 	}
802 	bzero(pr_val, pr_valsize);
803 	/* mostly read only */
804 	*perm = MAC_PROP_PERM_READ;
805 
806 	switch (pr_num) {
807 	case MAC_PROP_DUPLEX:
808 		if (pr_valsize < sizeof (link_duplex_t)) {
809 			err = EINVAL;
810 			goto out;
811 		}
812 		if (qlge->duplex)
813 			link_duplex = LINK_DUPLEX_FULL;
814 		else
815 			link_duplex = LINK_DUPLEX_HALF;
816 
817 		bcopy(&link_duplex, pr_val,
818 		    sizeof (link_duplex_t));
819 		break;
820 	case MAC_PROP_SPEED:
821 		if (pr_valsize < sizeof (speed)) {
822 			err = EINVAL;
823 			goto out;
824 		}
825 		speed = qlge->speed * 1000000ull;
826 		bcopy(&speed, pr_val, sizeof (speed));
827 		break;
828 	case MAC_PROP_STATUS:
829 		if (pr_valsize < sizeof (link_state_t)) {
830 			err = EINVAL;
831 			goto out;
832 		}
833 		if (qlge->port_link_state == LS_DOWN)
834 			link_state = LINK_STATE_DOWN;
835 		else
836 			link_state = LINK_STATE_UP;
837 		bcopy(&link_state, pr_val,
838 		    sizeof (link_state_t));
839 		break;
840 
841 	case MAC_PROP_PRIVATE:
842 		err = qlge_get_priv_prop(qlge, pr_name, pr_flags,
843 		    pr_valsize, pr_val);
844 		break;
845 
846 	default:
847 		err = ENOTSUP;
848 	}
849 out:
850 	mutex_exit(&qlge->gen_mutex);
851 	return (err);
852 }
853 
854 /* ARGSUSED */
855 static boolean_t
856 ql_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
857 {
858 	int ret = B_FALSE;
859 	uint32_t cksum = 0;
860 	qlge_t *qlge = (qlge_t *)arg;
861 
862 	switch (cap) {
863 	case MAC_CAPAB_HCKSUM:
864 		if ((qlge->cfg_flags & CFG_CKSUM_FULL_IPv4) != 0) {
865 			cksum |= HCKSUM_INET_FULL_V4;
866 		}
867 		if ((qlge->cfg_flags & CFG_CKSUM_FULL_IPv6) != 0) {
868 			cksum |= HCKSUM_INET_FULL_V6;
869 		}
870 		if ((qlge->cfg_flags & CFG_CKSUM_HEADER_IPv4) != 0) {
871 			cksum |= HCKSUM_IPHDRCKSUM;
872 		}
873 		if ((qlge->cfg_flags & CFG_CKSUM_PARTIAL) != 0) {
874 			cksum |= HCKSUM_INET_PARTIAL;
875 		}
876 		qlge->chksum_cap = cksum;
877 		*(uint32_t *)cap_data = cksum;
878 		ret = B_TRUE;
879 		break;
880 
881 	case MAC_CAPAB_LSO: {
882 		mac_capab_lso_t *cap_lso = (mac_capab_lso_t *)cap_data;
883 		uint32_t page_size;
884 
885 		if ((qlge->cfg_flags & CFG_LSO)&&
886 		    (qlge->cfg_flags & CFG_SUPPORT_SCATTER_GATHER)) {
887 			cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4;
888 			page_size = ddi_ptob(qlge->dip, (ulong_t)1);
889 			cap_lso->lso_basic_tcp_ipv4.lso_max = page_size *
890 			    (QL_MAX_TX_DMA_HANDLES-1);
891 			ret = B_TRUE;
892 		}
893 		break;
894 	}
895 
896 	default:
897 		return (B_FALSE);
898 	}
899 	return (ret);
900 }
901 
902 void
903 ql_gld3_init(qlge_t *qlge, mac_register_t *macp)
904 {
905 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
906 	macp->m_driver = qlge;
907 	macp->m_dip = qlge->dip;
908 	/* This is the mac address from flash to be used by the port */
909 	macp->m_src_addr = qlge->dev_addr.ether_addr_octet;
910 	macp->m_min_sdu = 0;
911 	macp->m_max_sdu = qlge->mtu;
912 	macp->m_margin = VLAN_TAGSZ;
913 	macp->m_priv_props = qlge_priv_prop;
914 	macp->m_priv_prop_count = QLGE_MAX_PRIV_PROPS;
915 	macp->m_v12n = 0;
916 	ql_m_callbacks.mc_unicst = ql_m_unicst;
917 	ql_m_callbacks.mc_tx = ql_m_tx;
918 	macp->m_callbacks = &ql_m_callbacks;
919 }
920