Print this page
6659 nvlist_free(NULL) is a no-op
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/fm/topo/modules/common/disk/disk_common.c
+++ new/usr/src/lib/fm/topo/modules/common/disk/disk_common.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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 */
25 25
26 26 /*
27 27 * Functions in this file are shared between the disk and ses enumerators.
28 28 *
29 29 * A topo_list_t of all disks is returned by a successful disk_list_gather()
30 30 * call, and the list is freed by a disk_list_free(). To create a 'disk' topo
31 31 * node below a specific 'bay' parent node either disk_declare_path() or
32 32 * disk_declare_addr() are called. The caller determines which 'disk' is
33 33 * in which 'bay'. A disk's 'label' and 'authority' information come from
34 34 * its parent 'bay' node.
35 35 */
36 36
37 37 #include <ctype.h>
38 38 #include <strings.h>
39 39 #include <libdevinfo.h>
40 40 #include <devid.h>
41 41 #include <sys/libdevid.h>
42 42 #include <pthread.h>
43 43 #include <inttypes.h>
44 44 #include <sys/dkio.h>
45 45 #include <sys/scsi/scsi_types.h>
46 46 #include <fm/topo_mod.h>
47 47 #include <fm/topo_list.h>
48 48 #include <fm/libdiskstatus.h>
49 49 #include <sys/fm/protocol.h>
50 50 #include <sys/scsi/generic/inquiry.h>
51 51 #include "disk.h"
52 52
53 53 /* common callback information for di_walk_node() and di_devlink_walk */
54 54 typedef struct disk_cbdata {
55 55 topo_mod_t *dcb_mod;
56 56 topo_list_t *dcb_list;
57 57
58 58 di_devlink_handle_t dcb_devhdl;
59 59 dev_di_node_t *dcb_dnode; /* for di_devlink_walk only */
60 60 } disk_cbdata_t;
61 61
62 62 /*
63 63 * Given a /devices path for a whole disk, appending this extension gives the
64 64 * path to a raw device that can be opened.
65 65 */
66 66 #if defined(__i386) || defined(__amd64)
67 67 #define PHYS_EXTN ":q,raw"
68 68 #elif defined(__sparc) || defined(__sparcv9)
69 69 #define PHYS_EXTN ":c,raw"
70 70 #else
71 71 #error Unknown architecture
72 72 #endif
73 73
74 74 /*
75 75 * Methods for disks. This is used by the disk-transport module to
76 76 * generate ereports based off SCSI disk status.
77 77 */
78 78 static int disk_status(topo_mod_t *, tnode_t *, topo_version_t,
79 79 nvlist_t *, nvlist_t **);
80 80
81 81 static const topo_method_t disk_methods[] = {
82 82 { TOPO_METH_DISK_STATUS, TOPO_METH_DISK_STATUS_DESC,
83 83 TOPO_METH_DISK_STATUS_VERSION, TOPO_STABILITY_INTERNAL,
84 84 disk_status },
85 85 { NULL }
86 86 };
87 87
88 88 static const topo_pgroup_info_t io_pgroup = {
89 89 TOPO_PGROUP_IO,
90 90 TOPO_STABILITY_PRIVATE,
91 91 TOPO_STABILITY_PRIVATE,
92 92 1
93 93 };
94 94
95 95 static const topo_pgroup_info_t disk_auth_pgroup = {
96 96 FM_FMRI_AUTHORITY,
97 97 TOPO_STABILITY_PRIVATE,
98 98 TOPO_STABILITY_PRIVATE,
99 99 1
100 100 };
101 101
102 102 static const topo_pgroup_info_t storage_pgroup = {
103 103 TOPO_PGROUP_STORAGE,
104 104 TOPO_STABILITY_PRIVATE,
105 105 TOPO_STABILITY_PRIVATE,
106 106 1
107 107 };
108 108
109 109 /*
110 110 * Set the properties of the disk node, from dev_di_node_t data.
111 111 * Properties include:
112 112 * group: protocol properties: resource, asru, label, fru
113 113 * group: authority properties: product-id, chasis-id, server-id
114 114 * group: io properties: devfs-path, devid
115 115 * group: storage properties:
116 116 * - logical-disk, disk-model, disk-manufacturer, serial-number
117 117 * - firmware-revision, capacity-in-bytes
118 118 *
119 119 * NOTE: the io and storage groups won't be present if the dnode passed in is
120 120 * NULL. This happens when a disk is found through ses, but is not enumerated
121 121 * in the devinfo tree.
122 122 */
123 123 static int
124 124 disk_set_props(topo_mod_t *mod, tnode_t *parent,
125 125 tnode_t *dtn, dev_di_node_t *dnode)
126 126 {
127 127 nvlist_t *asru = NULL;
128 128 char *label = NULL;
129 129 nvlist_t *fmri = NULL;
130 130 int err;
131 131
132 132 /* pull the label property down from our parent 'bay' node */
133 133 if (topo_node_label(parent, &label, &err) != 0) {
134 134 topo_mod_dprintf(mod, "disk_set_props: "
135 135 "label error %s\n", topo_strerror(err));
136 136 goto error;
137 137 }
138 138 if (topo_node_label_set(dtn, label, &err) != 0) {
139 139 topo_mod_dprintf(mod, "disk_set_props: "
140 140 "label_set error %s\n", topo_strerror(err));
141 141 goto error;
142 142 }
143 143
144 144 /* get the resource fmri, and use it as the fru */
145 145 if (topo_node_resource(dtn, &fmri, &err) != 0) {
146 146 topo_mod_dprintf(mod, "disk_set_props: "
147 147 "resource error: %s\n", topo_strerror(err));
148 148 goto error;
149 149 }
150 150 if (topo_node_fru_set(dtn, fmri, 0, &err) != 0) {
151 151 topo_mod_dprintf(mod, "disk_set_props: "
152 152 "fru_set error: %s\n", topo_strerror(err));
153 153 goto error;
154 154 }
155 155
156 156 /* create/set the authority group */
157 157 if ((topo_pgroup_create(dtn, &disk_auth_pgroup, &err) != 0) &&
158 158 (err != ETOPO_PROP_DEFD)) {
159 159 topo_mod_dprintf(mod, "disk_set_props: "
160 160 "create disk_auth error %s\n", topo_strerror(err));
161 161 goto error;
162 162 }
163 163
164 164 /* create the storage group */
165 165 if (topo_pgroup_create(dtn, &storage_pgroup, &err) != 0) {
166 166 topo_mod_dprintf(mod, "disk_set_props: "
167 167 "create storage error %s\n", topo_strerror(err));
168 168 goto error;
169 169 }
170 170
171 171 /* no dnode was found for this disk - skip the io and storage groups */
172 172 if (dnode == NULL) {
173 173 err = 0;
174 174 goto out;
175 175 }
176 176
177 177 /* form and set the asru */
178 178 if ((asru = topo_mod_devfmri(mod, FM_DEV_SCHEME_VERSION,
179 179 dnode->ddn_dpath, dnode->ddn_devid)) == NULL) {
180 180 err = ETOPO_FMRI_UNKNOWN;
181 181 topo_mod_dprintf(mod, "disk_set_props: "
182 182 "asru error %s\n", topo_strerror(err));
183 183 goto error;
184 184 }
185 185 if (topo_node_asru_set(dtn, asru, 0, &err) != 0) {
186 186 topo_mod_dprintf(mod, "disk_set_props: "
187 187 "asru_set error %s\n", topo_strerror(err));
188 188 goto error;
189 189 }
190 190
191 191 /* create/set the devfs-path and devid in the io group */
192 192 if (topo_pgroup_create(dtn, &io_pgroup, &err) != 0) {
193 193 topo_mod_dprintf(mod, "disk_set_props: "
194 194 "create io error %s\n", topo_strerror(err));
195 195 goto error;
196 196 }
197 197
198 198 if (topo_prop_set_string(dtn, TOPO_PGROUP_IO, TOPO_IO_DEV_PATH,
199 199 TOPO_PROP_IMMUTABLE, dnode->ddn_dpath, &err) != 0) {
200 200 topo_mod_dprintf(mod, "disk_set_props: "
201 201 "set dev error %s\n", topo_strerror(err));
202 202 goto error;
203 203 }
204 204
205 205 if (dnode->ddn_devid && topo_prop_set_string(dtn, TOPO_PGROUP_IO,
206 206 TOPO_IO_DEVID, TOPO_PROP_IMMUTABLE, dnode->ddn_devid, &err) != 0) {
207 207 topo_mod_dprintf(mod, "disk_set_props: "
208 208 "set devid error %s\n", topo_strerror(err));
209 209 goto error;
210 210 }
211 211
212 212 if (dnode->ddn_ppath_count != 0 &&
213 213 topo_prop_set_string_array(dtn, TOPO_PGROUP_IO, TOPO_IO_PHYS_PATH,
214 214 TOPO_PROP_IMMUTABLE, (const char **)dnode->ddn_ppath,
215 215 dnode->ddn_ppath_count, &err) != 0) {
216 216 topo_mod_dprintf(mod, "disk_set_props: "
217 217 "set phys-path error %s\n", topo_strerror(err));
218 218 goto error;
219 219 }
220 220
221 221 /* set the storage group public /dev name */
222 222 if (dnode->ddn_lpath != NULL &&
223 223 topo_prop_set_string(dtn, TOPO_PGROUP_STORAGE,
224 224 TOPO_STORAGE_LOGICAL_DISK_NAME, TOPO_PROP_IMMUTABLE,
225 225 dnode->ddn_lpath, &err) != 0) {
226 226 topo_mod_dprintf(mod, "disk_set_props: "
227 227 "set disk_name error %s\n", topo_strerror(err));
228 228 goto error;
229 229 }
230 230
231 231 /* populate other misc storage group properties */
232 232 if (dnode->ddn_mfg && (topo_prop_set_string(dtn, TOPO_PGROUP_STORAGE,
233 233 TOPO_STORAGE_MANUFACTURER, TOPO_PROP_IMMUTABLE,
234 234 dnode->ddn_mfg, &err) != 0)) {
235 235 topo_mod_dprintf(mod, "disk_set_props: "
236 236 "set mfg error %s\n", topo_strerror(err));
237 237 goto error;
238 238 }
239 239 if (dnode->ddn_model && (topo_prop_set_string(dtn, TOPO_PGROUP_STORAGE,
240 240 TOPO_STORAGE_MODEL, TOPO_PROP_IMMUTABLE,
241 241 dnode->ddn_model, &err) != 0)) {
242 242 topo_mod_dprintf(mod, "disk_set_props: "
243 243 "set model error %s\n", topo_strerror(err));
244 244 goto error;
245 245 }
246 246 if (dnode->ddn_serial && (topo_prop_set_string(dtn, TOPO_PGROUP_STORAGE,
247 247 TOPO_STORAGE_SERIAL_NUM, TOPO_PROP_IMMUTABLE,
248 248 dnode->ddn_serial, &err) != 0)) {
249 249 topo_mod_dprintf(mod, "disk_set_props: "
250 250 "set serial error %s\n", topo_strerror(err));
251 251 goto error;
252 252 }
253 253 if (dnode->ddn_firm && (topo_prop_set_string(dtn, TOPO_PGROUP_STORAGE,
254 254 TOPO_STORAGE_FIRMWARE_REV, TOPO_PROP_IMMUTABLE,
255 255 dnode->ddn_firm, &err) != 0)) {
256 256 topo_mod_dprintf(mod, "disk_set_props: "
257 257 "set firm error %s\n", topo_strerror(err));
258 258 goto error;
↓ open down ↓ |
258 lines elided |
↑ open up ↑ |
259 259 }
260 260 if (dnode->ddn_cap && (topo_prop_set_string(dtn, TOPO_PGROUP_STORAGE,
261 261 TOPO_STORAGE_CAPACITY, TOPO_PROP_IMMUTABLE,
262 262 dnode->ddn_cap, &err) != 0)) {
263 263 topo_mod_dprintf(mod, "disk_set_props: "
264 264 "set cap error %s\n", topo_strerror(err));
265 265 goto error;
266 266 }
267 267 err = 0;
268 268
269 -out: if (fmri)
270 - nvlist_free(fmri);
269 +out:
270 + nvlist_free(fmri);
271 271 if (label)
272 272 topo_mod_strfree(mod, label);
273 - if (asru)
274 - nvlist_free(asru);
273 + nvlist_free(asru);
275 274 return (err);
276 275
277 276 error: err = topo_mod_seterrno(mod, err);
278 277 goto out;
279 278 }
280 279
281 280 /*
282 281 * Trim leading and trailing whitespace from the string.
283 282 */
284 283 static char *
285 284 disk_trim_whitespace(topo_mod_t *mod, const char *begin)
286 285 {
287 286 const char *end;
288 287 char *buf;
289 288 size_t count;
290 289
291 290 if (begin == NULL)
292 291 return (NULL);
293 292
294 293 end = begin + strlen(begin);
295 294
296 295 while (begin < end && isspace(*begin))
297 296 begin++;
298 297 while (begin < end && isspace(*(end - 1)))
299 298 end--;
300 299
301 300 count = end - begin;
302 301 if ((buf = topo_mod_alloc(mod, count + 1)) == NULL)
303 302 return (NULL);
304 303
305 304 (void) strlcpy(buf, begin, count + 1);
306 305
307 306 return (buf);
308 307 }
309 308
310 309 /*
311 310 * Manufacturing strings can contain characters that are invalid for use in hc
312 311 * authority names. This trims leading and trailing whitespace, and
313 312 * substitutes any characters known to be bad.
314 313 */
315 314 char *
316 315 disk_auth_clean(topo_mod_t *mod, const char *str)
317 316 {
318 317 char *buf, *p;
319 318
320 319 if (str == NULL)
321 320 return (NULL);
322 321
323 322 if ((buf = topo_mod_strdup(mod, str)) == NULL)
324 323 return (NULL);
325 324
326 325 while ((p = strpbrk(buf, " :=")) != NULL)
327 326 *p = '-';
328 327
329 328 return (buf);
330 329 }
331 330
332 331 /* create the disk topo node */
333 332 static int
334 333 disk_tnode_create(topo_mod_t *mod, tnode_t *parent,
335 334 dev_di_node_t *dnode, const char *name, topo_instance_t i, tnode_t **rval)
336 335 {
337 336 int len;
338 337 nvlist_t *fmri;
339 338 tnode_t *dtn;
340 339 char *part = NULL;
341 340 nvlist_t *auth;
342 341 char *mfg, *model, *firm, *serial;
343 342
344 343 *rval = NULL;
345 344 if (dnode != NULL) {
346 345 mfg = disk_auth_clean(mod, dnode->ddn_mfg);
347 346 model = disk_auth_clean(mod, dnode->ddn_model);
348 347 firm = disk_auth_clean(mod, dnode->ddn_firm);
349 348 serial = disk_auth_clean(mod, dnode->ddn_serial);
350 349 } else {
351 350 mfg = model = firm = serial = NULL;
352 351 }
353 352
354 353 /* form 'part=' of fmri as "<mfg>-<model>" */
355 354 if (mfg != NULL && model != NULL) {
356 355 len = strlen(mfg) + 1 + strlen(model) + 1;
357 356 if ((part = topo_mod_alloc(mod, len)) != NULL)
358 357 (void) snprintf(part, len, "%s-%s",
359 358 mfg, model);
360 359 }
361 360
362 361 auth = topo_mod_auth(mod, parent);
363 362 fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, name, i, NULL,
364 363 auth, part ? part : model, firm, serial);
365 364 nvlist_free(auth);
366 365
367 366 topo_mod_strfree(mod, part);
368 367 topo_mod_strfree(mod, mfg);
369 368 topo_mod_strfree(mod, model);
370 369 topo_mod_strfree(mod, firm);
371 370 topo_mod_strfree(mod, serial);
372 371
373 372 if (fmri == NULL) {
374 373 topo_mod_dprintf(mod, "disk_tnode_create: "
375 374 "hcfmri (%s%d/%s%d) error %s\n",
376 375 topo_node_name(parent), topo_node_instance(parent),
377 376 name, i, topo_strerror(topo_mod_errno(mod)));
378 377 return (-1);
379 378 }
380 379
381 380 if ((dtn = topo_node_bind(mod, parent, name, i, fmri)) == NULL) {
382 381 if (topo_mod_errno(mod) == EMOD_NODE_BOUND) {
383 382 /*
384 383 * if disk 0 is already there then we're done
385 384 */
386 385 nvlist_free(fmri);
387 386 return (0);
388 387 }
389 388 topo_mod_dprintf(mod, "disk_tnode_create: "
390 389 "bind (%s%d/%s%d) error %s\n",
391 390 topo_node_name(parent), topo_node_instance(parent),
392 391 name, i, topo_strerror(topo_mod_errno(mod)));
393 392 nvlist_free(fmri);
394 393 return (-1);
395 394 }
396 395 nvlist_free(fmri);
397 396
398 397 /* add the properties of the disk */
399 398 if (disk_set_props(mod, parent, dtn, dnode) != 0) {
400 399 topo_mod_dprintf(mod, "disk_tnode_create: "
401 400 "disk_set_props (%s%d/%s%d) error %s\n",
402 401 topo_node_name(parent), topo_node_instance(parent),
403 402 name, i, topo_strerror(topo_mod_errno(mod)));
404 403 topo_node_unbind(dtn);
405 404 return (-1);
406 405 }
407 406 *rval = dtn;
408 407 return (0);
409 408 }
410 409
411 410 static int
412 411 disk_declare(topo_mod_t *mod, tnode_t *parent, dev_di_node_t *dnode,
413 412 tnode_t **childp)
414 413 {
415 414 tnode_t *dtn = NULL;
416 415 int rval;
417 416
418 417 rval = disk_tnode_create(mod, parent, dnode, DISK, 0, &dtn);
419 418 if (dtn == NULL) {
420 419 if (rval == 0)
421 420 return (0);
422 421 topo_mod_dprintf(mod, "disk_declare: "
423 422 "disk_tnode_create error %s\n",
424 423 topo_strerror(topo_mod_errno(mod)));
425 424 return (-1);
426 425 }
427 426
428 427 /* register disk_methods against the disk topo node */
429 428 if (topo_method_register(mod, dtn, disk_methods) != 0) {
430 429 topo_mod_dprintf(mod, "disk_declare: "
431 430 "topo_method_register error %s\n",
432 431 topo_strerror(topo_mod_errno(mod)));
433 432 topo_node_unbind(dtn);
434 433 return (-1);
435 434 }
436 435 if (childp != NULL)
437 436 *childp = dtn;
438 437 return (0);
439 438 }
440 439
441 440 int
442 441 disk_declare_path(topo_mod_t *mod, tnode_t *parent, topo_list_t *listp,
443 442 const char *path)
444 443 {
445 444 dev_di_node_t *dnode;
446 445 int i;
447 446
448 447 /*
449 448 * Check for match using physical phci (ddn_ppath). Use
450 449 * di_devfs_path_match so generic.vs.non-generic names match.
451 450 */
452 451 for (dnode = topo_list_next(listp); dnode != NULL;
453 452 dnode = topo_list_next(dnode)) {
454 453 if (dnode->ddn_ppath == NULL)
455 454 continue;
456 455
457 456 for (i = 0; i < dnode->ddn_ppath_count; i++) {
458 457 if (di_devfs_path_match(dnode->ddn_ppath[0], path))
459 458 return (disk_declare(mod, parent, dnode, NULL));
460 459 }
461 460 }
462 461
463 462 topo_mod_dprintf(mod, "disk_declare_path: "
464 463 "failed to find disk matching path %s", path);
465 464 return (0);
466 465 }
467 466
468 467 int
469 468 disk_declare_addr(topo_mod_t *mod, tnode_t *parent, topo_list_t *listp,
470 469 const char *addr, tnode_t **childp)
471 470 {
472 471 dev_di_node_t *dnode;
473 472 int i;
474 473
475 474 /* Check for match using addr. */
476 475 for (dnode = topo_list_next(listp); dnode != NULL;
477 476 dnode = topo_list_next(dnode)) {
478 477 if (dnode->ddn_target_port == NULL)
479 478 continue;
480 479
481 480 for (i = 0; i < dnode->ddn_ppath_count; i++) {
482 481 if ((dnode->ddn_target_port[i] != NULL) &&
483 482 (strncmp(dnode->ddn_target_port[i], addr,
484 483 strcspn(dnode->ddn_target_port[i], ":"))) == 0) {
485 484 topo_mod_dprintf(mod, "disk_declare_addr: "
486 485 "found disk matching addr %s", addr);
487 486 return (disk_declare(mod, parent, dnode,
488 487 childp));
489 488 }
490 489 }
491 490 }
492 491
493 492 topo_mod_dprintf(mod, "disk_declare_addr: "
494 493 "failed to find disk matching addr %s", addr);
495 494
496 495 return (1);
497 496 }
498 497
499 498 /*
500 499 * Used to declare a disk that has been discovered through other means (usually
501 500 * ses), that is not enumerated in the devinfo tree.
502 501 */
503 502 int
504 503 disk_declare_non_enumerated(topo_mod_t *mod, tnode_t *parent, tnode_t **childp)
505 504 {
506 505 return (disk_declare(mod, parent, NULL, childp));
507 506 }
508 507
509 508 /* di_devlink callback for dev_di_node_add */
510 509 static int
511 510 disk_devlink_callback(di_devlink_t dl, void *arg)
512 511 {
513 512 disk_cbdata_t *cbp = (disk_cbdata_t *)arg;
514 513 topo_mod_t *mod = cbp->dcb_mod;
515 514 dev_di_node_t *dnode = cbp->dcb_dnode;
516 515 const char *devpath;
517 516 char *ctds, *slice;
518 517
519 518 devpath = di_devlink_path(dl);
520 519 if ((dnode == NULL) || (devpath == NULL))
521 520 return (DI_WALK_TERMINATE);
522 521
523 522 /* trim the slice off the public name */
524 523 if (((ctds = strrchr(devpath, '/')) != NULL) &&
525 524 ((slice = strchr(ctds, 's')) != NULL))
526 525 *slice = '\0';
527 526
528 527 /* Establish the public /dev name (no slice) */
529 528 dnode->ddn_lpath = topo_mod_strdup(mod, ctds ? ctds + 1 : devpath);
530 529
531 530 if (ctds && slice)
532 531 *slice = 's';
533 532 return (DI_WALK_TERMINATE);
534 533 }
535 534
536 535 static void
537 536 dev_di_node_free(topo_mod_t *mod, dev_di_node_t *dnode)
538 537 {
539 538 int i;
540 539
541 540 /* free the stuff we point to */
542 541 if (dnode->ddn_devid)
543 542 topo_mod_strfree(mod, dnode->ddn_devid);
544 543 for (i = 0; i < dnode->ddn_ppath_count; i++) {
545 544 /* topo_mod_strfree does NULL checking. */
546 545 topo_mod_strfree(mod, dnode->ddn_ppath[i]);
547 546 topo_mod_strfree(mod, dnode->ddn_target_port[i]);
548 547 topo_mod_strfree(mod, dnode->ddn_attached_port[i]);
549 548 topo_mod_strfree(mod, dnode->ddn_bridge_port[i]);
550 549 }
551 550 topo_mod_free(mod, dnode->ddn_ppath,
552 551 dnode->ddn_ppath_count * sizeof (char *));
553 552 topo_mod_free(mod, dnode->ddn_target_port,
554 553 dnode->ddn_ppath_count * sizeof (char *));
555 554 topo_mod_free(mod, dnode->ddn_attached_port,
556 555 dnode->ddn_ppath_count * sizeof (char *));
557 556 topo_mod_free(mod, dnode->ddn_bridge_port,
558 557 dnode->ddn_ppath_count * sizeof (char *));
559 558 topo_mod_strfree(mod, dnode->ddn_dpath);
560 559 topo_mod_strfree(mod, dnode->ddn_lpath);
561 560
562 561 topo_mod_strfree(mod, dnode->ddn_mfg);
563 562 topo_mod_strfree(mod, dnode->ddn_model);
564 563 topo_mod_strfree(mod, dnode->ddn_serial);
565 564 topo_mod_strfree(mod, dnode->ddn_firm);
566 565 topo_mod_strfree(mod, dnode->ddn_cap);
567 566
568 567 /* free self */
569 568 topo_mod_free(mod, dnode, sizeof (dev_di_node_t));
570 569 }
571 570
572 571 static int
573 572 dev_di_node_add(di_node_t node, char *devid, disk_cbdata_t *cbp)
574 573 {
575 574 topo_mod_t *mod = cbp->dcb_mod;
576 575 dev_di_node_t *dnode;
577 576 di_path_t pnode;
578 577 char *path;
579 578 int mlen;
580 579 char *minorpath;
581 580 char *extn = ":a";
582 581 char *s;
583 582 int64_t *nblocksp;
584 583 uint64_t nblocks;
585 584 int *dblksizep;
586 585 uint_t dblksize;
587 586 char lentry[MAXPATHLEN];
588 587 int pathcount;
589 588 int *inq_dtype, itype;
590 589 int i;
591 590
592 591 if (devid) {
593 592 /*
594 593 * Check for list duplicate using devid search.
595 594 * Note if there is no devid, then we can end up with duplicates
596 595 * in the list, but this doesn't do any harm.
597 596 */
598 597 for (dnode = topo_list_next(cbp->dcb_list);
599 598 dnode != NULL; dnode = topo_list_next(dnode)) {
600 599 if (dnode->ddn_devid &&
601 600 devid_str_compare(dnode->ddn_devid, devid) == 0) {
602 601 topo_mod_dprintf(mod, "dev_di_node_add: "
603 602 "already there %s\n", devid);
604 603 return (0);
605 604 }
606 605 }
607 606 }
608 607
609 608 if ((dnode = topo_mod_zalloc(mod, sizeof (dev_di_node_t))) == NULL)
610 609 return (-1);
611 610
612 611 if (devid) {
613 612 /* Establish the devid. */
614 613 dnode->ddn_devid = topo_mod_strdup(mod, devid);
615 614 if (dnode->ddn_devid == NULL)
616 615 goto error;
617 616 }
618 617
619 618 /* Establish the devinfo dpath */
620 619 if ((path = di_devfs_path(node)) == NULL) {
621 620 (void) topo_mod_seterrno(mod, errno);
622 621 goto error;
623 622 }
624 623
625 624 dnode->ddn_dpath = topo_mod_strdup(mod, path);
626 625 di_devfs_path_free(path);
627 626 if (dnode->ddn_dpath == NULL)
628 627 goto error;
629 628
630 629 /*
631 630 * Establish the physical ppath and target ports. If the device is
632 631 * non-mpxio then dpath and ppath are the same, and the target port is a
633 632 * property of the device node.
634 633 *
635 634 * If dpath is a client node under scsi_vhci, then iterate over all
636 635 * paths and get their physical paths and target port properrties.
637 636 * di_path_client_next_path call below will
638 637 * return non-NULL, and ppath is set to the physical path to the first
639 638 * pathinfo node.
640 639 *
641 640 * NOTE: It is possible to get a generic.vs.non-generic path
642 641 * for di_devfs_path.vs.di_path_devfs_path like:
643 642 * xml: /pci@7b,0/pci1022,7458@11/pci1000,3060@2/sd@2,0
644 643 * pnode: /pci@7b,0/pci1022,7458@11/pci1000,3060@2/disk@2,0
645 644 * To resolve this issue disk_declare_path() needs to use the
646 645 * special di_devfs_path_match() interface.
647 646 */
648 647 pathcount = 0;
649 648 pnode = NULL;
650 649 while ((pnode = di_path_client_next_path(node, pnode)) != NULL) {
651 650 pathcount++;
652 651 }
653 652
654 653 if (pathcount == 0) {
655 654 if ((dnode->ddn_ppath =
656 655 topo_mod_zalloc(mod, sizeof (char *))) == NULL)
657 656 goto error;
658 657
659 658 dnode->ddn_ppath_count = 1;
660 659 if ((dnode->ddn_ppath[0] = topo_mod_strdup(mod,
661 660 dnode->ddn_dpath)) == NULL)
662 661 goto error;
663 662
664 663 if ((dnode->ddn_target_port = topo_mod_zalloc(mod,
665 664 sizeof (char *))) == NULL)
666 665 goto error;
667 666
668 667 if ((dnode->ddn_attached_port = topo_mod_zalloc(mod,
669 668 sizeof (char *))) == NULL)
670 669 goto error;
671 670
672 671 if ((dnode->ddn_bridge_port = topo_mod_zalloc(mod,
673 672 sizeof (char *))) == NULL)
674 673 goto error;
675 674
676 675 /* There should be only one target port for a devinfo node. */
677 676 if ((di_prop_lookup_strings(DDI_DEV_T_ANY, node,
678 677 SCSI_ADDR_PROP_TARGET_PORT, &s)) == 1) {
679 678 if ((dnode->ddn_target_port[0] =
680 679 topo_mod_strdup(mod,
681 680 scsi_wwnstr_skip_ua_prefix(s))) ==
682 681 NULL)
683 682 goto error;
684 683 }
685 684
686 685 if ((di_prop_lookup_strings(DDI_DEV_T_ANY, node,
687 686 SCSI_ADDR_PROP_ATTACHED_PORT, &s)) == 1) {
688 687 /* There should be one attached port if any. */
689 688 if ((dnode->ddn_attached_port[0] =
690 689 topo_mod_strdup(mod,
691 690 scsi_wwnstr_skip_ua_prefix(s))) ==
692 691 NULL)
693 692 goto error;
694 693 }
695 694
696 695 if ((di_prop_lookup_strings(DDI_DEV_T_ANY, node,
697 696 SCSI_ADDR_PROP_BRIDGE_PORT, &s)) == 1) {
698 697 /* There should be one bridge port if any. */
699 698 if ((dnode->ddn_bridge_port[0] =
700 699 topo_mod_strdup(mod,
701 700 scsi_wwnstr_skip_ua_prefix(s))) ==
702 701 NULL)
703 702 goto error;
704 703 }
705 704
706 705 } else {
707 706 /* processing a scsi_vhci device. */
708 707 if ((dnode->ddn_ppath = topo_mod_zalloc(mod,
709 708 pathcount * sizeof (char *))) == NULL)
710 709 goto error;
711 710
712 711 dnode->ddn_ppath_count = pathcount;
713 712
714 713 if ((dnode->ddn_target_port = topo_mod_zalloc(mod,
715 714 pathcount * sizeof (char *))) == NULL)
716 715 goto error;
717 716
718 717 if ((dnode->ddn_attached_port = topo_mod_zalloc(mod,
719 718 pathcount * sizeof (char *))) == NULL)
720 719 goto error;
721 720
722 721 if ((dnode->ddn_bridge_port = topo_mod_zalloc(mod,
723 722 pathcount * sizeof (char *))) == NULL)
724 723 goto error;
725 724
726 725 pnode = NULL;
727 726 pathcount = 0;
728 727 while ((pnode = di_path_client_next_path(node,
729 728 pnode)) != NULL) {
730 729 if ((path = di_path_devfs_path(pnode)) == NULL) {
731 730 (void) topo_mod_seterrno(mod, errno);
732 731 goto error;
733 732 }
734 733
735 734 dnode->ddn_ppath[pathcount] =
736 735 topo_mod_strdup(mod, path);
737 736 di_devfs_path_free(path);
738 737 if (dnode->ddn_ppath[pathcount] == NULL)
739 738 goto error;
740 739
741 740 if ((di_path_prop_lookup_strings(pnode,
742 741 SCSI_ADDR_PROP_TARGET_PORT, &s)) == 1) {
743 742 if ((dnode->ddn_target_port[pathcount] =
744 743 topo_mod_strdup(mod,
745 744 scsi_wwnstr_skip_ua_prefix(s))) ==
746 745 NULL)
747 746 goto error;
748 747 }
749 748
750 749 if ((di_path_prop_lookup_strings(pnode,
751 750 SCSI_ADDR_PROP_ATTACHED_PORT, &s)) == 1) {
752 751 if ((dnode->ddn_attached_port[pathcount] =
753 752 topo_mod_strdup(mod,
754 753 scsi_wwnstr_skip_ua_prefix(s))) ==
755 754 NULL)
756 755 goto error;
757 756 }
758 757
759 758 if ((di_path_prop_lookup_strings(pnode,
760 759 SCSI_ADDR_PROP_BRIDGE_PORT, &s)) == 1) {
761 760 if ((dnode->ddn_bridge_port[pathcount] =
762 761 topo_mod_strdup(mod,
763 762 scsi_wwnstr_skip_ua_prefix(s))) ==
764 763 NULL)
765 764 goto error;
766 765 }
767 766
768 767 pathcount++;
769 768 }
770 769 }
771 770
772 771 /*
773 772 * Find the public /dev name for a disk by adding a minor name and using
774 773 * di_devlink interface for reverse translation (use devinfo path).
775 774 */
776 775 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "inquiry-device-type",
777 776 &inq_dtype) > 0) {
778 777 dnode->ddn_dtype = *inq_dtype;
779 778 itype = (*inq_dtype) & DTYPE_MASK;
780 779 if (itype == DTYPE_DIRECT) {
781 780 mlen = strlen(dnode->ddn_dpath) + strlen(extn) + 1;
782 781 if ((minorpath = topo_mod_alloc(mod, mlen)) == NULL)
783 782 goto error;
784 783 (void) snprintf(minorpath, mlen, "%s%s",
785 784 dnode->ddn_dpath, extn);
786 785 cbp->dcb_dnode = dnode;
787 786 (void) di_devlink_walk(cbp->dcb_devhdl, "^dsk/",
788 787 minorpath, DI_PRIMARY_LINK, cbp,
789 788 disk_devlink_callback);
790 789 topo_mod_free(mod, minorpath, mlen);
791 790 if (dnode->ddn_lpath == NULL) {
792 791 topo_mod_dprintf(mod, "dev_di_node_add: "
793 792 "failed to determine logical path");
794 793 }
795 794 }
796 795 } else {
797 796 dnode->ddn_dtype = DTYPE_UNKNOWN;
798 797 }
799 798
800 799 /* cache various bits of optional information about the device. */
801 800 if (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
802 801 INQUIRY_VENDOR_ID, &s) > 0) {
803 802 if ((dnode->ddn_mfg = disk_trim_whitespace(mod, s)) == NULL)
804 803 goto error;
805 804 }
806 805 if (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
807 806 INQUIRY_PRODUCT_ID, &s) > 0) {
808 807 if ((dnode->ddn_model = disk_trim_whitespace(mod, s)) == NULL)
809 808 goto error;
810 809 }
811 810 if (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
812 811 INQUIRY_REVISION_ID, &s) > 0) {
813 812 if ((dnode->ddn_firm = disk_trim_whitespace(mod, s)) == NULL)
814 813 goto error;
815 814 }
816 815 if (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
817 816 INQUIRY_SERIAL_NO, &s) > 0) {
818 817 if ((dnode->ddn_serial = disk_trim_whitespace(mod, s)) == NULL)
819 818 goto error;
820 819 }
821 820 if (di_prop_lookup_int64(DDI_DEV_T_ANY, node,
822 821 "device-nblocks", &nblocksp) > 0) {
823 822 nblocks = (uint64_t)*nblocksp;
824 823 /*
825 824 * To save kernel memory, the driver may not define
826 825 * "device-dblksize" when its value is default DEV_BSIZE.
827 826 */
828 827 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node,
829 828 "device-dblksize", &dblksizep) > 0)
830 829 dblksize = (uint_t)*dblksizep;
831 830 else
832 831 dblksize = DEV_BSIZE; /* default value */
833 832 (void) snprintf(lentry, sizeof (lentry),
834 833 "%" PRIu64, nblocks * dblksize);
835 834 if ((dnode->ddn_cap = topo_mod_strdup(mod, lentry)) == NULL)
836 835 goto error;
837 836 }
838 837
839 838 topo_mod_dprintf(mod, "dev_di_node_add: "
840 839 "adding %s\n", devid ? dnode->ddn_devid : "NULL devid");
841 840 topo_mod_dprintf(mod, " "
842 841 " %s\n", dnode->ddn_dpath);
843 842 for (i = 0; i < dnode->ddn_ppath_count; i++) {
844 843 topo_mod_dprintf(mod, " "
845 844 " %s\n", dnode->ddn_ppath[i]);
846 845 }
847 846 topo_list_append(cbp->dcb_list, dnode);
848 847 return (0);
849 848
850 849 error:
851 850 dev_di_node_free(mod, dnode);
852 851 return (-1);
853 852 }
854 853
855 854 /* di_walk_node callback for disk_list_gather */
856 855 static int
857 856 dev_walk_di_nodes(di_node_t node, void *arg)
858 857 {
859 858 char *devidstr = NULL;
860 859 char *s;
861 860 int *val;
862 861
863 862 /*
864 863 * If it's not a scsi_vhci client and doesn't have a target_port
865 864 * property and doesn't have a target property then it's not a storage
866 865 * device and we're not interested.
867 866 */
868 867 if (di_path_client_next_path(node, NULL) == NULL &&
869 868 di_prop_lookup_strings(DDI_DEV_T_ANY, node,
870 869 SCSI_ADDR_PROP_TARGET_PORT, &s) <= 0 &&
871 870 di_prop_lookup_ints(DDI_DEV_T_ANY, node,
872 871 SCSI_ADDR_PROP_TARGET, &val) <= 0) {
873 872 return (DI_WALK_CONTINUE);
874 873 }
875 874 (void) di_prop_lookup_strings(DDI_DEV_T_ANY, node,
876 875 DEVID_PROP_NAME, &devidstr);
877 876
878 877 /* create/find the devid scsi topology node */
879 878 (void) dev_di_node_add(node, devidstr, arg);
880 879
881 880 return (DI_WALK_CONTINUE);
882 881 }
883 882
884 883 int
885 884 dev_list_gather(topo_mod_t *mod, topo_list_t *listp)
886 885 {
887 886 di_node_t devtree;
888 887 di_devlink_handle_t devhdl;
889 888 disk_cbdata_t dcb;
890 889
891 890 if ((devtree = topo_mod_devinfo(mod)) == DI_NODE_NIL) {
892 891 topo_mod_dprintf(mod, "disk_list_gather: "
893 892 "topo_mod_devinfo() failed");
894 893 return (-1);
895 894 }
896 895
897 896 if ((devhdl = di_devlink_init(NULL, 0)) == DI_NODE_NIL) {
898 897 topo_mod_dprintf(mod, "disk_list_gather: "
899 898 "di_devlink_init() failed");
900 899 return (-1);
901 900 }
902 901
903 902 dcb.dcb_mod = mod;
904 903 dcb.dcb_list = listp;
905 904 dcb.dcb_devhdl = devhdl;
906 905
907 906 /* walk the devinfo snapshot looking for disk nodes */
908 907 (void) di_walk_node(devtree, DI_WALK_CLDFIRST, &dcb,
909 908 dev_walk_di_nodes);
910 909
911 910 (void) di_devlink_fini(&devhdl);
912 911
913 912 return (0);
914 913 }
915 914
916 915 void
917 916 dev_list_free(topo_mod_t *mod, topo_list_t *listp)
918 917 {
919 918 dev_di_node_t *dnode;
920 919
921 920 while ((dnode = topo_list_next(listp)) != NULL) {
922 921 /* order of delete/free is important */
923 922 topo_list_delete(listp, dnode);
924 923 dev_di_node_free(mod, dnode);
925 924 }
926 925 }
927 926
928 927 /*
929 928 * Query the current disk status. If successful, the disk status is returned
930 929 * as an nvlist consisting of at least the following members:
931 930 *
932 931 * protocol string Supported protocol (currently "scsi")
933 932 *
934 933 * status nvlist Arbitrary protocol-specific information
935 934 * about the current state of the disk.
936 935 *
937 936 * faults nvlist A list of supported faults. Each
938 937 * element of this list is a boolean value.
939 938 * An element's existence indicates that
940 939 * the drive supports detecting this fault,
941 940 * and the value indicates the current
942 941 * state of the fault.
943 942 *
944 943 * <fault-name> nvlist For each fault named in 'faults', a
945 944 * nvlist describing protocol-specific
946 945 * attributes of the fault.
947 946 *
948 947 * This method relies on the libdiskstatus library to query this information.
949 948 */
950 949 static int
951 950 disk_status(topo_mod_t *mod, tnode_t *nodep, topo_version_t vers,
952 951 nvlist_t *in_nvl, nvlist_t **out_nvl)
953 952 {
954 953 disk_status_t *dsp;
955 954 char *devpath, *fullpath;
956 955 size_t pathlen;
957 956 nvlist_t *status;
958 957 int err;
959 958
960 959 *out_nvl = NULL;
961 960
962 961 if (vers != TOPO_METH_DISK_STATUS_VERSION)
963 962 return (topo_mod_seterrno(mod, EMOD_VER_NEW));
964 963
965 964 /*
966 965 * If the caller specifies the "path" parameter, then this indicates
967 966 * that we should use this instead of deriving it from the topo node
968 967 * itself.
969 968 */
970 969 if (nvlist_lookup_string(in_nvl, "path", &fullpath) == 0) {
971 970 devpath = NULL;
972 971 } else {
973 972 /*
974 973 * Get the /devices path and attempt to open the disk status
975 974 * handle.
976 975 */
977 976 if (topo_prop_get_string(nodep, TOPO_PGROUP_IO,
978 977 TOPO_IO_DEV_PATH, &devpath, &err) != 0)
979 978 return (topo_mod_seterrno(mod, EMOD_METHOD_NOTSUP));
980 979
981 980 /*
982 981 * Note that sizeof(string) includes the terminating NULL byte
983 982 */
984 983 pathlen = strlen(devpath) + sizeof ("/devices") +
985 984 sizeof (PHYS_EXTN) - 1;
986 985
987 986 if ((fullpath = topo_mod_alloc(mod, pathlen)) == NULL)
988 987 return (topo_mod_seterrno(mod, EMOD_NOMEM));
989 988
990 989 (void) snprintf(fullpath, pathlen, "/devices%s%s", devpath,
991 990 PHYS_EXTN);
992 991
993 992 topo_mod_strfree(mod, devpath);
994 993 }
995 994
996 995 if ((dsp = disk_status_open(fullpath, &err)) == NULL) {
997 996 if (devpath)
998 997 topo_mod_free(mod, fullpath, pathlen);
999 998 return (topo_mod_seterrno(mod, err == EDS_NOMEM ?
1000 999 EMOD_NOMEM : EMOD_METHOD_NOTSUP));
1001 1000 }
1002 1001
1003 1002 if (devpath)
1004 1003 topo_mod_free(mod, fullpath, pathlen);
1005 1004
1006 1005 if ((status = disk_status_get(dsp)) == NULL) {
1007 1006 err = (disk_status_errno(dsp) == EDS_NOMEM ?
1008 1007 EMOD_NOMEM : EMOD_METHOD_NOTSUP);
1009 1008 disk_status_close(dsp);
1010 1009 return (topo_mod_seterrno(mod, err));
1011 1010 }
1012 1011
1013 1012 *out_nvl = status;
1014 1013 disk_status_close(dsp);
1015 1014 return (0);
1016 1015 }
↓ open down ↓ |
732 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX