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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * IEEE 802.3ad Link Aggregation. 31 */ 32 33 #include <sys/types.h> 34 #include <sys/sysmacros.h> 35 #include <sys/conf.h> 36 #include <sys/cmn_err.h> 37 #include <sys/list.h> 38 #include <sys/ksynch.h> 39 #include <sys/kmem.h> 40 #include <sys/stream.h> 41 #include <sys/modctl.h> 42 #include <sys/ddi.h> 43 #include <sys/sunddi.h> 44 #include <sys/atomic.h> 45 #include <sys/stat.h> 46 47 #include <sys/aggr.h> 48 #include <sys/aggr_impl.h> 49 50 /* module description */ 51 #define AGGR_LINKINFO "Link Aggregation MAC" 52 53 /* device info ptr, only one for instance 0 */ 54 dev_info_t *aggr_dip; 55 56 static void aggr_dev_init(void); 57 static int aggr_dev_fini(void); 58 static int aggr_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 59 static int aggr_attach(dev_info_t *, ddi_attach_cmd_t); 60 static int aggr_detach(dev_info_t *, ddi_detach_cmd_t); 61 62 static struct cb_ops aggr_cb_ops = { 63 aggr_open, /* open */ 64 aggr_close, /* close */ 65 nulldev, /* strategy */ 66 nulldev, /* print */ 67 nodev, /* dump */ 68 nodev, /* read */ 69 nodev, /* write */ 70 aggr_ioctl, /* ioctl */ 71 nodev, /* devmap */ 72 nodev, /* mmap */ 73 nodev, /* segmap */ 74 nochpoll, /* poll */ 75 ddi_prop_op, /* cb_prop_op */ 76 0, /* streamtab */ 77 D_NEW | D_MP /* driver compatibility flag */ 78 }; 79 80 static struct dev_ops aggr_ops = { 81 DEVO_REV, /* devo_rev */ 82 0, /* refcnt */ 83 aggr_getinfo, /* getinfo */ 84 nulldev, /* identify */ 85 nulldev, /* probe */ 86 aggr_attach, /* attach */ 87 aggr_detach, /* detach */ 88 nodev, /* reset */ 89 &aggr_cb_ops, /* driver operations */ 90 NULL, /* bus operations */ 91 nodev /* dev power */ 92 }; 93 94 static struct modldrv modldrv = { 95 &mod_driverops, 96 AGGR_LINKINFO, 97 &aggr_ops 98 }; 99 100 static struct modlinkage modlinkage = { 101 MODREV_1, 102 &modldrv, 103 NULL 104 }; 105 106 int 107 _init(void) 108 { 109 int err; 110 111 aggr_dev_init(); 112 113 if ((err = mod_install(&modlinkage)) != 0) { 114 (void) aggr_dev_fini(); 115 return (err); 116 } 117 118 aggr_dip = NULL; 119 120 return (0); 121 } 122 123 int 124 _fini(void) 125 { 126 int err; 127 128 if ((err = aggr_dev_fini()) != 0) 129 return (err); 130 131 if ((err = mod_remove(&modlinkage)) != 0) { 132 aggr_dev_init(); 133 return (err); 134 } 135 136 return (0); 137 } 138 139 int 140 _info(struct modinfo *modinfop) 141 { 142 return (mod_info(&modlinkage, modinfop)); 143 } 144 145 static void 146 aggr_dev_init(void) 147 { 148 aggr_port_init(); 149 aggr_grp_init(); 150 } 151 152 static int 153 aggr_dev_fini(void) 154 { 155 int err; 156 157 if ((err = aggr_grp_fini()) != 0) 158 return (err); 159 if ((err = aggr_port_fini()) != 0) { 160 /* 161 * re-initialize the groups to keep a consistent 162 * state. 163 */ 164 aggr_grp_init(); 165 } 166 167 return (err); 168 } 169 170 /*ARGSUSED*/ 171 static int 172 aggr_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 173 void **result) 174 { 175 switch (infocmd) { 176 case DDI_INFO_DEVT2DEVINFO: 177 *result = aggr_dip; 178 return (DDI_SUCCESS); 179 case DDI_INFO_DEVT2INSTANCE: 180 *result = NULL; 181 return (DDI_SUCCESS); 182 } 183 return (DDI_FAILURE); 184 } 185 186 static int 187 aggr_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 188 { 189 switch (cmd) { 190 case DDI_ATTACH: 191 if (ddi_get_instance(dip) != 0) { 192 /* we only allow instance 0 to attach */ 193 return (DDI_FAILURE); 194 } 195 196 /* create minor node for control interface */ 197 if (ddi_create_minor_node(dip, AGGR_DEVNAME_CTL, S_IFCHR, 198 AGGR_MINOR_CTL, DDI_PSEUDO, 0) != DDI_SUCCESS) { 199 return (DDI_FAILURE); 200 } 201 202 aggr_dip = dip; 203 return (DDI_SUCCESS); 204 205 case DDI_RESUME: 206 return (DDI_SUCCESS); 207 208 default: 209 return (DDI_FAILURE); 210 } 211 } 212 213 /*ARGSUSED*/ 214 static int 215 aggr_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 216 { 217 switch (cmd) { 218 case DDI_DETACH: 219 aggr_dip = NULL; 220 ddi_remove_minor_node(dip, NULL); 221 222 return (DDI_SUCCESS); 223 224 case DDI_SUSPEND: 225 return (DDI_SUCCESS); 226 227 default: 228 return (DDI_FAILURE); 229 } 230 } 231