Print this page
OS-122 Assertion in e_devid_minor_to_devlist() in devid_cache.c
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/os/devid_cache.c
+++ new/usr/src/uts/common/os/devid_cache.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 *
|
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
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 (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
23 + * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
23 24 */
24 25
25 26 #include <sys/note.h>
26 27 #include <sys/t_lock.h>
27 28 #include <sys/cmn_err.h>
28 29 #include <sys/instance.h>
29 30 #include <sys/conf.h>
30 31 #include <sys/stat.h>
31 32 #include <sys/ddi.h>
32 33 #include <sys/hwconf.h>
33 34 #include <sys/sunddi.h>
34 35 #include <sys/sunndi.h>
35 36 #include <sys/sunmdi.h>
36 37 #include <sys/ddi_impldefs.h>
37 38 #include <sys/ndi_impldefs.h>
38 39 #include <sys/kobj.h>
39 40 #include <sys/devcache.h>
40 41 #include <sys/devid_cache.h>
41 42 #include <sys/sysmacros.h>
42 43
43 44 /*
44 45 * Discovery refers to the heroic effort made to discover a device which
45 46 * cannot be accessed at the physical path where it once resided. Discovery
46 47 * involves walking the entire device tree attaching all possible disk
47 48 * instances, to search for the device referenced by a devid. Obviously,
48 49 * full device discovery is something to be avoided where possible.
49 50 * Note that simply invoking devfsadm(1M) is equivalent to running full
50 51 * discovery at the devid cache level.
51 52 *
52 53 * Reasons why a disk may not be accessible:
53 54 * disk powered off
54 55 * disk removed or cable disconnected
55 56 * disk or adapter broken
56 57 *
57 58 * Note that discovery is not needed and cannot succeed in any of these
58 59 * cases.
59 60 *
60 61 * When discovery may succeed:
61 62 * Discovery will result in success when a device has been moved
62 63 * to a different address. Note that it's recommended that
63 64 * devfsadm(1M) be invoked (no arguments required) whenever a system's
64 65 * h/w configuration has been updated. Alternatively, a
65 66 * reconfiguration boot can be used to accomplish the same result.
66 67 *
67 68 * Note that discovery is not necessary to be able to correct an access
68 69 * failure for a device which was powered off. Assuming the cache has an
69 70 * entry for such a device, simply powering it on should permit the system
70 71 * to access it. If problems persist after powering it on, invoke
71 72 * devfsadm(1M).
72 73 *
73 74 * Discovery prior to mounting root is only of interest when booting
74 75 * from a filesystem which accesses devices by device id, which of
75 76 * not all do.
76 77 *
77 78 * Tunables
78 79 *
79 80 * devid_discovery_boot (default 1)
80 81 * Number of times discovery will be attempted prior to mounting root.
81 82 * Must be done at least once to recover from corrupted or missing
82 83 * devid cache backing store. Probably there's no reason to ever
83 84 * set this to greater than one as a missing device will remain
84 85 * unavailable no matter how often the system searches for it.
85 86 *
86 87 * devid_discovery_postboot (default 1)
87 88 * Number of times discovery will be attempted after mounting root.
88 89 * This must be performed at least once to discover any devices
89 90 * needed after root is mounted which may have been powered
90 91 * off and moved before booting.
91 92 * Setting this to a larger positive number will introduce
92 93 * some inconsistency in system operation. Searching for a device
93 94 * will take an indeterminate amount of time, sometimes slower,
94 95 * sometimes faster. In addition, the system will sometimes
95 96 * discover a newly powered on device, sometimes it won't.
96 97 * Use of this option is not therefore recommended.
97 98 *
98 99 * devid_discovery_postboot_always (default 0)
99 100 * Set to 1, the system will always attempt full discovery.
100 101 *
101 102 * devid_discovery_secs (default 0)
102 103 * Set to a positive value, the system will attempt full discovery
103 104 * but with a minimum delay between attempts. A device search
104 105 * within the period of time specified will result in failure.
105 106 *
106 107 * devid_cache_read_disable (default 0)
107 108 * Set to 1 to disable reading /etc/devices/devid_cache.
108 109 * Devid cache will continue to operate normally but
109 110 * at least one discovery attempt will be required.
110 111 *
111 112 * devid_cache_write_disable (default 0)
112 113 * Set to 1 to disable updates to /etc/devices/devid_cache.
113 114 * Any updates to the devid cache will not be preserved across a reboot.
114 115 *
115 116 * devid_report_error (default 0)
116 117 * Set to 1 to enable some error messages related to devid
117 118 * cache failures.
118 119 *
119 120 * The devid is packed in the cache file as a byte array. For
120 121 * portability, this could be done in the encoded string format.
121 122 */
122 123
123 124
124 125 int devid_discovery_boot = 1;
125 126 int devid_discovery_postboot = 1;
126 127 int devid_discovery_postboot_always = 0;
127 128 int devid_discovery_secs = 0;
128 129
129 130 int devid_cache_read_disable = 0;
130 131 int devid_cache_write_disable = 0;
131 132
132 133 int devid_report_error = 0;
133 134
134 135
135 136 /*
136 137 * State to manage discovery of devices providing a devid
137 138 */
138 139 static int devid_discovery_busy = 0;
139 140 static kmutex_t devid_discovery_mutex;
140 141 static kcondvar_t devid_discovery_cv;
141 142 static clock_t devid_last_discovery = 0;
142 143
143 144
144 145 #ifdef DEBUG
145 146 int nvp_devid_debug = 0;
146 147 int devid_debug = 0;
147 148 int devid_log_registers = 0;
148 149 int devid_log_finds = 0;
149 150 int devid_log_lookups = 0;
150 151 int devid_log_discovery = 0;
151 152 int devid_log_matches = 0;
152 153 int devid_log_paths = 0;
153 154 int devid_log_failures = 0;
154 155 int devid_log_hold = 0;
155 156 int devid_log_unregisters = 0;
156 157 int devid_log_removes = 0;
157 158 int devid_register_debug = 0;
158 159 int devid_log_stale = 0;
159 160 int devid_log_detaches = 0;
160 161 #endif /* DEBUG */
161 162
162 163 /*
163 164 * devid cache file registration for cache reads and updates
164 165 */
165 166 static nvf_ops_t devid_cache_ops = {
166 167 "/etc/devices/devid_cache", /* path to cache */
167 168 devid_cache_unpack_nvlist, /* read: nvlist to nvp */
168 169 devid_cache_pack_list, /* write: nvp to nvlist */
169 170 devid_list_free, /* free data list */
170 171 NULL /* write complete callback */
171 172 };
172 173
173 174 /*
174 175 * handle to registered devid cache handlers
175 176 */
176 177 nvf_handle_t dcfd_handle;
177 178
178 179
179 180 /*
180 181 * Initialize devid cache file management
181 182 */
182 183 void
183 184 devid_cache_init(void)
184 185 {
185 186 dcfd_handle = nvf_register_file(&devid_cache_ops);
186 187 ASSERT(dcfd_handle);
187 188
188 189 list_create(nvf_list(dcfd_handle), sizeof (nvp_devid_t),
189 190 offsetof(nvp_devid_t, nvp_link));
190 191
191 192 mutex_init(&devid_discovery_mutex, NULL, MUTEX_DEFAULT, NULL);
192 193 cv_init(&devid_discovery_cv, NULL, CV_DRIVER, NULL);
193 194 }
194 195
195 196 /*
196 197 * Read and initialize the devid cache from the persistent store
197 198 */
198 199 void
199 200 devid_cache_read(void)
200 201 {
201 202 if (!devid_cache_read_disable) {
202 203 rw_enter(nvf_lock(dcfd_handle), RW_WRITER);
203 204 ASSERT(list_head(nvf_list(dcfd_handle)) == NULL);
204 205 (void) nvf_read_file(dcfd_handle);
205 206 rw_exit(nvf_lock(dcfd_handle));
206 207 }
207 208 }
208 209
209 210 static void
210 211 devid_nvp_free(nvp_devid_t *dp)
211 212 {
212 213 if (dp->nvp_devpath)
213 214 kmem_free(dp->nvp_devpath, strlen(dp->nvp_devpath)+1);
214 215 if (dp->nvp_devid)
215 216 kmem_free(dp->nvp_devid, ddi_devid_sizeof(dp->nvp_devid));
216 217
217 218 kmem_free(dp, sizeof (nvp_devid_t));
218 219 }
219 220
220 221 static void
221 222 devid_list_free(nvf_handle_t fd)
222 223 {
223 224 list_t *listp;
224 225 nvp_devid_t *np;
225 226
226 227 ASSERT(RW_WRITE_HELD(nvf_lock(dcfd_handle)));
227 228
228 229 listp = nvf_list(fd);
229 230 while (np = list_head(listp)) {
230 231 list_remove(listp, np);
231 232 devid_nvp_free(np);
232 233 }
233 234 }
234 235
235 236 /*
236 237 * Free an nvp element in a list
237 238 */
238 239 static void
239 240 devid_nvp_unlink_and_free(nvf_handle_t fd, nvp_devid_t *np)
240 241 {
241 242 list_remove(nvf_list(fd), np);
242 243 devid_nvp_free(np);
243 244 }
244 245
245 246 /*
246 247 * Unpack a device path/nvlist pair to the list of devid cache elements.
247 248 * Used to parse the nvlist format when reading
248 249 * /etc/devices/devid_cache
249 250 */
250 251 static int
251 252 devid_cache_unpack_nvlist(nvf_handle_t fd, nvlist_t *nvl, char *name)
252 253 {
253 254 nvp_devid_t *np;
254 255 ddi_devid_t devidp;
255 256 int rval;
256 257 uint_t n;
257 258
258 259 NVP_DEVID_DEBUG_PATH((name));
259 260 ASSERT(RW_WRITE_HELD(nvf_lock(dcfd_handle)));
260 261
261 262 /*
262 263 * check path for a devid
263 264 */
264 265 rval = nvlist_lookup_byte_array(nvl,
265 266 DP_DEVID_ID, (uchar_t **)&devidp, &n);
266 267 if (rval == 0) {
267 268 if (ddi_devid_valid(devidp) == DDI_SUCCESS) {
268 269 ASSERT(n == ddi_devid_sizeof(devidp));
269 270 np = kmem_zalloc(sizeof (nvp_devid_t), KM_SLEEP);
270 271 np->nvp_devpath = i_ddi_strdup(name, KM_SLEEP);
271 272 np->nvp_devid = kmem_alloc(n, KM_SLEEP);
272 273 (void) bcopy(devidp, np->nvp_devid, n);
273 274 list_insert_tail(nvf_list(fd), np);
274 275 NVP_DEVID_DEBUG_DEVID((np->nvp_devid));
275 276 } else {
276 277 DEVIDERR((CE_CONT,
277 278 "%s: invalid devid\n", name));
278 279 }
279 280 } else {
280 281 DEVIDERR((CE_CONT,
281 282 "%s: devid not available\n", name));
282 283 }
283 284
284 285 return (0);
285 286 }
286 287
287 288 /*
288 289 * Pack the list of devid cache elements into a single nvlist
289 290 * Used when writing the nvlist file.
290 291 */
291 292 static int
292 293 devid_cache_pack_list(nvf_handle_t fd, nvlist_t **ret_nvl)
293 294 {
294 295 nvlist_t *nvl, *sub_nvl;
295 296 nvp_devid_t *np;
296 297 int rval;
297 298 list_t *listp;
298 299
299 300 ASSERT(RW_WRITE_HELD(nvf_lock(dcfd_handle)));
300 301
301 302 rval = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP);
302 303 if (rval != 0) {
303 304 nvf_error("%s: nvlist alloc error %d\n",
304 305 nvf_cache_name(fd), rval);
305 306 return (DDI_FAILURE);
306 307 }
307 308
308 309 listp = nvf_list(fd);
309 310 for (np = list_head(listp); np; np = list_next(listp, np)) {
310 311 if (np->nvp_devid == NULL)
311 312 continue;
312 313 NVP_DEVID_DEBUG_PATH(np->nvp_devpath);
313 314 rval = nvlist_alloc(&sub_nvl, NV_UNIQUE_NAME, KM_SLEEP);
314 315 if (rval != 0) {
315 316 nvf_error("%s: nvlist alloc error %d\n",
316 317 nvf_cache_name(fd), rval);
317 318 sub_nvl = NULL;
318 319 goto err;
319 320 }
320 321
321 322 rval = nvlist_add_byte_array(sub_nvl, DP_DEVID_ID,
322 323 (uchar_t *)np->nvp_devid,
323 324 ddi_devid_sizeof(np->nvp_devid));
324 325 if (rval == 0) {
325 326 NVP_DEVID_DEBUG_DEVID(np->nvp_devid);
326 327 } else {
327 328 nvf_error(
328 329 "%s: nvlist add error %d (devid)\n",
329 330 nvf_cache_name(fd), rval);
330 331 goto err;
331 332 }
332 333
333 334 rval = nvlist_add_nvlist(nvl, np->nvp_devpath, sub_nvl);
334 335 if (rval != 0) {
335 336 nvf_error("%s: nvlist add error %d (sublist)\n",
336 337 nvf_cache_name(fd), rval);
337 338 goto err;
338 339 }
339 340 nvlist_free(sub_nvl);
340 341 }
341 342
342 343 *ret_nvl = nvl;
343 344 return (DDI_SUCCESS);
344 345
345 346 err:
346 347 nvlist_free(sub_nvl);
347 348 nvlist_free(nvl);
348 349 *ret_nvl = NULL;
349 350 return (DDI_FAILURE);
350 351 }
351 352
352 353 static int
353 354 e_devid_do_discovery(void)
354 355 {
355 356 ASSERT(mutex_owned(&devid_discovery_mutex));
356 357
357 358 if (i_ddi_io_initialized() == 0) {
358 359 if (devid_discovery_boot > 0) {
359 360 devid_discovery_boot--;
360 361 return (1);
361 362 }
362 363 } else {
363 364 if (devid_discovery_postboot_always > 0)
364 365 return (1);
365 366 if (devid_discovery_postboot > 0) {
366 367 devid_discovery_postboot--;
367 368 return (1);
368 369 }
369 370 if (devid_discovery_secs > 0) {
370 371 if ((ddi_get_lbolt() - devid_last_discovery) >
371 372 drv_usectohz(devid_discovery_secs * MICROSEC)) {
372 373 return (1);
373 374 }
374 375 }
375 376 }
376 377
377 378 DEVID_LOG_DISC((CE_CONT, "devid_discovery: no discovery\n"));
378 379 return (0);
379 380 }
380 381
381 382 static void
382 383 e_ddi_devid_hold_by_major(major_t major)
383 384 {
384 385 DEVID_LOG_DISC((CE_CONT,
385 386 "devid_discovery: ddi_hold_installed_driver %d\n", major));
386 387
387 388 if (ddi_hold_installed_driver(major) == NULL)
388 389 return;
389 390
390 391 ddi_rele_driver(major);
391 392 }
392 393
393 394 /* legacy support - see below */
394 395 static char *e_ddi_devid_hold_driver_list[] = { "sd", "ssd" };
395 396
396 397 #define N_DRIVERS_TO_HOLD \
397 398 (sizeof (e_ddi_devid_hold_driver_list) / sizeof (char *))
398 399
399 400 static void
400 401 e_ddi_devid_hold_installed_driver(ddi_devid_t devid)
401 402 {
402 403 impl_devid_t *id = (impl_devid_t *)devid;
403 404 major_t major, hint_major;
404 405 char hint[DEVID_HINT_SIZE + 1];
405 406 struct devnames *dnp;
406 407 char **drvp;
407 408 int i;
408 409
409 410 /* Count non-null bytes */
410 411 for (i = 0; i < DEVID_HINT_SIZE; i++)
411 412 if (id->did_driver[i] == '\0')
412 413 break;
413 414
414 415 /* Make a copy of the driver hint */
415 416 bcopy(id->did_driver, hint, i);
416 417 hint[i] = '\0';
417 418
418 419 /* search for the devid using the hint driver */
419 420 hint_major = ddi_name_to_major(hint);
420 421 if (hint_major != DDI_MAJOR_T_NONE) {
421 422 e_ddi_devid_hold_by_major(hint_major);
422 423 }
423 424
424 425 /*
425 426 * search for the devid with each driver declaring
426 427 * itself as a devid registrant.
427 428 */
428 429 for (major = 0; major < devcnt; major++) {
429 430 if (major == hint_major)
430 431 continue;
431 432 dnp = &devnamesp[major];
432 433 if (dnp->dn_flags & DN_DEVID_REGISTRANT) {
433 434 e_ddi_devid_hold_by_major(major);
434 435 }
435 436 }
436 437
437 438 /*
438 439 * Legacy support: may be removed once an upgrade mechanism
439 440 * for driver conf files is available.
440 441 */
441 442 drvp = e_ddi_devid_hold_driver_list;
442 443 for (i = 0; i < N_DRIVERS_TO_HOLD; i++, drvp++) {
443 444 major = ddi_name_to_major(*drvp);
444 445 if (major != DDI_MAJOR_T_NONE && major != hint_major) {
445 446 e_ddi_devid_hold_by_major(major);
446 447 }
447 448 }
448 449 }
449 450
450 451 /*
451 452 * Return success if discovery was attempted, to indicate
452 453 * that the desired device may now be available.
453 454 */
454 455 int
455 456 e_ddi_devid_discovery(ddi_devid_t devid)
456 457 {
457 458 int flags;
458 459 int rval = DDI_SUCCESS;
459 460
460 461 mutex_enter(&devid_discovery_mutex);
461 462
462 463 if (devid_discovery_busy) {
463 464 DEVID_LOG_DISC((CE_CONT, "devid_discovery: busy\n"));
464 465 while (devid_discovery_busy) {
465 466 cv_wait(&devid_discovery_cv, &devid_discovery_mutex);
466 467 }
467 468 } else if (e_devid_do_discovery()) {
468 469 devid_discovery_busy = 1;
469 470 mutex_exit(&devid_discovery_mutex);
470 471
471 472 if (i_ddi_io_initialized() == 0) {
472 473 e_ddi_devid_hold_installed_driver(devid);
473 474 } else {
474 475 DEVID_LOG_DISC((CE_CONT,
475 476 "devid_discovery: ndi_devi_config\n"));
476 477 flags = NDI_DEVI_PERSIST | NDI_CONFIG | NDI_NO_EVENT;
477 478 if (i_ddi_io_initialized())
478 479 flags |= NDI_DRV_CONF_REPROBE;
479 480 (void) ndi_devi_config(ddi_root_node(), flags);
480 481 }
481 482
482 483 mutex_enter(&devid_discovery_mutex);
483 484 devid_discovery_busy = 0;
484 485 cv_broadcast(&devid_discovery_cv);
485 486 if (devid_discovery_secs > 0)
486 487 devid_last_discovery = ddi_get_lbolt();
487 488 DEVID_LOG_DISC((CE_CONT, "devid_discovery: done\n"));
488 489 } else {
489 490 rval = DDI_FAILURE;
490 491 DEVID_LOG_DISC((CE_CONT, "no devid discovery\n"));
491 492 }
492 493
493 494 mutex_exit(&devid_discovery_mutex);
494 495
495 496 return (rval);
496 497 }
497 498
498 499 /*
499 500 * As part of registering a devid for a device,
500 501 * update the devid cache with this device/devid pair
501 502 * or note that this combination has registered.
502 503 *
503 504 * If a devpath is provided it will be used as the path to register the
504 505 * devid against, otherwise we use ddi_pathname(dip). In both cases
505 506 * we duplicate the path string so that it can be cached/freed indepdently
506 507 * of the original owner.
507 508 */
508 509 static int
509 510 e_devid_cache_register_cmn(dev_info_t *dip, ddi_devid_t devid, char *devpath)
510 511 {
511 512 nvp_devid_t *np;
512 513 nvp_devid_t *new_nvp;
513 514 ddi_devid_t new_devid;
514 515 int new_devid_size;
515 516 char *path, *fullpath;
516 517 ddi_devid_t free_devid = NULL;
517 518 int pathlen;
518 519 list_t *listp;
519 520 int is_dirty = 0;
520 521
521 522
522 523 ASSERT(ddi_devid_valid(devid) == DDI_SUCCESS);
523 524
524 525 if (devpath) {
525 526 pathlen = strlen(devpath) + 1;
526 527 path = kmem_alloc(pathlen, KM_SLEEP);
527 528 bcopy(devpath, path, pathlen);
528 529 } else {
529 530 /*
530 531 * We are willing to accept DS_BOUND nodes if we can form a full
531 532 * ddi_pathname (i.e. the node is part way to becomming
532 533 * DS_INITIALIZED and devi_addr/ddi_get_name_addr are non-NULL).
533 534 */
534 535 if (ddi_get_name_addr(dip) == NULL)
535 536 return (DDI_FAILURE);
536 537
537 538 fullpath = kmem_alloc(MAXPATHLEN, KM_SLEEP);
538 539 (void) ddi_pathname(dip, fullpath);
539 540 pathlen = strlen(fullpath) + 1;
540 541 path = kmem_alloc(pathlen, KM_SLEEP);
541 542 bcopy(fullpath, path, pathlen);
542 543 kmem_free(fullpath, MAXPATHLEN);
543 544 }
544 545
545 546 DEVID_LOG_REG(("register", devid, path));
546 547
547 548 new_nvp = kmem_zalloc(sizeof (nvp_devid_t), KM_SLEEP);
548 549 new_devid_size = ddi_devid_sizeof(devid);
549 550 new_devid = kmem_alloc(new_devid_size, KM_SLEEP);
550 551 (void) bcopy(devid, new_devid, new_devid_size);
551 552
552 553 rw_enter(nvf_lock(dcfd_handle), RW_WRITER);
553 554
554 555 listp = nvf_list(dcfd_handle);
555 556 for (np = list_head(listp); np; np = list_next(listp, np)) {
556 557 if (strcmp(path, np->nvp_devpath) == 0) {
557 558 DEVID_DEBUG2((CE_CONT,
558 559 "register: %s path match\n", path));
559 560 if (np->nvp_devid == NULL) {
560 561 replace: np->nvp_devid = new_devid;
561 562 np->nvp_flags |=
562 563 NVP_DEVID_DIP | NVP_DEVID_REGISTERED;
563 564 np->nvp_dip = dip;
564 565 if (!devid_cache_write_disable) {
565 566 nvf_mark_dirty(dcfd_handle);
566 567 is_dirty = 1;
567 568 }
568 569 rw_exit(nvf_lock(dcfd_handle));
569 570 kmem_free(new_nvp, sizeof (nvp_devid_t));
570 571 kmem_free(path, pathlen);
571 572 goto exit;
572 573 }
573 574 if (ddi_devid_valid(np->nvp_devid) != DDI_SUCCESS) {
574 575 /* replace invalid devid */
575 576 free_devid = np->nvp_devid;
576 577 goto replace;
577 578 }
578 579 /*
579 580 * We're registering an already-cached path
580 581 * Does the device's devid match the cache?
581 582 */
582 583 if (ddi_devid_compare(devid, np->nvp_devid) != 0) {
583 584 DEVID_DEBUG((CE_CONT, "devid register: "
584 585 "devid %s does not match\n", path));
585 586 /*
586 587 * Replace cached devid for this path
587 588 * with newly registered devid. A devid
588 589 * may map to multiple paths but one path
589 590 * should only map to one devid.
590 591 */
591 592 devid_nvp_unlink_and_free(dcfd_handle, np);
592 593 np = NULL;
593 594 break;
594 595 } else {
595 596 DEVID_DEBUG2((CE_CONT,
596 597 "devid register: %s devid match\n", path));
597 598 np->nvp_flags |=
598 599 NVP_DEVID_DIP | NVP_DEVID_REGISTERED;
599 600 np->nvp_dip = dip;
600 601 rw_exit(nvf_lock(dcfd_handle));
601 602 kmem_free(new_nvp, sizeof (nvp_devid_t));
602 603 kmem_free(path, pathlen);
603 604 kmem_free(new_devid, new_devid_size);
604 605 return (DDI_SUCCESS);
605 606 }
606 607 }
607 608 }
608 609
609 610 /*
610 611 * Add newly registered devid to the cache
611 612 */
612 613 ASSERT(np == NULL);
613 614
614 615 new_nvp->nvp_devpath = path;
615 616 new_nvp->nvp_flags = NVP_DEVID_DIP | NVP_DEVID_REGISTERED;
616 617 new_nvp->nvp_dip = dip;
617 618 new_nvp->nvp_devid = new_devid;
618 619
619 620 if (!devid_cache_write_disable) {
620 621 is_dirty = 1;
621 622 nvf_mark_dirty(dcfd_handle);
622 623 }
623 624 list_insert_tail(nvf_list(dcfd_handle), new_nvp);
624 625
625 626 rw_exit(nvf_lock(dcfd_handle));
626 627
627 628 exit:
628 629 if (free_devid)
629 630 kmem_free(free_devid, ddi_devid_sizeof(free_devid));
630 631
631 632 if (is_dirty)
632 633 nvf_wake_daemon();
633 634
634 635 return (DDI_SUCCESS);
635 636 }
636 637
637 638 int
638 639 e_devid_cache_register(dev_info_t *dip, ddi_devid_t devid)
639 640 {
640 641 return (e_devid_cache_register_cmn(dip, devid, NULL));
641 642 }
642 643
643 644 /*
644 645 * Unregister a device's devid; the devinfo may hit on multiple entries
645 646 * arising from both pHCI and vHCI paths.
646 647 * Called as an instance detachs.
647 648 * Invalidate the devid's devinfo reference.
648 649 * Devid-path remains in the cache.
649 650 */
650 651
651 652 void
652 653 e_devid_cache_unregister(dev_info_t *dip)
653 654 {
654 655 nvp_devid_t *np;
655 656 list_t *listp;
656 657
657 658 rw_enter(nvf_lock(dcfd_handle), RW_WRITER);
658 659
659 660 listp = nvf_list(dcfd_handle);
660 661 for (np = list_head(listp); np; np = list_next(listp, np)) {
661 662 if (np->nvp_devid == NULL)
662 663 continue;
663 664 if ((np->nvp_flags & NVP_DEVID_DIP) && np->nvp_dip == dip) {
664 665 DEVID_LOG_UNREG((CE_CONT,
665 666 "unregister: %s\n", np->nvp_devpath));
666 667 np->nvp_flags &= ~NVP_DEVID_DIP;
667 668 np->nvp_dip = NULL;
668 669 }
669 670 }
670 671
671 672 rw_exit(nvf_lock(dcfd_handle));
672 673 }
673 674
674 675 int
675 676 e_devid_cache_pathinfo(mdi_pathinfo_t *pip, ddi_devid_t devid)
676 677 {
677 678 char *path = mdi_pi_pathname(pip);
678 679
679 680 return (e_devid_cache_register_cmn(mdi_pi_get_client(pip), devid,
680 681 path));
681 682 }
682 683
683 684 /*
684 685 * Purge devid cache of stale devids
685 686 */
686 687 void
687 688 devid_cache_cleanup(void)
688 689 {
689 690 nvp_devid_t *np, *next;
690 691 list_t *listp;
691 692 int is_dirty = 0;
692 693
693 694 rw_enter(nvf_lock(dcfd_handle), RW_WRITER);
694 695
695 696 listp = nvf_list(dcfd_handle);
696 697 for (np = list_head(listp); np; np = next) {
697 698 next = list_next(listp, np);
698 699 if (np->nvp_devid == NULL)
699 700 continue;
700 701 if ((np->nvp_flags & NVP_DEVID_REGISTERED) == 0) {
701 702 DEVID_LOG_REMOVE((CE_CONT,
702 703 "cleanup: %s\n", np->nvp_devpath));
703 704 if (!devid_cache_write_disable) {
704 705 nvf_mark_dirty(dcfd_handle);
705 706 is_dirty = 0;
706 707 }
707 708 devid_nvp_unlink_and_free(dcfd_handle, np);
708 709 }
709 710 }
710 711
711 712 rw_exit(nvf_lock(dcfd_handle));
712 713
713 714 if (is_dirty)
714 715 nvf_wake_daemon();
715 716 }
716 717
717 718
718 719 /*
719 720 * Build a list of dev_t's for a device/devid
720 721 *
721 722 * The effect of this function is cumulative, adding dev_t's
722 723 * for the device to the list of all dev_t's for a given
723 724 * devid.
724 725 */
725 726 static void
726 727 e_devid_minor_to_devlist(
727 728 dev_info_t *dip,
|
↓ open down ↓ |
695 lines elided |
↑ open up ↑ |
728 729 char *minor_name,
729 730 int ndevts_alloced,
730 731 int *devtcntp,
731 732 dev_t *devtsp)
732 733 {
733 734 int circ;
734 735 struct ddi_minor_data *dmdp;
735 736 int minor_all = 0;
736 737 int ndevts = *devtcntp;
737 738
738 - ASSERT(i_ddi_devi_attached(dip));
739 + if (!i_ddi_devi_attached(dip)) {
740 + return;
741 + }
739 742
740 743 /* are we looking for a set of minor nodes? */
741 744 if ((minor_name == DEVID_MINOR_NAME_ALL) ||
742 745 (minor_name == DEVID_MINOR_NAME_ALL_CHR) ||
743 746 (minor_name == DEVID_MINOR_NAME_ALL_BLK))
744 747 minor_all = 1;
745 748
746 749 /* Find matching minor names */
747 750 ndi_devi_enter(dip, &circ);
748 751 for (dmdp = DEVI(dip)->devi_minor; dmdp; dmdp = dmdp->next) {
749 752
750 753 /* Skip non-minors, and non matching minor names */
751 754 if ((dmdp->type != DDM_MINOR) || ((minor_all == 0) &&
752 755 strcmp(dmdp->ddm_name, minor_name)))
753 756 continue;
754 757
755 758 /* filter out minor_all mismatches */
756 759 if (minor_all &&
757 760 (((minor_name == DEVID_MINOR_NAME_ALL_CHR) &&
758 761 (dmdp->ddm_spec_type != S_IFCHR)) ||
759 762 ((minor_name == DEVID_MINOR_NAME_ALL_BLK) &&
760 763 (dmdp->ddm_spec_type != S_IFBLK))))
761 764 continue;
762 765
763 766 if (ndevts < ndevts_alloced)
764 767 devtsp[ndevts] = dmdp->ddm_dev;
765 768 ndevts++;
766 769 }
767 770 ndi_devi_exit(dip, circ);
768 771
769 772 *devtcntp = ndevts;
770 773 }
771 774
772 775 /*
773 776 * Search for cached entries matching a devid
774 777 * Return two lists:
775 778 * a list of dev_info nodes, for those devices in the attached state
776 779 * a list of pathnames whose instances registered the given devid
777 780 * If the lists passed in are not sufficient to return the matching
778 781 * references, return the size of lists required.
779 782 * The dev_info nodes are returned with a hold that the caller must release.
780 783 */
781 784 static int
782 785 e_devid_cache_devi_path_lists(ddi_devid_t devid, int retmax,
783 786 int *retndevis, dev_info_t **retdevis, int *retnpaths, char **retpaths)
784 787 {
785 788 nvp_devid_t *np;
786 789 int ndevis, npaths;
787 790 dev_info_t *dip, *pdip;
788 791 int circ;
789 792 int maxdevis = 0;
790 793 int maxpaths = 0;
791 794 list_t *listp;
792 795
793 796 ndevis = 0;
794 797 npaths = 0;
795 798 listp = nvf_list(dcfd_handle);
796 799 for (np = list_head(listp); np; np = list_next(listp, np)) {
797 800 if (np->nvp_devid == NULL)
798 801 continue;
799 802 if (ddi_devid_valid(np->nvp_devid) != DDI_SUCCESS) {
800 803 DEVIDERR((CE_CONT,
801 804 "find: invalid devid %s\n",
802 805 np->nvp_devpath));
803 806 continue;
804 807 }
805 808 if (ddi_devid_compare(devid, np->nvp_devid) == 0) {
806 809 DEVID_DEBUG2((CE_CONT,
807 810 "find: devid match: %s 0x%x\n",
808 811 np->nvp_devpath, np->nvp_flags));
809 812 DEVID_LOG_MATCH(("find", devid, np->nvp_devpath));
810 813 DEVID_LOG_PATHS((CE_CONT, "%s\n", np->nvp_devpath));
811 814
812 815 /*
813 816 * Check if we have a cached devinfo reference for this
814 817 * devid. Place a hold on it to prevent detach
815 818 * Otherwise, use the path instead.
816 819 * Note: returns with a hold on each dev_info
817 820 * node in the list.
818 821 */
819 822 dip = NULL;
820 823 if (np->nvp_flags & NVP_DEVID_DIP) {
821 824 pdip = ddi_get_parent(np->nvp_dip);
822 825 if (ndi_devi_tryenter(pdip, &circ)) {
823 826 dip = np->nvp_dip;
824 827 ndi_hold_devi(dip);
825 828 ndi_devi_exit(pdip, circ);
826 829 ASSERT(!DEVI_IS_ATTACHING(dip));
827 830 ASSERT(!DEVI_IS_DETACHING(dip));
828 831 } else {
829 832 DEVID_LOG_DETACH((CE_CONT,
830 833 "may be detaching: %s\n",
831 834 np->nvp_devpath));
832 835 }
833 836 }
834 837
835 838 if (dip) {
836 839 if (ndevis < retmax) {
837 840 retdevis[ndevis++] = dip;
838 841 } else {
839 842 ndi_rele_devi(dip);
840 843 }
841 844 maxdevis++;
842 845 } else {
843 846 if (npaths < retmax)
844 847 retpaths[npaths++] = np->nvp_devpath;
845 848 maxpaths++;
846 849 }
847 850 }
848 851 }
849 852
850 853 *retndevis = ndevis;
851 854 *retnpaths = npaths;
852 855 return (maxdevis > maxpaths ? maxdevis : maxpaths);
853 856 }
854 857
855 858
856 859 /*
857 860 * Search the devid cache, returning dev_t list for all
858 861 * device paths mapping to the device identified by the
859 862 * given devid.
860 863 *
861 864 * Primary interface used by ddi_lyr_devid_to_devlist()
862 865 */
863 866 int
864 867 e_devid_cache_to_devt_list(ddi_devid_t devid, char *minor_name,
865 868 int *retndevts, dev_t **retdevts)
866 869 {
867 870 char *path, **paths;
868 871 int i, j, n;
869 872 dev_t *devts, *udevts;
870 873 dev_t tdevt;
871 874 int ndevts, undevts, ndevts_alloced;
872 875 dev_info_t *devi, **devis;
873 876 int ndevis, npaths, nalloced;
874 877 ddi_devid_t match_devid;
875 878
876 879 DEVID_LOG_FIND(("find", devid, NULL));
877 880
878 881 ASSERT(ddi_devid_valid(devid) == DDI_SUCCESS);
879 882 if (ddi_devid_valid(devid) != DDI_SUCCESS) {
880 883 DEVID_LOG_ERR(("invalid devid", devid, NULL));
881 884 return (DDI_FAILURE);
882 885 }
883 886
884 887 nalloced = 128;
885 888
886 889 for (;;) {
887 890 paths = kmem_zalloc(nalloced * sizeof (char *), KM_SLEEP);
888 891 devis = kmem_zalloc(nalloced * sizeof (dev_info_t *), KM_SLEEP);
889 892
890 893 rw_enter(nvf_lock(dcfd_handle), RW_READER);
891 894 n = e_devid_cache_devi_path_lists(devid, nalloced,
892 895 &ndevis, devis, &npaths, paths);
893 896 if (n <= nalloced)
894 897 break;
895 898 rw_exit(nvf_lock(dcfd_handle));
896 899 for (i = 0; i < ndevis; i++)
897 900 ndi_rele_devi(devis[i]);
898 901 kmem_free(paths, nalloced * sizeof (char *));
899 902 kmem_free(devis, nalloced * sizeof (dev_info_t *));
900 903 nalloced = n + 128;
901 904 }
902 905
903 906 for (i = 0; i < npaths; i++) {
904 907 path = i_ddi_strdup(paths[i], KM_SLEEP);
905 908 paths[i] = path;
906 909 }
907 910 rw_exit(nvf_lock(dcfd_handle));
908 911
909 912 if (ndevis == 0 && npaths == 0) {
910 913 DEVID_LOG_ERR(("no devid found", devid, NULL));
911 914 kmem_free(paths, nalloced * sizeof (char *));
912 915 kmem_free(devis, nalloced * sizeof (dev_info_t *));
913 916 return (DDI_FAILURE);
914 917 }
915 918
916 919 ndevts_alloced = 128;
917 920 restart:
918 921 ndevts = 0;
919 922 devts = kmem_alloc(ndevts_alloced * sizeof (dev_t), KM_SLEEP);
920 923 for (i = 0; i < ndevis; i++) {
921 924 ASSERT(!DEVI_IS_ATTACHING(devis[i]));
922 925 ASSERT(!DEVI_IS_DETACHING(devis[i]));
923 926 e_devid_minor_to_devlist(devis[i], minor_name,
924 927 ndevts_alloced, &ndevts, devts);
925 928 if (ndevts > ndevts_alloced) {
926 929 kmem_free(devts, ndevts_alloced * sizeof (dev_t));
927 930 ndevts_alloced += 128;
928 931 goto restart;
929 932 }
930 933 }
931 934 for (i = 0; i < npaths; i++) {
932 935 DEVID_LOG_LOOKUP((CE_CONT, "lookup %s\n", paths[i]));
933 936 devi = e_ddi_hold_devi_by_path(paths[i], 0);
934 937 if (devi == NULL) {
935 938 DEVID_LOG_STALE(("stale device reference",
936 939 devid, paths[i]));
937 940 continue;
938 941 }
939 942 /*
940 943 * Verify the newly attached device registered a matching devid
941 944 */
942 945 if (i_ddi_devi_get_devid(DDI_DEV_T_ANY, devi,
943 946 &match_devid) != DDI_SUCCESS) {
944 947 DEVIDERR((CE_CONT,
945 948 "%s: no devid registered on attach\n",
946 949 paths[i]));
947 950 ddi_release_devi(devi);
948 951 continue;
949 952 }
950 953
951 954 if (ddi_devid_compare(devid, match_devid) != 0) {
952 955 DEVID_LOG_STALE(("new devid registered",
953 956 devid, paths[i]));
954 957 ddi_release_devi(devi);
955 958 ddi_devid_free(match_devid);
956 959 continue;
957 960 }
958 961 ddi_devid_free(match_devid);
959 962
960 963 e_devid_minor_to_devlist(devi, minor_name,
961 964 ndevts_alloced, &ndevts, devts);
962 965 ddi_release_devi(devi);
963 966 if (ndevts > ndevts_alloced) {
964 967 kmem_free(devts,
965 968 ndevts_alloced * sizeof (dev_t));
966 969 ndevts_alloced += 128;
967 970 goto restart;
968 971 }
969 972 }
970 973
971 974 /* drop hold from e_devid_cache_devi_path_lists */
972 975 for (i = 0; i < ndevis; i++) {
973 976 ndi_rele_devi(devis[i]);
974 977 }
975 978 for (i = 0; i < npaths; i++) {
976 979 kmem_free(paths[i], strlen(paths[i]) + 1);
977 980 }
978 981 kmem_free(paths, nalloced * sizeof (char *));
979 982 kmem_free(devis, nalloced * sizeof (dev_info_t *));
980 983
981 984 if (ndevts == 0) {
982 985 DEVID_LOG_ERR(("no devid found", devid, NULL));
983 986 kmem_free(devts, ndevts_alloced * sizeof (dev_t));
984 987 return (DDI_FAILURE);
985 988 }
986 989
987 990 /*
988 991 * Build the final list of sorted dev_t's with duplicates collapsed so
989 992 * returned results are consistent. This prevents implementation
990 993 * artifacts from causing unnecessary changes in SVM namespace.
991 994 */
992 995 /* bubble sort */
993 996 for (i = 0; i < (ndevts - 1); i++) {
994 997 for (j = 0; j < ((ndevts - 1) - i); j++) {
995 998 if (devts[j + 1] < devts[j]) {
996 999 tdevt = devts[j];
997 1000 devts[j] = devts[j + 1];
998 1001 devts[j + 1] = tdevt;
999 1002 }
1000 1003 }
1001 1004 }
1002 1005
1003 1006 /* determine number of unique values */
1004 1007 for (undevts = ndevts, i = 1; i < ndevts; i++) {
1005 1008 if (devts[i - 1] == devts[i])
1006 1009 undevts--;
1007 1010 }
1008 1011
1009 1012 /* allocate unique */
1010 1013 udevts = kmem_alloc(undevts * sizeof (dev_t), KM_SLEEP);
1011 1014
1012 1015 /* copy unique */
1013 1016 udevts[0] = devts[0];
1014 1017 for (i = 1, j = 1; i < ndevts; i++) {
1015 1018 if (devts[i - 1] != devts[i])
1016 1019 udevts[j++] = devts[i];
1017 1020 }
1018 1021 ASSERT(j == undevts);
1019 1022
1020 1023 kmem_free(devts, ndevts_alloced * sizeof (dev_t));
1021 1024
1022 1025 *retndevts = undevts;
1023 1026 *retdevts = udevts;
1024 1027
1025 1028 return (DDI_SUCCESS);
1026 1029 }
1027 1030
1028 1031 void
1029 1032 e_devid_cache_free_devt_list(int ndevts, dev_t *devt_list)
1030 1033 {
1031 1034 kmem_free(devt_list, ndevts * sizeof (dev_t *));
1032 1035 }
1033 1036
1034 1037 /*
1035 1038 * If given a full path and NULL ua, search for a cache entry
1036 1039 * whose path matches the full path. On a cache hit duplicate the
1037 1040 * devid of the matched entry into the given devid (caller
1038 1041 * must free); nodenamebuf is not touched for this usage.
1039 1042 *
1040 1043 * Given a path and a non-NULL unit address, search the cache for any entry
1041 1044 * matching "<path>/%@<unit-address>" where '%' is a wildcard meaning
1042 1045 * any node name. The path should not end a '/'. On a cache hit
1043 1046 * duplicate the devid as before (caller must free) and copy into
1044 1047 * the caller-provided nodenamebuf (if not NULL) the nodename of the
1045 1048 * matched entry.
1046 1049 *
1047 1050 * We must not make use of nvp_dip since that may be NULL for cached
1048 1051 * entries that are not present in the current tree.
1049 1052 */
1050 1053 int
1051 1054 e_devid_cache_path_to_devid(char *path, char *ua,
1052 1055 char *nodenamebuf, ddi_devid_t *devidp)
1053 1056 {
1054 1057 size_t pathlen, ualen;
1055 1058 int rv = DDI_FAILURE;
1056 1059 nvp_devid_t *np;
1057 1060 list_t *listp;
1058 1061 char *cand;
1059 1062
1060 1063 if (path == NULL || *path == '\0' || (ua && *ua == '\0') ||
1061 1064 devidp == NULL)
1062 1065 return (DDI_FAILURE);
1063 1066
1064 1067 *devidp = NULL;
1065 1068
1066 1069 if (ua) {
1067 1070 pathlen = strlen(path);
1068 1071 ualen = strlen(ua);
1069 1072 }
1070 1073
1071 1074 rw_enter(nvf_lock(dcfd_handle), RW_READER);
1072 1075
1073 1076 listp = nvf_list(dcfd_handle);
1074 1077 for (np = list_head(listp); np; np = list_next(listp, np)) {
1075 1078 size_t nodelen, candlen, n;
1076 1079 ddi_devid_t devid_dup;
1077 1080 char *uasep, *node;
1078 1081
1079 1082 if (np->nvp_devid == NULL)
1080 1083 continue;
1081 1084
1082 1085 if (ddi_devid_valid(np->nvp_devid) != DDI_SUCCESS) {
1083 1086 DEVIDERR((CE_CONT,
1084 1087 "pathsearch: invalid devid %s\n",
1085 1088 np->nvp_devpath));
1086 1089 continue;
1087 1090 }
1088 1091
1089 1092 cand = np->nvp_devpath; /* candidate path */
1090 1093
1091 1094 /* If a full pathname was provided the compare is easy */
1092 1095 if (ua == NULL) {
1093 1096 if (strcmp(cand, path) == 0)
1094 1097 goto match;
1095 1098 else
1096 1099 continue;
1097 1100 }
1098 1101
1099 1102 /*
1100 1103 * The compare for initial path plus ua and unknown nodename
1101 1104 * is trickier.
1102 1105 *
1103 1106 * Does the initial path component match 'path'?
1104 1107 */
1105 1108 if (strncmp(path, cand, pathlen) != 0)
1106 1109 continue;
1107 1110
1108 1111 candlen = strlen(cand);
1109 1112
1110 1113 /*
1111 1114 * The next character must be a '/' and there must be no
1112 1115 * further '/' thereafter. Begin by checking that the
1113 1116 * candidate is long enough to include at mininum a
1114 1117 * "/<nodename>@<ua>" after the initial portion already
1115 1118 * matched assuming a nodename length of 1.
1116 1119 */
1117 1120 if (candlen < pathlen + 1 + 1 + 1 + ualen ||
1118 1121 cand[pathlen] != '/' ||
1119 1122 strchr(cand + pathlen + 1, '/') != NULL)
1120 1123 continue;
1121 1124
1122 1125 node = cand + pathlen + 1; /* <node>@<ua> string */
1123 1126
1124 1127 /*
1125 1128 * Find the '@' before the unit address. Check for
1126 1129 * unit address match.
1127 1130 */
1128 1131 if ((uasep = strchr(node, '@')) == NULL)
1129 1132 continue;
1130 1133
1131 1134 /*
1132 1135 * Check we still have enough length and that ua matches
1133 1136 */
1134 1137 nodelen = (uintptr_t)uasep - (uintptr_t)node;
1135 1138 if (candlen < pathlen + 1 + nodelen + 1 + ualen ||
1136 1139 strncmp(ua, uasep + 1, ualen) != 0)
1137 1140 continue;
1138 1141 match:
1139 1142 n = ddi_devid_sizeof(np->nvp_devid);
1140 1143 devid_dup = kmem_alloc(n, KM_SLEEP); /* caller must free */
1141 1144 (void) bcopy(np->nvp_devid, devid_dup, n);
1142 1145 *devidp = devid_dup;
1143 1146
1144 1147 if (ua && nodenamebuf) {
1145 1148 (void) strncpy(nodenamebuf, node, nodelen);
1146 1149 nodenamebuf[nodelen] = '\0';
1147 1150 }
1148 1151
1149 1152 rv = DDI_SUCCESS;
1150 1153 break;
1151 1154 }
1152 1155
1153 1156 rw_exit(nvf_lock(dcfd_handle));
1154 1157
1155 1158 return (rv);
1156 1159 }
1157 1160
1158 1161 #ifdef DEBUG
1159 1162 static void
1160 1163 devid_log(char *fmt, ddi_devid_t devid, char *path)
1161 1164 {
1162 1165 char *devidstr = ddi_devid_str_encode(devid, NULL);
1163 1166 if (path) {
1164 1167 cmn_err(CE_CONT, "%s: %s %s\n", fmt, path, devidstr);
1165 1168 } else {
1166 1169 cmn_err(CE_CONT, "%s: %s\n", fmt, devidstr);
1167 1170 }
1168 1171 ddi_devid_str_free(devidstr);
1169 1172 }
1170 1173 #endif /* DEBUG */
|
↓ open down ↓ |
422 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX