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