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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * IEEE 802.3ad Link Aggregation. 30 */ 31 32 #include <sys/types.h> 33 #include <sys/sysmacros.h> 34 #include <sys/conf.h> 35 #include <sys/cmn_err.h> 36 #include <sys/list.h> 37 #include <sys/ksynch.h> 38 #include <sys/kmem.h> 39 #include <sys/stream.h> 40 #include <sys/strsun.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/dld_impl.h> 48 #include <sys/aggr.h> 49 #include <sys/aggr_impl.h> 50 #include <inet/common.h> 51 52 /* module description */ 53 #define AGGR_LINKINFO "Link Aggregation MAC" 54 #define AGGR_DRIVER_NAME "aggr" 55 56 /* device info ptr, only one for instance 0 */ 57 dev_info_t *aggr_dip = NULL; 58 59 static int aggr_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 60 static int aggr_attach(dev_info_t *, ddi_attach_cmd_t); 61 static int aggr_detach(dev_info_t *, ddi_detach_cmd_t); 62 static int aggr_open(queue_t *, dev_t *, int, int, cred_t *); 63 static int aggr_close(queue_t *); 64 static void aggr_wput(queue_t *, mblk_t *); 65 66 /* 67 * mi_hiwat is set to 1 because of the flow control mechanism implemented 68 * in dld. refer to the comments in dld_str.c for details. 69 */ 70 static struct module_info aggr_module_info = { 71 0, 72 AGGR_DRIVER_NAME, 73 0, 74 INFPSZ, 75 1, 76 0 77 }; 78 79 static struct qinit aggr_r_qinit = { /* read queues */ 80 NULL, 81 NULL, 82 aggr_open, 83 aggr_close, 84 NULL, 85 &aggr_module_info 86 }; 87 88 static struct qinit aggr_w_qinit = { /* write queues */ 89 (pfi_t)dld_wput, 90 (pfi_t)dld_wsrv, 91 NULL, 92 NULL, 93 NULL, 94 &aggr_module_info 95 }; 96 97 /* 98 * Entry points for aggr control node 99 */ 100 static struct qinit aggr_w_ctl_qinit = { 101 (pfi_t)aggr_wput, 102 NULL, 103 NULL, 104 NULL, 105 NULL, 106 &aggr_module_info 107 }; 108 109 static struct streamtab aggr_streamtab = { 110 &aggr_r_qinit, 111 &aggr_w_qinit 112 }; 113 114 DDI_DEFINE_STREAM_OPS(aggr_dev_ops, nulldev, nulldev, aggr_attach, aggr_detach, 115 nodev, aggr_getinfo, D_MP, &aggr_streamtab); 116 117 static struct modldrv aggr_modldrv = { 118 &mod_driverops, /* Type of module. This one is a driver */ 119 AGGR_LINKINFO, /* short description */ 120 &aggr_dev_ops /* driver specific ops */ 121 }; 122 123 static struct modlinkage modlinkage = { 124 MODREV_1, 125 &aggr_modldrv, 126 NULL 127 }; 128 129 130 int 131 _init(void) 132 { 133 return (mod_install(&modlinkage)); 134 } 135 136 int 137 _fini(void) 138 { 139 return (mod_remove(&modlinkage)); 140 } 141 142 int 143 _info(struct modinfo *modinfop) 144 { 145 return (mod_info(&modlinkage, modinfop)); 146 } 147 148 static int 149 aggr_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) 150 { 151 if (q->q_ptr != NULL) 152 return (EBUSY); 153 154 if (getminor(*devp) == AGGR_MINOR_CTL) { 155 dld_str_t *dsp; 156 157 dsp = dld_str_create(q, DLD_CONTROL, getmajor(*devp), 158 DL_STYLE1); 159 if (dsp == NULL) 160 return (ENOSR); 161 162 /* 163 * The ioctl handling callback to process control ioctl 164 * messages; see comments above dld_ioctl() for details. 165 */ 166 dsp->ds_ioctl = aggr_ioctl; 167 168 /* 169 * The aggr control node uses its own set of entry points. 170 */ 171 WR(q)->q_qinfo = &aggr_w_ctl_qinit; 172 *devp = makedevice(getmajor(*devp), dsp->ds_minor); 173 qprocson(q); 174 return (0); 175 } 176 return (dld_open(q, devp, flag, sflag, credp)); 177 } 178 179 static int 180 aggr_close(queue_t *q) 181 { 182 dld_str_t *dsp = q->q_ptr; 183 184 if (dsp->ds_type == DLD_CONTROL) { 185 qprocsoff(q); 186 dld_finish_pending_task(dsp); 187 dsp->ds_ioctl = NULL; 188 dld_str_destroy(dsp); 189 return (0); 190 } 191 return (dld_close(q)); 192 } 193 194 static void 195 aggr_wput(queue_t *q, mblk_t *mp) 196 { 197 if (DB_TYPE(mp) == M_IOCTL) 198 dld_ioctl(q, mp); 199 else 200 freemsg(mp); 201 } 202 203 /*ARGSUSED*/ 204 static int 205 aggr_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 206 void **result) 207 { 208 switch (infocmd) { 209 case DDI_INFO_DEVT2DEVINFO: 210 *result = aggr_dip; 211 return (DDI_SUCCESS); 212 case DDI_INFO_DEVT2INSTANCE: 213 *result = NULL; 214 return (DDI_SUCCESS); 215 } 216 return (DDI_FAILURE); 217 } 218 219 static int 220 aggr_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 221 { 222 switch (cmd) { 223 case DDI_ATTACH: 224 if (ddi_get_instance(dip) != 0) { 225 /* we only allow instance 0 to attach */ 226 return (DDI_FAILURE); 227 } 228 229 /* create minor node for control interface */ 230 if (ddi_create_minor_node(dip, AGGR_DEVNAME_CTL, S_IFCHR, 231 AGGR_MINOR_CTL, DDI_PSEUDO, 0) != DDI_SUCCESS) { 232 return (DDI_FAILURE); 233 } 234 235 aggr_dip = dip; 236 aggr_port_init(); 237 aggr_grp_init(); 238 aggr_lacp_init(); 239 return (DDI_SUCCESS); 240 241 case DDI_RESUME: 242 return (DDI_SUCCESS); 243 244 default: 245 return (DDI_FAILURE); 246 } 247 } 248 249 /*ARGSUSED*/ 250 static int 251 aggr_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 252 { 253 switch (cmd) { 254 case DDI_DETACH: 255 if (aggr_grp_count() > 0) 256 return (DDI_FAILURE); 257 258 aggr_dip = NULL; 259 ddi_remove_minor_node(dip, AGGR_DEVNAME_CTL); 260 aggr_port_fini(); 261 aggr_grp_fini(); 262 aggr_lacp_fini(); 263 return (DDI_SUCCESS); 264 265 case DDI_SUSPEND: 266 return (DDI_SUCCESS); 267 268 default: 269 return (DDI_FAILURE); 270 } 271 } 272