4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright (c) 2011 by Delphix. All rights reserved.
28 #include <libdevinfo.h>
33 #include <sys/sunddi.h>
34 #include <sys/types.h>
35 #include <sys/mkdev.h>
40 #include <sys/fs/zfs.h>
42 #include "libdiskmgt.h"
43 #include "disks_private.h"
45 #define CLUSTER_DEV "did"
47 /* specify which disk links to use in the /dev directory */
48 #define DEVLINK_REGEX "rdsk/.*"
49 #define DEVLINK_FLOPPY_REGEX "rdiskette[0-9]"
50 #define DEVLINK_DID_REGEX "did/rdsk/.*"
52 #define FLOPPY_NAME "rdiskette"
54 #define MAXPROPLEN 1024
55 #define DEVICE_ID_PROP "devid"
56 #define PROD_ID_PROP "inquiry-product-id"
57 #define PROD_ID_USB_PROP "usb-product-name"
58 #define REMOVABLE_PROP "removable-media"
59 #define HOTPLUGGABLE_PROP "hotpluggable"
60 #define SCSI_OPTIONS_PROP "scsi-options"
61 #define VENDOR_ID_PROP "inquiry-vendor-id"
62 #define VENDOR_ID_USB_PROP "usb-vendor-name"
63 #define WWN_PROP "node-wwn"
65 static char *ctrltypes
[] = {
67 DDI_NT_SCSI_ATTACHMENT_POINT
,
68 DDI_NT_FC_ATTACHMENT_POINT
,
72 static char *bustypes
[] = {
79 static bus_t
*add_bus(struct search_args
*args
, di_node_t node
,
80 di_minor_t minor
, controller_t
*cp
);
81 static int add_cluster_devs(di_node_t node
, di_minor_t minor
,
83 static controller_t
*add_controller(struct search_args
*args
,
84 di_node_t node
, di_minor_t minor
);
85 static int add_devpath(di_devlink_t devlink
, void *arg
);
86 static int add_devs(di_node_t node
, di_minor_t minor
, void *arg
);
87 static int add_disk2controller(disk_t
*diskp
,
88 struct search_args
*args
);
89 static int add_disk2path(disk_t
*dp
, path_t
*pp
,
90 di_path_state_t st
, char *wwn
);
91 static int add_int2array(int p
, int **parray
);
92 static int add_ptr2array(void *p
, void ***parray
);
93 static char *bus_type(di_node_t node
, di_minor_t minor
,
95 static void remove_controller(controller_t
*cp
,
97 static void clean_paths(struct search_args
*args
);
98 static disk_t
*create_disk(char *deviceid
, char *kernel_name
,
99 struct search_args
*args
);
100 static char *ctype(di_node_t node
, di_minor_t minor
);
101 static boolean_t
disk_is_cdrom(const char *type
);
102 static alias_t
*find_alias(disk_t
*diskp
, char *kernel_name
);
103 static bus_t
*find_bus(struct search_args
*args
, char *name
);
104 static controller_t
*find_controller(struct search_args
*args
, char *name
);
105 static int fix_cluster_devpath(di_devlink_t devlink
, void *arg
);
106 static disk_t
*get_disk_by_deviceid(disk_t
*listp
, char *devid
);
107 static void get_disk_name_from_path(char *path
, char *name
,
109 static char *get_byte_prop(char *prop_name
, di_node_t node
);
110 static di_node_t
get_parent_bus(di_node_t node
,
111 struct search_args
*args
);
112 static int get_prom_int(char *prop_name
, di_node_t node
,
113 di_prom_handle_t ph
);
114 static char *get_prom_str(char *prop_name
, di_node_t node
,
115 di_prom_handle_t ph
);
116 static int get_prop(char *prop_name
, di_node_t node
);
117 static char *get_str_prop(char *prop_name
, di_node_t node
);
118 static int have_disk(struct search_args
*args
, char *devid
,
119 char *kernel_name
, disk_t
**diskp
);
120 static int is_cluster_disk(di_node_t node
, di_minor_t minor
);
121 static int is_ctds(char *name
);
122 static int is_drive(di_minor_t minor
);
123 static int is_zvol(di_node_t node
, di_minor_t minor
);
124 static int is_HBA(di_node_t node
, di_minor_t minor
);
125 static int new_alias(disk_t
*diskp
, char *kernel_path
,
126 char *devlink_path
, struct search_args
*args
);
127 static int new_devpath(alias_t
*ap
, char *devpath
);
128 static path_t
*new_path(controller_t
*cp
, disk_t
*diskp
,
129 di_node_t node
, di_path_state_t st
, char *wwn
);
130 static void remove_invalid_controller(char *name
,
131 controller_t
*currp
, struct search_args
*args
);
132 static char *str_case_index(register char *s1
, register char *s2
);
135 * The functions in this file do a dev tree walk to build up a model of the
136 * disks, controllers and paths on the system. This model is returned in the
137 * args->disk_listp and args->controller_listp members of the args param.
138 * There is no global data for this file so it is thread safe. It is up to
139 * the caller to merge the resulting model with any existing model that is
140 * cached. The caller must also free the memory for this model when it is
144 findevs(struct search_args
*args
)
149 args
->dev_walk_status
= 0;
150 args
->disk_listp
= NULL
;
151 args
->controller_listp
= NULL
;
152 args
->bus_listp
= NULL
;
154 args
->handle
= di_devlink_init(NULL
, 0);
157 * Have to make several passes at this with the new devfs caching.
158 * First, we find non-mpxio devices. Then we find mpxio/multipath
159 * devices. Finally, we get cluster devices.
162 di_root
= di_init("/", flags
);
163 args
->ph
= di_prom_init();
164 (void) di_walk_minor(di_root
, NULL
, 0, args
, add_devs
);
167 flags
= DINFOCPYALL
| DINFOPATH
;
168 di_root
= di_init("/", flags
);
169 (void) di_walk_minor(di_root
, NULL
, 0, args
, add_devs
);
172 /* do another pass to clean up cluster devpaths */
174 di_root
= di_init("/", flags
);
175 (void) di_walk_minor(di_root
, DDI_PSEUDO
, 0, args
, add_cluster_devs
);
176 if (args
->ph
!= DI_PROM_HANDLE_NIL
) {
177 (void) di_prom_fini(args
->ph
);
181 (void) di_devlink_fini(&(args
->handle
));
187 * Definitions of private functions
191 add_bus(struct search_args
*args
, di_node_t node
, di_minor_t minor
,
197 char kstat_name
[MAXPATHLEN
];
200 if (node
== DI_NODE_NIL
) {
204 if ((btype
= bus_type(node
, minor
, args
->ph
)) == NULL
) {
205 return (add_bus(args
, di_parent_node(node
),
206 di_minor_next(di_parent_node(node
), NULL
), cp
));
209 devpath
= di_devfs_path(node
);
211 if ((bp
= find_bus(args
, devpath
)) != NULL
) {
212 di_devfs_path_free((void *) devpath
);
215 if (add_ptr2array(cp
,
216 (void ***)&bp
->controllers
) != 0) {
217 args
->dev_walk_status
= ENOMEM
;
224 /* Special handling for root node. */
225 if (strcmp(devpath
, "/") == 0) {
226 di_devfs_path_free((void *) devpath
);
231 (void) fprintf(stderr
, "INFO: add_bus %s\n", devpath
);
234 bp
= (bus_t
*)calloc(1, sizeof (bus_t
));
239 bp
->name
= strdup(devpath
);
240 di_devfs_path_free((void *) devpath
);
241 if (bp
->name
== NULL
) {
242 args
->dev_walk_status
= ENOMEM
;
247 bp
->btype
= strdup(btype
);
248 if (bp
->btype
== NULL
) {
249 args
->dev_walk_status
= ENOMEM
;
254 (void) snprintf(kstat_name
, sizeof (kstat_name
), "%s%d",
255 di_node_name(node
), di_instance(node
));
257 if ((bp
->kstat_name
= strdup(kstat_name
)) == NULL
) {
258 args
->dev_walk_status
= ENOMEM
;
263 /* if parent node is a bus, get its name */
264 if ((pnode
= get_parent_bus(node
, args
)) != NULL
) {
265 devpath
= di_devfs_path(pnode
);
266 bp
->pname
= strdup(devpath
);
267 di_devfs_path_free((void *) devpath
);
268 if (bp
->pname
== NULL
) {
269 args
->dev_walk_status
= ENOMEM
;
278 bp
->freq
= get_prom_int("clock-frequency", node
, args
->ph
);
280 bp
->controllers
= (controller_t
**)calloc(1, sizeof (controller_t
*));
281 if (bp
->controllers
== NULL
) {
282 args
->dev_walk_status
= ENOMEM
;
286 bp
->controllers
[0] = NULL
;
289 if (add_ptr2array(cp
, (void ***)&bp
->controllers
) != 0) {
290 args
->dev_walk_status
= ENOMEM
;
295 bp
->next
= args
->bus_listp
;
296 args
->bus_listp
= bp
;
302 add_cluster_devs(di_node_t node
, di_minor_t minor
, void *arg
)
304 struct search_args
*args
;
306 char slice_path
[MAXPATHLEN
];
307 int result
= DI_WALK_CONTINUE
;
309 if (!is_cluster_disk(node
, minor
)) {
310 return (DI_WALK_CONTINUE
);
313 args
= (struct search_args
*)arg
;
316 /* This is all just debugging code */
318 char dev_name
[MAXPATHLEN
];
320 devpath
= di_devfs_path(node
);
321 (void) snprintf(dev_name
, sizeof (dev_name
), "%s:%s", devpath
,
322 di_minor_name(minor
));
323 di_devfs_path_free((void *) devpath
);
325 (void) fprintf(stderr
, "INFO: cluster dev: %s\n", dev_name
);
330 args
->dev_walk_status
= 0;
333 * Fix the devpaths for the cluster drive.
335 * We will come through here once for each raw slice device name.
337 devpath
= di_devfs_path(node
);
338 (void) snprintf(slice_path
, sizeof (slice_path
), "%s:%s", devpath
,
339 di_minor_name(minor
));
340 di_devfs_path_free((void *) devpath
);
342 /* Walk the /dev tree to get the cluster devlinks. */
343 (void) di_devlink_walk(args
->handle
, DEVLINK_DID_REGEX
, slice_path
,
344 DI_PRIMARY_LINK
, arg
, fix_cluster_devpath
);
346 if (args
->dev_walk_status
!= 0) {
347 result
= DI_WALK_TERMINATE
;
353 static controller_t
*
354 add_controller(struct search_args
*args
, di_node_t node
, di_minor_t minor
)
358 char kstat_name
[MAXPATHLEN
];
359 char *c_type
= DM_CTYPE_UNKNOWN
;
361 devpath
= di_devfs_path(node
);
363 if ((cp
= find_controller(args
, devpath
)) != NULL
) {
364 di_devfs_path_free((void *) devpath
);
368 /* Special handling for fp attachment node. */
369 if (strcmp(di_node_name(node
), "fp") == 0) {
372 pnode
= di_parent_node(node
);
373 if (pnode
!= DI_NODE_NIL
) {
374 di_devfs_path_free((void *) devpath
);
375 devpath
= di_devfs_path(pnode
);
377 if ((cp
= find_controller(args
, devpath
)) != NULL
) {
378 di_devfs_path_free((void *) devpath
);
382 /* not in the list, create it */
384 c_type
= DM_CTYPE_FIBRE
;
389 (void) fprintf(stderr
, "INFO: add_controller %s\n", devpath
);
392 cp
= (controller_t
*)calloc(1, sizeof (controller_t
));
397 cp
->name
= strdup(devpath
);
398 di_devfs_path_free((void *) devpath
);
399 if (cp
->name
== NULL
) {
400 cache_free_controller(cp
);
404 if (strcmp(c_type
, DM_CTYPE_UNKNOWN
) == 0) {
405 c_type
= ctype(node
, minor
);
409 (void) snprintf(kstat_name
, sizeof (kstat_name
), "%s%d",
410 di_node_name(node
), di_instance(node
));
412 if ((cp
->kstat_name
= strdup(kstat_name
)) == NULL
) {
413 cache_free_controller(cp
);
417 if (libdiskmgt_str_eq(cp
->ctype
, "scsi")) {
418 cp
->scsi_options
= get_prop(SCSI_OPTIONS_PROP
, node
);
421 if (libdiskmgt_str_eq(di_node_name(node
), "scsi_vhci")) {
427 cp
->freq
= get_prom_int("clock-frequency", node
, args
->ph
);
429 cp
->disks
= (disk_t
**)calloc(1, sizeof (disk_t
*));
430 if (cp
->disks
== NULL
) {
431 cache_free_controller(cp
);
436 cp
->next
= args
->controller_listp
;
437 args
->controller_listp
= cp
;
439 cp
->bus
= add_bus(args
, di_parent_node(node
),
440 di_minor_next(di_parent_node(node
), NULL
), cp
);
446 add_devpath(di_devlink_t devlink
, void *arg
)
448 struct search_args
*args
;
451 char kernel_name
[MAXPATHLEN
];
453 args
= (struct search_args
*)arg
;
456 * Get the diskp value from calling have_disk. Can either be found
457 * by kernel name or devid.
461 devidstr
= get_str_prop(DEVICE_ID_PROP
, args
->node
);
462 (void) snprintf(kernel_name
, sizeof (kernel_name
), "%s%d",
463 di_node_name(args
->node
), di_instance(args
->node
));
465 (void) have_disk(args
, devidstr
, kernel_name
, &diskp
);
468 * The devlink_path is usually of the form /dev/rdsk/c0t0d0s0.
469 * For diskettes it is /dev/rdiskette*.
470 * On Intel we would also get each fdisk partition as well
471 * (e.g. /dev/rdsk/c0t0d0p0).
477 if (diskp
->drv_type
!= DM_DT_FLOPPY
) {
479 * Add other controllers for multipath disks.
480 * This will have no effect if the controller
481 * relationship is already set up.
483 if (add_disk2controller(diskp
, args
) != 0) {
484 args
->dev_walk_status
= ENOMEM
;
488 (void) snprintf(kernel_name
, sizeof (kernel_name
), "%s%d",
489 di_node_name(args
->node
), di_instance(args
->node
));
490 devlink_path
= (char *)di_devlink_path(devlink
);
493 (void) fprintf(stderr
,
494 "INFO: devpath %s\n", devlink_path
);
497 if ((ap
= find_alias(diskp
, kernel_name
)) == NULL
) {
498 if (new_alias(diskp
, kernel_name
, devlink_path
,
500 args
->dev_walk_status
= ENOMEM
;
504 * It is possible that we have already added this
505 * devpath. Do not add it again. new_devpath will
506 * return a 0 if found, and not add the path.
508 if (new_devpath(ap
, devlink_path
) != 0) {
509 args
->dev_walk_status
= ENOMEM
;
514 return (DI_WALK_CONTINUE
);
518 add_devs(di_node_t node
, di_minor_t minor
, void *arg
)
520 struct search_args
*args
;
521 int result
= DI_WALK_CONTINUE
;
523 args
= (struct search_args
*)arg
;
526 /* This is all just debugging code */
528 char dev_name
[MAXPATHLEN
];
530 devpath
= di_devfs_path(node
);
531 (void) snprintf(dev_name
, sizeof (dev_name
), "%s:%s", devpath
,
532 di_minor_name(minor
));
533 di_devfs_path_free((void *) devpath
);
535 (void) fprintf(stderr
,
536 "INFO: dev: %s, node: %s%d, minor: 0x%x, type: %s\n",
537 dev_name
, di_node_name(node
), di_instance(node
),
538 di_minor_spectype(minor
),
539 (di_minor_nodetype(minor
) != NULL
?
540 di_minor_nodetype(minor
) : "NULL"));
543 if (bus_type(node
, minor
, args
->ph
) != NULL
) {
544 if (add_bus(args
, node
, minor
, NULL
) == NULL
) {
545 args
->dev_walk_status
= ENOMEM
;
546 result
= DI_WALK_TERMINATE
;
549 } else if (is_HBA(node
, minor
)) {
550 if (add_controller(args
, node
, minor
) == NULL
) {
551 args
->dev_walk_status
= ENOMEM
;
552 result
= DI_WALK_TERMINATE
;
555 } else if (di_minor_spectype(minor
) == S_IFCHR
&&
556 (is_drive(minor
) || is_zvol(node
, minor
))) {
558 char kernel_name
[MAXPATHLEN
];
561 (void) snprintf(kernel_name
, sizeof (kernel_name
), "%s%d",
562 di_node_name(node
), di_instance(node
));
563 devidstr
= get_str_prop(DEVICE_ID_PROP
, node
);
568 * Check if we already got this disk and
569 * this is another slice.
571 if (!have_disk(args
, devidstr
, kernel_name
, &diskp
)) {
572 args
->dev_walk_status
= 0;
574 * This is a newly found disk, create the
577 diskp
= create_disk(devidstr
, kernel_name
, args
);
579 args
->dev_walk_status
= ENOMEM
;
582 if (diskp
->drv_type
!= DM_DT_FLOPPY
) {
583 /* add the controller relationship */
584 if (args
->dev_walk_status
== 0) {
585 if (add_disk2controller(diskp
,
587 args
->dev_walk_status
= ENOMEM
;
592 if (is_zvol(node
, minor
)) {
593 char zvdsk
[MAXNAMELEN
];
597 if (di_prop_lookup_strings(di_minor_devt(minor
),
598 node
, "name", &str
) == -1)
599 return (DI_WALK_CONTINUE
);
600 (void) snprintf(zvdsk
, MAXNAMELEN
, "/dev/zvol/rdsk/%s",
602 if ((ap
= find_alias(diskp
, kernel_name
)) == NULL
) {
603 if (new_alias(diskp
, kernel_name
,
605 args
->dev_walk_status
= ENOMEM
;
609 * It is possible that we have already added
611 * Do not add it again. new_devpath will
612 * return a 0 if found, and not add the path.
614 if (new_devpath(ap
, zvdsk
) != 0) {
615 args
->dev_walk_status
= ENOMEM
;
620 /* Add the devpaths for the drive. */
621 if (args
->dev_walk_status
== 0) {
623 char slice_path
[MAXPATHLEN
];
627 * We will come through here once for each of
628 * the raw slice device names.
630 devpath
= di_devfs_path(node
);
631 (void) snprintf(slice_path
,
632 sizeof (slice_path
), "%s:%s",
633 devpath
, di_minor_name(minor
));
634 di_devfs_path_free((void *) devpath
);
636 if (libdiskmgt_str_eq(di_minor_nodetype(minor
),
638 pattern
= DEVLINK_FLOPPY_REGEX
;
640 pattern
= DEVLINK_REGEX
;
643 /* Walk the /dev tree to get the devlinks. */
644 (void) di_devlink_walk(args
->handle
, pattern
,
645 slice_path
, DI_PRIMARY_LINK
, arg
, add_devpath
);
648 if (args
->dev_walk_status
!= 0) {
649 result
= DI_WALK_TERMINATE
;
657 add_disk2controller(disk_t
*diskp
, struct search_args
*args
)
667 pnode
= di_parent_node(node
);
668 if (pnode
== DI_NODE_NIL
) {
672 minor
= di_minor_next(pnode
, NULL
);
677 if ((cp
= add_controller(args
, pnode
, minor
)) == NULL
) {
681 /* check if the disk <-> ctrl assoc is already there */
682 for (i
= 0; diskp
->controllers
[i
]; i
++) {
683 if (cp
== diskp
->controllers
[i
]) {
688 /* this is a new controller for this disk */
690 /* add the disk to the controlller */
691 if (add_ptr2array(diskp
, (void ***)&cp
->disks
) != 0) {
695 /* add the controlller to the disk */
696 if (add_ptr2array(cp
, (void ***)&diskp
->controllers
) != 0) {
701 * Set up paths for mpxio controlled drives.
703 if (libdiskmgt_str_eq(di_node_name(pnode
), "scsi_vhci")) {
704 /* note: mpxio di_path stuff is all consolidation private */
705 di_path_t pi
= DI_PATH_NIL
;
708 (pi
= di_path_client_next_path(node
, pi
)) != DI_PATH_NIL
) {
711 char str
[MAXPATHLEN
];
714 di_node_t phci_node
= di_path_phci_node(pi
);
716 /* get the node wwn */
717 cnt
= di_path_prop_lookup_bytes(pi
, WWN_PROP
, &bytes
);
723 for (i
= 0; i
< cnt
; i
++) {
725 * A byte is only 2 hex chars + null.
729 (void) snprintf(bstr
,
730 sizeof (bstr
), "%.2x", bytes
[i
]);
731 (void) strlcat(str
, bstr
, sizeof (str
));
736 if (new_path(cp
, diskp
, phci_node
,
737 di_path_state(pi
), wwn
) == NULL
) {
747 add_disk2path(disk_t
*dp
, path_t
*pp
, di_path_state_t st
, char *wwn
)
749 /* add the disk to the path */
750 if (add_ptr2array(dp
, (void ***)&pp
->disks
) != 0) {
755 /* add the path to the disk */
756 if (add_ptr2array(pp
, (void ***)&dp
->paths
) != 0) {
761 /* add the path state for this disk */
762 if (add_int2array(st
, &pp
->states
) != 0) {
767 /* add the path state for this disk */
771 if ((wp
= strdup(wwn
)) != NULL
) {
772 if (add_ptr2array(wp
, (void ***)(&pp
->wwns
)) != 0) {
783 add_int2array(int p
, int **parray
)
794 for (; pa
[cnt
] != -1; cnt
++)
798 new_array
= (int *)calloc(cnt
+ 2, sizeof (int *));
799 if (new_array
== NULL
) {
803 /* copy the existing array */
804 for (i
= 0; i
< cnt
; i
++) {
805 new_array
[i
] = pa
[i
];
809 new_array
[i
+ 1] = -1;
818 add_ptr2array(void *p
, void ***parray
)
829 for (; pa
[cnt
]; cnt
++)
833 new_array
= (void **)calloc(cnt
+ 2, sizeof (void *));
834 if (new_array
== NULL
) {
838 /* copy the existing array */
839 for (i
= 0; i
< cnt
; i
++) {
840 new_array
[i
] = pa
[i
];
844 new_array
[i
+ 1] = NULL
;
853 * This function checks to see if a controller has other associations
854 * that may be valid. If we are calling this function, we have found that
855 * a controller for an mpxio device is showing up independently of the
856 * mpxio controller, noted as /scsi_vhci. This can happen with some FC
857 * cards that have inbound management devices that show up as well, with
858 * the real controller data associated. We do not want to display these
859 * 'devices' as real devices in libdiskmgt.
862 remove_controller(controller_t
*cp
, controller_t
*currp
)
868 (void) fprintf(stderr
, "ERROR: removing current"
874 if (cp
->disks
!= NULL
&& cp
->disks
[0] != NULL
) {
876 (void) fprintf(stderr
,
877 "INFO: removing inbound management controller"
878 " with disk ptrs.\n");
881 * loop through the disks and remove the reference to the
882 * controller for this disk structure. The disk itself
883 * is still a valid device, the controller being removed
884 * is a 'path' so any disk that has a reference to it
885 * as a controller needs to have this reference removed.
887 for (i
= 0; cp
->disks
[i
]; i
++) {
888 disk_t
*dp
= cp
->disks
[i
];
891 for (j
= 0; dp
->controllers
[j
]; j
++) {
894 if (libdiskmgt_str_eq(dp
->controllers
[j
]->name
,
898 (void) fprintf(stderr
,
899 "INFO: REMOVING disk %s on "
901 dp
->kernel_name
, cp
->name
);
903 for (k
= j
; dp
->controllers
[k
]; k
++) {
905 dp
->controllers
[k
+ 1];
912 * Paths are removed with the call to cache_free_controller()
916 if (cp
->paths
!= NULL
&& cp
->paths
[0] != NULL
) {
918 (void) fprintf(stderr
,
919 "INFO: removing inbound management controller"
920 " with path ptrs. \n");
923 cache_free_controller(cp
);
927 * If we have a controller in the list that is really a path then we need to
928 * take that controller out of the list since nodes that are paths are not
929 * considered to be controllers.
932 clean_paths(struct search_args
*args
)
936 cp
= args
->controller_listp
;
944 for (i
= 0; pp
[i
]; i
++) {
945 remove_invalid_controller(pp
[i
]->name
, cp
,
954 create_disk(char *deviceid
, char *kernel_name
, struct search_args
*args
)
962 (void) fprintf(stderr
, "INFO: create_disk %s\n", kernel_name
);
965 diskp
= calloc(1, sizeof (disk_t
));
970 diskp
->controllers
= (controller_t
**)
971 calloc(1, sizeof (controller_t
*));
972 if (diskp
->controllers
== NULL
) {
973 cache_free_disk(diskp
);
976 diskp
->controllers
[0] = NULL
;
979 if (deviceid
!= NULL
) {
980 if ((diskp
->device_id
= strdup(deviceid
)) == NULL
) {
981 cache_free_disk(diskp
);
984 (void) devid_str_decode(deviceid
, &(diskp
->devid
), NULL
);
987 if (kernel_name
!= NULL
) {
988 diskp
->kernel_name
= strdup(kernel_name
);
989 if (diskp
->kernel_name
== NULL
) {
990 cache_free_disk(diskp
);
996 diskp
->aliases
= NULL
;
1000 type
= di_minor_nodetype(args
->minor
);
1002 prod_id
= get_str_prop(PROD_ID_PROP
, args
->node
);
1003 if (prod_id
!= NULL
) {
1004 if ((diskp
->product_id
= strdup(prod_id
)) == NULL
) {
1005 cache_free_disk(diskp
);
1009 prod_id
= get_str_prop(PROD_ID_USB_PROP
, args
->node
);
1010 if (prod_id
!= NULL
) {
1011 if ((diskp
->product_id
= strdup(prod_id
)) == NULL
) {
1012 cache_free_disk(diskp
);
1018 vendor_id
= get_str_prop(VENDOR_ID_PROP
, args
->node
);
1019 if (vendor_id
!= NULL
) {
1020 if ((diskp
->vendor_id
= strdup(vendor_id
)) == NULL
) {
1021 cache_free_disk(diskp
);
1025 vendor_id
= get_str_prop(VENDOR_ID_PROP
, args
->node
);
1026 if (vendor_id
!= NULL
) {
1027 if ((diskp
->vendor_id
= strdup(vendor_id
)) == NULL
) {
1028 cache_free_disk(diskp
);
1035 * DVD, CD-ROM, CD-RW, MO, etc. are all reported as CD-ROMS.
1036 * We try to use uscsi later to determine the real type.
1037 * The cd_rom flag tells us that the kernel categorized the drive
1038 * as a CD-ROM. We leave the drv_type as UKNOWN for now.
1039 * The combination of the cd_rom flag being set with the drv_type of
1040 * unknown is what triggers the uscsi probe in drive.c.
1042 if (disk_is_cdrom(type
)) {
1043 diskp
->drv_type
= DM_DT_UNKNOWN
;
1045 diskp
->removable
= 1;
1046 } else if (libdiskmgt_str_eq(type
, DDI_NT_FD
)) {
1047 diskp
->drv_type
= DM_DT_FLOPPY
;
1048 diskp
->removable
= 1;
1050 /* not a "CD-ROM" or Floppy */
1051 diskp
->removable
= get_prop(REMOVABLE_PROP
, args
->node
);
1053 if (diskp
->removable
== -1) {
1054 diskp
->removable
= 0;
1055 #if defined(i386) || defined(__amd64)
1057 * x86 does not have removable property.
1058 * Check for common removable drives, zip & jaz,
1059 * and mark those correctly.
1061 if (vendor_id
!= NULL
&& prod_id
!= NULL
) {
1062 if (str_case_index(vendor_id
,
1063 "iomega") != NULL
) {
1064 if (str_case_index(prod_id
,
1066 diskp
->removable
= 1;
1067 } else if (str_case_index(prod_id
,
1069 diskp
->removable
= 1;
1076 if (diskp
->removable
) {
1078 * For removable jaz or zip drives there is no way
1079 * to get the drive type unless media is inserted,so
1080 * we look at the product-id for a hint.
1082 diskp
->drv_type
= DM_DT_UNKNOWN
;
1084 if (prod_id
!= NULL
) {
1085 if (str_case_index(prod_id
, "jaz") != NULL
) {
1086 diskp
->drv_type
= DM_DT_JAZ
;
1087 } else if (str_case_index(prod_id
,
1089 diskp
->drv_type
= DM_DT_ZIP
;
1093 diskp
->drv_type
= DM_DT_FIXED
;
1097 diskp
->next
= args
->disk_listp
;
1098 args
->disk_listp
= diskp
;
1104 ctype(di_node_t node
, di_minor_t minor
)
1109 type
= di_minor_nodetype(minor
);
1110 name
= di_node_name(node
);
1112 /* IDE disks use SCSI nexus as the type, so handle this special case */
1113 if (libdiskmgt_str_eq(name
, "ide")) {
1114 return (DM_CTYPE_ATA
);
1117 if (libdiskmgt_str_eq(di_minor_name(minor
), "scsa2usb")) {
1118 return (DM_CTYPE_USB
);
1121 if (libdiskmgt_str_eq(type
, DDI_NT_SCSI_NEXUS
) ||
1122 libdiskmgt_str_eq(type
, DDI_NT_SCSI_ATTACHMENT_POINT
)) {
1123 return (DM_CTYPE_SCSI
);
1126 if (libdiskmgt_str_eq(type
, DDI_NT_FC_ATTACHMENT_POINT
)) {
1127 return (DM_CTYPE_FIBRE
);
1130 if (libdiskmgt_str_eq(type
, DDI_NT_NEXUS
) &&
1131 libdiskmgt_str_eq(name
, "fp")) {
1132 return (DM_CTYPE_FIBRE
);
1135 if (libdiskmgt_str_eq(type
, DDI_PSEUDO
) &&
1136 libdiskmgt_str_eq(name
, "ide")) {
1137 return (DM_CTYPE_ATA
);
1140 return (DM_CTYPE_UNKNOWN
);
1144 disk_is_cdrom(const char *type
)
1146 return (strncmp(type
, DDI_NT_CD
, strlen(DDI_NT_CD
)) == 0);
1150 find_alias(disk_t
*diskp
, char *kernel_name
)
1154 ap
= diskp
->aliases
;
1155 while (ap
!= NULL
) {
1156 if (libdiskmgt_str_eq(ap
->kstat_name
, kernel_name
)) {
1166 find_bus(struct search_args
*args
, char *name
)
1170 listp
= args
->bus_listp
;
1171 while (listp
!= NULL
) {
1172 if (libdiskmgt_str_eq(listp
->name
, name
)) {
1175 listp
= listp
->next
;
1181 static controller_t
*
1182 find_controller(struct search_args
*args
, char *name
)
1184 controller_t
*listp
;
1186 listp
= args
->controller_listp
;
1187 while (listp
!= NULL
) {
1188 if (libdiskmgt_str_eq(listp
->name
, name
)) {
1191 listp
= listp
->next
;
1198 fix_cluster_devpath(di_devlink_t devlink
, void *arg
)
1201 struct search_args
*args
;
1203 disk_t
*diskp
= NULL
;
1207 * The devlink_path is of the form /dev/did/rdsk/d1s0.
1210 args
= (struct search_args
*)arg
;
1212 /* Find the disk by the deviceid we read from the cluster disk. */
1213 devlink_path
= (char *)di_devlink_path(devlink
);
1214 if (devlink_path
== NULL
) {
1215 return (DI_WALK_CONTINUE
);
1218 if ((fd
= open(devlink_path
, O_RDONLY
|O_NDELAY
)) >= 0) {
1222 (void) fprintf(stderr
, "INFO: cluster devpath %s\n",
1226 if (devid_get(fd
, &devid
) == 0) {
1230 minor
= di_minor_name(args
->minor
);
1233 devid_str_encode(devid
, minor
)) != NULL
) {
1234 diskp
= get_disk_by_deviceid(args
->disk_listp
,
1237 * This really shouldn't happen, since
1238 * we should have found all of the disks
1239 * during our first pass through
1240 * the dev tree, but just in case...
1242 if (diskp
== NULL
) {
1244 (void) fprintf(stderr
,
1245 "INFO: cluster create"
1249 diskp
= create_disk(devidstr
,
1251 if (diskp
== NULL
) {
1252 args
->dev_walk_status
= ENOMEM
;
1255 /* add the controller relationship */
1256 if (args
->dev_walk_status
== 0) {
1257 if (add_disk2controller(diskp
,
1259 args
->dev_walk_status
1264 if (new_alias(diskp
, NULL
,
1265 devlink_path
, args
) != 0) {
1266 args
->dev_walk_status
= ENOMEM
;
1269 devid_str_free(devidstr
);
1277 if (diskp
!= NULL
) {
1279 (void) fprintf(stderr
, "INFO: cluster found"
1282 ap
= diskp
->aliases
;
1287 * NOTE: if ap->next != NULL have cluster
1288 * disks w/ multiple paths.
1296 char alias
[MAXPATHLEN
];
1299 * First time; save the /dev/rdsk devpaths and
1300 * update the alias info with the new alias name.
1302 ap
->orig_paths
= ap
->devpaths
;
1303 ap
->devpaths
= NULL
;
1307 /* get the new cluster alias name */
1308 basep
= strrchr(devlink_path
, '/');
1309 if (basep
== NULL
) {
1310 basep
= devlink_path
;
1314 size
= sizeof (alias
) - 1;
1317 while (*basep
!= 0 && *basep
!= 's' && cnt
< size
) {
1318 *namep
++ = *basep
++;
1323 if ((ap
->alias
= strdup(alias
)) == NULL
) {
1324 args
->dev_walk_status
= ENOMEM
;
1330 if (new_devpath(ap
, devlink_path
) != 0) {
1331 args
->dev_walk_status
= ENOMEM
;
1335 return (DI_WALK_CONTINUE
);
1339 * Check if we have the drive in our list, based upon the device id.
1340 * We got the device id from the dev tree walk. This is encoded
1341 * using devid_str_encode(3DEVID). In order to check the device ids we need
1342 * to use the devid_compare(3DEVID) function, so we need to decode the
1343 * string representation of the device id.
1346 get_disk_by_deviceid(disk_t
*listp
, char *devidstr
)
1350 if (devidstr
== NULL
|| devid_str_decode(devidstr
, &devid
, NULL
) != 0) {
1354 while (listp
!= NULL
) {
1355 if (listp
->devid
!= NULL
&&
1356 devid_compare(listp
->devid
, devid
) == 0) {
1359 listp
= listp
->next
;
1367 * Get the base disk name with no path prefix and no slice (if there is one).
1368 * The name parameter should be big enough to hold the name.
1369 * This handles diskette names ok (/dev/rdiskette0) since there is no slice,
1370 * and converts the raw diskette name.
1371 * But, we don't know how to strip off the slice from third party drive
1372 * names. That just means that their drive name will include a slice on
1376 get_disk_name_from_path(char *path
, char *name
, int size
)
1381 basep
= strrchr(path
, '/');
1382 if (basep
== NULL
) {
1388 size
= size
- 1; /* leave room for terminating 0 */
1390 if (is_ctds(basep
)) {
1391 while (*basep
!= 0 && *basep
!= 's' && cnt
< size
) {
1397 if (strncmp(basep
, FLOPPY_NAME
,
1398 sizeof (FLOPPY_NAME
) - 1) == 0) {
1400 * a floppy, convert rdiskette name to diskette name,
1401 * by skipping over the 'r' for raw diskette
1406 /* not a ctds name, just copy it */
1407 (void) strlcpy(name
, basep
, size
);
1412 get_byte_prop(char *prop_name
, di_node_t node
)
1417 char str
[MAXPATHLEN
];
1419 cnt
= di_prop_lookup_bytes(DDI_DEV_T_ANY
, node
, prop_name
, &bytes
);
1425 for (i
= 0; i
< cnt
; i
++) {
1426 char bstr
[8]; /* a byte is only 2 hex chars + null */
1428 (void) snprintf(bstr
, sizeof (bstr
), "%.2x", bytes
[i
]);
1429 (void) strlcat(str
, bstr
, sizeof (str
));
1431 return (strdup(str
));
1435 get_parent_bus(di_node_t node
, struct search_args
*args
)
1439 pnode
= di_parent_node(node
);
1440 if (pnode
== DI_NODE_NIL
) {
1444 if (bus_type(pnode
, di_minor_next(pnode
, NULL
), args
->ph
) != NULL
) {
1448 return (get_parent_bus(pnode
, args
));
1452 get_prom_int(char *prop_name
, di_node_t node
, di_prom_handle_t ph
)
1456 if (di_prom_prop_lookup_ints(ph
, node
, prop_name
, &n
) == 1) {
1464 get_prom_str(char *prop_name
, di_node_t node
, di_prom_handle_t ph
)
1468 if (di_prom_prop_lookup_strings(ph
, node
, prop_name
, &str
) == 1) {
1476 * Get one of the positive int or boolean properties.
1479 get_prop(char *prop_name
, di_node_t node
)
1484 if ((num
= di_prop_lookup_ints(DDI_DEV_T_ANY
, node
, prop_name
, &ip
))
1489 } else if (num
== 1) {
1498 get_str_prop(char *prop_name
, di_node_t node
)
1502 if (di_prop_lookup_strings(DDI_DEV_T_ANY
, node
, prop_name
, &str
) == 1) {
1510 * Check if we have the drive in our list, based upon the device id, if the
1511 * drive has a device id, or the kernel name, if it doesn't have a device id.
1514 have_disk(struct search_args
*args
, char *devidstr
, char *kernel_name
,
1520 listp
= args
->disk_listp
;
1521 if (devidstr
!= NULL
) {
1522 if ((*diskp
= get_disk_by_deviceid(listp
, devidstr
)) != NULL
) {
1527 /* no devid, try matching the kernel names on the drives */
1528 while (listp
!= NULL
) {
1529 if (libdiskmgt_str_eq(kernel_name
,
1530 listp
->kernel_name
)) {
1534 listp
= listp
->next
;
1541 bus_type(di_node_t node
, di_minor_t minor
, di_prom_handle_t ph
)
1546 type
= get_prom_str("device_type", node
, ph
);
1548 type
= di_node_name(node
);
1551 for (i
= 0; bustypes
[i
]; i
++) {
1552 if (libdiskmgt_str_eq(type
, bustypes
[i
])) {
1557 if (minor
!= NULL
&& strcmp(di_minor_nodetype(minor
),
1558 DDI_NT_USB_ATTACHMENT_POINT
) == 0) {
1566 is_cluster_disk(di_node_t node
, di_minor_t minor
)
1568 if (di_minor_spectype(minor
) == S_IFCHR
&&
1569 libdiskmgt_str_eq(di_minor_nodetype(minor
), DDI_PSEUDO
) &&
1570 libdiskmgt_str_eq(di_node_name(node
), CLUSTER_DEV
)) {
1578 * If the input name is in c[t]ds format then return 1, otherwise return 0.
1590 /* skip controller digits */
1591 while (isdigit(*p
)) {
1595 /* handle optional target */
1598 /* skip over target */
1599 while (isdigit(*p
) || isupper(*p
)) {
1607 while (isdigit(*p
)) {
1615 /* check the slice number */
1616 while (isdigit(*p
)) {
1628 is_drive(di_minor_t minor
)
1630 return (strncmp(di_minor_nodetype(minor
), DDI_NT_BLOCK
,
1631 strlen(DDI_NT_BLOCK
)) == 0);
1635 is_zvol(di_node_t node
, di_minor_t minor
)
1637 if ((strncmp(di_node_name(node
), ZFS_DRIVER
, 3) == 0) &&
1638 minor(di_minor_devt(minor
)))
1644 is_HBA(di_node_t node
, di_minor_t minor
)
1650 type
= di_minor_nodetype(minor
);
1653 while (ctrltypes
[type_index
] != NULL
) {
1654 if (libdiskmgt_str_eq(type
, ctrltypes
[type_index
])) {
1660 name
= di_node_name(node
);
1661 if (libdiskmgt_str_eq(type
, DDI_PSEUDO
) &&
1662 libdiskmgt_str_eq(name
, "ide")) {
1670 new_alias(disk_t
*diskp
, char *kernel_name
, char *devlink_path
,
1671 struct search_args
*args
)
1674 char alias
[MAXPATHLEN
];
1677 aliasp
= malloc(sizeof (alias_t
));
1678 if (aliasp
== NULL
) {
1682 aliasp
->alias
= NULL
;
1683 aliasp
->kstat_name
= NULL
;
1685 aliasp
->devpaths
= NULL
;
1686 aliasp
->orig_paths
= NULL
;
1688 get_disk_name_from_path(devlink_path
, alias
, sizeof (alias
));
1690 aliasp
->alias
= strdup(alias
);
1691 if (aliasp
->alias
== NULL
) {
1692 cache_free_alias(aliasp
);
1696 if (kernel_name
!= NULL
) {
1697 aliasp
->kstat_name
= strdup(kernel_name
);
1698 if (aliasp
->kstat_name
== NULL
) {
1699 cache_free_alias(aliasp
);
1703 aliasp
->kstat_name
= NULL
;
1706 aliasp
->cluster
= 0;
1707 aliasp
->lun
= get_prop(DM_LUN
, args
->node
);
1708 aliasp
->target
= get_prop(DM_TARGET
, args
->node
);
1709 aliasp
->wwn
= get_byte_prop(WWN_PROP
, args
->node
);
1711 pnode
= di_parent_node(args
->node
);
1712 if (pnode
!= DI_NODE_NIL
) {
1713 char prop_name
[MAXPROPLEN
];
1715 (void) snprintf(prop_name
, sizeof (prop_name
),
1716 "target%d-sync-speed", aliasp
->target
);
1717 diskp
->sync_speed
= get_prop(prop_name
, pnode
);
1718 (void) snprintf(prop_name
, sizeof (prop_name
), "target%d-wide",
1720 diskp
->wide
= get_prop(prop_name
, pnode
);
1723 if (new_devpath(aliasp
, devlink_path
) != 0) {
1724 cache_free_alias(aliasp
);
1728 aliasp
->next
= diskp
->aliases
;
1729 diskp
->aliases
= aliasp
;
1735 * Append the new devpath to the end of the devpath list. This is important
1736 * since we may want to use the order of the devpaths to match up the vtoc
1740 new_devpath(alias_t
*ap
, char *devpath
)
1746 * First, search the alias list to be sure that this devpath is
1747 * not already there.
1750 for (alistp
= ap
->devpaths
; alistp
!= NULL
; alistp
= alistp
->next
) {
1751 if (libdiskmgt_str_eq(alistp
->devpath
, devpath
)) {
1757 * Otherwise, not found so add this new devpath to the list.
1760 newdp
= malloc(sizeof (slice_t
));
1761 if (newdp
== NULL
) {
1765 newdp
->devpath
= strdup(devpath
);
1766 if (newdp
->devpath
== NULL
) {
1770 newdp
->slice_num
= -1;
1773 if (ap
->devpaths
== NULL
) {
1774 ap
->devpaths
= newdp
;
1776 /* append the devpath to the end of the list */
1780 while (dp
->next
!= NULL
) {
1791 new_path(controller_t
*cp
, disk_t
*dp
, di_node_t node
, di_path_state_t st
,
1798 /* Special handling for fp attachment node. */
1799 if (strcmp(di_node_name(node
), "fp") == 0) {
1802 pnode
= di_parent_node(node
);
1803 if (pnode
!= DI_NODE_NIL
) {
1808 devpath
= di_devfs_path(node
);
1810 /* check if the path is already there */
1812 if (cp
->paths
!= NULL
) {
1815 for (i
= 0; cp
->paths
[i
]; i
++) {
1816 if (libdiskmgt_str_eq(devpath
, cp
->paths
[i
]->name
)) {
1824 /* the path exists, add this disk to it */
1826 di_devfs_path_free((void *) devpath
);
1827 if (!add_disk2path(dp
, pp
, st
, wwn
)) {
1833 /* create a new path */
1835 pp
= calloc(1, sizeof (path_t
));
1837 di_devfs_path_free((void *) devpath
);
1841 pp
->name
= strdup(devpath
);
1842 di_devfs_path_free((void *) devpath
);
1843 if (pp
->name
== NULL
) {
1844 cache_free_path(pp
);
1848 /* add the disk to the path */
1849 if (!add_disk2path(dp
, pp
, st
, wwn
)) {
1853 /* add the path to the controller */
1854 if (add_ptr2array(pp
, (void ***)&cp
->paths
) != 0) {
1855 cache_free_path(pp
);
1859 /* add the controller to the path */
1860 pp
->controller
= cp
;
1862 minor
= di_minor_next(node
, NULL
);
1863 if (minor
!= NULL
) {
1864 pp
->ctype
= ctype(node
, minor
);
1866 pp
->ctype
= DM_CTYPE_UNKNOWN
;
1873 * We pass in the current controller pointer (currp) so we can double check
1874 * that we aren't corrupting the list by removing the element we are on. This
1875 * should never happen, but it doesn't hurt to double check.
1878 remove_invalid_controller(char *name
, controller_t
*currp
,
1879 struct search_args
*args
)
1883 controller_t
*prevp
;
1885 bp
= args
->bus_listp
;
1886 while (bp
!= NULL
) {
1889 for (i
= 0; bp
->controllers
[i
]; i
++) {
1890 if (libdiskmgt_str_eq(bp
->controllers
[i
]->name
, name
)) {
1893 * remove pointer to invalid controller.
1896 for (j
= i
; bp
->controllers
[j
]; j
++) {
1897 bp
->controllers
[j
] =
1898 bp
->controllers
[j
+ 1];
1905 if (args
->controller_listp
== NULL
) {
1909 cp
= args
->controller_listp
;
1910 if (libdiskmgt_str_eq(cp
->name
, name
)) {
1911 args
->controller_listp
= cp
->next
;
1913 (void) fprintf(stderr
,
1914 "INFO: Removed controller %s from list\n",
1917 remove_controller(cp
, currp
);
1923 while (cp
!= NULL
) {
1924 if (libdiskmgt_str_eq(cp
->name
, name
)) {
1926 (void) fprintf(stderr
,
1927 "INFO: Removed controller %s from list\n",
1930 prevp
->next
= cp
->next
;
1931 remove_controller(cp
, currp
);
1940 * This is the standard strstr code modified for case independence.
1943 str_case_index(register char *s1
, register char *s2
)
1945 uint_t s2len
= strlen(s2
); /* length of the second string */
1947 /* If the length of the second string is 0, return the first arg. */
1952 while (strlen(s1
) >= s2len
) {
1953 if (strncasecmp(s1
, s2
, s2len
) == 0) {