Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/scsi/targets/smp.c
+++ new/usr/src/uts/common/io/scsi/targets/smp.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 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27
28 28 /*
29 29 * SMP - Serial Management Protocol Device Driver
30 30 *
31 31 * The SMP driver provides user programs access to SAS Serial Management
32 32 * Protocol devices by providing ioctl interface.
33 33 */
34 34
35 35 #include <sys/modctl.h>
36 36 #include <sys/file.h>
37 37 #include <sys/scsi/scsi.h>
38 38 #include <sys/scsi/targets/smp.h>
39 39 #include <sys/sdt.h>
40 40
41 41 /*
42 42 * Standard entrypoints
43 43 */
44 44 static int smp_attach(dev_info_t *, ddi_attach_cmd_t);
45 45 static int smp_detach(dev_info_t *, ddi_detach_cmd_t);
46 46 static int smp_open(dev_t *, int, int, cred_t *);
47 47 static int smp_close(dev_t, int, int, cred_t *);
48 48 static int smp_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
49 49
50 50 /*
51 51 * Configuration routines
52 52 */
53 53 static int smp_do_attach(dev_info_t *);
54 54 static int smp_do_detach(dev_info_t *);
55 55
56 56 /*
57 57 * Command handle routing
58 58 */
59 59 static int smp_handle_func(dev_t, intptr_t, int, cred_t *, int *);
60 60
61 61 /*
62 62 * Logging/debugging routines
63 63 */
64 64 static void smp_log(smp_state_t *, int, const char *, ...);
65 65
66 66 int smp_retry_times = SMP_DEFAULT_RETRY_TIMES;
67 67 int smp_retry_delay = 10000; /* 10msec */
68 68 int smp_delay_cmd = 1; /* 1usec */
69 69 int smp_single_command = 1; /* one command at a time */
70 70
71 71 static int smp_retry_recovered = 0; /* retry recovery counter */
72 72 static int smp_retry_failed = 0; /* retry failed counter */
73 73 static int smp_failed = 0;
74 74
75 75 static struct cb_ops smp_cb_ops = {
76 76 smp_open, /* open */
77 77 smp_close, /* close */
78 78 nodev, /* strategy */
79 79 nodev, /* print */
80 80 nodev, /* dump */
81 81 nodev, /* read */
82 82 nodev, /* write */
83 83 smp_ioctl, /* ioctl */
84 84 nodev, /* devmap */
85 85 nodev, /* mmap */
86 86 nodev, /* segmap */
87 87 nochpoll, /* poll */
88 88 ddi_prop_op, /* cb_prop_op */
89 89 0, /* streamtab */
90 90 D_MP | D_NEW | D_HOTPLUG /* Driver compatibility flag */
91 91 };
92 92
93 93 static struct dev_ops smp_dev_ops = {
94 94 DEVO_REV, /* devo_rev, */
95 95 0, /* refcnt */
96 96 ddi_getinfo_1to1, /* info */
97 97 nulldev, /* identify */
98 98 NULL, /* probe */
99 99 smp_attach, /* attach */
100 100 smp_detach, /* detach */
101 101 nodev, /* reset */
102 102 &smp_cb_ops, /* driver operations */
103 103 (struct bus_ops *)0, /* bus operations */
104 104 NULL, /* power */
↓ open down ↓ |
104 lines elided |
↑ open up ↑ |
105 105 ddi_quiesce_not_needed, /* quiesce */
106 106 };
107 107
108 108 static void *smp_soft_state = NULL;
109 109
110 110 static struct modldrv modldrv = {
111 111 &mod_driverops, "smp device driver", &smp_dev_ops
112 112 };
113 113
114 114 static struct modlinkage modlinkage = {
115 - MODREV_1, &modldrv, NULL
115 + MODREV_1, { &modldrv, NULL }
116 116 };
117 117
118 118 int
119 119 _init(void)
120 120 {
121 121 int err;
122 122
123 123 if ((err = ddi_soft_state_init(&smp_soft_state,
124 124 sizeof (smp_state_t), SMP_ESTIMATED_NUM_DEVS)) != 0) {
125 125 return (err);
126 126 }
127 127
128 128 if ((err = mod_install(&modlinkage)) != 0) {
129 129 ddi_soft_state_fini(&smp_soft_state);
130 130 }
131 131
132 132 return (err);
133 133 }
134 134
135 135 int
136 136 _fini(void)
137 137 {
138 138 int err;
139 139
140 140 if ((err = mod_remove(&modlinkage)) == 0) {
141 141 ddi_soft_state_fini(&smp_soft_state);
142 142 }
143 143
144 144 return (err);
145 145 }
146 146
147 147 int
148 148 _info(struct modinfo *modinfop)
149 149 {
150 150 return (mod_info(&modlinkage, modinfop));
151 151 }
152 152
153 153 /*
154 154 * smp_attach()
155 155 * attach(9e) entrypoint.
156 156 */
157 157 static int
158 158 smp_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
159 159 {
160 160 int err;
161 161
162 162 switch (cmd) {
163 163 case DDI_ATTACH:
164 164 err = smp_do_attach(dip);
165 165 break;
166 166 case DDI_RESUME:
167 167 err = DDI_SUCCESS;
168 168 break;
169 169 default:
170 170 err = DDI_FAILURE;
171 171 break;
172 172 }
173 173
174 174 if (err != DDI_SUCCESS) {
175 175 smp_log(NULL, CE_NOTE, "!smp_attach(), "
176 176 "device unit-address @%s failed",
177 177 ddi_get_name_addr(dip));
178 178 }
179 179 return (err);
180 180 }
181 181
182 182 /*
183 183 * smp_do_attach()
184 184 * handle the nitty details of attach.
185 185 */
186 186 static int
187 187 smp_do_attach(dev_info_t *dip)
188 188 {
189 189 int instance;
190 190 struct smp_device *smp_sd;
191 191 uchar_t *srmir = NULL;
192 192 uint_t srmirlen = 0;
193 193 ddi_devid_t devid = NULL;
194 194 smp_state_t *smp_state;
195 195
196 196 instance = ddi_get_instance(dip);
197 197 smp_sd = ddi_get_driver_private(dip);
198 198 ASSERT(smp_sd != NULL);
199 199
200 200 DTRACE_PROBE2(smp__attach__detach, int, instance, char *,
201 201 ddi_get_name_addr(dip));
202 202
203 203 /* make sure device is there, and establish srmir identity property */
204 204 if (smp_probe(smp_sd) != DDI_PROBE_SUCCESS) {
205 205 smp_log(NULL, CE_NOTE,
206 206 "!smp_do_attach: failed smp_probe, "
207 207 "device unit-address @%s", ddi_get_name_addr(dip));
208 208 return (DDI_FAILURE);
209 209 }
210 210
211 211 /* if we have not already registered a devid, then do so now */
212 212 if (ddi_devid_get(dip, &devid) != DDI_SUCCESS) {
213 213 /* get the srmir identity information for use in devid */
214 214 (void) ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip,
215 215 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
216 216 SMP_PROP_REPORT_MANUFACTURER, &srmir, &srmirlen);
217 217
218 218 /* Convert smp unit-address and srmir into devid */
219 219 if (ddi_devid_smp_encode(DEVID_SMP_ENCODE_VERSION_LATEST,
220 220 (char *)ddi_driver_name(dip), ddi_get_name_addr(dip),
221 221 srmir, srmirlen, &devid) == DDI_SUCCESS) {
222 222 /* register the devid */
223 223 (void) ddi_devid_register(dip, devid);
224 224 }
225 225 ddi_prop_free(srmir);
226 226 }
227 227
228 228 /* We don't need the devid for our own operation, so free now. */
229 229 if (devid)
230 230 ddi_devid_free(devid);
231 231
232 232 /* we are now done with srmir identity property defined by smp_probe */
233 233 (void) ndi_prop_remove(DDI_DEV_T_NONE,
234 234 dip, SMP_PROP_REPORT_MANUFACTURER);
235 235
236 236 if (ddi_soft_state_zalloc(smp_soft_state, instance) != DDI_SUCCESS) {
237 237 smp_log(NULL, CE_NOTE,
238 238 "!smp_do_attach: failed to allocate softstate, "
239 239 "device unit-address @%s", ddi_get_name_addr(dip));
240 240 return (DDI_FAILURE);
241 241 }
242 242
243 243 smp_state = ddi_get_soft_state(smp_soft_state, instance);
244 244 smp_state->smp_sd = smp_sd;
245 245
246 246 /*
247 247 * For simplicity, the minor number == the instance number
248 248 */
249 249 if (ddi_create_minor_node(dip, "smp", S_IFCHR,
250 250 instance, DDI_NT_SMP, NULL) == DDI_FAILURE) {
251 251 smp_log(smp_state, CE_NOTE,
252 252 "!smp_do_attach: minor node creation failed, "
253 253 "device unit-address @%s", ddi_get_name_addr(dip));
254 254 ddi_soft_state_free(smp_soft_state, instance);
255 255 return (DDI_FAILURE);
256 256 }
257 257
258 258 mutex_init(&smp_state->smp_mutex, NULL, MUTEX_DRIVER, NULL);
259 259 smp_state->smp_open_flag = SMP_CLOSED;
260 260
261 261 ddi_report_dev(dip);
262 262 return (DDI_SUCCESS);
263 263 }
264 264
265 265 /*
266 266 * smp_detach()
267 267 * detach(9E) entrypoint
268 268 */
269 269 static int
270 270 smp_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
271 271 {
272 272 int instance;
273 273 smp_state_t *smp_state;
274 274
275 275 instance = ddi_get_instance(dip);
276 276 smp_state = ddi_get_soft_state(smp_soft_state, instance);
277 277
278 278 if (smp_state == NULL) {
279 279 smp_log(NULL, CE_NOTE,
280 280 "!smp_detach: failed, no softstate found (%d), "
281 281 "device unit-address @%s",
282 282 instance, ddi_get_name_addr(dip));
283 283 return (DDI_FAILURE);
284 284 }
285 285
286 286 switch (cmd) {
287 287 case DDI_DETACH:
288 288 return (smp_do_detach(dip));
289 289 case DDI_SUSPEND:
290 290 return (DDI_SUCCESS);
291 291 default:
292 292 return (DDI_FAILURE);
293 293 }
294 294 }
295 295
296 296 /*
297 297 * smp_do_detach()
298 298 * detach the driver, tearing down resources.
299 299 */
300 300 static int
301 301 smp_do_detach(dev_info_t *dip)
302 302 {
303 303 int instance;
304 304 smp_state_t *smp_state;
305 305
306 306 instance = ddi_get_instance(dip);
307 307 smp_state = ddi_get_soft_state(smp_soft_state, instance);
308 308
309 309 DTRACE_PROBE2(smp__attach__detach, int, instance, char *,
310 310 ddi_get_name_addr(dip));
311 311
312 312 mutex_destroy(&smp_state->smp_mutex);
313 313 ddi_soft_state_free(smp_soft_state, instance);
314 314 ddi_remove_minor_node(dip, NULL);
315 315 return (DDI_SUCCESS);
316 316 }
317 317
318 318 /*ARGSUSED*/
319 319 static int
320 320 smp_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
321 321 {
322 322 smp_state_t *smp_state;
323 323 int instance;
324 324 int rv = 0;
325 325
326 326 instance = getminor(*dev_p);
327 327 if ((smp_state = ddi_get_soft_state(smp_soft_state, instance))
328 328 == NULL) {
329 329 return (ENXIO);
330 330 }
331 331
332 332 mutex_enter(&smp_state->smp_mutex);
333 333 if (flag & FEXCL) {
334 334 if (smp_state->smp_open_flag != SMP_CLOSED) {
335 335 rv = EBUSY;
336 336 } else {
337 337 smp_state->smp_open_flag = SMP_EXOPENED;
338 338 }
339 339 } else {
340 340 if (smp_state->smp_open_flag == SMP_EXOPENED) {
341 341 rv = EBUSY;
342 342 } else {
343 343 smp_state->smp_open_flag = SMP_SOPENED;
344 344 }
345 345 }
346 346 mutex_exit(&smp_state->smp_mutex);
347 347
348 348 return (rv);
349 349 }
350 350
351 351 /*ARGSUSED*/
352 352 static int
353 353 smp_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
354 354 {
355 355 smp_state_t *smp_state;
356 356 int instance;
357 357 int rv = 0;
358 358
359 359 instance = getminor(dev);
360 360 if ((smp_state = ddi_get_soft_state(smp_soft_state, instance))
361 361 == NULL) {
362 362 return (ENXIO);
363 363 }
364 364
365 365 mutex_enter(&smp_state->smp_mutex);
366 366 if (smp_state->smp_open_flag == SMP_CLOSED) {
367 367 smp_log(smp_state, CE_NOTE, "!smp device is already in close");
368 368 } else {
369 369 smp_state->smp_open_flag = SMP_CLOSED;
370 370 }
371 371 mutex_exit(&smp_state->smp_mutex);
372 372 return (rv);
373 373 }
374 374
375 375 /*ARGSUSED*/
376 376 static int
377 377 smp_handle_func(dev_t dev,
378 378 intptr_t arg, int flag, cred_t *cred_p, int *rval_p)
379 379 {
380 380 usmp_cmd_t usmp_cmd_data, *usmp_cmd = &usmp_cmd_data;
381 381 smp_pkt_t smp_pkt_data, *smp_pkt = &smp_pkt_data;
382 382 smp_state_t *smp_state;
383 383 int instance, retrycount;
384 384 cred_t *cr;
385 385 uint64_t cmd_flags = 0;
386 386 int rval = 0;
387 387
388 388 #ifdef _MULTI_DATAMODEL
389 389 usmp_cmd32_t usmp_cmd32_data, *usmp_cmd32 = &usmp_cmd32_data;
390 390 #endif
391 391
392 392 /* require PRIV_SYS_DEVICES privilege */
393 393 cr = ddi_get_cred();
394 394 if ((drv_priv(cred_p) != 0) && (drv_priv(cr) != 0)) {
395 395 return (EPERM);
396 396 }
397 397
398 398 bzero(smp_pkt, sizeof (smp_pkt_t));
399 399
400 400 instance = getminor(dev);
401 401 if ((smp_state = ddi_get_soft_state(smp_soft_state, instance))
402 402 == NULL) {
403 403 return (ENXIO);
404 404 }
405 405
406 406 #ifdef _MULTI_DATAMODEL
407 407 switch (ddi_model_convert_from(flag & FMODELS)) {
408 408 case DDI_MODEL_ILP32:
409 409 if (ddi_copyin((void *)arg, usmp_cmd32, sizeof (usmp_cmd32_t),
410 410 flag)) {
411 411 return (EFAULT);
412 412 }
413 413
414 414 usmp_cmd32tousmp_cmd(usmp_cmd32, usmp_cmd);
415 415 break;
416 416 case DDI_MODEL_NONE:
417 417 if (ddi_copyin((void *)arg, usmp_cmd, sizeof (usmp_cmd_t),
418 418 flag)) {
419 419 return (EFAULT);
420 420 }
421 421 break;
422 422 }
423 423 #else /* ! _MULTI_DATAMODEL */
424 424 if (ddi_copyin((void *)arg, usmp_cmd, sizeof (usmp_cmd_t), flag)) {
425 425 return (EFAULT);
426 426 }
427 427 #endif /* _MULTI_DATAMODEL */
428 428
429 429 if ((usmp_cmd->usmp_reqsize < SMP_MIN_REQUEST_SIZE) ||
430 430 (usmp_cmd->usmp_reqsize > SMP_MAX_REQUEST_SIZE) ||
431 431 (usmp_cmd->usmp_rspsize < SMP_MIN_RESPONSE_SIZE) ||
432 432 (usmp_cmd->usmp_rspsize > SMP_MAX_RESPONSE_SIZE)) {
433 433 rval = EINVAL;
434 434 goto done;
435 435 }
436 436
437 437 smp_pkt->smp_pkt_reqsize = usmp_cmd->usmp_reqsize;
438 438 smp_pkt->smp_pkt_rspsize = usmp_cmd->usmp_rspsize;
439 439
440 440 /* allocate memory space for smp request and response frame in kernel */
441 441 smp_pkt->smp_pkt_req = kmem_zalloc((size_t)usmp_cmd->usmp_reqsize,
442 442 KM_SLEEP);
443 443 cmd_flags |= SMP_FLAG_REQBUF;
444 444
445 445 smp_pkt->smp_pkt_rsp = kmem_zalloc((size_t)usmp_cmd->usmp_rspsize,
446 446 KM_SLEEP);
447 447 cmd_flags |= SMP_FLAG_RSPBUF;
448 448
449 449 /* copy smp request frame to kernel space */
450 450 if (ddi_copyin(usmp_cmd->usmp_req, smp_pkt->smp_pkt_req,
451 451 (size_t)usmp_cmd->usmp_reqsize, flag) != 0) {
452 452 rval = EFAULT;
453 453 goto done;
454 454 }
455 455
456 456 DTRACE_PROBE1(smp__transport__start, caddr_t, smp_pkt->smp_pkt_req);
457 457
458 458 smp_pkt->smp_pkt_address = &smp_state->smp_sd->smp_sd_address;
459 459 if (usmp_cmd->usmp_timeout <= 0) {
460 460 smp_pkt->smp_pkt_timeout = SMP_DEFAULT_TIMEOUT;
461 461 } else {
462 462 smp_pkt->smp_pkt_timeout = usmp_cmd->usmp_timeout;
463 463 }
464 464
465 465 /* call smp_transport entry and send smp_pkt to HBA driver */
466 466 cmd_flags |= SMP_FLAG_XFER;
467 467 for (retrycount = 0; retrycount <= smp_retry_times; retrycount++) {
468 468
469 469 /*
470 470 * To improve transport reliability, only allow one command
471 471 * outstanding at a time in smp_transport().
472 472 *
473 473 * NOTE: Some expanders have issues with heavy smp load.
474 474 */
475 475 if (smp_single_command) {
476 476 mutex_enter(&smp_state->smp_mutex);
477 477 while (smp_state->smp_busy)
478 478 cv_wait(&smp_state->smp_cv,
479 479 &smp_state->smp_mutex);
480 480 smp_state->smp_busy = 1;
481 481 mutex_exit(&smp_state->smp_mutex);
482 482 }
483 483
484 484 /* Let the transport know if more retries are possible. */
485 485 smp_pkt->smp_pkt_will_retry =
486 486 (retrycount < smp_retry_times) ? 1 : 0;
487 487
488 488 smp_pkt->smp_pkt_reason = 0;
489 489 rval = smp_transport(smp_pkt); /* put on the wire */
490 490
491 491 if (smp_delay_cmd)
492 492 delay(drv_usectohz(smp_delay_cmd));
493 493
494 494 if (smp_single_command) {
495 495 mutex_enter(&smp_state->smp_mutex);
496 496 smp_state->smp_busy = 0;
497 497 cv_signal(&smp_state->smp_cv);
498 498 mutex_exit(&smp_state->smp_mutex);
499 499 }
500 500
501 501 if (rval == DDI_SUCCESS) {
502 502 if (retrycount)
503 503 smp_retry_recovered++;
504 504 rval = 0;
505 505 break;
506 506 }
507 507
508 508 switch (smp_pkt->smp_pkt_reason) {
509 509 case EAGAIN:
510 510 if (retrycount < smp_retry_times) {
511 511 bzero(smp_pkt->smp_pkt_rsp,
512 512 (size_t)usmp_cmd->usmp_rspsize);
513 513 if (smp_retry_delay)
514 514 delay(drv_usectohz(smp_retry_delay));
515 515 continue;
516 516 } else {
517 517 smp_retry_failed++;
518 518 smp_log(smp_state, CE_NOTE,
519 519 "!smp_transport failed, smp_pkt_reason %d",
520 520 smp_pkt->smp_pkt_reason);
521 521 rval = smp_pkt->smp_pkt_reason;
522 522 goto copyout;
523 523 }
524 524 default:
525 525 smp_log(smp_state, CE_NOTE,
526 526 "!smp_transport failed, smp_pkt_reason %d",
527 527 smp_pkt->smp_pkt_reason);
528 528 rval = smp_pkt->smp_pkt_reason;
529 529 goto copyout;
530 530 }
531 531 }
532 532
533 533 copyout:
534 534 /* copy out smp response to user process */
535 535 if (ddi_copyout(smp_pkt->smp_pkt_rsp, usmp_cmd->usmp_rsp,
536 536 (size_t)usmp_cmd->usmp_rspsize, flag) != 0) {
537 537 rval = EFAULT;
538 538 }
539 539
540 540 done:
541 541 if ((cmd_flags & SMP_FLAG_XFER) != 0) {
542 542 DTRACE_PROBE2(smp__transport__done, caddr_t,
543 543 smp_pkt->smp_pkt_rsp, uchar_t, smp_pkt->smp_pkt_reason);
544 544 }
545 545 if ((cmd_flags & SMP_FLAG_REQBUF) != 0) {
546 546 kmem_free(smp_pkt->smp_pkt_req, smp_pkt->smp_pkt_reqsize);
547 547 }
548 548 if ((cmd_flags & SMP_FLAG_RSPBUF) != 0) {
549 549 kmem_free(smp_pkt->smp_pkt_rsp, smp_pkt->smp_pkt_rspsize);
550 550 }
551 551
552 552 if (rval)
553 553 smp_failed++;
554 554 return (rval);
555 555 }
556 556
557 557 /*ARGSUSED*/
558 558 static int
559 559 smp_ioctl(dev_t dev,
560 560 int cmd, intptr_t arg, int flag, cred_t *cred_p, int *rval_p)
561 561 {
562 562 int rval = 0;
563 563
564 564 switch (cmd) {
565 565 case USMPFUNC:
566 566 /*
567 567 * The response payload is valid only if return value is 0
568 568 * or EOVERFLOW.
569 569 */
570 570 rval = smp_handle_func(dev, arg, flag, cred_p, rval_p);
571 571 break;
572 572 default:
573 573 rval = EINVAL;
574 574 }
575 575 return (rval);
576 576 }
577 577
578 578 static void
579 579 smp_log(smp_state_t *smp_state, int level, const char *fmt, ...)
580 580 {
581 581 va_list ap;
582 582 char buf[256];
583 583 dev_info_t *dip;
584 584
585 585 if (smp_state == (smp_state_t *)NULL) {
586 586 dip = NULL;
587 587 } else {
588 588 dip = smp_state->smp_sd->smp_sd_dev;
589 589 }
590 590
591 591 va_start(ap, fmt);
592 592 (void) vsnprintf(buf, sizeof (buf), fmt, ap);
593 593 va_end(ap);
594 594
595 595 scsi_log(dip, "smp", level, "%s", buf);
596 596 }
↓ open down ↓ |
471 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX