xref: /titanic_44/usr/src/uts/common/io/usb/clients/usbecm/usbecm.c (revision 3db80ed28191e6c4e26251526d7c2376382492f8)
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 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * USB Ethernet Control Model
29  *
30  * USB-IF defines three ethernet network related specifications: EEM,
31  * ECM and NCM. This driver focuses specifically on ECM compatible
32  * devices. This kind of devices generally have one pair of bulk
33  * endpoints for in/out packet data and one interrupt endpoint for
34  * device notification.
35  *
36  * Devices which don't report ECM compatibility through descriptors but
37  * implement the ECM functions may also bind to this driver. This driver
38  * will try to find at least a bulk in endpoint and a bulk out endpoint
39  * in this case. If the non-compatible devices use vendor specific data
40  * format, this driver will not function.
41  *
42  * This driver is a normal USBA client driver. It's also a GLDv3 driver,
43  * which provides the necessary interfaces the GLDv3 framework requires.
44  *
45  */
46 
47 #include <sys/types.h>
48 #include <sys/strsun.h>
49 #include <sys/ddi.h>
50 #include <sys/sunddi.h>
51 #include <sys/byteorder.h>
52 #include <sys/usb/usba/usbai_version.h>
53 #include <sys/usb/usba.h>
54 #include <sys/usb/usba/usba_types.h>
55 #include <sys/usb/clients/usbcdc/usb_cdc.h>
56 #include <sys/usb/clients/usbecm/usbecm.h>
57 #include <sys/mac_provider.h>
58 #include <sys/strsubr.h>
59 #include <sys/ethernet.h>
60 #include <sys/mac_ether.h> /* MAC_PLUGIN_IDENT_ETHER */
61 #include <sys/random.h> /* random_get_bytes */
62 #include <sys/sdt.h>	/* sdt */
63 #include <inet/nd.h>
64 
65 /* MAC callbacks */
66 static int	usbecm_m_stat(void *arg, uint_t stat, uint64_t *val);
67 static int	usbecm_m_start(void *arg);
68 static void	usbecm_m_stop(void *arg);
69 static int	usbecm_m_unicst(void *arg, const uint8_t *macaddr);
70 static int	usbecm_m_multicst(void *arg, boolean_t add, const uint8_t *m);
71 static int	usbecm_m_promisc(void *arg, boolean_t on);
72 static void	usbecm_m_ioctl(void *arg, queue_t *wq, mblk_t *mp);
73 static mblk_t	*usbecm_m_tx(void *arg, mblk_t *mp);
74 static int	usbecm_m_getprop(void *arg, const char *pr_name,
75     mac_prop_id_t wldp_pr_num, uint_t wldp_length, void *wldp_buf);
76 static int	usbecm_m_setprop(void *arg, const char *pr_name,
77     mac_prop_id_t wldp_pr_num, uint_t wldp_length, const void *wldp_buf);
78 
79 static int	usbecm_usb_init(usbecm_state_t *ecmp);
80 static int	usbecm_mac_init(usbecm_state_t *ecmp);
81 static int	usbecm_mac_fini(usbecm_state_t *ecmp);
82 
83 
84 /* utils */
85 static void	generate_ether_addr(uint8_t *mac_addr);
86 static int	usbecm_rx_start(usbecm_state_t *ecmp);
87 
88 static void	usbecm_pipe_start_polling(usbecm_state_t *ecmp);
89 static void	usbecm_intr_cb(usb_pipe_handle_t ph, usb_intr_req_t *req);
90 static void	usbecm_intr_ex_cb(usb_pipe_handle_t ph, usb_intr_req_t *req);
91 static void	usbecm_parse_intr_data(usbecm_state_t *ecmp, mblk_t *data);
92 
93 static int	usbecm_reconnect_event_cb(dev_info_t *dip);
94 static int	usbecm_disconnect_event_cb(dev_info_t *dip);
95 
96 static int	usbecm_open_pipes(usbecm_state_t *ecmp);
97 static void	usbecm_close_pipes(usbecm_state_t *ecmp);
98 
99 static int	usbecm_ctrl_read(usbecm_state_t *ecmp, uchar_t request,
100     uint16_t value, mblk_t **data, int len);
101 static int	usbecm_ctrl_write(usbecm_state_t *ecmp, uchar_t request,
102     uint16_t value, mblk_t **data);
103 static int	usbecm_send_data(usbecm_state_t *ecmp, mblk_t *data);
104 static int	usbecm_send_zero_data(usbecm_state_t *ecmp);
105 static int	usbecm_get_statistics(usbecm_state_t *ecmp, uint32_t fs,
106     uint32_t *stat_data);
107 
108 static int	usbecm_create_pm_components(usbecm_state_t *ecmp);
109 static void	usbecm_destroy_pm_components(usbecm_state_t *ecmp);
110 static int	usbecm_power(dev_info_t *dip, int comp, int level);
111 static void	usbecm_pm_set_busy(usbecm_state_t *ecmp);
112 static void	usbecm_pm_set_idle(usbecm_state_t *ecmp);
113 
114 static int	usbecm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
115 static int	usbecm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
116 
117 static int	usbecm_suspend(usbecm_state_t *ecmp);
118 static int	usbecm_resume(usbecm_state_t *ecmp);
119 static int	usbecm_restore_device_state(usbecm_state_t *ecmp);
120 static void	usbecm_cleanup(usbecm_state_t *ecmp);
121 
122 /* Driver identification */
123 static char usbecm_ident[] = "usbecm 1.0";
124 
125 /* Global state pointer for managing per-device soft states */
126 void *usbecm_statep;
127 
128 /* print levels */
129 static uint_t   usbecm_errlevel = USB_LOG_L3;
130 static uint_t   usbecm_errmask = 0xffffffff;
131 static uint_t   usbecm_instance_debug = (uint_t)-1;
132 
133 /*
134  * to prevent upper layers packet flood from exhausting system
135  * resources(USBA does not set limitation of requests on a pipe),
136  * we set a upper limit for the transfer queue length.
137  */
138 static	int	usbecm_tx_max = 32;
139 
140 #define	SUN_SP_VENDOR_ID	0x0430
141 #define	SUN_SP_PRODUCT_ID	0xa4a2
142 
143 static uint8_t	usbecm_broadcast[ETHERADDRL] = {
144 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
145 };
146 
147 static usb_event_t usbecm_events = {
148 	usbecm_disconnect_event_cb,
149 	usbecm_reconnect_event_cb,
150 	NULL, NULL
151 };
152 
153 #define	ECM_DS_OP_VALID(op) ((ecmp->ecm_ds_ops) && (ecmp->ecm_ds_ops->op))
154 
155 /*
156  * MAC Call Back entries
157  */
158 static mac_callbacks_t usbecm_m_callbacks = {
159 	MC_IOCTL | MC_SETPROP | MC_GETPROP,
160 	usbecm_m_stat,		/* Get the value of a statistic */
161 	usbecm_m_start,		/* Start the device */
162 	usbecm_m_stop,		/* Stop the device */
163 	usbecm_m_promisc,	/* Enable or disable promiscuous mode */
164 	usbecm_m_multicst,	/* Enable or disable a multicast addr */
165 	usbecm_m_unicst,	/* Set the unicast MAC address */
166 	usbecm_m_tx,		/* Transmit a packet */
167 	NULL,
168 	usbecm_m_ioctl,		/* Process an unknown ioctl */
169 	NULL,			/* mc_getcapab */
170 	NULL,			/* mc_open */
171 	NULL,			/* mc_close */
172 	usbecm_m_setprop, 	/* mc_setprop */
173 	usbecm_m_getprop,	/* mc_getprop */
174 	NULL
175 };
176 
177 
178 /*
179  *  Module Loading Data & Entry Points
180  *     Can't use DDI_DEFINE_STREAM_OPS, since it does
181  *     not provide devo_power entry.
182  */
183 static struct cb_ops cb_usbecm = {
184 	nulldev,		/* cb_open */
185 	nulldev,		/* cb_close */
186 	nodev,			/* cb_strategy */
187 	nodev,			/* cb_print */
188 	nodev,			/* cb_dump */
189 	nodev,			/* cb_read */
190 	nodev,			/* cb_write */
191 	nodev,			/* cb_ioctl */
192 	nodev,			/* cb_devmap */
193 	nodev,			/* cb_mmap */
194 	nodev,			/* cb_segmap */
195 	nochpoll,		/* cb_chpoll */
196 	ddi_prop_op,		/* cb_prop_op */
197 	NULL,			/* cb_stream */
198 	D_MP,			/* cb_flag */
199 	CB_REV,			/* cb_rev */
200 	nodev,			/* cb_aread */
201 	nodev,			/* cb_awrite */
202 };
203 
204 static struct dev_ops usbecm_devops = {
205 	DEVO_REV,		/* devo_rev */
206 	0,			/* devo_refcnt */
207 	NULL,			/* devo_getinfo */
208 	nulldev,		/* devo_identify */
209 	nulldev,		/* devo_probe */
210 	usbecm_attach,		/* devo_attach */
211 	usbecm_detach,		/* devo_detach */
212 	nodev,			/* devo_reset */
213 	&(cb_usbecm),		/* devo_cb_ops */
214 	(struct bus_ops *)NULL,	/* devo_bus_ops */
215 	usbecm_power,		/* devo_power */
216 	ddi_quiesce_not_needed	/* devo_quiesce */
217 };
218 
219 static struct modldrv usbecm_modldrv = {
220 	&mod_driverops,		/* drv_modops */
221 	usbecm_ident,		/* drv_linkinfo */
222 	&usbecm_devops		/* drv_dev_ops */
223 };
224 
225 static struct modlinkage usbecm_ml = {
226 	MODREV_1,		/* ml_rev */
227 	&usbecm_modldrv, NULL	/* ml_linkage */
228 };
229 
230 
231 /*
232  * Device operations
233  */
234 /*
235  * Binding the driver to a device.
236  *
237  * Concurrency: Until usbecm_attach() returns with success,
238  * the only other entry point that can be executed is getinfo().
239  * Thus no locking here yet.
240  */
241 static int
usbecm_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)242 usbecm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
243 {
244 	char strbuf[32];
245 	int instance;
246 	int err;
247 	usbecm_state_t *ecmp = NULL;
248 
249 	switch (cmd) {
250 	case DDI_ATTACH:
251 		break;
252 
253 	case DDI_RESUME:
254 		ecmp = (usbecm_state_t *)ddi_get_soft_state(usbecm_statep,
255 		    ddi_get_instance(dip));
256 
257 		(void) usbecm_resume(ecmp);
258 
259 		return (DDI_SUCCESS);
260 
261 	default:
262 		return (DDI_FAILURE);
263 	}
264 
265 	instance = ddi_get_instance(dip);
266 
267 	if (ddi_soft_state_zalloc(usbecm_statep, instance) == DDI_SUCCESS) {
268 		ecmp = ddi_get_soft_state(usbecm_statep, instance);
269 	}
270 	if (ecmp == NULL) {
271 		cmn_err(CE_WARN, "usbecm_attach: fail to get soft state");
272 
273 		return (DDI_FAILURE);
274 	}
275 
276 	ecmp->ecm_dip = dip;
277 
278 	ecmp->ecm_lh = usb_alloc_log_hdl(ecmp->ecm_dip, "usbecm",
279 	    &usbecm_errlevel, &usbecm_errmask, &usbecm_instance_debug, 0);
280 
281 	if (usbecm_usb_init(ecmp) != USB_SUCCESS) {
282 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
283 		    "usbecm_attach: failed to init usb");
284 
285 		goto fail;
286 	}
287 
288 	if (ECM_DS_OP_VALID(ecm_ds_init)) {
289 		if (ecmp->ecm_ds_ops->ecm_ds_init(ecmp) != USB_SUCCESS) {
290 			USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
291 			    "usbecm_attach: failed to init DS");
292 
293 			goto fail;
294 		}
295 	}
296 
297 	if (usbecm_mac_init(ecmp) != DDI_SUCCESS) {
298 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
299 		    "usbecm_attach: failed to init mac");
300 
301 		goto fail;
302 	}
303 	ecmp->ecm_init_flags |= USBECM_INIT_MAC;
304 
305 	/*
306 	 * Create minor node of type usb_net. Not necessary to create
307 	 * DDI_NT_NET since it's created in mac_register(). Otherwise,
308 	 * system will panic.
309 	 */
310 	(void) snprintf(strbuf, sizeof (strbuf), "usbecm%d", instance);
311 	err = ddi_create_minor_node(dip, strbuf, S_IFCHR,
312 	    instance + 1, "usb_net", 0);
313 	if (err != DDI_SUCCESS) {
314 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
315 		    "failed to create minor node");
316 
317 		goto fail;
318 	}
319 
320 	/* always busy. May change to a more precise PM in future */
321 	usbecm_pm_set_busy(ecmp);
322 
323 	ddi_report_dev(dip);
324 
325 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ecmp->ecm_lh,
326 	    "usbecm_attach: succeed!");
327 
328 	return (DDI_SUCCESS);
329 
330 fail:
331 	USB_DPRINTF_L1(PRINT_MASK_ATTA, ecmp->ecm_lh,
332 	    "usbecm_attach: Attach fail");
333 
334 	usbecm_cleanup(ecmp);
335 	ddi_prop_remove_all(dip);
336 	ddi_soft_state_free(usbecm_statep, instance);
337 
338 	return (DDI_FAILURE);
339 
340 }
341 
342 
343 /*
344  * Detach the driver from a device.
345  *
346  * Concurrency: Will be called only after a successful attach
347  * (and not concurrently).
348  */
349 static int
usbecm_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)350 usbecm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
351 {
352 	usbecm_state_t *ecmp = NULL;
353 	int instance;
354 
355 	instance = ddi_get_instance(dip);
356 	ecmp = ddi_get_soft_state(usbecm_statep, instance);
357 	ASSERT(ecmp != NULL);
358 
359 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ecmp->ecm_lh,
360 	    "usbecm_detach: entry ");
361 
362 	switch (cmd) {
363 	case DDI_DETACH:
364 		break;
365 
366 	case DDI_SUSPEND:
367 
368 		return (usbecm_suspend(ecmp));
369 
370 	default:
371 		return (DDI_FAILURE);
372 	}
373 
374 	usbecm_pm_set_idle(ecmp);
375 
376 	if (ECM_DS_OP_VALID(ecm_ds_fini)) {
377 		if (ecmp->ecm_ds_ops->ecm_ds_fini(ecmp) != USB_SUCCESS) {
378 			USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
379 			    "usbecm_detach: deinitialize DS fail!");
380 
381 			return (DDI_FAILURE);
382 		}
383 	}
384 
385 	if (usbecm_mac_fini(ecmp) != 0) {
386 
387 		return (DDI_FAILURE);
388 	}
389 
390 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ecmp->ecm_lh,
391 	    "usbecm_detach: exit");
392 
393 	usbecm_cleanup(ecmp);
394 	ddi_soft_state_free(usbecm_statep, instance);
395 
396 	return (DDI_SUCCESS);
397 }
398 
399 
400 /*
401  * Mac Call Back functions
402  */
403 
404 /*
405  * Read device statistic information.
406  */
407 static int
usbecm_m_stat(void * arg,uint_t stat,uint64_t * val)408 usbecm_m_stat(void *arg, uint_t stat, uint64_t *val)
409 {
410 	usbecm_state_t *ecmp = (usbecm_state_t *)arg;
411 	uint32_t	stats;
412 	int		rval;
413 	uint32_t	fs;
414 
415 	USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
416 	    "usbecm_m_stat: entry, stat=%d", stat);
417 
418 	/*
419 	 * Some of the stats are MII specific. We try to
420 	 * resolve all the statistics we understand. If
421 	 * the usb device can't provide it, return ENOTSUP.
422 	 */
423 	switch (stat) {
424 	case MAC_STAT_IFSPEED:
425 		/* return link speed */
426 		mutex_enter(&ecmp->ecm_mutex);
427 		if (ecmp->ecm_stat.es_downspeed) {
428 			*val = ecmp->ecm_stat.es_downspeed;
429 		} else {
430 			*val = 10 * 1000000ull; /* set a default value */
431 		}
432 		mutex_exit(&ecmp->ecm_mutex);
433 
434 		return (0);
435 	case ETHER_STAT_LINK_DUPLEX:
436 		*val = LINK_DUPLEX_FULL;
437 
438 		return (0);
439 
440 	case ETHER_STAT_SQE_ERRORS:
441 		*val = 0;
442 
443 		return (0);
444 
445 	/* Map MAC/Ether stats to ECM statistics */
446 	case MAC_STAT_NORCVBUF:
447 		fs = ECM_RCV_NO_BUFFER;
448 
449 		break;
450 	case MAC_STAT_NOXMTBUF:
451 		fs = ECM_XMIT_ERROR;
452 
453 		break;
454 	case MAC_STAT_IERRORS:
455 		fs = ECM_RCV_ERROR;
456 
457 		break;
458 	case MAC_STAT_OERRORS:
459 		fs = ECM_XMIT_ERROR;
460 
461 		break;
462 	case MAC_STAT_RBYTES:
463 		fs = ECM_DIRECTED_BYTES_RCV;
464 
465 		break;
466 	case MAC_STAT_IPACKETS:
467 		fs = ECM_RCV_OK; /* frames */
468 
469 		break;
470 	case MAC_STAT_OBYTES:
471 		fs = ECM_DIRECTED_BYTES_XMIT;
472 
473 		break;
474 	case MAC_STAT_OPACKETS:
475 		fs = ECM_XMIT_OK; /* frames */
476 
477 		break;
478 	case MAC_STAT_MULTIRCV:
479 		fs = ECM_MULTICAST_FRAMES_RCV;
480 
481 		break;
482 	case MAC_STAT_BRDCSTRCV:
483 		fs = ECM_BROADCAST_FRAMES_RCV;
484 
485 		break;
486 	case MAC_STAT_MULTIXMT:
487 		fs = ECM_MULTICAST_FRAMES_XMIT;
488 
489 		break;
490 	case MAC_STAT_BRDCSTXMT:
491 		fs = ECM_BROADCAST_FRAMES_XMIT;
492 
493 		break;
494 	case MAC_STAT_COLLISIONS:
495 		fs = ECM_XMIT_MAX_COLLISIONS;
496 
497 		break;
498 	case MAC_STAT_OVERFLOWS:
499 		fs = ECM_RCV_OVERRUN;
500 
501 		break;
502 	case MAC_STAT_UNDERFLOWS:
503 		fs = ECM_XMIT_UNDERRUN;
504 
505 		break;
506 	case ETHER_STAT_FCS_ERRORS:
507 		fs = ECM_RCV_CRC_ERROR;
508 
509 		break;
510 	case ETHER_STAT_ALIGN_ERRORS:
511 		fs = ECM_RCV_ERROR_ALIGNMENT;
512 
513 		break;
514 	case ETHER_STAT_DEFER_XMTS:
515 		fs = ECM_XMIT_DEFERRED;
516 
517 		break;
518 	case ETHER_STAT_FIRST_COLLISIONS:
519 		fs = ECM_XMIT_ONE_COLLISION;
520 
521 		break;
522 	case ETHER_STAT_MULTI_COLLISIONS:
523 		fs = ECM_XMIT_MORE_COLLISIONS;
524 
525 		break;
526 	case ETHER_STAT_TX_LATE_COLLISIONS:
527 		fs = ECM_XMIT_LATE_COLLISIONS;
528 
529 		break;
530 
531 	default:
532 		return (ENOTSUP);
533 	}
534 
535 	/*
536 	 * we need to access device to get required stats,
537 	 * so check device state first
538 	 */
539 	mutex_enter(&ecmp->ecm_mutex);
540 	if (ecmp->ecm_dev_state != USB_DEV_ONLINE) {
541 		USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
542 		    "usbecm_m_stat: device not ONLINE");
543 
544 		mutex_exit(&ecmp->ecm_mutex);
545 
546 		return (EIO);
547 	}
548 	mutex_exit(&ecmp->ecm_mutex);
549 
550 	rval = usbecm_get_statistics(ecmp,
551 	    ECM_STAT_SELECTOR(fs), &stats);
552 	if (rval != USB_SUCCESS) {
553 		mutex_enter(&ecmp->ecm_mutex);
554 		switch (stat) {
555 		case MAC_STAT_IERRORS:
556 			*val = ecmp->ecm_stat.es_ierrors;
557 
558 			break;
559 		case MAC_STAT_OERRORS:
560 			*val = ecmp->ecm_stat.es_oerrors;
561 
562 			break;
563 		case MAC_STAT_RBYTES:
564 			*val = ecmp->ecm_stat.es_ibytes;
565 
566 			break;
567 		case MAC_STAT_IPACKETS:
568 			*val = ecmp->ecm_stat.es_ipackets;
569 
570 			break;
571 		case MAC_STAT_OBYTES:
572 			*val = ecmp->ecm_stat.es_obytes;
573 
574 			break;
575 		case MAC_STAT_OPACKETS:
576 			*val = ecmp->ecm_stat.es_opackets;
577 
578 			break;
579 		case MAC_STAT_MULTIRCV:
580 			*val = ecmp->ecm_stat.es_multircv;
581 
582 			break;
583 		case MAC_STAT_MULTIXMT:
584 			*val = ecmp->ecm_stat.es_multixmt;
585 
586 			break;
587 		case MAC_STAT_BRDCSTRCV:
588 			*val = ecmp->ecm_stat.es_brdcstrcv;
589 
590 			break;
591 		case MAC_STAT_BRDCSTXMT:
592 			*val = ecmp->ecm_stat.es_brdcstxmt;
593 
594 			break;
595 		case ETHER_STAT_MACXMT_ERRORS:
596 			*val = ecmp->ecm_stat.es_macxmt_err;
597 			break;
598 		default:
599 			*val = 0;
600 
601 			break;
602 		}
603 		mutex_exit(&ecmp->ecm_mutex);
604 	} else {
605 		*val = stats;
606 	}
607 
608 	USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
609 	    "usbecm_m_stat: end");
610 
611 	return (0);
612 }
613 
614 
615 /*
616  * Start the device:
617  *	- Set proper altsettings of the data interface
618  *	- Open status and data endpoints
619  *	- Start status polling
620  *	- Get bulk-in ep ready to receive data from ethernet
621  *
622  * Concurrency: Presumably fully concurrent, must lock.
623  */
624 static int
usbecm_m_start(void * arg)625 usbecm_m_start(void *arg)
626 {
627 	usbecm_state_t *ecmp = (usbecm_state_t *)arg;
628 	int rval;
629 
630 	USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
631 	    "usbecm_m_start: entry");
632 
633 	(void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
634 	mutex_enter(&ecmp->ecm_mutex);
635 	if (ecmp->ecm_dev_state != USB_DEV_ONLINE) {
636 		USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
637 		    "usbecm_m_start: device not online");
638 		rval = ENODEV;
639 		mutex_exit(&ecmp->ecm_mutex);
640 
641 		goto fail;
642 	}
643 	mutex_exit(&ecmp->ecm_mutex);
644 
645 	if (usbecm_open_pipes(ecmp) != USB_SUCCESS) {
646 		USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
647 		    "usbecm_m_start: open pipes fail");
648 		rval = EIO;
649 
650 		goto fail;
651 	}
652 
653 	mutex_enter(&ecmp->ecm_mutex);
654 	if (usbecm_rx_start(ecmp) != USB_SUCCESS) {
655 		USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
656 		    "usbecm_m_start: fail to start_rx");
657 		mutex_exit(&ecmp->ecm_mutex);
658 		rval = EIO;
659 
660 		goto fail;
661 	}
662 	ecmp->ecm_mac_state = USBECM_MAC_STARTED;
663 	mutex_exit(&ecmp->ecm_mutex);
664 
665 	/* set the device to receive all multicast/broadcast pkts */
666 	rval = usbecm_ctrl_write(ecmp, CDC_ECM_SET_ETH_PKT_FLT,
667 	    CDC_ECM_PKT_TYPE_DIRECTED | CDC_ECM_PKT_TYPE_ALL_MCAST |
668 	    CDC_ECM_PKT_TYPE_BCAST, NULL);
669 	if (rval != USB_SUCCESS) {
670 		USB_DPRINTF_L3(PRINT_MASK_OPS, ecmp->ecm_lh,
671 		    "usbecm_m_start: set packet filters fail,"
672 		    " rval=%d, continue", rval);
673 	}
674 
675 	if (ECM_DS_OP_VALID(ecm_ds_start)) {
676 		if (ecmp->ecm_ds_ops->ecm_ds_start(ecmp) != USB_SUCCESS) {
677 			USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
678 			    "usbecm_m_start: Can't start hardware");
679 
680 			goto fail;
681 		}
682 	}
683 
684 	usb_release_access(ecmp->ecm_ser_acc);
685 
686 	USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
687 	    "usbecm_m_start: end");
688 
689 	/*
690 	 * To mark the link as RUNNING.
691 	 *
692 	 * ECM spec doesn't provide a way for host to get the status
693 	 * of the physical link initiatively. Only the device can
694 	 * report the link state through interrupt endpoints.
695 	 */
696 	mac_link_update(ecmp->ecm_mh, LINK_STATE_UP);
697 	mutex_enter(&ecmp->ecm_mutex);
698 	ecmp->ecm_stat.es_linkstate = LINK_STATE_UP;
699 	mutex_exit(&ecmp->ecm_mutex);
700 
701 	return (DDI_SUCCESS);
702 fail:
703 	usb_release_access(ecmp->ecm_ser_acc);
704 
705 	return (rval);
706 }
707 
708 /*
709  * Stop the device.
710  */
711 static void
usbecm_m_stop(void * arg)712 usbecm_m_stop(void *arg)
713 {
714 	usbecm_state_t *ecmp = (usbecm_state_t *)arg;
715 
716 	USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
717 	    "usbecm_m_stop: entry");
718 
719 	(void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
720 	if (ECM_DS_OP_VALID(ecm_ds_stop)) {
721 		if (ecmp->ecm_ds_ops->ecm_ds_stop(ecmp) != USB_SUCCESS) {
722 			USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
723 			    "usbecm_m_stop: fail to stop hardware");
724 		}
725 	}
726 
727 	usbecm_close_pipes(ecmp);
728 	usb_release_access(ecmp->ecm_ser_acc);
729 
730 	mutex_enter(&ecmp->ecm_mutex);
731 	ecmp->ecm_mac_state = USBECM_MAC_STOPPED;
732 	mutex_exit(&ecmp->ecm_mutex);
733 
734 	mac_link_update(ecmp->ecm_mh, LINK_STATE_DOWN);
735 	mutex_enter(&ecmp->ecm_mutex);
736 	ecmp->ecm_stat.es_linkstate = LINK_STATE_DOWN;
737 	mutex_exit(&ecmp->ecm_mutex);
738 
739 	USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
740 	    "usbecm_m_stop: end");
741 }
742 
743 /*
744  * Change the MAC address of the device.
745  */
746 /*ARGSUSED*/
747 static int
usbecm_m_unicst(void * arg,const uint8_t * macaddr)748 usbecm_m_unicst(void *arg, const uint8_t *macaddr)
749 {
750 	usbecm_state_t *ecmp = (usbecm_state_t *)arg;
751 	uint16_t	filter;
752 	int		rval;
753 
754 	USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
755 	    "usbecm_m_unicst: entry");
756 
757 	/*
758 	 * The device doesn't support to set a different MAC addr.
759 	 * Hence, it's not necessary to stop the device first if
760 	 * the mac addresses are identical. And we just set unicast
761 	 * filter only.
762 	 */
763 	if (bcmp(macaddr, ecmp->ecm_srcaddr, ETHERADDRL) != 0) {
764 		USB_DPRINTF_L3(PRINT_MASK_OPS, ecmp->ecm_lh,
765 		    "usbecm_m_unicst: not supported to set a"
766 		    " different MAC addr");
767 
768 		return (DDI_FAILURE);
769 	}
770 	mutex_enter(&ecmp->ecm_mutex);
771 	filter = ecmp->ecm_pkt_flt |= CDC_ECM_PKT_TYPE_DIRECTED;
772 	mutex_exit(&ecmp->ecm_mutex);
773 
774 	(void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
775 	rval = usbecm_ctrl_write(ecmp, CDC_ECM_SET_ETH_PKT_FLT,
776 	    filter, NULL);
777 	usb_release_access(ecmp->ecm_ser_acc);
778 
779 	USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
780 	    "usbecm_m_unicst: rval = %d", rval);
781 
782 	/* some devices may not support this request, we just return success */
783 	return (DDI_SUCCESS);
784 }
785 
786 /*
787  * Enable/disable multicast.
788  */
789 /*ARGSUSED*/
790 static int
usbecm_m_multicst(void * arg,boolean_t add,const uint8_t * m)791 usbecm_m_multicst(void *arg, boolean_t add, const uint8_t *m)
792 {
793 	usbecm_state_t *ecmp = (usbecm_state_t *)arg;
794 	uint16_t	filter;
795 	int	rval = 0;
796 
797 	USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
798 	    "usbecm_m_multicst: entry");
799 	mutex_enter(&ecmp->ecm_mutex);
800 
801 	/*
802 	 * To simplify the implementation, we support switching
803 	 * all multicast on/off feature only
804 	 */
805 	if (add == B_TRUE) {
806 		ecmp->ecm_pkt_flt |= CDC_ECM_PKT_TYPE_ALL_MCAST;
807 	} else {
808 		ecmp->ecm_pkt_flt &= ~CDC_ECM_PKT_TYPE_ALL_MCAST;
809 	}
810 	filter = ecmp->ecm_pkt_flt;
811 	mutex_exit(&ecmp->ecm_mutex);
812 
813 	(void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
814 	if (ecmp->ecm_compatibility &&
815 	    (ecmp->ecm_desc.wNumberMCFilters & 0x7F)) {
816 	/* Device supports SetEthernetMulticastFilters request */
817 		rval = usbecm_ctrl_write(ecmp, CDC_ECM_SET_ETH_PKT_FLT,
818 		    filter, NULL);
819 		USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
820 		    "usbecm_m_multicst: rval = %d", rval);
821 	}
822 	usb_release_access(ecmp->ecm_ser_acc);
823 
824 	/* some devices may not support this request, we just return success */
825 	return (DDI_SUCCESS);
826 }
827 
828 /*
829  * Enable/disable promiscuous mode.
830  */
831 static int
usbecm_m_promisc(void * arg,boolean_t on)832 usbecm_m_promisc(void *arg, boolean_t on)
833 {
834 	usbecm_state_t *ecmp = (usbecm_state_t *)arg;
835 	uint16_t	filter;
836 	int		rval;
837 
838 	USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
839 	    "usbecm_m_promisc: entry");
840 
841 	mutex_enter(&ecmp->ecm_mutex);
842 	if (ecmp->ecm_dev_state != USB_DEV_ONLINE) {
843 		USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
844 		    "usbecm_m_promisc: device not ONLINE");
845 		mutex_exit(&ecmp->ecm_mutex);
846 
847 		return (DDI_FAILURE);
848 	}
849 
850 
851 	if (on == B_TRUE) {
852 		ecmp->ecm_pkt_flt |= CDC_ECM_PKT_TYPE_PROMISC;
853 	} else {
854 		ecmp->ecm_pkt_flt &= ~CDC_ECM_PKT_TYPE_PROMISC;
855 	}
856 	filter = ecmp->ecm_pkt_flt;
857 	mutex_exit(&ecmp->ecm_mutex);
858 
859 	(void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
860 	rval = usbecm_ctrl_write(ecmp, CDC_ECM_SET_ETH_PKT_FLT,
861 	    filter, NULL);
862 	usb_release_access(ecmp->ecm_ser_acc);
863 
864 	USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
865 	    "usbecm_m_promisc: rval=%d", rval);
866 
867 	/*
868 	 * devices may not support this request, we just
869 	 * return success to let upper layer to do further
870 	 * operation.
871 	 */
872 	return (DDI_SUCCESS);
873 }
874 
875 /*
876  * IOCTL request: Does not do anything. Will be enhanced
877  *	in future.
878  */
879 static void
usbecm_m_ioctl(void * arg,queue_t * wq,mblk_t * mp)880 usbecm_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
881 {
882 	usbecm_state_t *ecmp = (usbecm_state_t *)arg;
883 	struct iocblk   *iocp;
884 	int cmd;
885 
886 	USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
887 	    "usbecm_m_ioctl: entry");
888 
889 	mutex_enter(&ecmp->ecm_mutex);
890 	if (ecmp->ecm_dev_state != USB_DEV_ONLINE) {
891 		USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
892 		    "usbecm_m_ioctl: device not ONLINE");
893 		mutex_exit(&ecmp->ecm_mutex);
894 
895 		miocnak(wq, mp, 0, EIO);
896 
897 		return;
898 	}
899 	mutex_exit(&ecmp->ecm_mutex);
900 
901 	iocp = (void *)mp->b_rptr;
902 	iocp->ioc_error = 0;
903 	cmd = iocp->ioc_cmd;
904 
905 	(void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
906 
907 	switch (cmd) {
908 	default:
909 		USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
910 		    "unknown cmd 0x%x", cmd);
911 		usb_release_access(ecmp->ecm_ser_acc);
912 		miocnak(wq, mp, 0, EINVAL);
913 
914 		return;
915 	}
916 }
917 
918 /*
919  * callback functions for get/set properties
920  *	Does not do anything. Will be enhanced to
921  *	support set/get properties in future.
922  */
923 /*ARGSUSED*/
924 static int
usbecm_m_setprop(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,uint_t wldp_length,const void * wldp_buf)925 usbecm_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
926     uint_t wldp_length, const void *wldp_buf)
927 {
928 	usbecm_state_t *ecmp = (usbecm_state_t *)arg;
929 	int err = ENOTSUP;
930 
931 	USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
932 	    "usbecm_m_setprop: entry");
933 
934 	return (err);
935 }
936 
937 /*ARGSUSED*/
usbecm_m_getprop(void * arg,const char * pr_name,mac_prop_id_t wldp_pr_num,uint_t wldp_length,void * wldp_buf)938 static int usbecm_m_getprop(void *arg, const char *pr_name,
939     mac_prop_id_t wldp_pr_num, uint_t wldp_length, void *wldp_buf)
940 {
941 	usbecm_state_t *ecmp = (usbecm_state_t *)arg;
942 	int err = ENOTSUP;
943 
944 	USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
945 	    "usbecm_m_getprop: entry");
946 
947 	mutex_enter(&ecmp->ecm_mutex);
948 	if (ecmp->ecm_dev_state != USB_DEV_ONLINE) {
949 		mutex_exit(&ecmp->ecm_mutex);
950 
951 		return (EIO);
952 	}
953 	mutex_exit(&ecmp->ecm_mutex);
954 
955 	return (err);
956 }
957 
958 /*
959  * Transmit a data frame.
960  */
961 static mblk_t *
usbecm_m_tx(void * arg,mblk_t * mp)962 usbecm_m_tx(void *arg, mblk_t *mp)
963 {
964 	usbecm_state_t *ecmp = (usbecm_state_t *)arg;
965 	mblk_t *next;
966 	int count = 0;
967 
968 	ASSERT(mp != NULL);
969 
970 	USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
971 	    "usbecm_m_tx: entry");
972 
973 	mutex_enter(&ecmp->ecm_mutex);
974 	if (ecmp->ecm_dev_state != USB_DEV_ONLINE) {
975 		USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
976 		    "usbecm_m_tx: device not ONLINE");
977 		mutex_exit(&ecmp->ecm_mutex);
978 
979 		return (mp);
980 	}
981 	mutex_exit(&ecmp->ecm_mutex);
982 
983 	(void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
984 
985 	/*
986 	 * To make use of the device maximum capability,
987 	 * concatenate msg blocks in a msg to ETHERMAX length.
988 	 */
989 	while (mp != NULL) {
990 		next = mp->b_next;
991 		mp->b_next = NULL;
992 
993 		if (usbecm_send_data(ecmp, mp) != DDI_SUCCESS) {
994 			USB_DPRINTF_L3(PRINT_MASK_OPS, ecmp->ecm_lh,
995 			    "usbecm_m_tx: send data fail");
996 
997 			/* failure statistics */
998 			mutex_enter(&ecmp->ecm_mutex);
999 			ecmp->ecm_stat.es_oerrors++;
1000 			mutex_exit(&ecmp->ecm_mutex);
1001 
1002 			mp->b_next = next;
1003 
1004 			break;
1005 		}
1006 
1007 		/*
1008 		 * To make it simple, we count all packets, no matter
1009 		 * the device supports ethernet statistics or not.
1010 		 */
1011 		mutex_enter(&ecmp->ecm_mutex);
1012 		ecmp->ecm_stat.es_opackets++;
1013 		ecmp->ecm_stat.es_obytes += MBLKL(mp);
1014 		mutex_exit(&ecmp->ecm_mutex);
1015 
1016 		freemsg(mp); /* free this msg upon success */
1017 
1018 		mp = next;
1019 		USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
1020 		    "usbecm_m_tx: %d msgs processed", ++count);
1021 	}
1022 
1023 	usb_release_access(ecmp->ecm_ser_acc);
1024 
1025 	return (mp);
1026 }
1027 
1028 /*
1029  * usbecm_bulkin_cb:
1030  *	Bulk In regular and exeception callback;
1031  *	USBA framework will call this callback
1032  *	after deal with bulkin request.
1033  */
1034 /*ARGSUSED*/
1035 static void
usbecm_bulkin_cb(usb_pipe_handle_t pipe,usb_bulk_req_t * req)1036 usbecm_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
1037 {
1038 	usbecm_state_t	*ecmp = (usbecm_state_t *)req->bulk_client_private;
1039 	mblk_t		*data, *mp;
1040 	int		data_len;
1041 	int		max_pkt_size = ecmp->ecm_bulkin_sz;
1042 
1043 	data = req->bulk_data;
1044 	data_len = (data) ? MBLKL(data) : 0;
1045 
1046 	ASSERT(data->b_cont == NULL);
1047 
1048 	mutex_enter(&ecmp->ecm_mutex);
1049 
1050 	USB_DPRINTF_L4(PRINT_MASK_CB, ecmp->ecm_lh,
1051 	    "usbecm_bulkin_cb: state=%d, len=%d", ecmp->ecm_bulkin_state,
1052 	    data_len);
1053 
1054 	/*
1055 	 * may receive a zero length packet according
1056 	 * to USB short packet semantics
1057 	 */
1058 	if ((ecmp->ecm_dev_state == USB_DEV_ONLINE) &&
1059 	    (req->bulk_completion_reason == USB_CR_OK)) {
1060 		if (data_len) {
1061 			if (ecmp->ecm_rcv_queue == NULL) {
1062 				ecmp->ecm_rcv_queue = data;
1063 			} else {
1064 				if ((msgsize(ecmp->ecm_rcv_queue) + data_len)
1065 				    > ETHERMAX) {
1066 				/*
1067 				 * Exceed the ethernet maximum length, we think
1068 				 * something is wrong with this frame and hence
1069 				 * free older data. Accept new data instead.
1070 				 */
1071 					freemsg(ecmp->ecm_rcv_queue);
1072 					ecmp->ecm_rcv_queue = data;
1073 				} else {
1074 					linkb(ecmp->ecm_rcv_queue, data);
1075 				}
1076 			}
1077 		} else {
1078 		/*
1079 		 * Do not put zero length packet to receive queue.
1080 		 * Otherwise, msgpullup will dupmsg() a zero length
1081 		 * mblk, which will cause memleaks.
1082 		 */
1083 			freemsg(data);
1084 		}
1085 
1086 		/*
1087 		 * ECM V1.2, section 3.3.1, a short(including zero length)
1088 		 * packet signifies end of frame. We can submit this frame
1089 		 * to upper layer now.
1090 		 */
1091 		if ((data_len < max_pkt_size) &&
1092 		    (msgsize(ecmp->ecm_rcv_queue) > 0)) {
1093 			mp = msgpullup(ecmp->ecm_rcv_queue, -1);
1094 			freemsg(ecmp->ecm_rcv_queue);
1095 			ecmp->ecm_rcv_queue = NULL;
1096 
1097 			ecmp->ecm_stat.es_ipackets++;
1098 			ecmp->ecm_stat.es_ibytes += msgsize(mp);
1099 			if (mp && (mp->b_rptr[0] & 0x01)) {
1100 				if (bcmp(mp->b_rptr, usbecm_broadcast,
1101 				    ETHERADDRL) != 0) {
1102 					ecmp->ecm_stat.es_multircv++;
1103 				} else {
1104 					ecmp->ecm_stat.es_brdcstrcv++;
1105 				}
1106 			}
1107 
1108 			if (mp) {
1109 				mutex_exit(&ecmp->ecm_mutex);
1110 				mac_rx(ecmp->ecm_mh, NULL, mp);
1111 				mutex_enter(&ecmp->ecm_mutex);
1112 			}
1113 		}
1114 
1115 		/* prevent USBA from freeing data along with the request */
1116 		req->bulk_data = NULL;
1117 	} else if (req->bulk_completion_reason != USB_CR_OK) {
1118 		ecmp->ecm_stat.es_ierrors++;
1119 	}
1120 	mutex_exit(&ecmp->ecm_mutex);
1121 
1122 	usb_free_bulk_req(req);
1123 
1124 	/* receive more */
1125 	mutex_enter(&ecmp->ecm_mutex);
1126 	if (((ecmp->ecm_bulkin_state == USBECM_PIPE_BUSY) ||
1127 	    (ecmp->ecm_bulkin_state == USBECM_PIPE_IDLE)) &&
1128 	    (ecmp->ecm_dev_state == USB_DEV_ONLINE)) {
1129 		if (usbecm_rx_start(ecmp) != USB_SUCCESS) {
1130 			USB_DPRINTF_L2(PRINT_MASK_CB, ecmp->ecm_lh,
1131 			    "usbecm_bulkin_cb: restart rx fail "
1132 			    "ecmp_state = %d", ecmp->ecm_bulkin_state);
1133 		}
1134 	} else if (ecmp->ecm_bulkin_state == USBECM_PIPE_BUSY) {
1135 		ecmp->ecm_bulkin_state = USBECM_PIPE_IDLE;
1136 	}
1137 	mutex_exit(&ecmp->ecm_mutex);
1138 }
1139 
1140 /*
1141  * usbsecm_rx_start:
1142  *	start data receipt
1143  */
1144 static int
usbecm_rx_start(usbecm_state_t * ecmp)1145 usbecm_rx_start(usbecm_state_t *ecmp)
1146 {
1147 	usb_bulk_req_t	*br;
1148 	int		rval = USB_FAILURE;
1149 	int		data_len;
1150 
1151 	ASSERT(mutex_owned(&ecmp->ecm_mutex));
1152 
1153 	DTRACE_PROBE2(usbecm_rx__start, int, ecmp->ecm_xfer_sz,
1154 	    int, ecmp->ecm_bulkin_sz);
1155 
1156 	ecmp->ecm_bulkin_state = USBECM_PIPE_BUSY;
1157 	data_len = ecmp->ecm_bulkin_sz;
1158 
1159 	mutex_exit(&ecmp->ecm_mutex);
1160 	br = usb_alloc_bulk_req(ecmp->ecm_dip, data_len, USB_FLAGS_SLEEP);
1161 	if (br == NULL) {
1162 		USB_DPRINTF_L2(PRINT_MASK_CB, ecmp->ecm_lh,
1163 		    "usbsecm_rx_start: allocate bulk request failed");
1164 
1165 		mutex_enter(&ecmp->ecm_mutex);
1166 
1167 		return (USB_FAILURE);
1168 	}
1169 	/* initialize bulk in request. */
1170 	br->bulk_len = data_len;
1171 	br->bulk_timeout = 0;
1172 	br->bulk_cb = usbecm_bulkin_cb;
1173 	br->bulk_exc_cb = usbecm_bulkin_cb;
1174 	br->bulk_client_private = (usb_opaque_t)ecmp;
1175 	br->bulk_attributes = USB_ATTRS_AUTOCLEARING
1176 	    | USB_ATTRS_SHORT_XFER_OK;
1177 
1178 	rval = usb_pipe_bulk_xfer(ecmp->ecm_bulkin_ph, br, 0);
1179 	mutex_enter(&ecmp->ecm_mutex);
1180 	if (rval != USB_SUCCESS) {
1181 		USB_DPRINTF_L2(PRINT_MASK_CB, ecmp->ecm_lh,
1182 		    "usbsecm_rx_start: bulk transfer failed %d", rval);
1183 		usb_free_bulk_req(br);
1184 		ecmp->ecm_bulkin_state = USBECM_PIPE_IDLE;
1185 	}
1186 
1187 	return (rval);
1188 }
1189 
1190 /*
1191  * usbecm_bulkout_cb:
1192  *	Bulk Out regular and exeception callback;
1193  *	USBA framework will call this callback function
1194  *	after deal with bulkout request.
1195  */
1196 /*ARGSUSED*/
1197 static void
usbecm_bulkout_cb(usb_pipe_handle_t pipe,usb_bulk_req_t * req)1198 usbecm_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
1199 {
1200 	usbecm_state_t *ecmp = (usbecm_state_t *)req->bulk_client_private;
1201 	int		data_len;
1202 	boolean_t	need_update = B_FALSE;
1203 
1204 	data_len = (req->bulk_data) ? MBLKL(req->bulk_data) : 0;
1205 
1206 	USB_DPRINTF_L4(PRINT_MASK_CB, ecmp->ecm_lh,
1207 	    "usbecm_bulkout_cb: data_len = %d, cr=%d", data_len,
1208 	    req->bulk_completion_reason);
1209 
1210 	mutex_enter(&ecmp->ecm_mutex);
1211 	if ((data_len > 0) && (ecmp->ecm_tx_cnt > 0)) {
1212 		if (ecmp->ecm_tx_cnt == usbecm_tx_max) {
1213 			need_update = B_TRUE;
1214 		}
1215 		ecmp->ecm_tx_cnt--;
1216 	}
1217 	mutex_exit(&ecmp->ecm_mutex);
1218 
1219 	if (req->bulk_completion_reason && (data_len > 0)) {
1220 		mutex_enter(&ecmp->ecm_mutex);
1221 		ecmp->ecm_stat.es_oerrors++;
1222 		mutex_exit(&ecmp->ecm_mutex);
1223 
1224 		need_update = B_TRUE;
1225 	}
1226 
1227 	/*
1228 	 * notify MAC layer to retransfer the failed packet
1229 	 * Or notity MAC that we have more buffer now.
1230 	 */
1231 	if (need_update) {
1232 		mac_tx_update(ecmp->ecm_mh);
1233 	}
1234 
1235 	usb_free_bulk_req(req);
1236 }
1237 
1238 static int
usbecm_send_data(usbecm_state_t * ecmp,mblk_t * data)1239 usbecm_send_data(usbecm_state_t *ecmp, mblk_t *data)
1240 {
1241 	usb_bulk_req_t	*br;
1242 	int		rval = USB_FAILURE;
1243 	int		data_len = MBLKL(data);
1244 	int		max_pkt_size;
1245 	mblk_t		*new_data = NULL;
1246 	int		new_data_len = 0;
1247 
1248 	USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
1249 	    "usbecm_send_data: length = %d, total len=%d",
1250 	    data_len, (int)msgdsize(data));
1251 
1252 	mutex_enter(&ecmp->ecm_mutex);
1253 	if (ecmp->ecm_tx_cnt >= usbecm_tx_max) {
1254 		USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
1255 		    "usbecm_send_data: (%d) exceeds TX max queue length",
1256 		    ecmp->ecm_tx_cnt);
1257 		mutex_exit(&ecmp->ecm_mutex);
1258 
1259 		return (USB_FAILURE);
1260 	}
1261 	mutex_exit(&ecmp->ecm_mutex);
1262 
1263 	data_len = msgsize(data);
1264 	if (data_len > ETHERMAX) {
1265 		mutex_enter(&ecmp->ecm_mutex);
1266 		ecmp->ecm_stat.es_macxmt_err++;
1267 		mutex_exit(&ecmp->ecm_mutex);
1268 
1269 		USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
1270 		    "usbecm_send_data: packet too long, %d", data_len);
1271 
1272 		return (USB_FAILURE);
1273 	}
1274 
1275 	if (data_len < ETHERMIN) {
1276 		mblk_t *tmp;
1277 
1278 		USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
1279 		    "usbecm_send_data: short packet, padding to ETHERMIN");
1280 
1281 		new_data_len = ETHERMIN;
1282 		if ((new_data = allocb(new_data_len, 0)) == NULL) {
1283 			USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
1284 			    "usbecm_send_data: fail to allocb");
1285 
1286 			return (USB_FAILURE);
1287 		}
1288 		bzero(new_data->b_wptr, new_data_len);
1289 		for (tmp = data; tmp != NULL; tmp = tmp->b_cont) {
1290 			bcopy(tmp->b_rptr, new_data->b_wptr, MBLKL(tmp));
1291 			new_data->b_wptr += MBLKL(tmp);
1292 		}
1293 
1294 		new_data->b_wptr = new_data->b_rptr + new_data_len;
1295 	}
1296 
1297 	br = usb_alloc_bulk_req(ecmp->ecm_dip, 0, USB_FLAGS_SLEEP);
1298 	if (br == NULL) {
1299 		USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
1300 		    "usbecm_send_data: alloc req failed.");
1301 
1302 		return (USB_FAILURE);
1303 	}
1304 
1305 	/* initialize the bulk out request */
1306 	if (new_data) {
1307 		br->bulk_data = msgpullup(new_data, -1); /* msg allocated! */
1308 		br->bulk_len = new_data_len;
1309 	} else {
1310 		br->bulk_data = msgpullup(data, -1); /* msg allocated! */
1311 		br->bulk_len = data_len;
1312 	}
1313 
1314 	USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
1315 	    "usbecm_send_data: bulk_len = %d", br->bulk_len);
1316 
1317 	br->bulk_timeout = USBECM_BULKOUT_TIMEOUT;
1318 	br->bulk_cb = usbecm_bulkout_cb;
1319 	br->bulk_exc_cb = usbecm_bulkout_cb;
1320 	br->bulk_client_private = (usb_opaque_t)ecmp;
1321 	br->bulk_attributes = USB_ATTRS_AUTOCLEARING;
1322 
1323 	if (br->bulk_data != NULL) {
1324 		if (br->bulk_data->b_rptr[0] & 0x01) {
1325 			mutex_enter(&ecmp->ecm_mutex);
1326 			if (bcmp(br->bulk_data->b_rptr, usbecm_broadcast,
1327 			    ETHERADDRL) != 0) {
1328 				ecmp->ecm_stat.es_multixmt++;
1329 			} else {
1330 				ecmp->ecm_stat.es_brdcstxmt++;
1331 			}
1332 			mutex_exit(&ecmp->ecm_mutex);
1333 		}
1334 		rval = usb_pipe_bulk_xfer(ecmp->ecm_bulkout_ph, br, 0);
1335 	}
1336 
1337 	if (rval != USB_SUCCESS) {
1338 		USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
1339 		    "usbecm_send_data: Send Data failed.");
1340 
1341 		/*
1342 		 * br->bulk_data should be freed because we allocated
1343 		 * it in this function.
1344 		 */
1345 		usb_free_bulk_req(br);
1346 
1347 	} else {
1348 		mutex_enter(&ecmp->ecm_mutex);
1349 		ecmp->ecm_tx_cnt++;
1350 		mutex_exit(&ecmp->ecm_mutex);
1351 
1352 		/*
1353 		 * ECM V1.2, section 3.3.1, a short(including zero length)
1354 		 * packet signifies end of frame. We should send a zero length
1355 		 * packet to device if the total data lenght is multiple of
1356 		 * bulkout endpoint's max packet size.
1357 		 */
1358 		max_pkt_size = ecmp->ecm_bulk_out_ep->ep_descr.wMaxPacketSize;
1359 		if ((data_len % max_pkt_size) == 0) {
1360 			if ((rval = usbecm_send_zero_data(ecmp))
1361 			    != USB_SUCCESS) {
1362 				USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
1363 				    "usbecm_send_data: fail to send padding");
1364 			}
1365 		}
1366 	}
1367 
1368 	if (new_data) {
1369 		freemsg(new_data);
1370 	}
1371 
1372 	USB_DPRINTF_L4(PRINT_MASK_EVENTS, ecmp->ecm_lh,
1373 	    "usbecm_send_data: len(%d) data sent, rval=%d",
1374 	    new_data_len ? new_data_len : data_len, rval);
1375 
1376 	return (rval);
1377 }
1378 
1379 static int
usbecm_send_zero_data(usbecm_state_t * ecmp)1380 usbecm_send_zero_data(usbecm_state_t *ecmp)
1381 {
1382 	usb_bulk_req_t	*br;
1383 	int		rval = USB_FAILURE;
1384 
1385 	USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
1386 	    "usbecm_send_zero_data: entry");
1387 
1388 	br = usb_alloc_bulk_req(ecmp->ecm_dip, 0, USB_FLAGS_SLEEP);
1389 	if (br == NULL) {
1390 		USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
1391 		    "usbecm_send_data: alloc req failed.");
1392 
1393 		return (USB_FAILURE);
1394 	}
1395 
1396 	/* initialize the bulk out request */
1397 	br->bulk_len = 0;
1398 	br->bulk_timeout = USBECM_BULKOUT_TIMEOUT;
1399 	br->bulk_cb = usbecm_bulkout_cb;
1400 	br->bulk_exc_cb = usbecm_bulkout_cb;
1401 	br->bulk_client_private = (usb_opaque_t)ecmp;
1402 	br->bulk_attributes = USB_ATTRS_AUTOCLEARING;
1403 
1404 	rval = usb_pipe_bulk_xfer(ecmp->ecm_bulkout_ph, br, 0);
1405 
1406 	if (rval != USB_SUCCESS) {
1407 		USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
1408 		    "usbecm_send_zero_data: Send data failed, rval=%d",
1409 		    rval);
1410 
1411 		/*
1412 		 * br->bulk_data should be freed because we allocated
1413 		 * it in this function.
1414 		 */
1415 		usb_free_bulk_req(br);
1416 
1417 	}
1418 
1419 	USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
1420 	    "usbecm_send_zero_data: end");
1421 
1422 	return (rval);
1423 }
1424 
1425 /*
1426  * Loadable module configuration entry points
1427  */
1428 
1429 /*
1430  * _init module entry point.
1431  *
1432  * Called when the module is being loaded into memory.
1433  */
1434 int
_init(void)1435 _init(void)
1436 {
1437 	int err;
1438 
1439 	err = ddi_soft_state_init(&usbecm_statep, sizeof (usbecm_state_t), 1);
1440 
1441 	if (err != DDI_SUCCESS)
1442 		return (err);
1443 
1444 	mac_init_ops(&usbecm_devops, "usbecm");
1445 	err = mod_install(&usbecm_ml);
1446 
1447 	if (err != DDI_SUCCESS) {
1448 		mac_fini_ops(&usbecm_devops);
1449 		ddi_soft_state_fini(&usbecm_statep);
1450 	}
1451 
1452 	return (err);
1453 }
1454 
1455 /*
1456  * _info module entry point.
1457  *
1458  * Called to obtain information about the module.
1459  */
1460 int
_info(struct modinfo * modinfop)1461 _info(struct modinfo *modinfop)
1462 {
1463 	return (mod_info(&usbecm_ml, modinfop));
1464 }
1465 
1466 /*
1467  * _fini module entry point.
1468  *
1469  * Called when the module is being unloaded.
1470  */
1471 int
_fini(void)1472 _fini(void)
1473 {
1474 	int err;
1475 
1476 	err = mod_remove(&usbecm_ml);
1477 	if (err == DDI_SUCCESS) {
1478 		mac_fini_ops(&usbecm_devops);
1479 		ddi_soft_state_fini(&usbecm_statep);
1480 	}
1481 
1482 	return (err);
1483 }
1484 
1485 /*
1486  * usbecm_pipe_start_polling:
1487  *	start polling on the interrupt pipe
1488  */
1489 static void
usbecm_pipe_start_polling(usbecm_state_t * ecmp)1490 usbecm_pipe_start_polling(usbecm_state_t *ecmp)
1491 {
1492 	usb_intr_req_t	*intr;
1493 	int		rval;
1494 
1495 	USB_DPRINTF_L4(PRINT_MASK_OPEN, ecmp->ecm_lh,
1496 	    "usbecm_pipe_start_polling: ");
1497 
1498 	if (ecmp->ecm_intr_ph == NULL) {
1499 
1500 		return;
1501 	}
1502 
1503 	intr = usb_alloc_intr_req(ecmp->ecm_dip, 0, USB_FLAGS_SLEEP);
1504 
1505 	/*
1506 	 * If it is in interrupt context, usb_alloc_intr_req will return NULL if
1507 	 * called with SLEEP flag.
1508 	 */
1509 	if (!intr) {
1510 		USB_DPRINTF_L2(PRINT_MASK_OPEN, ecmp->ecm_lh,
1511 		    "usbecm_pipe_start_polling: alloc req failed.");
1512 
1513 		return;
1514 	}
1515 
1516 	/* initialize the interrupt request. */
1517 	intr->intr_attributes = USB_ATTRS_SHORT_XFER_OK |
1518 	    USB_ATTRS_AUTOCLEARING;
1519 	intr->intr_len = ecmp->ecm_intr_ep->ep_descr.wMaxPacketSize;
1520 	intr->intr_client_private = (usb_opaque_t)ecmp;
1521 	intr->intr_cb = usbecm_intr_cb;
1522 	intr->intr_exc_cb = usbecm_intr_ex_cb;
1523 
1524 	rval = usb_pipe_intr_xfer(ecmp->ecm_intr_ph, intr, USB_FLAGS_SLEEP);
1525 
1526 	mutex_enter(&ecmp->ecm_mutex);
1527 	if (rval == USB_SUCCESS) {
1528 		ecmp->ecm_intr_state = USBECM_PIPE_BUSY;
1529 	} else {
1530 		usb_free_intr_req(intr);
1531 		ecmp->ecm_intr_state = USBECM_PIPE_IDLE;
1532 		USB_DPRINTF_L3(PRINT_MASK_OPEN, ecmp->ecm_lh,
1533 		    "usbecm_pipe_start_polling: failed (%d)", rval);
1534 	}
1535 	mutex_exit(&ecmp->ecm_mutex);
1536 
1537 	USB_DPRINTF_L3(PRINT_MASK_OPEN, ecmp->ecm_lh,
1538 	    "usbecm_pipe_start_polling: end, rval=%d", rval);
1539 }
1540 
1541 
1542 /*
1543  * usbsecm_intr_cb:
1544  *	interrupt pipe normal callback
1545  */
1546 /*ARGSUSED*/
1547 static void
usbecm_intr_cb(usb_pipe_handle_t ph,usb_intr_req_t * req)1548 usbecm_intr_cb(usb_pipe_handle_t ph, usb_intr_req_t *req)
1549 {
1550 	usbecm_state_t *ecmp = (usbecm_state_t *)req->intr_client_private;
1551 	mblk_t		*data = req->intr_data;
1552 	int		data_len;
1553 
1554 	data_len = (data) ? MBLKL(data) : 0;
1555 
1556 	DTRACE_PROBE2(usbecm_intr__cb, (usb_intr_req_t *), req, int, data_len);
1557 
1558 	/* check data length */
1559 	if (data_len < 8) {
1560 		USB_DPRINTF_L2(PRINT_MASK_CB, ecmp->ecm_lh,
1561 		    "usbsecm_intr_cb: %d packet too short", data_len);
1562 		usb_free_intr_req(req);
1563 
1564 		return;
1565 	}
1566 	req->intr_data = NULL;
1567 	usb_free_intr_req(req);
1568 
1569 	mutex_enter(&ecmp->ecm_mutex);
1570 	/* parse interrupt data -- notifications */
1571 	usbecm_parse_intr_data(ecmp, data);
1572 	mutex_exit(&ecmp->ecm_mutex);
1573 }
1574 
1575 
1576 /*
1577  * usbsecm_intr_ex_cb:
1578  *	interrupt pipe exception callback
1579  */
1580 /*ARGSUSED*/
1581 static void
usbecm_intr_ex_cb(usb_pipe_handle_t ph,usb_intr_req_t * req)1582 usbecm_intr_ex_cb(usb_pipe_handle_t ph, usb_intr_req_t *req)
1583 {
1584 	usbecm_state_t *ecmp = (usbecm_state_t *)req->intr_client_private;
1585 	usb_cr_t	cr = req->intr_completion_reason;
1586 
1587 	DTRACE_PROBE2(usbecm_intr_ex__cb, int, ecmp->ecm_dev_state,
1588 	    (usb_cr_t), cr);
1589 
1590 	usb_free_intr_req(req);
1591 
1592 	/*
1593 	 * If completion reason isn't USB_CR_PIPE_CLOSING and
1594 	 * USB_CR_STOPPED_POLLING, restart polling.
1595 	 */
1596 	if ((cr != USB_CR_PIPE_CLOSING) && (cr != USB_CR_STOPPED_POLLING)) {
1597 		mutex_enter(&ecmp->ecm_mutex);
1598 
1599 		if (ecmp->ecm_dev_state != USB_DEV_ONLINE) {
1600 
1601 			USB_DPRINTF_L2(PRINT_MASK_CB, ecmp->ecm_lh,
1602 			    "usbsecm_intr_ex_cb: state = %d",
1603 			    ecmp->ecm_dev_state);
1604 
1605 			mutex_exit(&ecmp->ecm_mutex);
1606 
1607 			return;
1608 		}
1609 		mutex_exit(&ecmp->ecm_mutex);
1610 
1611 		usbecm_pipe_start_polling(ecmp);
1612 	}
1613 }
1614 
1615 
1616 /*
1617  * usbsecm_parse_intr_data:
1618  *	Parse data received from interrupt callback
1619  */
1620 static void
usbecm_parse_intr_data(usbecm_state_t * ecmp,mblk_t * data)1621 usbecm_parse_intr_data(usbecm_state_t *ecmp, mblk_t *data)
1622 {
1623 	uint8_t		bmRequestType;
1624 	uint8_t		bNotification;
1625 	uint16_t	wValue;
1626 	uint16_t	wLength;
1627 	int		linkstate;
1628 
1629 	bmRequestType = data->b_rptr[0];
1630 	bNotification = data->b_rptr[1];
1631 	/*
1632 	 * If Notification type is NETWORK_CONNECTION, wValue is 0 or 1,
1633 	 * mLength is 0. If Notification type is SERIAL_TYPE, mValue is 0,
1634 	 * mLength is 2. So we directly get the value from the byte.
1635 	 */
1636 	wValue = data->b_rptr[2];
1637 	wLength = data->b_rptr[6];
1638 
1639 	if (ecmp->ecm_compatibility) {
1640 		if (bmRequestType != USB_CDC_NOTIFICATION_REQUEST_TYPE) {
1641 			USB_DPRINTF_L2(PRINT_MASK_CB, ecmp->ecm_lh,
1642 			    "usbsecm_parse_intr_data: unknown request "
1643 			    "type - 0x%x", bmRequestType);
1644 
1645 			freemsg(data);
1646 
1647 			return;
1648 		}
1649 	} else {
1650 		/* non-compatible device specific parsing */
1651 		if (ECM_DS_OP_VALID(ecm_ds_intr_cb)) {
1652 			if (ecmp->ecm_ds_ops->ecm_ds_intr_cb(ecmp, data)
1653 			    != USB_SUCCESS) {
1654 				USB_DPRINTF_L2(PRINT_MASK_CB, ecmp->ecm_lh,
1655 				    "usbsecm_parse_intr_data: unknown request"
1656 				    "type - 0x%x", bmRequestType);
1657 			}
1658 		}
1659 		freemsg(data);
1660 
1661 		return;
1662 	}
1663 
1664 	/*
1665 	 * Check the return value of compatible devices
1666 	 */
1667 	switch (bNotification) {
1668 	case USB_CDC_NOTIFICATION_NETWORK_CONNECTION:
1669 		USB_DPRINTF_L3(PRINT_MASK_CB, ecmp->ecm_lh,
1670 		    "usbsecm_parse_intr_data: %s network!",
1671 		    wValue ? "connected to" :"disconnected from");
1672 
1673 		linkstate = wValue ? LINK_STATE_UP:LINK_STATE_DOWN;
1674 		if (ecmp->ecm_stat.es_linkstate == linkstate) {
1675 		/* no changes to previous state */
1676 			break;
1677 		}
1678 
1679 		ecmp->ecm_stat.es_linkstate = linkstate;
1680 		mutex_exit(&ecmp->ecm_mutex);
1681 		mac_link_update(ecmp->ecm_mh, linkstate);
1682 		mutex_enter(&ecmp->ecm_mutex);
1683 
1684 		break;
1685 	case USB_CDC_NOTIFICATION_RESPONSE_AVAILABLE:
1686 		USB_DPRINTF_L3(PRINT_MASK_CB, ecmp->ecm_lh,
1687 		    "usbsecm_parse_intr_data: A response is a available.");
1688 
1689 		break;
1690 	case USB_CDC_NOTIFICATION_SPEED_CHANGE:
1691 		USB_DPRINTF_L3(PRINT_MASK_CB, ecmp->ecm_lh,
1692 		    "usbsecm_parse_intr_data: speed change");
1693 
1694 		/* check the parameter's length. */
1695 		if (wLength != 8) {
1696 			USB_DPRINTF_L3(PRINT_MASK_CB, ecmp->ecm_lh,
1697 			    "usbsecm_parse_intr_data: error data length.");
1698 		} else {
1699 			uint32_t	us_rate, ds_rate;
1700 			uint8_t		*sp;
1701 
1702 			sp = &data->b_rptr[8];
1703 			LE_TO_UINT32(sp, us_rate);
1704 			sp = &data->b_rptr[12];
1705 			LE_TO_UINT32(sp, ds_rate);
1706 			ecmp->ecm_stat.es_upspeed = us_rate;
1707 			ecmp->ecm_stat.es_downspeed = ds_rate;
1708 		}
1709 
1710 		break;
1711 	default:
1712 		USB_DPRINTF_L3(PRINT_MASK_CB, ecmp->ecm_lh,
1713 		    "usbsecm_parse_intr_data: unknown notification - 0x%x!",
1714 		    bNotification);
1715 
1716 		break;
1717 	}
1718 
1719 	freemsg(data);
1720 }
1721 
1722 /*
1723  * usbecm_restore_device_state:
1724  *	restore device state after CPR resume or reconnect
1725  */
1726 static int
usbecm_restore_device_state(usbecm_state_t * ecmp)1727 usbecm_restore_device_state(usbecm_state_t *ecmp)
1728 {
1729 	int	state;
1730 
1731 	USB_DPRINTF_L4(PRINT_MASK_EVENTS, ecmp->ecm_lh,
1732 	    "usbecm_restore_device_state: ");
1733 
1734 	mutex_enter(&ecmp->ecm_mutex);
1735 	state = ecmp->ecm_dev_state;
1736 	mutex_exit(&ecmp->ecm_mutex);
1737 
1738 	/* Check device status */
1739 	if ((state != USB_DEV_DISCONNECTED) && (state != USB_DEV_SUSPENDED)) {
1740 
1741 		return (state);
1742 	}
1743 
1744 	/* Check if we are talking to the same device */
1745 	if (usb_check_same_device(ecmp->ecm_dip, ecmp->ecm_lh, USB_LOG_L0,
1746 	    -1, USB_CHK_ALL, NULL) != USB_SUCCESS) {
1747 		mutex_enter(&ecmp->ecm_mutex);
1748 		state = ecmp->ecm_dev_state = USB_DEV_DISCONNECTED;
1749 		mutex_exit(&ecmp->ecm_mutex);
1750 
1751 		return (state);
1752 	}
1753 
1754 	if (state == USB_DEV_DISCONNECTED) {
1755 		USB_DPRINTF_L1(PRINT_MASK_EVENTS, ecmp->ecm_lh,
1756 		    "usbecm_restore_device_state: Device has been reconnected "
1757 		    "but data may have been lost");
1758 	}
1759 
1760 	/* if MAC was started, restarted it */
1761 	mutex_enter(&ecmp->ecm_mutex);
1762 	if (ecmp->ecm_mac_state == USBECM_MAC_STARTED) {
1763 		USB_DPRINTF_L3(PRINT_MASK_EVENTS, ecmp->ecm_lh,
1764 		    "usbecm_restore_device_state: MAC was started");
1765 
1766 		mutex_exit(&ecmp->ecm_mutex);
1767 		/* Do the same operation as usbecm_m_start() does */
1768 		if (usbecm_open_pipes(ecmp) != USB_SUCCESS) {
1769 
1770 			return (state);
1771 		}
1772 
1773 		mutex_enter(&ecmp->ecm_mutex);
1774 		if (usbecm_rx_start(ecmp) != USB_SUCCESS) {
1775 			mutex_exit(&ecmp->ecm_mutex);
1776 
1777 			return (state);
1778 		}
1779 	}
1780 	mutex_exit(&ecmp->ecm_mutex);
1781 
1782 	/*
1783 	 * init device state
1784 	 */
1785 	mutex_enter(&ecmp->ecm_mutex);
1786 	state = ecmp->ecm_dev_state = USB_DEV_ONLINE;
1787 	mutex_exit(&ecmp->ecm_mutex);
1788 
1789 	return (state);
1790 }
1791 
1792 /*
1793  * usbecm_reconnect_event_cb:
1794  *     called upon when the device is hotplugged back
1795  */
1796 /*ARGSUSED*/
1797 static int
usbecm_reconnect_event_cb(dev_info_t * dip)1798 usbecm_reconnect_event_cb(dev_info_t *dip)
1799 {
1800 	usbecm_state_t	*ecmp =
1801 	    (usbecm_state_t *)ddi_get_soft_state(usbecm_statep,
1802 	    ddi_get_instance(dip));
1803 
1804 	ASSERT(ecmp != NULL);
1805 
1806 	USB_DPRINTF_L4(PRINT_MASK_EVENTS, ecmp->ecm_lh,
1807 	    "usbecm_reconnect_event_cb: entry");
1808 
1809 	(void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
1810 
1811 	mutex_enter(&ecmp->ecm_mutex);
1812 	ASSERT(ecmp->ecm_dev_state == USB_DEV_DISCONNECTED);
1813 
1814 	mutex_exit(&ecmp->ecm_mutex);
1815 
1816 	if (usbecm_restore_device_state(ecmp) != USB_DEV_ONLINE) {
1817 		usb_release_access(ecmp->ecm_ser_acc);
1818 
1819 		return (USB_FAILURE);
1820 	}
1821 
1822 	usb_release_access(ecmp->ecm_ser_acc);
1823 
1824 	return (USB_SUCCESS);
1825 }
1826 
1827 
1828 /*
1829  * usbecm_disconnect_event_cb:
1830  *	callback for disconnect events
1831  */
1832 /*ARGSUSED*/
1833 static int
usbecm_disconnect_event_cb(dev_info_t * dip)1834 usbecm_disconnect_event_cb(dev_info_t *dip)
1835 {
1836 	usbecm_state_t	*ecmp = (usbecm_state_t *)ddi_get_soft_state(
1837 	    usbecm_statep, ddi_get_instance(dip));
1838 
1839 	USB_DPRINTF_L4(PRINT_MASK_EVENTS, ecmp->ecm_lh,
1840 	    "usbecm_disconnect_event_cb: entry");
1841 
1842 	(void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
1843 
1844 	mutex_enter(&ecmp->ecm_mutex);
1845 	ecmp->ecm_dev_state = USB_DEV_DISCONNECTED;
1846 	mutex_exit(&ecmp->ecm_mutex);
1847 
1848 	usbecm_close_pipes(ecmp);
1849 
1850 	usb_release_access(ecmp->ecm_ser_acc);
1851 
1852 	USB_DPRINTF_L4(PRINT_MASK_EVENTS, ecmp->ecm_lh,
1853 	    "usbecm_disconnect_event_cb: End");
1854 
1855 	return (USB_SUCCESS);
1856 }
1857 
1858 /*
1859  * power management
1860  * ----------------
1861  *
1862  * usbecm_create_pm_components:
1863  *	create PM components
1864  */
1865 static int
usbecm_create_pm_components(usbecm_state_t * ecmp)1866 usbecm_create_pm_components(usbecm_state_t *ecmp)
1867 {
1868 	dev_info_t	*dip = ecmp->ecm_dip;
1869 	usbecm_pm_t	*pm;
1870 	uint_t		pwr_states;
1871 
1872 	USB_DPRINTF_L4(PRINT_MASK_PM, ecmp->ecm_lh,
1873 	    "usbecm_create_pm_components: entry");
1874 
1875 	if (usb_create_pm_components(dip, &pwr_states) != USB_SUCCESS) {
1876 		USB_DPRINTF_L2(PRINT_MASK_PM, ecmp->ecm_lh,
1877 		    "usbecm_create_pm_components: failed");
1878 
1879 		/* don't fail the attach process */
1880 		return (USB_SUCCESS);
1881 	}
1882 
1883 	pm = ecmp->ecm_pm =
1884 	    (usbecm_pm_t *)kmem_zalloc(sizeof (usbecm_pm_t), KM_SLEEP);
1885 
1886 	pm->pm_pwr_states = (uint8_t)pwr_states;
1887 	pm->pm_cur_power = USB_DEV_OS_FULL_PWR;
1888 	pm->pm_wakeup_enabled = (usb_handle_remote_wakeup(dip,
1889 	    USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS);
1890 
1891 	(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
1892 
1893 	return (USB_SUCCESS);
1894 }
1895 
1896 /*
1897  * usbecm_cleanup:
1898  *	Release resources of current device during detach.
1899  */
1900 static void
usbecm_cleanup(usbecm_state_t * ecmp)1901 usbecm_cleanup(usbecm_state_t *ecmp)
1902 {
1903 	USB_DPRINTF_L4(PRINT_MASK_CLOSE, ecmp->ecm_lh,
1904 	    "usbecm_cleanup: ");
1905 
1906 	if (ecmp == NULL) {
1907 
1908 		return;
1909 	}
1910 
1911 	usbecm_close_pipes(ecmp);
1912 
1913 	/* unregister callback function */
1914 	if (ecmp->ecm_init_flags & USBECM_INIT_EVENTS) {
1915 		USB_DPRINTF_L4(PRINT_MASK_CLOSE, ecmp->ecm_lh,
1916 		    "usbecm_cleanup: unregister events");
1917 
1918 		usb_unregister_event_cbs(ecmp->ecm_dip, &usbecm_events);
1919 	}
1920 
1921 	/* destroy power management components */
1922 	if (ecmp->ecm_pm != NULL) {
1923 		USB_DPRINTF_L4(PRINT_MASK_CLOSE, ecmp->ecm_lh,
1924 		    "usbecm_cleanup: destroy pm");
1925 		usbecm_destroy_pm_components(ecmp);
1926 	}
1927 
1928 	/* free description of device tree. */
1929 	if (ecmp->ecm_def_ph != NULL) {
1930 		mutex_destroy(&ecmp->ecm_mutex);
1931 
1932 		usb_free_descr_tree(ecmp->ecm_dip, ecmp->ecm_dev_data);
1933 		ecmp->ecm_def_ph = NULL;
1934 	}
1935 
1936 	if (ecmp->ecm_lh != NULL) {
1937 		usb_free_log_hdl(ecmp->ecm_lh);
1938 		ecmp->ecm_lh = NULL;
1939 	}
1940 
1941 	/* detach client device */
1942 	if (ecmp->ecm_dev_data != NULL) {
1943 		usb_client_detach(ecmp->ecm_dip, ecmp->ecm_dev_data);
1944 	}
1945 
1946 	if (ecmp->ecm_init_flags & USBECM_INIT_MAC) {
1947 		(void) usbecm_mac_fini(ecmp);
1948 	}
1949 
1950 	if (ecmp->ecm_init_flags & USBECM_INIT_SER) {
1951 		usb_fini_serialization(ecmp->ecm_ser_acc);
1952 	}
1953 
1954 	ddi_prop_remove_all(ecmp->ecm_dip);
1955 	ddi_remove_minor_node(ecmp->ecm_dip, NULL);
1956 }
1957 
1958 /*
1959  * usbecm_destroy_pm_components:
1960  *	destroy PM components
1961  */
1962 static void
usbecm_destroy_pm_components(usbecm_state_t * ecmp)1963 usbecm_destroy_pm_components(usbecm_state_t *ecmp)
1964 {
1965 	usbecm_pm_t	*pm = ecmp->ecm_pm;
1966 	dev_info_t	*dip = ecmp->ecm_dip;
1967 	int		rval;
1968 
1969 	USB_DPRINTF_L4(PRINT_MASK_PM, ecmp->ecm_lh,
1970 	    "usbecm_destroy_pm_components: ");
1971 
1972 	if (ecmp->ecm_dev_state != USB_DEV_DISCONNECTED) {
1973 		if (pm->pm_wakeup_enabled) {
1974 			rval = pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
1975 			if (rval != DDI_SUCCESS) {
1976 				USB_DPRINTF_L2(PRINT_MASK_PM, ecmp->ecm_lh,
1977 				    "usbecm_destroy_pm_components: "
1978 				    "raising power failed (%d)", rval);
1979 			}
1980 
1981 			rval = usb_handle_remote_wakeup(dip,
1982 			    USB_REMOTE_WAKEUP_DISABLE);
1983 			if (rval != USB_SUCCESS) {
1984 				USB_DPRINTF_L2(PRINT_MASK_PM, ecmp->ecm_lh,
1985 				    "usbecm_destroy_pm_components: "
1986 				    "disable remote wakeup failed (%d)", rval);
1987 			}
1988 		}
1989 
1990 		(void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
1991 	}
1992 	kmem_free((caddr_t)pm, sizeof (usbecm_pm_t));
1993 	ecmp->ecm_pm = NULL;
1994 }
1995 
1996 /*
1997  * usbecm_pm_set_busy:
1998  *	mark device busy and raise power
1999  */
2000 static void
usbecm_pm_set_busy(usbecm_state_t * ecmp)2001 usbecm_pm_set_busy(usbecm_state_t *ecmp)
2002 {
2003 	usbecm_pm_t	*pm = ecmp->ecm_pm;
2004 	dev_info_t	*dip = ecmp->ecm_dip;
2005 	int		rval;
2006 
2007 	USB_DPRINTF_L4(PRINT_MASK_PM, ecmp->ecm_lh,
2008 	    "usbecm_pm_set_busy: pm = 0x%p", (void *)pm);
2009 
2010 	if (pm == NULL) {
2011 
2012 		return;
2013 	}
2014 
2015 	mutex_enter(&ecmp->ecm_mutex);
2016 	/* if already marked busy, just increment the counter */
2017 	if (pm->pm_busy_cnt++ > 0) {
2018 		mutex_exit(&ecmp->ecm_mutex);
2019 
2020 		return;
2021 	}
2022 
2023 	(void) pm_busy_component(dip, 0);
2024 
2025 	if (pm->pm_cur_power == USB_DEV_OS_FULL_PWR) {
2026 		mutex_exit(&ecmp->ecm_mutex);
2027 
2028 		return;
2029 	}
2030 
2031 	/* need to raise power	*/
2032 	pm->pm_raise_power = B_TRUE;
2033 	mutex_exit(&ecmp->ecm_mutex);
2034 
2035 	rval = pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
2036 	if (rval != DDI_SUCCESS) {
2037 		USB_DPRINTF_L2(PRINT_MASK_PM, ecmp->ecm_lh,
2038 		    "usbecm_pm_set_busy: raising power failed");
2039 	}
2040 
2041 	mutex_enter(&ecmp->ecm_mutex);
2042 	pm->pm_raise_power = B_FALSE;
2043 	mutex_exit(&ecmp->ecm_mutex);
2044 }
2045 
2046 
2047 /*
2048  * usbecm_pm_set_idle:
2049  *	mark device idle
2050  */
2051 static void
usbecm_pm_set_idle(usbecm_state_t * ecmp)2052 usbecm_pm_set_idle(usbecm_state_t *ecmp)
2053 {
2054 	usbecm_pm_t	*pm = ecmp->ecm_pm;
2055 	dev_info_t	*dip = ecmp->ecm_dip;
2056 
2057 	USB_DPRINTF_L4(PRINT_MASK_PM, ecmp->ecm_lh,
2058 	    "usbecm_pm_set_idle: ");
2059 
2060 	if (pm == NULL) {
2061 
2062 		return;
2063 	}
2064 
2065 	mutex_enter(&ecmp->ecm_mutex);
2066 	if (--pm->pm_busy_cnt > 0) {
2067 		mutex_exit(&ecmp->ecm_mutex);
2068 
2069 		return;
2070 	}
2071 
2072 	if (pm) {
2073 		(void) pm_idle_component(dip, 0);
2074 	}
2075 	mutex_exit(&ecmp->ecm_mutex);
2076 }
2077 
2078 
2079 /*
2080  * usbecm_pwrlvl0:
2081  *	Functions to handle power transition for OS levels 0 -> 3
2082  *	The same level as OS state, different from USB state
2083  */
2084 static int
usbecm_pwrlvl0(usbecm_state_t * ecmp)2085 usbecm_pwrlvl0(usbecm_state_t *ecmp)
2086 {
2087 	int		rval;
2088 
2089 	ASSERT(mutex_owned(&ecmp->ecm_mutex));
2090 
2091 	USB_DPRINTF_L4(PRINT_MASK_PM, ecmp->ecm_lh,
2092 	    "usbecm_pwrlvl0: ");
2093 
2094 	switch (ecmp->ecm_dev_state) {
2095 	case USB_DEV_ONLINE:
2096 		/* issue USB D3 command to the device */
2097 		rval = usb_set_device_pwrlvl3(ecmp->ecm_dip);
2098 		ASSERT(rval == USB_SUCCESS);
2099 		if ((ecmp->ecm_intr_ph != NULL) &&
2100 		    (ecmp->ecm_intr_state == USBECM_PIPE_BUSY)) {
2101 			mutex_exit(&ecmp->ecm_mutex);
2102 			usb_pipe_stop_intr_polling(ecmp->ecm_intr_ph,
2103 			    USB_FLAGS_SLEEP);
2104 			mutex_enter(&ecmp->ecm_mutex);
2105 
2106 			ecmp->ecm_intr_state = USBECM_PIPE_IDLE;
2107 		}
2108 		ecmp->ecm_dev_state = USB_DEV_PWRED_DOWN;
2109 		ecmp->ecm_pm->pm_cur_power = USB_DEV_OS_PWR_OFF;
2110 
2111 		/* FALLTHRU */
2112 	case USB_DEV_DISCONNECTED:
2113 	case USB_DEV_SUSPENDED:
2114 		/* allow a disconnect/cpr'ed device to go to lower power */
2115 
2116 		return (USB_SUCCESS);
2117 	case USB_DEV_PWRED_DOWN:
2118 	default:
2119 		USB_DPRINTF_L2(PRINT_MASK_PM, ecmp->ecm_lh,
2120 		    "usbecm_pwrlvl0: illegal device state");
2121 
2122 		return (USB_FAILURE);
2123 	}
2124 }
2125 
2126 
2127 /*
2128  * usbecm_pwrlvl1:
2129  *	Functions to handle power transition for OS levels 1 -> 2
2130  */
2131 static int
usbecm_pwrlvl1(usbecm_state_t * ecmp)2132 usbecm_pwrlvl1(usbecm_state_t *ecmp)
2133 {
2134 	/* issue USB D2 command to the device */
2135 	(void) usb_set_device_pwrlvl2(ecmp->ecm_dip);
2136 
2137 	return (USB_FAILURE);
2138 }
2139 
2140 
2141 /*
2142  * usbecm_pwrlvl2:
2143  *	Functions to handle power transition for OS levels 2 -> 1
2144  */
2145 static int
usbecm_pwrlvl2(usbecm_state_t * ecmp)2146 usbecm_pwrlvl2(usbecm_state_t *ecmp)
2147 {
2148 	/* issue USB D1 command to the device */
2149 	(void) usb_set_device_pwrlvl1(ecmp->ecm_dip);
2150 
2151 	return (USB_FAILURE);
2152 }
2153 
2154 
2155 /*
2156  * usbecm_pwrlvl3:
2157  *	Functions to handle power transition for OS levels 3 -> 0
2158  *	The same level as OS state, different from USB state
2159  */
2160 static int
usbecm_pwrlvl3(usbecm_state_t * ecmp)2161 usbecm_pwrlvl3(usbecm_state_t *ecmp)
2162 {
2163 	int		rval;
2164 
2165 	USB_DPRINTF_L4(PRINT_MASK_PM, ecmp->ecm_lh,
2166 	    "usbecm_pwrlvl3: ");
2167 
2168 	ASSERT(mutex_owned(&ecmp->ecm_mutex));
2169 
2170 	switch (ecmp->ecm_dev_state) {
2171 	case USB_DEV_PWRED_DOWN:
2172 		/* Issue USB D0 command to the device here */
2173 		rval = usb_set_device_pwrlvl0(ecmp->ecm_dip);
2174 		ASSERT(rval == USB_SUCCESS);
2175 
2176 		if (ecmp->ecm_intr_ph != NULL &&
2177 		    ecmp->ecm_intr_state == USBECM_PIPE_IDLE) {
2178 			mutex_exit(&ecmp->ecm_mutex);
2179 			usbecm_pipe_start_polling(ecmp);
2180 			mutex_enter(&ecmp->ecm_mutex);
2181 		}
2182 
2183 		ecmp->ecm_dev_state = USB_DEV_ONLINE;
2184 		ecmp->ecm_pm->pm_cur_power = USB_DEV_OS_FULL_PWR;
2185 
2186 		/* FALLTHRU */
2187 	case USB_DEV_ONLINE:
2188 		/* we are already in full power */
2189 
2190 		/* FALLTHRU */
2191 	case USB_DEV_DISCONNECTED:
2192 	case USB_DEV_SUSPENDED:
2193 
2194 		return (USB_SUCCESS);
2195 	default:
2196 		USB_DPRINTF_L2(PRINT_MASK_PM, ecmp->ecm_lh,
2197 		    "usbecm_pwrlvl3: illegal device state");
2198 
2199 		return (USB_FAILURE);
2200 	}
2201 }
2202 
2203 /*ARGSUSED*/
2204 static int
usbecm_power(dev_info_t * dip,int comp,int level)2205 usbecm_power(dev_info_t *dip, int comp, int level)
2206 {
2207 	usbecm_state_t	*ecmp;
2208 	usbecm_pm_t	*pm;
2209 	int		rval = USB_SUCCESS;
2210 
2211 	ecmp = ddi_get_soft_state(usbecm_statep, ddi_get_instance(dip));
2212 	pm = ecmp->ecm_pm;
2213 
2214 	USB_DPRINTF_L4(PRINT_MASK_PM, ecmp->ecm_lh,
2215 	    "usbecm_power: entry");
2216 
2217 	/* check if pm is NULL */
2218 	if (pm == NULL) {
2219 		USB_DPRINTF_L2(PRINT_MASK_PM, ecmp->ecm_lh,
2220 		    "usbecm_power: pm is NULL.");
2221 
2222 		return (USB_FAILURE);
2223 	}
2224 
2225 	mutex_enter(&ecmp->ecm_mutex);
2226 	/*
2227 	 * check if we are transitioning to a legal power level
2228 	 */
2229 	if (USB_DEV_PWRSTATE_OK(pm->pm_pwr_states, level)) {
2230 		USB_DPRINTF_L2(PRINT_MASK_PM, ecmp->ecm_lh,
2231 		    "usbecm_power: "
2232 		    "illegal power level %d, pwr_states=%x",
2233 		    level, pm->pm_pwr_states);
2234 		mutex_exit(&ecmp->ecm_mutex);
2235 
2236 		return (USB_FAILURE);
2237 	}
2238 
2239 	/*
2240 	 * if we are about to raise power and asked to lower power, fail
2241 	 */
2242 	if (pm->pm_raise_power && (level < (int)pm->pm_cur_power)) {
2243 		USB_DPRINTF_L2(PRINT_MASK_PM, ecmp->ecm_lh,
2244 		    "usbecm_power: wrong condition.");
2245 		mutex_exit(&ecmp->ecm_mutex);
2246 
2247 		return (USB_FAILURE);
2248 	}
2249 
2250 	/*
2251 	 * Set the power status of device by request level.
2252 	 */
2253 	switch (level) {
2254 	case USB_DEV_OS_PWR_OFF:
2255 		rval = usbecm_pwrlvl0(ecmp);
2256 
2257 		break;
2258 	case USB_DEV_OS_PWR_1:
2259 		rval = usbecm_pwrlvl1(ecmp);
2260 
2261 		break;
2262 	case USB_DEV_OS_PWR_2:
2263 		rval = usbecm_pwrlvl2(ecmp);
2264 
2265 		break;
2266 	case USB_DEV_OS_FULL_PWR:
2267 		rval = usbecm_pwrlvl3(ecmp);
2268 
2269 		break;
2270 	}
2271 
2272 	mutex_exit(&ecmp->ecm_mutex);
2273 
2274 	return (rval);
2275 }
2276 
2277 /*
2278  * Register with the MAC layer.
2279  */
2280 static int
usbecm_mac_init(usbecm_state_t * ecmp)2281 usbecm_mac_init(usbecm_state_t *ecmp)
2282 {
2283 	mac_register_t *macp;
2284 	int err;
2285 
2286 	/*
2287 	 * Initialize mac structure
2288 	 */
2289 	macp = mac_alloc(MAC_VERSION);
2290 	if (macp == NULL) {
2291 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2292 		    "failed to allocate MAC structure");
2293 
2294 		return (USB_FAILURE);
2295 	}
2296 
2297 	/*
2298 	 * Initialize pointer to device specific functions
2299 	 */
2300 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
2301 	macp->m_driver = ecmp;
2302 	macp->m_dip = ecmp->ecm_dip;
2303 
2304 	macp->m_src_addr = ecmp->ecm_srcaddr;
2305 	macp->m_callbacks = &usbecm_m_callbacks;
2306 	macp->m_min_sdu = 0;
2307 	macp->m_max_sdu = ETHERMTU;
2308 
2309 	/*
2310 	 * Register the macp to mac
2311 	 */
2312 	err = mac_register(macp, &ecmp->ecm_mh);
2313 	mac_free(macp);
2314 
2315 	if (err != DDI_SUCCESS) {
2316 		USB_DPRINTF_L1(PRINT_MASK_ATTA, ecmp->ecm_lh,
2317 		    "failed to register MAC structure");
2318 
2319 		return (USB_FAILURE);
2320 	}
2321 
2322 	mac_link_update(ecmp->ecm_mh, LINK_STATE_DOWN);
2323 	ecmp->ecm_stat.es_linkstate = LINK_STATE_DOWN;
2324 	ecmp->ecm_tx_cnt = 0;
2325 
2326 	return (USB_SUCCESS);
2327 }
2328 
2329 static int
usbecm_mac_fini(usbecm_state_t * ecmp)2330 usbecm_mac_fini(usbecm_state_t *ecmp)
2331 {
2332 	int rval = DDI_SUCCESS;
2333 
2334 	if ((ecmp->ecm_init_flags & USBECM_INIT_MAC) == 0) {
2335 		return (DDI_SUCCESS);
2336 	}
2337 
2338 	ecmp->ecm_init_flags &= ~USBECM_INIT_MAC;
2339 	if ((rval = mac_disable(ecmp->ecm_mh)) != 0) {
2340 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2341 		    "failed to disable MAC");
2342 
2343 		return (rval);
2344 	}
2345 
2346 	(void) mac_unregister(ecmp->ecm_mh);
2347 
2348 	return (rval);
2349 }
2350 
2351 static int
usbecm_resume(usbecm_state_t * ecmp)2352 usbecm_resume(usbecm_state_t *ecmp)
2353 {
2354 	int		current_state;
2355 	int		ret;
2356 
2357 	USB_DPRINTF_L4(PRINT_MASK_PM, ecmp->ecm_lh,
2358 	    "usbecm_resume: ");
2359 
2360 	mutex_enter(&ecmp->ecm_mutex);
2361 	current_state = ecmp->ecm_dev_state;
2362 	mutex_exit(&ecmp->ecm_mutex);
2363 
2364 	/* restore the status of device */
2365 	if (current_state != USB_DEV_ONLINE) {
2366 		ret = usbecm_restore_device_state(ecmp);
2367 	} else {
2368 		ret = USB_DEV_ONLINE;
2369 	}
2370 
2371 	return (ret);
2372 }
2373 
2374 static int
usbecm_suspend(usbecm_state_t * ecmp)2375 usbecm_suspend(usbecm_state_t *ecmp)
2376 {
2377 	(void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
2378 
2379 	mutex_enter(&ecmp->ecm_mutex);
2380 	ecmp->ecm_dev_state = USB_DEV_SUSPENDED;
2381 	mutex_exit(&ecmp->ecm_mutex);
2382 
2383 	usbecm_close_pipes(ecmp);
2384 
2385 	usb_release_access(ecmp->ecm_ser_acc);
2386 
2387 	return (0);
2388 }
2389 
2390 /*
2391  * Translate MAC address from string to 6 bytes array int value
2392  * Can't use ether_aton() since it requires format of x:x:x:x:x:x
2393  */
2394 void
label_to_mac(char * hex,unsigned char * mac)2395 label_to_mac(char *hex, unsigned char *mac)
2396 {
2397 	int i;
2398 	char c;
2399 
2400 	/* can only count 6 bytes! */
2401 	for (i = 0; i < 6; i++) {
2402 		/* upper 4 bits */
2403 		if (!isdigit(hex[2*i])) {
2404 			c = (toupper(hex[2 * i]) - 'A' + 10);
2405 		} else {
2406 			c = (hex[2 * i] - '0');
2407 		}
2408 		mac[i] = c * 16;
2409 
2410 		/* lower 4 bits */
2411 		if (!isdigit(hex[2*i + 1])) {
2412 			c = (toupper(hex[2 * i + 1]) - 'A' + 10);
2413 		} else {
2414 			c = hex[2 * i + 1] - '0';
2415 		}
2416 		mac[i] += c;
2417 	}
2418 }
2419 
2420 /*
2421  * usbecm_get_descriptors:
2422  *	parse functional descriptors of ecm compatible device
2423  */
2424 static int
usbecm_get_descriptors(usbecm_state_t * ecmp)2425 usbecm_get_descriptors(usbecm_state_t *ecmp)
2426 {
2427 	int			i;
2428 	usb_cfg_data_t		*cfg;
2429 	usb_alt_if_data_t	*altif;
2430 	usb_cvs_data_t		*cvs;
2431 	int16_t			master_if = -1, slave_if = -1;
2432 	usb_cdc_ecm_descr_t	ecm_desc;
2433 	usb_ep_data_t		*ep_data;
2434 	usb_dev_descr_t		*usb_dev_desc;
2435 
2436 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ecmp->ecm_lh,
2437 	    "usbecm_get_descriptors: ");
2438 
2439 	usb_dev_desc = ecmp->ecm_dev_data->dev_descr;
2440 
2441 	/*
2442 	 * Special treatment of Sun's SP Ethernet device.
2443 	 */
2444 	if ((usb_dev_desc->idVendor == SUN_SP_VENDOR_ID) &&
2445 	    (usb_dev_desc->idProduct == SUN_SP_PRODUCT_ID)) {
2446 		if (usb_set_cfg(ecmp->ecm_dip, ecmp->ecm_cfg_index,
2447 		    USB_FLAGS_SLEEP, NULL, NULL) != USB_SUCCESS) {
2448 			USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2449 			    "usbecm_get_descriptors: fail to set cfg ");
2450 		} else {
2451 			usb_free_dev_data(ecmp->ecm_dip, ecmp->ecm_dev_data);
2452 			if (usb_get_dev_data(ecmp->ecm_dip, &ecmp->ecm_dev_data,
2453 			    USB_PARSE_LVL_ALL, 0) != USB_SUCCESS) {
2454 				USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2455 				    "usbecm_get_descriptors: fail to get"
2456 				    " dev_data");
2457 
2458 				return (USB_FAILURE);
2459 			}
2460 		}
2461 	}
2462 
2463 	cfg = ecmp->ecm_dev_data->dev_curr_cfg;
2464 
2465 	/* set default control and data interface */
2466 	ecmp->ecm_ctrl_if_no = ecmp->ecm_data_if_no = 0;
2467 
2468 	/* get current interfaces */
2469 	ecmp->ecm_ctrl_if_no = ecmp->ecm_dev_data->dev_curr_if;
2470 	if (cfg->cfg_if[ecmp->ecm_ctrl_if_no].if_n_alt == 0) {
2471 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2472 		    "usbecm_get_descriptors: elements in if_alt is %d",
2473 		    cfg->cfg_if[ecmp->ecm_ctrl_if_no].if_n_alt);
2474 
2475 		return (USB_FAILURE);
2476 	}
2477 
2478 	altif = &cfg->cfg_if[ecmp->ecm_ctrl_if_no].if_alt[0];
2479 
2480 	/*
2481 	 * Based on CDC specification, ECM devices usually include the
2482 	 * following function descriptors: Header, Union and ECM
2483 	 * Contry Selection function descriptors. This loop search tree data
2484 	 * structure for each ecm class descriptor.
2485 	 */
2486 	for (i = 0; i < altif->altif_n_cvs; i++) {
2487 		cvs = &altif->altif_cvs[i];
2488 
2489 		if ((cvs->cvs_buf == NULL) ||
2490 		    (cvs->cvs_buf[1] != USB_CDC_CS_INTERFACE)) {
2491 			continue;
2492 		}
2493 
2494 		switch (cvs->cvs_buf[2]) {
2495 		case USB_CDC_DESCR_TYPE_HEADER:
2496 			/*
2497 			 * parse header functional descriptor
2498 			 * Just to check integrity.
2499 			 */
2500 			if (cvs->cvs_buf_len != 5) {
2501 				return (USB_FAILURE);
2502 			}
2503 			break;
2504 		case USB_CDC_DESCR_TYPE_ETHERNET:
2505 			/* parse ECM functional descriptor */
2506 			if (cvs->cvs_buf_len >= USB_CDC_ECM_LEN) {
2507 				char buf[USB_MAXSTRINGLEN];
2508 
2509 				if (usb_parse_data("4cl2sc", cvs->cvs_buf,
2510 				    cvs->cvs_buf_len, (void *)&ecm_desc,
2511 				    (size_t)USB_CDC_ECM_LEN) <
2512 				    USB_CDC_ECM_LEN) {
2513 
2514 					return (USB_FAILURE);
2515 				}
2516 
2517 				/* get the MAC address */
2518 				if (usb_get_string_descr(ecmp->ecm_dip,
2519 				    USB_LANG_ID, ecm_desc.iMACAddress, buf,
2520 				    USB_MAXSTRINGLEN) != USB_SUCCESS) {
2521 
2522 					return (USB_FAILURE);
2523 				}
2524 
2525 				USB_DPRINTF_L3(PRINT_MASK_ATTA, ecmp->ecm_lh,
2526 				    "usbecm_get_descriptors: macaddr=%s ",
2527 				    buf);
2528 
2529 				/* expects 12 characters */
2530 				if (strlen(buf) < 12) {
2531 					return (USB_FAILURE);
2532 				}
2533 				label_to_mac(buf, ecmp->ecm_srcaddr);
2534 
2535 				bcopy(&ecm_desc, &ecmp->ecm_desc,
2536 				    USB_CDC_ECM_LEN);
2537 			}
2538 			break;
2539 		case USB_CDC_DESCR_TYPE_UNION:
2540 			/* parse Union functional descriptor. */
2541 			if (cvs->cvs_buf_len >= 5) {
2542 				master_if = cvs->cvs_buf[3];
2543 				slave_if = cvs->cvs_buf[4];
2544 			}
2545 			break;
2546 		default:
2547 			break;
2548 		}
2549 	}
2550 
2551 	/* For usb ecm devices, it must satisfy the following options. */
2552 	if (cfg->cfg_n_if < 2) {
2553 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2554 		    "usbecm_get_descriptors: # of interfaces %d < 2",
2555 		    cfg->cfg_n_if);
2556 
2557 		return (USB_FAILURE);
2558 	}
2559 
2560 	if (ecmp->ecm_data_if_no == 0 &&
2561 	    slave_if != ecmp->ecm_data_if_no) {
2562 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2563 		    "usbecm_get_descriptors: Device has no call management "
2564 		    "descriptor and use Union Descriptor.");
2565 
2566 		ecmp->ecm_data_if_no = slave_if;
2567 	}
2568 
2569 	if ((master_if != ecmp->ecm_ctrl_if_no) ||
2570 	    (slave_if != ecmp->ecm_data_if_no)) {
2571 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2572 		    "usbecm_get_descriptors: control interface or "
2573 		    "data interface don't match.");
2574 
2575 		return (USB_FAILURE);
2576 	}
2577 
2578 	if ((ecmp->ecm_ctrl_if_no >= cfg->cfg_n_if) ||
2579 	    (ecmp->ecm_data_if_no >= cfg->cfg_n_if)) {
2580 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2581 		    "usbecm_get_descriptors: control interface %d or "
2582 		    "data interface %d out of range.",
2583 		    ecmp->ecm_ctrl_if_no, ecmp->ecm_data_if_no);
2584 
2585 		return (USB_FAILURE);
2586 	}
2587 
2588 	/* ECM data interface has a minimal of two altsettings */
2589 	if (cfg->cfg_if[ecmp->ecm_data_if_no].if_n_alt < 2) {
2590 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2591 		    "usbecm_get_descriptors: elements in if_alt is %d,"
2592 		    " MUST >= 2", cfg->cfg_if[ecmp->ecm_ctrl_if_no].if_n_alt);
2593 
2594 		return (USB_FAILURE);
2595 	}
2596 
2597 	/* control interface must have interrupt endpoint */
2598 	if ((ep_data = usb_lookup_ep_data(ecmp->ecm_dip, ecmp->ecm_dev_data,
2599 	    ecmp->ecm_ctrl_if_no, 0, 0, USB_EP_ATTR_INTR,
2600 	    USB_EP_DIR_IN)) == NULL) {
2601 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2602 		    "usbecm_get_descriptors: "
2603 		    "ctrl interface %d has no interrupt endpoint",
2604 		    ecmp->ecm_data_if_no);
2605 
2606 		return (USB_FAILURE);
2607 	}
2608 	ecmp->ecm_intr_ep = ep_data;
2609 
2610 	/* data interface alt 1 must have bulk in and out(ECM v1.2,p5) */
2611 	if ((ep_data = usb_lookup_ep_data(ecmp->ecm_dip, ecmp->ecm_dev_data,
2612 	    ecmp->ecm_data_if_no, 1, 0, USB_EP_ATTR_BULK,
2613 	    USB_EP_DIR_IN)) == NULL) {
2614 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2615 		    "usbecm_get_descriptors: "
2616 		    "data interface %d has no bulk in endpoint",
2617 		    ecmp->ecm_data_if_no);
2618 
2619 		return (USB_FAILURE);
2620 	}
2621 	ecmp->ecm_bulk_in_ep = ep_data;
2622 
2623 	if ((ep_data = usb_lookup_ep_data(ecmp->ecm_dip, ecmp->ecm_dev_data,
2624 	    ecmp->ecm_data_if_no, 1, 0, USB_EP_ATTR_BULK,
2625 	    USB_EP_DIR_OUT)) == NULL) {
2626 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2627 		    "usbecm_get_descriptors: "
2628 		    "data interface %d has no bulk out endpoint",
2629 		    ecmp->ecm_data_if_no);
2630 
2631 		return (USB_FAILURE);
2632 	}
2633 	ecmp->ecm_bulk_out_ep = ep_data;
2634 
2635 	/* set default value for ethernet packet filter */
2636 	ecmp->ecm_pkt_flt = CDC_ECM_PKT_TYPE_DIRECTED;
2637 
2638 	return (USB_SUCCESS);
2639 }
2640 
2641 /* Generate IEEE802 style MAC address */
2642 static void
generate_ether_addr(uint8_t * mac_addr)2643 generate_ether_addr(uint8_t *mac_addr)
2644 {
2645 	(void) random_get_bytes(mac_addr, 6);
2646 	mac_addr [0] &= 0xfe;	/* unicast only */
2647 	mac_addr [0] |= 0x02;	/* set locally administered bit */
2648 }
2649 
2650 /*
2651  * Find a pair of bulk In/Out endpoints
2652  */
usbecm_find_bulk_in_out_eps(usbecm_state_t * ecmp,uint16_t ifc,usb_if_data_t * intf)2653 int usbecm_find_bulk_in_out_eps(usbecm_state_t *ecmp,
2654     uint16_t ifc, usb_if_data_t *intf)
2655 {
2656 	uint16_t alt, alt_num;
2657 	usb_ep_data_t *intr_ep = NULL;
2658 	usb_ep_data_t *bulk_in, *bulk_out, *ep;
2659 
2660 	alt_num = intf->if_n_alt;
2661 
2662 	/*
2663 	 * for the non-compatible devices, to make it simple, we
2664 	 * suppose the devices have this kind of configuration:
2665 	 *	INTR In EP(if exists) + BULK In + Bulk Out in the
2666 	 *	same altsetting of the same interface
2667 	 */
2668 	for (alt = 0; alt < alt_num; alt++) {
2669 		/* search pair of bulk in/out EPs */
2670 		if (((bulk_in = usb_lookup_ep_data(ecmp->ecm_dip,
2671 		    ecmp->ecm_dev_data, ifc, alt, 0,
2672 		    USB_EP_ATTR_BULK,
2673 		    USB_EP_DIR_IN)) == NULL) ||
2674 		    (bulk_out = usb_lookup_ep_data(ecmp->ecm_dip,
2675 		    ecmp->ecm_dev_data, ifc, alt, 0,
2676 		    USB_EP_ATTR_BULK,
2677 		    USB_EP_DIR_OUT)) == NULL) {
2678 
2679 			continue;
2680 		}
2681 
2682 		/*
2683 		 * search interrupt pipe.
2684 		 */
2685 		if ((ep = usb_lookup_ep_data(ecmp->ecm_dip,
2686 		    ecmp->ecm_dev_data, ifc, alt, 0,
2687 		    USB_EP_ATTR_INTR, USB_EP_DIR_IN)) != NULL) {
2688 			intr_ep = ep;
2689 		}
2690 
2691 
2692 		ecmp->ecm_data_if_no = ifc;
2693 		ecmp->ecm_data_if_alt = alt;
2694 		ecmp->ecm_intr_ep = intr_ep;
2695 		ecmp->ecm_ctrl_if_no = ifc;
2696 		ecmp->ecm_bulk_in_ep = bulk_in;
2697 		ecmp->ecm_bulk_out_ep = bulk_out;
2698 
2699 		return (USB_SUCCESS);
2700 	}
2701 
2702 	return (USB_FAILURE);
2703 }
2704 
2705 static int
usbecm_init_non_compatible_device(usbecm_state_t * ecmp)2706 usbecm_init_non_compatible_device(usbecm_state_t *ecmp)
2707 {
2708 	usb_if_data_t *cur_if;
2709 	uint16_t if_num, i;
2710 
2711 	/*
2712 	 * If device don't conform to spec, search pairs of bulk in/out
2713 	 * endpoints and fill related structure. We suppose this driver
2714 	 * is bound to a interface.
2715 	 */
2716 	cur_if = ecmp->ecm_dev_data->dev_curr_cfg->cfg_if;
2717 	if_num = ecmp->ecm_dev_data->dev_curr_cfg->cfg_n_if;
2718 
2719 	/* search each interface which have bulk in and out */
2720 	for (i = 0; i < if_num; i++) {
2721 		if (usbecm_find_bulk_in_out_eps(ecmp, i,
2722 		    cur_if) == USB_SUCCESS) {
2723 
2724 			break;
2725 		}
2726 		cur_if++;
2727 	}
2728 
2729 	USB_DPRINTF_L4(PRINT_MASK_ATTA, ecmp->ecm_lh,
2730 	    "usbecm_init_non_compatible_device: ctrl_if=%d,"
2731 	    " data_if=%d, alt=%d", ecmp->ecm_ctrl_if_no,
2732 	    ecmp->ecm_data_if_no, ecmp->ecm_data_if_alt);
2733 
2734 	return (USB_SUCCESS);
2735 }
2736 
2737 static boolean_t
usbecm_is_compatible(usbecm_state_t * ecmp)2738 usbecm_is_compatible(usbecm_state_t *ecmp)
2739 {
2740 	usb_cfg_data_t *cfg_data;
2741 	usb_if_data_t *intf;
2742 	usb_alt_if_data_t *alt;
2743 	int alt_num, if_num, cfg_num;
2744 	int i, j, cfg_index;
2745 
2746 	cfg_num = ecmp->ecm_dev_data->dev_n_cfg;
2747 	USB_DPRINTF_L3(PRINT_MASK_ATTA, ecmp->ecm_lh,
2748 	    "usbecm_is_compatible: entry, cfg_num=%d", cfg_num);
2749 
2750 	for (cfg_index = 0; cfg_index < cfg_num; cfg_index++) {
2751 		cfg_data = &(ecmp->ecm_dev_data->dev_cfg[cfg_index]);
2752 
2753 		USB_DPRINTF_L3(PRINT_MASK_ATTA, ecmp->ecm_lh,
2754 		    "usbecm_is_compatible: cfg_index=%d, value=%d",
2755 		    cfg_index, cfg_data->cfg_descr.bConfigurationValue);
2756 
2757 		intf = cfg_data->cfg_if;
2758 		if_num = cfg_data->cfg_n_if;
2759 
2760 		for (i = 0; i < if_num; i++) {
2761 			alt_num = intf->if_n_alt;
2762 			for (j = 0; j < alt_num; j++) {
2763 			alt = &intf->if_alt[j];
2764 			if ((alt->altif_descr.bInterfaceClass == 0x02) &&
2765 			    (alt->altif_descr.bInterfaceSubClass == 0x06)) {
2766 				ecmp->ecm_cfg_index = cfg_index;
2767 
2768 				USB_DPRINTF_L3(PRINT_MASK_ATTA, ecmp->ecm_lh,
2769 				    "usbecm_is_compatible: cfg_index=%d",
2770 				    cfg_index);
2771 
2772 				return (B_TRUE);
2773 			}
2774 			}
2775 			intf++;
2776 		}
2777 	}
2778 
2779 	return (B_FALSE);
2780 }
2781 
2782 
2783 static int
usbecm_usb_init(usbecm_state_t * ecmp)2784 usbecm_usb_init(usbecm_state_t *ecmp)
2785 {
2786 
2787 	if (usb_client_attach(ecmp->ecm_dip, USBDRV_VERSION, 0) !=
2788 	    USB_SUCCESS) {
2789 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2790 		"usbecm_usb_init: fail to attach");
2791 
2792 		return (USB_FAILURE);
2793 	}
2794 
2795 	/* Get the configuration information of device */
2796 	if (usb_get_dev_data(ecmp->ecm_dip, &ecmp->ecm_dev_data,
2797 	    USB_PARSE_LVL_ALL, 0) != USB_SUCCESS) {
2798 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2799 		"usbecm_usb_init: fail to get_dev_data");
2800 
2801 		return (USB_FAILURE);
2802 	}
2803 	ecmp->ecm_def_ph = ecmp->ecm_dev_data->dev_default_ph;
2804 	ecmp->ecm_dev_state = USB_DEV_ONLINE;
2805 
2806 	mutex_init(&ecmp->ecm_mutex, NULL, MUTEX_DRIVER,
2807 	    ecmp->ecm_dev_data->dev_iblock_cookie);
2808 
2809 	if ((strcmp(ddi_binding_name(ecmp->ecm_dip),
2810 	    "usbif,class2.6") == 0) ||
2811 	    ((strcmp(ddi_binding_name(ecmp->ecm_dip),
2812 	    "usb,class2.6.0") == 0))) {
2813 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2814 		    "usbecm_usb_init: A CDC ECM device is attached");
2815 		ecmp->ecm_compatibility = B_TRUE;
2816 	} else if (usb_owns_device(ecmp->ecm_dip) &&
2817 	    usbecm_is_compatible(ecmp)) {
2818 		/*
2819 		 * Current Sun SP ECM device has two configurations. Hence
2820 		 * USBA doesn't create interface level compatible names
2821 		 * for it, see usba_ready_device_node(). We have to check
2822 		 * manually to see if compatible interfaces exist, when
2823 		 * the driver owns the entire device.
2824 		 */
2825 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2826 		    "usbecm_usb_init: A CDC ECM device is attached");
2827 		ecmp->ecm_compatibility = B_TRUE;
2828 	} else {
2829 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2830 		    "usbecm_usb_init: A nonstandard device is attached to "
2831 		    "usbecm(7D) driver. This device doesn't conform to "
2832 		    "usb cdc spec.");
2833 		ecmp->ecm_compatibility = B_FALSE;
2834 
2835 		/* generate a random MAC addr */
2836 		generate_ether_addr(ecmp->ecm_srcaddr);
2837 	}
2838 
2839 	if ((ecmp->ecm_compatibility == B_TRUE) &&
2840 	    (usbecm_get_descriptors(ecmp) != USB_SUCCESS)) {
2841 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2842 		    "usbecm_usb_init: A compatible device is attached, but "
2843 		    "fail to get standard descriptors");
2844 
2845 		return (USB_FAILURE);
2846 	}
2847 
2848 	if (ecmp->ecm_compatibility == B_FALSE) {
2849 		(void) usbecm_init_non_compatible_device(ecmp);
2850 	}
2851 
2852 	/* Create power management components */
2853 	if (usbecm_create_pm_components(ecmp) != USB_SUCCESS) {
2854 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2855 		    "usbecm_usb_init: create pm components failed.");
2856 
2857 		return (USB_FAILURE);
2858 	}
2859 
2860 	/* Register to get callbacks for USB events */
2861 	if (usb_register_event_cbs(ecmp->ecm_dip, &usbecm_events, 0)
2862 	    != USB_SUCCESS) {
2863 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2864 		    "usbsecm_attach: register event callback failed.");
2865 
2866 		return (USB_FAILURE);
2867 	}
2868 	ecmp->ecm_init_flags |= USBECM_INIT_EVENTS;
2869 
2870 
2871 	/* Get max data size of bulk transfer */
2872 	if (usb_pipe_get_max_bulk_transfer_size(ecmp->ecm_dip,
2873 	    &ecmp->ecm_xfer_sz) != USB_SUCCESS) {
2874 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2875 		    "usbsecm_ds_attach: get max size of transfer failed.");
2876 
2877 		return (USB_FAILURE);
2878 	}
2879 
2880 
2881 	ecmp->ecm_ser_acc = usb_init_serialization(ecmp->ecm_dip,
2882 	    USB_INIT_SER_CHECK_SAME_THREAD);
2883 	ecmp->ecm_init_flags |= USBECM_INIT_SER;
2884 
2885 	return (USB_SUCCESS);
2886 }
2887 
2888 
2889 /*
2890  * Open operation pipes. Each ECM device should have Bulk In, Bulk Out
2891  * and Interrupt In endpoints
2892  */
2893 static int
usbecm_open_pipes(usbecm_state_t * ecmp)2894 usbecm_open_pipes(usbecm_state_t *ecmp)
2895 {
2896 	int		rval = USB_SUCCESS;
2897 	usb_ep_data_t	*in_data, *out_data, *intr_pipe;
2898 	usb_pipe_policy_t policy;
2899 	int		altif;
2900 
2901 	ASSERT(!mutex_owned(&ecmp->ecm_mutex));
2902 
2903 	USB_DPRINTF_L4(PRINT_MASK_OPEN, ecmp->ecm_lh,
2904 	    "usbsecm_open_pipes: ecmp = 0x%p", (void *)ecmp);
2905 
2906 	if (ecmp->ecm_compatibility == B_TRUE) {
2907 	/* compatible device has minimum of 2 altsetting, select alt 1 */
2908 		altif = 1;
2909 	} else {
2910 		altif = ecmp->ecm_data_if_alt;
2911 	}
2912 	intr_pipe = ecmp->ecm_intr_ep;
2913 	in_data = ecmp->ecm_bulk_in_ep;
2914 	out_data = ecmp->ecm_bulk_out_ep;
2915 
2916 	/* Bulk in and out must exist simultaneously. */
2917 	if ((in_data == NULL) || (out_data == NULL)) {
2918 		USB_DPRINTF_L2(PRINT_MASK_OPEN, ecmp->ecm_lh,
2919 		    "usbsecm_open_pipes: look up bulk pipe failed in "
2920 		    "interface %d ",
2921 		    ecmp->ecm_data_if_no);
2922 
2923 		return (USB_FAILURE);
2924 	}
2925 	/*
2926 	 * If device conform to ecm spec, it must have an interrupt pipe
2927 	 * for this device.
2928 	 */
2929 	if (ecmp->ecm_compatibility == B_TRUE && intr_pipe == NULL) {
2930 		USB_DPRINTF_L2(PRINT_MASK_OPEN, ecmp->ecm_lh,
2931 		    "usbecm_open_pipes: look up interrupt pipe failed in "
2932 		    "interface %d", ecmp->ecm_ctrl_if_no);
2933 
2934 		return (USB_FAILURE);
2935 	}
2936 
2937 	USB_DPRINTF_L3(PRINT_MASK_OPEN, ecmp->ecm_lh,
2938 	    "usbsecm_open_pipes: open intr %02x, bulkin %02x bulkout %02x",
2939 	    intr_pipe?intr_pipe->ep_descr.bEndpointAddress:0,
2940 	    in_data->ep_descr.bEndpointAddress,
2941 	    out_data->ep_descr.bEndpointAddress);
2942 
2943 	USB_DPRINTF_L3(PRINT_MASK_OPEN, ecmp->ecm_lh,
2944 	    "usbsecm_open_pipes: set data if(%d) alt(%d) ",
2945 	    ecmp->ecm_data_if_no, altif);
2946 
2947 	if ((rval = usb_set_alt_if(ecmp->ecm_dip, ecmp->ecm_data_if_no,
2948 	    altif, USB_FLAGS_SLEEP, NULL, NULL)) != USB_SUCCESS) {
2949 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2950 		    "usbecm_open_pipes: set alternate failed (%d)",
2951 		    rval);
2952 
2953 		return (rval);
2954 	}
2955 
2956 	policy.pp_max_async_reqs = 2;
2957 
2958 	/* Open bulk in endpoint */
2959 	if (usb_pipe_open(ecmp->ecm_dip, &in_data->ep_descr, &policy,
2960 	    USB_FLAGS_SLEEP, &ecmp->ecm_bulkin_ph) != USB_SUCCESS) {
2961 		USB_DPRINTF_L2(PRINT_MASK_OPEN, ecmp->ecm_lh,
2962 		    "usbecm_open_pipes: open bulkin pipe failed!");
2963 
2964 		return (USB_FAILURE);
2965 	}
2966 
2967 	/* Open bulk out endpoint */
2968 	if (usb_pipe_open(ecmp->ecm_dip, &out_data->ep_descr, &policy,
2969 	    USB_FLAGS_SLEEP, &ecmp->ecm_bulkout_ph) != USB_SUCCESS) {
2970 		USB_DPRINTF_L2(PRINT_MASK_OPEN, ecmp->ecm_lh,
2971 		    "usbecm_open_pipes: open bulkout pipe failed!");
2972 
2973 		usb_pipe_close(ecmp->ecm_dip, ecmp->ecm_bulkin_ph,
2974 		    USB_FLAGS_SLEEP, NULL, NULL);
2975 
2976 		return (USB_FAILURE);
2977 	}
2978 
2979 	/* Open interrupt endpoint if found. */
2980 	if (intr_pipe != NULL) {
2981 		if (usb_pipe_open(ecmp->ecm_dip, &intr_pipe->ep_descr, &policy,
2982 		    USB_FLAGS_SLEEP, &ecmp->ecm_intr_ph) != USB_SUCCESS) {
2983 			USB_DPRINTF_L2(PRINT_MASK_OPEN, ecmp->ecm_lh,
2984 			    "usbecm_open_pipes: "
2985 			    "open intr pipe failed");
2986 
2987 			usb_pipe_close(ecmp->ecm_dip, ecmp->ecm_bulkin_ph,
2988 			    USB_FLAGS_SLEEP, NULL, NULL);
2989 			usb_pipe_close(ecmp->ecm_dip, ecmp->ecm_bulkout_ph,
2990 			    USB_FLAGS_SLEEP, NULL, NULL);
2991 
2992 			return (USB_FAILURE);
2993 		}
2994 	}
2995 
2996 	/* initialize the pipe related data */
2997 	mutex_enter(&ecmp->ecm_mutex);
2998 	ecmp->ecm_bulkin_sz = in_data->ep_descr.wMaxPacketSize;
2999 	ecmp->ecm_bulkin_state = USBECM_PIPE_IDLE;
3000 	ecmp->ecm_bulkout_state = USBECM_PIPE_IDLE;
3001 	if (ecmp->ecm_intr_ph != NULL) {
3002 		ecmp->ecm_intr_state = USBECM_PIPE_IDLE;
3003 	}
3004 	mutex_exit(&ecmp->ecm_mutex);
3005 
3006 	if (ecmp->ecm_intr_ph != NULL) {
3007 
3008 		usbecm_pipe_start_polling(ecmp);
3009 	}
3010 
3011 	USB_DPRINTF_L4(PRINT_MASK_OPEN, ecmp->ecm_lh,
3012 	    "usbsecm_open_pipes: end");
3013 
3014 	return (rval);
3015 }
3016 
3017 
3018 /*
3019  * usbsecm_close_pipes:
3020  *	Close pipes
3021  *	Each device could include three pipes: bulk in, bulk out and interrupt.
3022  */
3023 static void
usbecm_close_pipes(usbecm_state_t * ecmp)3024 usbecm_close_pipes(usbecm_state_t *ecmp)
3025 {
3026 
3027 	mutex_enter(&ecmp->ecm_mutex);
3028 
3029 	USB_DPRINTF_L4(PRINT_MASK_CLOSE, ecmp->ecm_lh,
3030 	    "usbsecm_close_pipes: ecm_bulkin_state = %d",
3031 	    ecmp->ecm_bulkin_state);
3032 
3033 	/*
3034 	 * Check the status of the pipes. If pipe is closing or closed,
3035 	 * return directly.
3036 	 */
3037 	if ((ecmp->ecm_bulkin_state == USBECM_PIPE_CLOSED) ||
3038 	    (ecmp->ecm_bulkin_state == USBECM_PIPE_CLOSING)) {
3039 		USB_DPRINTF_L2(PRINT_MASK_CLOSE, ecmp->ecm_lh,
3040 		    "usbsecm_close_pipes: pipe is closing or has closed");
3041 		mutex_exit(&ecmp->ecm_mutex);
3042 
3043 		return;
3044 	}
3045 
3046 	ecmp->ecm_bulkin_state = USBECM_PIPE_CLOSING;
3047 	mutex_exit(&ecmp->ecm_mutex);
3048 
3049 	/* reset the data interface's altsetting to 0 */
3050 	if ((ecmp->ecm_dev_state == USB_DEV_ONLINE) &&
3051 	    (usb_set_alt_if(ecmp->ecm_dip, ecmp->ecm_data_if_no,
3052 	    0, USB_FLAGS_SLEEP, NULL, NULL) != USB_SUCCESS)) {
3053 		USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
3054 		    "usbecm_close_pipes: reset alternate failed ");
3055 	}
3056 
3057 	/* Close pipes */
3058 	usb_pipe_reset(ecmp->ecm_dip, ecmp->ecm_bulkin_ph,
3059 	    USB_FLAGS_SLEEP, NULL, 0);
3060 	usb_pipe_close(ecmp->ecm_dip, ecmp->ecm_bulkin_ph,
3061 	    USB_FLAGS_SLEEP, NULL, 0);
3062 	usb_pipe_close(ecmp->ecm_dip, ecmp->ecm_bulkout_ph,
3063 	    USB_FLAGS_SLEEP, NULL, 0);
3064 
3065 	if (ecmp->ecm_intr_ph != NULL) {
3066 		usb_pipe_stop_intr_polling(ecmp->ecm_intr_ph,
3067 		    USB_FLAGS_SLEEP);
3068 		usb_pipe_close(ecmp->ecm_dip, ecmp->ecm_intr_ph,
3069 		    USB_FLAGS_SLEEP, NULL, 0);
3070 	}
3071 
3072 	mutex_enter(&ecmp->ecm_mutex);
3073 	/* Reset the status of pipes to closed */
3074 	ecmp->ecm_bulkin_state = USBECM_PIPE_CLOSED;
3075 	ecmp->ecm_bulkin_ph = NULL;
3076 	ecmp->ecm_bulkout_state = USBECM_PIPE_CLOSED;
3077 	ecmp->ecm_bulkout_ph = NULL;
3078 	if (ecmp->ecm_intr_ph != NULL) {
3079 		ecmp->ecm_intr_state = USBECM_PIPE_CLOSED;
3080 		ecmp->ecm_intr_ph = NULL;
3081 	}
3082 
3083 	mutex_exit(&ecmp->ecm_mutex);
3084 
3085 	USB_DPRINTF_L4(PRINT_MASK_CLOSE, ecmp->ecm_lh,
3086 	    "usbsecm_close_pipes: pipes have been closed.");
3087 }
3088 
3089 
3090 static int
usbecm_ctrl_write(usbecm_state_t * ecmp,uchar_t request,uint16_t value,mblk_t ** data)3091 usbecm_ctrl_write(usbecm_state_t *ecmp, uchar_t request,
3092     uint16_t value, mblk_t **data)
3093 {
3094 	usb_ctrl_setup_t setup;
3095 	usb_cb_flags_t	cb_flags;
3096 	usb_cr_t	cr;
3097 	int		rval;
3098 
3099 	USB_DPRINTF_L4(PRINT_MASK_ALL, ecmp->ecm_lh,
3100 	    "usbecm_ctrl_write: ");
3101 
3102 	/* initialize the control request. */
3103 	setup.bmRequestType = USB_DEV_REQ_HOST_TO_DEV |
3104 	    USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
3105 	setup.bRequest = request;
3106 	setup.wValue = value;
3107 	setup.wIndex = ecmp->ecm_ctrl_if_no;
3108 	setup.wLength = ((data != NULL) && (*data != NULL)) ? MBLKL(*data) : 0;
3109 	setup.attrs = 0;
3110 
3111 	rval = usb_pipe_ctrl_xfer_wait(ecmp->ecm_def_ph, &setup, data,
3112 	    &cr, &cb_flags, 0);
3113 
3114 	USB_DPRINTF_L4(PRINT_MASK_ALL, ecmp->ecm_lh,
3115 	    "usbecm_ctrl_write: rval = %d", rval);
3116 
3117 	return (rval);
3118 }
3119 
3120 static int
usbecm_ctrl_read(usbecm_state_t * ecmp,uchar_t request,uint16_t value,mblk_t ** data,int len)3121 usbecm_ctrl_read(usbecm_state_t *ecmp, uchar_t request,
3122     uint16_t value, mblk_t **data, int len)
3123 {
3124 	usb_ctrl_setup_t setup;
3125 	usb_cb_flags_t	cb_flags;
3126 	usb_cr_t	cr;
3127 
3128 	USB_DPRINTF_L4(PRINT_MASK_ALL, ecmp->ecm_lh,
3129 	    "usbecm_ctrl_read: ");
3130 
3131 	/* initialize the control request. */
3132 	setup.bmRequestType = USB_DEV_REQ_DEV_TO_HOST |
3133 	    USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
3134 	setup.bRequest = request;
3135 	setup.wValue = value;
3136 	setup.wIndex = ecmp->ecm_ctrl_if_no;
3137 	setup.wLength = (uint16_t)len;
3138 	setup.attrs = 0;
3139 
3140 	return (usb_pipe_ctrl_xfer_wait(ecmp->ecm_def_ph, &setup, data,
3141 	    &cr, &cb_flags, 0));
3142 }
3143 
3144 /* Get specific statistic data from device */
3145 static int
usbecm_get_statistics(usbecm_state_t * ecmp,uint32_t fs,uint32_t * stat_data)3146 usbecm_get_statistics(usbecm_state_t *ecmp, uint32_t fs, uint32_t *stat_data)
3147 {
3148 	mblk_t *data = NULL;
3149 	uint32_t stat;
3150 
3151 	/* first check to see if this stat is collected by device */
3152 	if ((ecmp->ecm_compatibility == B_TRUE) &&
3153 	    (ecmp->ecm_desc.bmEthernetStatistics & ECM_STAT_CAP_MASK(fs))) {
3154 		if (usbecm_ctrl_read(ecmp, CDC_ECM_GET_ETH_STAT,
3155 		    ecmp->ecm_ctrl_if_no, &data, 4) != USB_SUCCESS) {
3156 
3157 			return (USB_FAILURE);
3158 		}
3159 		stat = (data->b_rptr[3] << 24) | (data->b_rptr[2] << 16) |
3160 		    (data->b_rptr[1] << 8) | (data->b_rptr[0]);
3161 		*stat_data = stat;
3162 
3163 		freemsg(data);
3164 
3165 		return (USB_SUCCESS);
3166 	}
3167 
3168 	return (USB_FAILURE);
3169 }
3170