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