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