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 /* 27 * Standard module for handling DLPI Style 2 attach/detach 28 */ 29 30 #include <sys/types.h> 31 #include <sys/conf.h> 32 #include <sys/modctl.h> 33 #include <sys/cmn_err.h> 34 #include <sys/sunddi.h> 35 #include <sys/esunddi.h> 36 #include <sys/strsubr.h> 37 #include <sys/ddi.h> 38 #include <sys/dlpi.h> 39 #include <sys/strsun.h> 40 #include <sys/policy.h> 41 42 static struct streamtab drstab; 43 44 static struct fmodsw fsw = { 45 DRMODNAME, 46 &drstab, 47 D_MP 48 }; 49 50 51 /* 52 * Module linkage information for the kernel. 53 */ 54 55 static struct modlstrmod modlstrmod = { 56 &mod_strmodops, "dr compatibility for DLPI style 2 drivers", &fsw 57 }; 58 59 60 static struct modlinkage modlinkage = { 61 MODREV_1, &modlstrmod, NULL 62 }; 63 64 65 int 66 _init(void) 67 { 68 return (mod_install(&modlinkage)); 69 } 70 71 int 72 _fini(void) 73 { 74 return (mod_remove(&modlinkage)); 75 } 76 77 int 78 _info(struct modinfo *modinfop) 79 { 80 return (mod_info(&modlinkage, modinfop)); 81 } 82 83 84 static int dropen(queue_t *, dev_t *, int, int, cred_t *); 85 static int drclose(queue_t *, int, cred_t *); 86 static int drrput(queue_t *, mblk_t *); 87 static int drwput(queue_t *, mblk_t *); 88 89 static struct module_info drinfo = { 90 0, 91 DRMODNAME, 92 0, 93 INFPSZ, 94 1, 95 0 96 }; 97 98 static struct qinit drrinit = { 99 (int (*)())drrput, 100 NULL, 101 dropen, 102 drclose, 103 NULL, 104 &drinfo 105 }; 106 107 static struct qinit drwinit = { 108 (int (*)())drwput, 109 NULL, 110 NULL, 111 NULL, 112 NULL, 113 &drinfo 114 }; 115 116 static struct streamtab drstab = { 117 &drrinit, 118 &drwinit, 119 NULL, 120 NULL 121 }; 122 123 /* 124 * This module is pushed directly on top of the bottom driver 125 * in a DLPI style-2 stream by stropen(). It intercepts 126 * DL_ATTACH_REQ/DL_DETACH_REQ messages on the write side 127 * and acks on the read side, calls qassociate where needed. 128 * The primary purpose is to workaround a DR race condition 129 * affecting non-DDI compliant DLPI style 2 drivers, which may 130 * cause the system to panic. 131 * 132 * The following action is taken: 133 * Write side (drwput): 134 * attach request: hold driver instance assuming ppa == instance. 135 * This way, the instance cannot be detached while the 136 * driver is processing DL_ATTACH_REQ. 137 * 138 * On a successful hold, store the dip in a ring buffer 139 * to be processed lated by the read side. 140 * If hold fails (most likely ppa != instance), we store 141 * NULL in the ring buffer and read side won't take 142 * any action on ack. 143 * 144 * Read side (drrput): 145 * attach success: if (dip held on write side) associate queue with dip 146 * attach failure: if (dip held on write side) release hold on dip 147 * detach success: associate queue with NULL 148 * detach failure: do nothing 149 * 150 * The module assumes that incoming DL_ATTACH_REQ/DL_DETACH_REQ 151 * messages are ordered (non-concurrent) and the bottom 152 * driver processes them and sends acknowledgements in the same 153 * order. This assumption is reasonable because concurrent 154 * association results in non-deterministic queue behavior. 155 * The module is coded carefully such that unordered messages 156 * do not result in a system panic. 157 * 158 * The module handles multiple outstanding messages queued 159 * in the bottom driver. Messages processed on the write side 160 * but not yet arrived at read side are placed in the ring buffer 161 * dr_dip[], between dr_nfirst and dr_nlast. The write side is 162 * producer and the read side is the consumer. The buffer is full 163 * when dr_nfirst == dr_nlast. 164 * 165 * The current size of the ring buffer is 64 (MAX_DLREQS) per stream. 166 * During normal testing, we have not seen outstanding messages 167 * above 10. 168 */ 169 170 #define MAX_DLREQS 64 171 #define INCR(x) {(x)++; if ((x) >= MAX_DLREQS) (x) = 0; } 172 173 struct drstate { 174 kmutex_t dr_lock; 175 major_t dr_major; 176 int dr_nfirst; 177 int dr_nlast; 178 dev_info_t *dr_dip[MAX_DLREQS]; 179 }; 180 181 /* ARGSUSED1 */ 182 static int 183 dropen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *crp) 184 { 185 struct drstate *dsp; 186 187 if (sflag != MODOPEN) { /* must be a pushed module */ 188 return (EINVAL); 189 } 190 191 if (secpolicy_net_rawaccess(crp) != 0) { 192 return (EPERM); 193 } 194 195 if (q->q_ptr != NULL) { 196 return (0); /* already open */ 197 } 198 199 dsp = kmem_zalloc(sizeof (*dsp), KM_SLEEP); 200 dsp->dr_major = getmajor(*devp); 201 mutex_init(&dsp->dr_lock, NULL, MUTEX_DEFAULT, NULL); 202 q->q_ptr = OTHERQ(q)->q_ptr = dsp; 203 qprocson(q); 204 ddi_assoc_queue_with_devi(q, NULL); 205 return (0); 206 } 207 208 /* ARGSUSED1 */ 209 static int 210 drclose(queue_t *q, int cflag, cred_t *crp) 211 { 212 struct drstate *dsp = q->q_ptr; 213 214 ASSERT(dsp); 215 ddi_assoc_queue_with_devi(q, NULL); 216 qprocsoff(q); 217 218 mutex_destroy(&dsp->dr_lock); 219 kmem_free(dsp, sizeof (*dsp)); 220 q->q_ptr = NULL; 221 222 return (0); 223 } 224 225 static int 226 drrput(queue_t *q, mblk_t *mp) 227 { 228 struct drstate *dsp; 229 union DL_primitives *dlp; 230 dev_info_t *dip; 231 232 switch (DB_TYPE(mp)) { 233 case M_PROTO: 234 case M_PCPROTO: 235 break; 236 default: 237 putnext(q, mp); 238 return (0); 239 } 240 241 /* make sure size is sufficient for dl_primitive */ 242 if (MBLKL(mp) < sizeof (t_uscalar_t)) { 243 putnext(q, mp); 244 return (0); 245 } 246 247 dlp = (union DL_primitives *)mp->b_rptr; 248 switch (dlp->dl_primitive) { 249 case DL_OK_ACK: { 250 /* check for proper size, let upper layer deal with error */ 251 if (MBLKL(mp) < DL_OK_ACK_SIZE) { 252 putnext(q, mp); 253 return (0); 254 } 255 256 dsp = q->q_ptr; 257 switch (dlp->ok_ack.dl_correct_primitive) { 258 case DL_ATTACH_REQ: 259 /* 260 * ddi_assoc_queue_with_devi() will hold dip, 261 * so release after association. 262 * 263 * dip is NULL means we didn't hold dip on read side. 264 * (unlikely, but possible), so we do nothing. 265 */ 266 mutex_enter(&dsp->dr_lock); 267 dip = dsp->dr_dip[dsp->dr_nlast]; 268 dsp->dr_dip[dsp->dr_nlast] = NULL; 269 INCR(dsp->dr_nlast); 270 mutex_exit(&dsp->dr_lock); 271 if (dip) { 272 ddi_assoc_queue_with_devi(q, dip); 273 ddi_release_devi(dip); 274 } 275 break; 276 277 case DL_DETACH_REQ: 278 ddi_assoc_queue_with_devi(q, NULL); 279 break; 280 default: 281 break; 282 } 283 break; 284 } 285 case DL_ERROR_ACK: 286 if (dlp->error_ack.dl_error_primitive != DL_ATTACH_REQ) 287 break; 288 289 dsp = q->q_ptr; 290 mutex_enter(&dsp->dr_lock); 291 dip = dsp->dr_dip[dsp->dr_nlast]; 292 dsp->dr_dip[dsp->dr_nlast] = NULL; 293 INCR(dsp->dr_nlast); 294 mutex_exit(&dsp->dr_lock); 295 /* 296 * Release dip on attach failure 297 */ 298 if (dip) { 299 ddi_release_devi(dip); 300 } 301 break; 302 default: 303 break; 304 } 305 306 putnext(q, mp); 307 return (0); 308 } 309 310 /* 311 * Detect dl attach, hold the dip to prevent it from detaching 312 */ 313 static int 314 drwput(queue_t *q, mblk_t *mp) 315 { 316 struct drstate *dsp; 317 union DL_primitives *dlp; 318 dev_info_t *dip; 319 320 switch (DB_TYPE(mp)) { 321 case M_PROTO: 322 case M_PCPROTO: 323 break; 324 default: 325 putnext(q, mp); 326 return (0); 327 } 328 329 /* make sure size is sufficient for dl_primitive */ 330 if (MBLKL(mp) < sizeof (t_uscalar_t)) { 331 putnext(q, mp); 332 return (0); 333 } 334 335 dlp = (union DL_primitives *)mp->b_rptr; 336 switch (dlp->dl_primitive) { 337 case DL_ATTACH_REQ: 338 /* 339 * Check for proper size of the message. 340 * 341 * If size is correct, get the ppa and attempt to 342 * hold the device assuming ppa is instance. 343 * 344 * If size is wrong, we can't get the ppa, but 345 * still increment dr_nfirst because the read side 346 * will get a error ack on DL_ATTACH_REQ. 347 */ 348 dip = NULL; 349 dsp = q->q_ptr; 350 if (MBLKL(mp) >= DL_OK_ACK_SIZE) { 351 dip = ddi_hold_devi_by_instance(dsp->dr_major, 352 dlp->attach_req.dl_ppa, E_DDI_HOLD_DEVI_NOATTACH); 353 } 354 355 mutex_enter(&dsp->dr_lock); 356 dsp->dr_dip[dsp->dr_nfirst] = dip; 357 INCR(dsp->dr_nfirst); 358 /* 359 * Check if ring buffer is full. If so, assert in debug 360 * kernel and produce a warning in non-debug kernel. 361 */ 362 ASSERT(dsp->dr_nfirst != dsp->dr_nlast); 363 if (dsp->dr_nfirst == dsp->dr_nlast) { 364 cmn_err(CE_WARN, "drcompat: internal buffer full"); 365 } 366 mutex_exit(&dsp->dr_lock); 367 break; 368 default: 369 break; 370 } 371 372 putnext(q, mp); 373 return (0); 374 } 375