xref: /titanic_52/usr/src/lib/libdiskmgt/common/findevs.c (revision 629270abbcc9bcad8f09aeb9500f67a1933334d1)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <fcntl.h>
29 #include <libdevinfo.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/stat.h>
34 #include <sys/sunddi.h>
35 #include <sys/types.h>
36 #include <ctype.h>
37 #include <libgen.h>
38 #include <unistd.h>
39 #include <devid.h>
40 #include <sys/fs/zfs.h>
41 
42 #include "libdiskmgt.h"
43 #include "disks_private.h"
44 
45 #define	CLUSTER_DEV	"did"
46 
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/.*"
51 
52 #define	FLOPPY_NAME	"rdiskette"
53 
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"
64 
65 /* The list of names of possible disk types used by libdevinfo. */
66 static char *disktypes[] = {
67 	DDI_NT_BLOCK,
68 	DDI_NT_BLOCK_CHAN,
69 	DDI_NT_BLOCK_WWN,
70 	DDI_NT_BLOCK_FABRIC,
71 	DDI_NT_CD_CHAN,
72 	DDI_NT_CD,
73 	DDI_NT_FD,
74 	NULL
75 };
76 
77 /*
78  * Most of the removable media will be lumped under here; CD, DVD, MO, etc.
79  */
80 static char *cdromtypes[] = {
81 	DDI_NT_CD_CHAN,
82 	DDI_NT_CD,
83 	NULL
84 };
85 
86 static char *ctrltypes[] = {
87 	DDI_NT_SCSI_NEXUS,
88 	DDI_NT_SCSI_ATTACHMENT_POINT,
89 	DDI_NT_FC_ATTACHMENT_POINT,
90 	NULL
91 };
92 
93 static char *bustypes[] = {
94 	"sbus",
95 	"pci",
96 	"usb",
97 	NULL
98 };
99 
100 static bus_t		*add_bus(struct search_args *args, di_node_t node,
101 			    di_minor_t minor, controller_t *cp);
102 static int		add_cluster_devs(di_node_t node, di_minor_t minor,
103 			    void *arg);
104 static controller_t	*add_controller(struct search_args *args,
105 			    di_node_t node, di_minor_t minor);
106 static int		add_devpath(di_devlink_t devlink, void *arg);
107 static int		add_devs(di_node_t node, di_minor_t minor, void *arg);
108 static int		add_disk2controller(disk_t *diskp,
109 			    struct search_args *args);
110 static int		add_disk2path(disk_t *dp, path_t *pp,
111 			    di_path_state_t st, char *wwn);
112 static int		add_int2array(int p, int **parray);
113 static int		add_ptr2array(void *p, void ***parray);
114 static char		*bus_type(di_node_t node, di_minor_t minor,
115 			    di_prom_handle_t ph);
116 static int		can_remove_controller(controller_t *cp,
117 			    controller_t *currp);
118 static void		clean_paths(struct search_args *args);
119 static disk_t		*create_disk(char *deviceid, char *kernel_name,
120 			    struct search_args *args);
121 static char		*ctype(di_node_t node, di_minor_t minor);
122 static boolean_t	disk_is_cdrom(char *type);
123 static alias_t		*find_alias(disk_t *diskp, char *kernel_name);
124 static bus_t		*find_bus(struct search_args *args, char *name);
125 static controller_t	*find_controller(struct search_args *args, char *name);
126 static int		fix_cluster_devpath(di_devlink_t devlink, void *arg);
127 static disk_t		*get_disk_by_deviceid(disk_t *listp, char *devid);
128 static void		get_disk_name_from_path(char *path, char *name,
129 			    int size);
130 static char		*get_byte_prop(char *prop_name, di_node_t node);
131 static di_node_t	get_parent_bus(di_node_t node,
132 			    struct search_args *args);
133 static int		get_prom_int(char *prop_name, di_node_t node,
134 			    di_prom_handle_t ph);
135 static char		*get_prom_str(char *prop_name, di_node_t node,
136 			    di_prom_handle_t ph);
137 static int		get_prop(char *prop_name, di_node_t node);
138 static char		*get_str_prop(char *prop_name, di_node_t node);
139 static int		have_disk(struct search_args *args, char *devid,
140 			    char *kernel_name, disk_t **diskp);
141 static int		is_cluster_disk(di_node_t node, di_minor_t minor);
142 static int		is_ctds(char *name);
143 static int		is_drive(di_minor_t minor);
144 static int		is_zvol(di_node_t node, di_minor_t minor);
145 static int		is_HBA(di_node_t node, di_minor_t minor);
146 static int		new_alias(disk_t *diskp, char *kernel_path,
147 			    char *devlink_path, struct search_args *args);
148 static int		new_devpath(alias_t *ap, char *devpath);
149 static path_t		*new_path(controller_t *cp, disk_t *diskp,
150 			    di_node_t node, di_path_state_t st, char *wwn);
151 static void		remove_invalid_controller(char *name,
152 			    controller_t *currp, struct search_args *args);
153 static char		*str_case_index(register char *s1, register char *s2);
154 
155 /*
156  * The functions in this file do a dev tree walk to build up a model of the
157  * disks, controllers and paths on the system.  This model is returned in the
158  * args->disk_listp and args->controller_listp members of the args param.
159  * There is no global data for this file so it is thread safe.  It is up to
160  * the caller to merge the resulting model with any existing model that is
161  * cached.  The caller must also free the memory for this model when it is
162  * no longer needed.
163  */
164 void
165 findevs(struct search_args *args)
166 {
167 	uint_t			flags;
168 	di_node_t		di_root;
169 
170 	args->dev_walk_status = 0;
171 	args->disk_listp = NULL;
172 	args->controller_listp = NULL;
173 	args->bus_listp = NULL;
174 
175 	args->handle = di_devlink_init(NULL, 0);
176 
177 	/*
178 	 * Have to make several passes at this with the new devfs caching.
179 	 * First, we find non-mpxio devices. Then we find mpxio/multipath
180 	 * devices. Finally, we get cluster devices.
181 	 */
182 	flags = DINFOCACHE;
183 	di_root = di_init("/", flags);
184 	args->ph = di_prom_init();
185 	(void) di_walk_minor(di_root, NULL, 0, args, add_devs);
186 	di_fini(di_root);
187 
188 	flags = DINFOCPYALL | DINFOPATH;
189 	di_root = di_init("/", flags);
190 	(void) di_walk_minor(di_root, NULL, 0, args, add_devs);
191 	di_fini(di_root);
192 
193 	/* do another pass to clean up cluster devpaths */
194 	flags = DINFOCACHE;
195 	di_root = di_init("/", flags);
196 	(void) di_walk_minor(di_root, DDI_PSEUDO, 0, args, add_cluster_devs);
197 	if (args->ph != DI_PROM_HANDLE_NIL) {
198 	    (void) di_prom_fini(args->ph);
199 	}
200 	di_fini(di_root);
201 
202 	(void) di_devlink_fini(&(args->handle));
203 
204 	clean_paths(args);
205 }
206 
207 /*
208  * Definitions of private functions
209  */
210 
211 static bus_t *
212 add_bus(struct search_args *args, di_node_t node, di_minor_t minor,
213 	controller_t *cp)
214 {
215 	char		*btype;
216 	char		*devpath;
217 	bus_t		*bp;
218 	char		kstat_name[MAXPATHLEN];
219 	di_node_t	pnode;
220 
221 	if (node == DI_NODE_NIL) {
222 	    return (NULL);
223 	}
224 
225 	if ((btype = bus_type(node, minor, args->ph)) == NULL) {
226 	    return (add_bus(args, di_parent_node(node),
227 		di_minor_next(di_parent_node(node), NULL), cp));
228 	}
229 
230 	devpath = di_devfs_path(node);
231 
232 	if ((bp = find_bus(args, devpath)) != NULL) {
233 	    di_devfs_path_free((void *) devpath);
234 
235 	    if (cp != NULL) {
236 		if (add_ptr2array(cp, (void ***)&bp->controllers) != 0) {
237 		    args->dev_walk_status = ENOMEM;
238 		    return (NULL);
239 		}
240 	    }
241 	    return (bp);
242 	}
243 
244 	/* Special handling for root node. */
245 	if (strcmp(devpath, "/") == 0) {
246 	    di_devfs_path_free((void *) devpath);
247 	    return (NULL);
248 	}
249 
250 	if (dm_debug) {
251 	    (void) fprintf(stderr, "INFO: add_bus %s\n", devpath);
252 	}
253 
254 	bp = (bus_t *)calloc(1, sizeof (bus_t));
255 	if (bp == NULL) {
256 	    return (NULL);
257 	}
258 
259 	bp->name = strdup(devpath);
260 	di_devfs_path_free((void *) devpath);
261 	if (bp->name == NULL) {
262 	    args->dev_walk_status = ENOMEM;
263 	    cache_free_bus(bp);
264 	    return (NULL);
265 	}
266 
267 	bp->btype = strdup(btype);
268 	if (bp->btype == NULL) {
269 	    args->dev_walk_status = ENOMEM;
270 	    cache_free_bus(bp);
271 	    return (NULL);
272 	}
273 
274 	(void) snprintf(kstat_name, sizeof (kstat_name), "%s%d",
275 	    di_node_name(node), di_instance(node));
276 
277 	if ((bp->kstat_name = strdup(kstat_name)) == NULL) {
278 	    args->dev_walk_status = ENOMEM;
279 	    cache_free_bus(bp);
280 	    return (NULL);
281 	}
282 
283 	/* if parent node is a bus, get its name */
284 	if ((pnode = get_parent_bus(node, args)) != NULL) {
285 	    devpath = di_devfs_path(pnode);
286 	    bp->pname = strdup(devpath);
287 	    di_devfs_path_free((void *) devpath);
288 	    if (bp->pname == NULL) {
289 		args->dev_walk_status = ENOMEM;
290 		cache_free_bus(bp);
291 		return (NULL);
292 	    }
293 
294 	} else {
295 	    bp->pname = NULL;
296 	}
297 
298 	bp->freq = get_prom_int("clock-frequency", node, args->ph);
299 
300 	bp->controllers = (controller_t **)calloc(1, sizeof (controller_t *));
301 	if (bp->controllers == NULL) {
302 	    args->dev_walk_status = ENOMEM;
303 	    cache_free_bus(bp);
304 	    return (NULL);
305 	}
306 	bp->controllers[0] = NULL;
307 
308 	if (cp != NULL) {
309 	    if (add_ptr2array(cp, (void ***)&bp->controllers) != 0) {
310 		args->dev_walk_status = ENOMEM;
311 		return (NULL);
312 	    }
313 	}
314 
315 	bp->next = args->bus_listp;
316 	args->bus_listp = bp;
317 
318 	return (bp);
319 }
320 
321 static int
322 add_cluster_devs(di_node_t node, di_minor_t minor, void *arg)
323 {
324 	struct search_args	*args;
325 	char			*devpath;
326 	char			slice_path[MAXPATHLEN];
327 	int			result = DI_WALK_CONTINUE;
328 
329 	if (!is_cluster_disk(node, minor)) {
330 	    return (DI_WALK_CONTINUE);
331 	}
332 
333 	args = (struct search_args *)arg;
334 
335 	if (dm_debug > 1) {
336 	    /* This is all just debugging code */
337 	    char	*devpath;
338 	    char	dev_name[MAXPATHLEN];
339 
340 	    devpath = di_devfs_path(node);
341 	    (void) snprintf(dev_name, sizeof (dev_name), "%s:%s", devpath,
342 		di_minor_name(minor));
343 	    di_devfs_path_free((void *) devpath);
344 
345 	    (void) fprintf(stderr, "INFO: cluster dev: %s\n", dev_name);
346 	}
347 
348 	args->node = node;
349 	args->minor = minor;
350 	args->dev_walk_status = 0;
351 
352 	/*
353 	 * Fix the devpaths for the cluster drive.
354 	 *
355 	 * We will come through here once for each raw slice device name.
356 	 */
357 	devpath = di_devfs_path(node);
358 	(void) snprintf(slice_path, sizeof (slice_path), "%s:%s", devpath,
359 	    di_minor_name(minor));
360 	di_devfs_path_free((void *) devpath);
361 
362 	/* Walk the /dev tree to get the cluster devlinks. */
363 	(void) di_devlink_walk(args->handle, DEVLINK_DID_REGEX, slice_path,
364 	    DI_PRIMARY_LINK, arg, fix_cluster_devpath);
365 
366 	if (args->dev_walk_status != 0) {
367 	    result = DI_WALK_TERMINATE;
368 	}
369 
370 	return (result);
371 }
372 
373 static controller_t *
374 add_controller(struct search_args *args, di_node_t node, di_minor_t minor)
375 {
376 	char		*devpath;
377 	controller_t	*cp;
378 	char		kstat_name[MAXPATHLEN];
379 	char		*c_type = DM_CTYPE_UNKNOWN;
380 
381 	devpath = di_devfs_path(node);
382 
383 	if ((cp = find_controller(args, devpath)) != NULL) {
384 	    di_devfs_path_free((void *) devpath);
385 	    return (cp);
386 	}
387 
388 	/* Special handling for fp attachment node. */
389 	if (strcmp(di_node_name(node), "fp") == 0) {
390 	    di_node_t pnode;
391 
392 	    pnode = di_parent_node(node);
393 	    if (pnode != DI_NODE_NIL) {
394 		di_devfs_path_free((void *) devpath);
395 		devpath = di_devfs_path(pnode);
396 
397 		if ((cp = find_controller(args, devpath)) != NULL) {
398 		    di_devfs_path_free((void *) devpath);
399 		    return (cp);
400 		}
401 
402 		/* not in the list, create it */
403 		node = pnode;
404 		c_type = DM_CTYPE_FIBRE;
405 	    }
406 	}
407 
408 	if (dm_debug) {
409 	    (void) fprintf(stderr, "INFO: add_controller %s\n", devpath);
410 	}
411 
412 	cp = (controller_t *)calloc(1, sizeof (controller_t));
413 	if (cp == NULL) {
414 	    return (NULL);
415 	}
416 
417 	cp->name = strdup(devpath);
418 	di_devfs_path_free((void *) devpath);
419 	if (cp->name == NULL) {
420 	    cache_free_controller(cp);
421 	    return (NULL);
422 	}
423 
424 	if (strcmp(c_type, DM_CTYPE_UNKNOWN) == 0) {
425 	    c_type = ctype(node, minor);
426 	}
427 	cp->ctype = c_type;
428 
429 	(void) snprintf(kstat_name, sizeof (kstat_name), "%s%d",
430 	    di_node_name(node), di_instance(node));
431 
432 	if ((cp->kstat_name = strdup(kstat_name)) == NULL) {
433 	    cache_free_controller(cp);
434 	    return (NULL);
435 	}
436 
437 	if (libdiskmgt_str_eq(cp->ctype, "scsi")) {
438 	    cp->scsi_options = get_prop(SCSI_OPTIONS_PROP, node);
439 	}
440 
441 	if (libdiskmgt_str_eq(di_node_name(node), "scsi_vhci")) {
442 	    cp->multiplex = 1;
443 	} else {
444 	    cp->multiplex = 0;
445 	}
446 
447 	cp->freq = get_prom_int("clock-frequency", node, args->ph);
448 
449 	cp->disks = (disk_t **)calloc(1, sizeof (disk_t *));
450 	if (cp->disks == NULL) {
451 	    cache_free_controller(cp);
452 	    return (NULL);
453 	}
454 	cp->disks[0] = NULL;
455 
456 	cp->next = args->controller_listp;
457 	args->controller_listp = cp;
458 
459 	cp->bus = add_bus(args, di_parent_node(node),
460 	    di_minor_next(di_parent_node(node), NULL), cp);
461 
462 	return (cp);
463 }
464 
465 static int
466 add_devpath(di_devlink_t devlink, void *arg)
467 {
468 	struct search_args *args;
469 	char		*devidstr;
470 	disk_t		*diskp;
471 	char		kernel_name[MAXPATHLEN];
472 
473 	args =	(struct search_args *)arg;
474 
475 	/*
476 	 * Get the diskp value from calling have_disk. Can either be found
477 	 * by kernel name or devid.
478 	 */
479 
480 	diskp = NULL;
481 	devidstr = get_str_prop(DEVICE_ID_PROP, args->node);
482 	(void) snprintf(kernel_name, sizeof (kernel_name), "%s%d",
483 	    di_node_name(args->node), di_instance(args->node));
484 
485 	(void) have_disk(args, devidstr, kernel_name, &diskp);
486 
487 	/*
488 	 * The devlink_path is usually of the form /dev/rdsk/c0t0d0s0.
489 	 * For diskettes it is /dev/rdiskette*.
490 	 * On Intel we would also get each fdisk partition as well
491 	 * (e.g. /dev/rdsk/c0t0d0p0).
492 	 */
493 	if (diskp != NULL) {
494 	    alias_t	*ap;
495 	    char	*devlink_path;
496 
497 	    if (diskp->drv_type != DM_DT_FLOPPY) {
498 		/*
499 		 * Add other controllers for multipath disks.  This will have
500 		 * no effect if the controller relationship is already set up.
501 		 */
502 		if (add_disk2controller(diskp, args) != 0) {
503 		    args->dev_walk_status = ENOMEM;
504 		}
505 	    }
506 
507 	    (void) snprintf(kernel_name, sizeof (kernel_name), "%s%d",
508 		di_node_name(args->node), di_instance(args->node));
509 	    devlink_path = (char *)di_devlink_path(devlink);
510 
511 	    if (dm_debug > 1) {
512 		(void) fprintf(stderr, "INFO:     devpath %s\n", devlink_path);
513 	    }
514 
515 	    if ((ap = find_alias(diskp, kernel_name)) == NULL) {
516 		if (new_alias(diskp, kernel_name, devlink_path, args) != 0) {
517 		    args->dev_walk_status = ENOMEM;
518 		}
519 	    } else {
520 		/*
521 		 * It is possible that we have already added this devpath.
522 		 * Do not add it again. new_devpath will return a 0 if
523 		 * found, and not add the path.
524 		 */
525 		if (new_devpath(ap, devlink_path) != 0) {
526 		    args->dev_walk_status = ENOMEM;
527 		}
528 	    }
529 	}
530 
531 	return (DI_WALK_CONTINUE);
532 }
533 
534 static int
535 add_devs(di_node_t node, di_minor_t minor, void *arg)
536 {
537 	struct search_args	*args;
538 	int result = DI_WALK_CONTINUE;
539 
540 	args = (struct search_args *)arg;
541 
542 	if (dm_debug > 1) {
543 	    /* This is all just debugging code */
544 	    char	*devpath;
545 	    char	dev_name[MAXPATHLEN];
546 
547 	    devpath = di_devfs_path(node);
548 	    (void) snprintf(dev_name, sizeof (dev_name), "%s:%s", devpath,
549 		di_minor_name(minor));
550 	    di_devfs_path_free((void *) devpath);
551 
552 	    (void) fprintf(stderr,
553 		"INFO: dev: %s, node: %s%d, minor: 0x%x, type: %s\n",
554 		dev_name,
555 		di_node_name(node), di_instance(node),
556 		di_minor_spectype(minor),
557 		(di_minor_nodetype(minor) != NULL ?
558 		    di_minor_nodetype(minor) : "NULL"));
559 	}
560 
561 	if (bus_type(node, minor, args->ph) != NULL) {
562 	    if (add_bus(args, node, minor, NULL) == NULL) {
563 		args->dev_walk_status = ENOMEM;
564 		result = DI_WALK_TERMINATE;
565 	    }
566 
567 	} else if (is_HBA(node, minor)) {
568 	    if (add_controller(args, node, minor) == NULL) {
569 		args->dev_walk_status = ENOMEM;
570 		result = DI_WALK_TERMINATE;
571 	    }
572 
573 	} else if (di_minor_spectype(minor) == S_IFCHR &&
574 		(is_drive(minor) || is_zvol(node, minor))) {
575 	    char	*devidstr;
576 	    char	kernel_name[MAXPATHLEN];
577 	    disk_t	*diskp;
578 
579 	    (void) snprintf(kernel_name, sizeof (kernel_name), "%s%d",
580 		di_node_name(node), di_instance(node));
581 	    devidstr = get_str_prop(DEVICE_ID_PROP, node);
582 
583 	    args->node = node;
584 	    args->minor = minor;
585 
586 	    /* Check if we already got this disk and this is another slice */
587 	    if (!have_disk(args, devidstr, kernel_name, &diskp)) {
588 
589 		args->dev_walk_status = 0;
590 		/* This is a newly found disk, create the disk structure. */
591 		diskp = create_disk(devidstr, kernel_name, args);
592 		if (diskp == NULL) {
593 		    args->dev_walk_status = ENOMEM;
594 		}
595 
596 		if (diskp->drv_type != DM_DT_FLOPPY) {
597 		    /* add the controller relationship */
598 		    if (args->dev_walk_status == 0) {
599 			if (add_disk2controller(diskp, args) != 0) {
600 			    args->dev_walk_status = ENOMEM;
601 			}
602 		    }
603 		}
604 	    }
605 
606 	    /* Add the devpaths for the drive. */
607 	    if (args->dev_walk_status == 0) {
608 		char	*devpath;
609 		char	slice_path[MAXPATHLEN];
610 		char	*pattern;
611 
612 		/*
613 		 * We will come through here once for each of the raw slice
614 		 * device names.
615 		 */
616 		devpath = di_devfs_path(node);
617 		(void) snprintf(slice_path, sizeof (slice_path), "%s:%s",
618 		    devpath, di_minor_name(minor));
619 		di_devfs_path_free((void *) devpath);
620 
621 		if (libdiskmgt_str_eq(di_minor_nodetype(minor), DDI_NT_FD)) {
622 		    pattern = DEVLINK_FLOPPY_REGEX;
623 		} else {
624 		    pattern = DEVLINK_REGEX;
625 		}
626 
627 		/* Walk the /dev tree to get the devlinks. */
628 		(void) di_devlink_walk(args->handle, pattern, slice_path,
629 		    DI_PRIMARY_LINK, arg, add_devpath);
630 	    }
631 
632 	    if (args->dev_walk_status != 0) {
633 		result = DI_WALK_TERMINATE;
634 	    }
635 	}
636 
637 	return (result);
638 }
639 
640 static int
641 add_disk2controller(disk_t *diskp, struct search_args *args)
642 {
643 	di_node_t	pnode;
644 	controller_t	*cp;
645 	di_minor_t	minor;
646 	di_node_t	node;
647 	int		i;
648 
649 	node = args->node;
650 
651 	pnode = di_parent_node(node);
652 	if (pnode == DI_NODE_NIL) {
653 	    return (0);
654 	}
655 
656 	minor = di_minor_next(pnode, NULL);
657 	if (minor == NULL) {
658 	    return (0);
659 	}
660 
661 	if ((cp = add_controller(args, pnode, minor)) == NULL) {
662 	    return (ENOMEM);
663 	}
664 
665 	/* check if the disk <-> ctrl assoc is already there */
666 	for (i = 0; diskp->controllers[i]; i++) {
667 	    if (cp == diskp->controllers[i]) {
668 		return (0);
669 	    }
670 	}
671 
672 	/* this is a new controller for this disk */
673 
674 	/* add the disk to the controlller */
675 	if (add_ptr2array(diskp, (void ***)&cp->disks) != 0) {
676 	    return (ENOMEM);
677 	}
678 
679 	/* add the controlller to the disk */
680 	if (add_ptr2array(cp, (void ***)&diskp->controllers) != 0) {
681 	    return (ENOMEM);
682 	}
683 
684 	/*
685 	 * Set up paths for mpxio controlled drives.
686 	 */
687 	if (libdiskmgt_str_eq(di_node_name(pnode), "scsi_vhci")) {
688 	    /* note: mpxio di_path stuff is all consolidation private */
689 	    di_path_t   pi = DI_PATH_NIL;
690 
691 	    while ((pi = di_path_client_next_path(node, pi)) != DI_PATH_NIL) {
692 		int	cnt;
693 		uchar_t	*bytes;
694 		char	str[MAXPATHLEN];
695 		char	*wwn;
696 
697 		di_node_t phci_node = di_path_phci_node(pi);
698 
699 		/* get the node wwn */
700 		cnt = di_path_prop_lookup_bytes(pi, WWN_PROP, &bytes);
701 		wwn = NULL;
702 		if (cnt > 0) {
703 		    int	i;
704 
705 		    str[0] = 0;
706 		    for (i = 0; i < cnt; i++) {
707 			char bstr[8];	/* a byte is only 2 hex chars + null */
708 
709 			(void) snprintf(bstr, sizeof (bstr), "%.2x", bytes[i]);
710 			(void) strlcat(str, bstr, sizeof (str));
711 		    }
712 		    wwn = str;
713 		}
714 
715 		if (new_path(cp, diskp, phci_node, di_path_state(pi), wwn)
716 		    == NULL) {
717 		    return (ENOMEM);
718 		}
719 	    }
720 	}
721 
722 	return (0);
723 }
724 
725 static int
726 add_disk2path(disk_t *dp, path_t *pp, di_path_state_t st, char *wwn)
727 {
728 	/* add the disk to the path */
729 	if (add_ptr2array(dp, (void ***)&pp->disks) != 0) {
730 	    cache_free_path(pp);
731 	    return (0);
732 	}
733 
734 	/* add the path to the disk */
735 	if (add_ptr2array(pp, (void ***)&dp->paths) != 0) {
736 	    cache_free_path(pp);
737 	    return (0);
738 	}
739 
740 	/* add the path state for this disk */
741 	if (add_int2array(st, &pp->states) != 0) {
742 	    cache_free_path(pp);
743 	    return (0);
744 	}
745 
746 	/* add the path state for this disk */
747 	if (wwn != NULL) {
748 	    char	*wp;
749 
750 	    if ((wp = strdup(wwn)) != NULL) {
751 		if (add_ptr2array(wp, (void ***)(&pp->wwns)) != 0) {
752 		    cache_free_path(pp);
753 		    return (0);
754 		}
755 	    }
756 	}
757 
758 	return (1);
759 }
760 
761 static int
762 add_int2array(int p, int **parray)
763 {
764 	int		i;
765 	int		cnt;
766 	int		*pa;
767 	int		*new_array;
768 
769 	pa = *parray;
770 
771 	cnt = 0;
772 	if (pa != NULL) {
773 	    for (; pa[cnt] != -1; cnt++)
774 		;
775 	}
776 
777 	new_array = (int *)calloc(cnt + 2, sizeof (int *));
778 	if (new_array == NULL) {
779 	    return (ENOMEM);
780 	}
781 
782 	/* copy the existing array */
783 	for (i = 0; i < cnt; i++) {
784 	    new_array[i] = pa[i];
785 	}
786 
787 	new_array[i] = p;
788 	new_array[i + 1] = -1;
789 
790 	free(pa);
791 	*parray = new_array;
792 
793 	return (0);
794 }
795 
796 static int
797 add_ptr2array(void *p, void ***parray)
798 {
799 	int		i;
800 	int		cnt;
801 	void		**pa;
802 	void		**new_array;
803 
804 	pa = *parray;
805 
806 	cnt = 0;
807 	if (pa != NULL) {
808 	    for (; pa[cnt]; cnt++)
809 		;
810 	}
811 
812 	new_array = (void **)calloc(cnt + 2, sizeof (void *));
813 	if (new_array == NULL) {
814 	    return (ENOMEM);
815 	}
816 
817 	/* copy the existing array */
818 	for (i = 0; i < cnt; i++) {
819 	    new_array[i] = pa[i];
820 	}
821 
822 	new_array[i] = p;
823 	new_array[i + 1] = NULL;
824 
825 	free(pa);
826 	*parray = new_array;
827 
828 	return (0);
829 }
830 
831 /*
832  * This double checks that we aren't going to get into a bad situation.
833  * This function should never fail, but I just want to double check things.
834  */
835 static int
836 can_remove_controller(controller_t *cp, controller_t *currp)
837 {
838 	if (dm_debug) {
839 	    if (cp == currp) {
840 		(void) fprintf(stderr, "ERROR: remove current controller\n");
841 	    }
842 
843 	    if (cp->disks != NULL && cp->disks[0] != NULL) {
844 		(void) fprintf(stderr,
845 		    "ERROR: remove controller with disk ptrs\n");
846 	    }
847 
848 	    if (cp->paths != NULL && cp->paths[0] != NULL) {
849 		(void) fprintf(stderr,
850 		    "ERROR: remove controller with path ptrs\n");
851 	    }
852 	}
853 
854 	return (1);
855 }
856 
857 /*
858  * If we have a controller in the list that is really a path then we need to
859  * take that controller out of the list since nodes that are paths are not
860  * considered to be controllers.
861  */
862 static void
863 clean_paths(struct search_args *args)
864 {
865 	controller_t	*cp;
866 
867 	cp = args->controller_listp;
868 	while (cp != NULL) {
869 	    path_t	**pp;
870 
871 	    pp = cp->paths;
872 	    if (pp != NULL) {
873 		int i;
874 
875 		for (i = 0; pp[i]; i++) {
876 		    remove_invalid_controller(pp[i]->name, cp, args);
877 		}
878 	    }
879 	    cp = cp->next;
880 	}
881 }
882 
883 static disk_t *
884 create_disk(char *deviceid, char *kernel_name, struct search_args *args)
885 {
886 	disk_t	*diskp;
887 	char	*type;
888 	char	*prod_id;
889 	char	*vendor_id;
890 
891 	if (dm_debug) {
892 	    (void) fprintf(stderr, "INFO: create_disk %s\n", kernel_name);
893 	}
894 
895 	diskp = calloc(1, sizeof (disk_t));
896 	if (diskp == NULL) {
897 	    return (NULL);
898 	}
899 
900 	diskp->controllers = (controller_t **)
901 	    calloc(1, sizeof (controller_t *));
902 	if (diskp->controllers == NULL) {
903 	    cache_free_disk(diskp);
904 	    return (NULL);
905 	}
906 	diskp->controllers[0] = NULL;
907 
908 	diskp->devid = NULL;
909 	if (deviceid != NULL) {
910 	    if ((diskp->device_id = strdup(deviceid)) == NULL) {
911 		cache_free_disk(diskp);
912 		return (NULL);
913 	    }
914 
915 	    (void) devid_str_decode(deviceid, &(diskp->devid), NULL);
916 	}
917 
918 	if (kernel_name != NULL) {
919 	    diskp->kernel_name = strdup(kernel_name);
920 	    if (diskp->kernel_name == NULL) {
921 		cache_free_disk(diskp);
922 		return (NULL);
923 	    }
924 	}
925 
926 	diskp->paths = NULL;
927 	diskp->aliases = NULL;
928 
929 	diskp->cd_rom = 0;
930 	diskp->rpm = 0;
931 	type = di_minor_nodetype(args->minor);
932 
933 	prod_id = get_str_prop(PROD_ID_PROP, args->node);
934 	if (prod_id != NULL) {
935 	    if ((diskp->product_id = strdup(prod_id)) == NULL) {
936 		cache_free_disk(diskp);
937 		return (NULL);
938 	    }
939 	} else {
940 	    prod_id = get_str_prop(PROD_ID_USB_PROP, args->node);
941 	    if (prod_id != NULL) {
942 		if ((diskp->product_id = strdup(prod_id)) == NULL) {
943 		    cache_free_disk(diskp);
944 		    return (NULL);
945 		}
946 	    }
947 	}
948 
949 	vendor_id = get_str_prop(VENDOR_ID_PROP, args->node);
950 	if (vendor_id != NULL) {
951 	    if ((diskp->vendor_id = strdup(vendor_id)) == NULL) {
952 		cache_free_disk(diskp);
953 		return (NULL);
954 	    }
955 	} else {
956 	    vendor_id = get_str_prop(VENDOR_ID_PROP, args->node);
957 	    if (vendor_id != NULL) {
958 		if ((diskp->vendor_id = strdup(vendor_id)) == NULL) {
959 		    cache_free_disk(diskp);
960 		    return (NULL);
961 		}
962 	    }
963 	}
964 
965 	/*
966 	 * DVD, CD-ROM, CD-RW, MO, etc. are all reported as CD-ROMS.
967 	 * We try to use uscsi later to determine the real type.
968 	 * The cd_rom flag tells us that the kernel categorized the drive
969 	 * as a CD-ROM.  We leave the drv_type as UKNOWN for now.
970 	 * The combination of the cd_rom flag being set with the drv_type of
971 	 * unknown is what triggers the uscsi probe in drive.c.
972 	 */
973 	if (disk_is_cdrom(type)) {
974 	    diskp->drv_type = DM_DT_UNKNOWN;
975 	    diskp->cd_rom = 1;
976 	    diskp->removable = 1;
977 	} else if (libdiskmgt_str_eq(type, DDI_NT_FD)) {
978 	    diskp->drv_type = DM_DT_FLOPPY;
979 	    diskp->removable = 1;
980 	} else {
981 		/* not a "CD-ROM" or Floppy */
982 
983 	    diskp->removable = get_prop(REMOVABLE_PROP, args->node);
984 
985 	    if (diskp->removable == -1) {
986 		diskp->removable = 0;
987 #if defined(i386) || defined(__amd64)
988 		/*
989 		 * x86 does not have removable property.  Check for common
990 		 * removable drives, zip & jaz, and mark those correctly.
991 		 */
992 		if (vendor_id != NULL && prod_id != NULL) {
993 		    if (str_case_index(vendor_id, "iomega") != NULL) {
994 			if (str_case_index(prod_id, "jaz") != NULL) {
995 			    diskp->removable = 1;
996 			} else if (str_case_index(prod_id, "zip") != NULL) {
997 			    diskp->removable = 1;
998 			}
999 		    }
1000 		}
1001 #endif
1002 	    }
1003 
1004 	    if (diskp->removable) {
1005 		/*
1006 		 * For removable jaz or zip drives there is no way
1007 		 * to get the drive type unless media is inserted, so we
1008 		 * look at the product-id for a hint.
1009 		 */
1010 
1011 		diskp->drv_type = DM_DT_UNKNOWN;
1012 
1013 		if (prod_id != NULL) {
1014 		    if (str_case_index(prod_id, "jaz") != NULL) {
1015 			diskp->drv_type = DM_DT_JAZ;
1016 		    } else if (str_case_index(prod_id, "zip") != NULL) {
1017 			diskp->drv_type = DM_DT_ZIP;
1018 		    }
1019 		}
1020 	    } else {
1021 		diskp->drv_type = DM_DT_FIXED;
1022 	    }
1023 	}
1024 
1025 	diskp->next = args->disk_listp;
1026 	args->disk_listp = diskp;
1027 
1028 	return (diskp);
1029 }
1030 
1031 static char *
1032 ctype(di_node_t node, di_minor_t minor)
1033 {
1034 	char	*type;
1035 	char	*name;
1036 
1037 	type = di_minor_nodetype(minor);
1038 	name = di_node_name(node);
1039 
1040 	/* IDE disks use SCSI nexus as the type, so handle this special case */
1041 	if (libdiskmgt_str_eq(name, "ide")) {
1042 	    return (DM_CTYPE_ATA);
1043 	}
1044 
1045 	if (libdiskmgt_str_eq(di_minor_name(minor), "scsa2usb")) {
1046 	    return (DM_CTYPE_USB);
1047 	}
1048 
1049 	if (libdiskmgt_str_eq(type, DDI_NT_SCSI_NEXUS) ||
1050 	    libdiskmgt_str_eq(type, DDI_NT_SCSI_ATTACHMENT_POINT)) {
1051 	    return (DM_CTYPE_SCSI);
1052 	}
1053 
1054 	if (libdiskmgt_str_eq(type, DDI_NT_FC_ATTACHMENT_POINT)) {
1055 	    return (DM_CTYPE_FIBRE);
1056 	}
1057 
1058 	if (libdiskmgt_str_eq(type, DDI_NT_NEXUS) &&
1059 	    libdiskmgt_str_eq(name, "fp")) {
1060 	    return (DM_CTYPE_FIBRE);
1061 	}
1062 
1063 	if (libdiskmgt_str_eq(type, DDI_PSEUDO) &&
1064 	    libdiskmgt_str_eq(name, "ide")) {
1065 	    return (DM_CTYPE_ATA);
1066 	}
1067 
1068 	return (DM_CTYPE_UNKNOWN);
1069 }
1070 
1071 static boolean_t
1072 disk_is_cdrom(char *type)
1073 {
1074 
1075 	int		type_index;
1076 
1077 	for (type_index = 0; cdromtypes[type_index] != NULL; type_index++) {
1078 	    if (libdiskmgt_str_eq(type, cdromtypes[type_index])) {
1079 		return (B_TRUE);
1080 	    }
1081 	}
1082 
1083 	return (B_FALSE);
1084 }
1085 
1086 static alias_t *
1087 find_alias(disk_t *diskp, char *kernel_name)
1088 {
1089 	alias_t	*ap;
1090 
1091 	ap = diskp->aliases;
1092 	while (ap != NULL) {
1093 	    if (libdiskmgt_str_eq(ap->kstat_name, kernel_name)) {
1094 		return (ap);
1095 	    }
1096 	    ap = ap->next;
1097 	}
1098 
1099 	return (NULL);
1100 }
1101 
1102 static bus_t *
1103 find_bus(struct search_args *args, char *name)
1104 {
1105 	bus_t *listp;
1106 
1107 	listp = args->bus_listp;
1108 	while (listp != NULL) {
1109 	    if (libdiskmgt_str_eq(listp->name, name)) {
1110 		return (listp);
1111 	    }
1112 
1113 	    listp = listp->next;
1114 	}
1115 
1116 	return (NULL);
1117 }
1118 
1119 static controller_t *
1120 find_controller(struct search_args *args, char *name)
1121 {
1122 	controller_t *listp;
1123 
1124 	listp = args->controller_listp;
1125 	while (listp != NULL) {
1126 	    if (libdiskmgt_str_eq(listp->name, name)) {
1127 		return (listp);
1128 	    }
1129 
1130 	    listp = listp->next;
1131 	}
1132 
1133 	return (NULL);
1134 }
1135 
1136 static int
1137 fix_cluster_devpath(di_devlink_t devlink, void *arg)
1138 {
1139 	int			fd;
1140 	struct search_args	*args;
1141 	char			*devlink_path;
1142 	disk_t			*diskp = NULL;
1143 	alias_t			*ap = NULL;
1144 
1145 	/*
1146 	 * The devlink_path is of the form /dev/did/rdsk/d1s0.
1147 	 */
1148 
1149 	args =	(struct search_args *)arg;
1150 
1151 	/* Find the disk by the deviceid we read from the cluster disk. */
1152 	devlink_path = (char *)di_devlink_path(devlink);
1153 	if (devlink_path == NULL) {
1154 	    return (DI_WALK_CONTINUE);
1155 	}
1156 
1157 	if ((fd = open(devlink_path, O_RDONLY|O_NDELAY)) >= 0) {
1158 	    ddi_devid_t	devid;
1159 
1160 	    if (dm_debug > 1) {
1161 		(void) fprintf(stderr, "INFO:     cluster devpath %s\n",
1162 		    devlink_path);
1163 	    }
1164 
1165 	    if (devid_get(fd, &devid) == 0) {
1166 		char *minor;
1167 		char *devidstr;
1168 
1169 		minor = di_minor_name(args->minor);
1170 
1171 		if ((devidstr = devid_str_encode(devid, minor)) != NULL) {
1172 		    diskp = get_disk_by_deviceid(args->disk_listp, devidstr);
1173 
1174 			/*
1175 			 * This really shouldn't happen, since we should have
1176 			 * found all of the disks during our first pass through
1177 			 * the dev tree, but just in case...
1178 			 */
1179 			if (diskp == NULL) {
1180 			    if (dm_debug > 1) {
1181 				(void) fprintf(stderr,
1182 				    "INFO:     cluster create disk\n");
1183 			    }
1184 
1185 			    diskp = create_disk(devidstr, NULL, args);
1186 			    if (diskp == NULL) {
1187 				args->dev_walk_status = ENOMEM;
1188 			    }
1189 
1190 			    /* add the controller relationship */
1191 			    if (args->dev_walk_status == 0) {
1192 				if (add_disk2controller(diskp, args) != 0) {
1193 				    args->dev_walk_status = ENOMEM;
1194 				}
1195 			    }
1196 
1197 			    if (new_alias(diskp, NULL, devlink_path, args)
1198 				!= 0) {
1199 				args->dev_walk_status = ENOMEM;
1200 			    }
1201 			}
1202 
1203 			devid_str_free(devidstr);
1204 		}
1205 
1206 		devid_free(devid);
1207 	    }
1208 	    (void) close(fd);
1209 	}
1210 
1211 
1212 	if (diskp != NULL) {
1213 	    if (dm_debug > 1) {
1214 		(void) fprintf(stderr, "INFO:     cluster found disk\n");
1215 	    }
1216 
1217 	    ap = diskp->aliases;
1218 	}
1219 
1220 	if (ap != NULL) {
1221 	    /* NOTE: if ap->next != NULL have cluster disks w/ multiple paths */
1222 
1223 	    if (!ap->cluster) {
1224 		char	*basep;
1225 		char	*namep;
1226 		int	cnt = 0;
1227 		int	size;
1228 		char	alias[MAXPATHLEN];
1229 
1230 		/*
1231 		 * First time; save the /dev/rdsk devpaths and update the
1232 		 * alias info with the new alias name.
1233 		 */
1234 		ap->orig_paths = ap->devpaths;
1235 		ap->devpaths = NULL;
1236 
1237 		free(ap->alias);
1238 
1239 		/* get the new cluster alias name */
1240 		basep = strrchr(devlink_path, '/');
1241 		if (basep == NULL) {
1242 		    basep = devlink_path;
1243 		} else {
1244 		    basep++;
1245 		}
1246 
1247 		size = sizeof (alias) - 1;
1248 		namep = alias;
1249 		while (*basep != 0 && *basep != 's' && cnt < size) {
1250 		    *namep++ = *basep++;
1251 		    cnt++;
1252 		}
1253 		*namep = 0;
1254 
1255 		if ((ap->alias = strdup(alias)) == NULL) {
1256 		    args->dev_walk_status = ENOMEM;
1257 		}
1258 
1259 		ap->cluster = 1;
1260 	    }
1261 
1262 	    if (new_devpath(ap, devlink_path) != 0) {
1263 		args->dev_walk_status = ENOMEM;
1264 	    }
1265 	}
1266 
1267 	return (DI_WALK_CONTINUE);
1268 }
1269 
1270 /*
1271  * Check if we have the drive in our list, based upon the device id.
1272  * We got the device id from the dev tree walk.  This is encoded
1273  * using devid_str_encode(3DEVID).   In order to check the device ids we need
1274  * to use the devid_compare(3DEVID) function, so we need to decode the
1275  * string representation of the device id.
1276  */
1277 static disk_t *
1278 get_disk_by_deviceid(disk_t *listp, char *devidstr)
1279 {
1280 	ddi_devid_t	devid;
1281 
1282 	if (devidstr == NULL || devid_str_decode(devidstr, &devid, NULL) != 0) {
1283 	    return (NULL);
1284 	}
1285 
1286 	while (listp != NULL) {
1287 	    if (listp->devid != NULL &&
1288 		devid_compare(listp->devid, devid) == 0) {
1289 		break;
1290 	    }
1291 
1292 	    listp = listp->next;
1293 	}
1294 
1295 	devid_free(devid);
1296 
1297 	return (listp);
1298 }
1299 
1300 /*
1301  * Get the base disk name with no path prefix and no slice (if there is one).
1302  * The name parameter should be big enough to hold the name.
1303  * This handles diskette names ok (/dev/rdiskette0) since there is no slice,
1304  * and converts the raw diskette name.
1305  * But, we don't know how to strip off the slice from third party drive
1306  * names.  That just means that their drive name will include a slice on
1307  * it.
1308  */
1309 static void
1310 get_disk_name_from_path(char *path, char *name, int size)
1311 {
1312 	char		*basep;
1313 	int		cnt = 0;
1314 
1315 	basep = strrchr(path, '/');
1316 	if (basep == NULL) {
1317 	    basep = path;
1318 	} else {
1319 	    basep++;
1320 	}
1321 
1322 	size = size - 1;	/* leave room for terminating 0 */
1323 
1324 	if (is_ctds(basep)) {
1325 	    while (*basep != 0 && *basep != 's' && cnt < size) {
1326 		*name++ = *basep++;
1327 		cnt++;
1328 	    }
1329 	    *name = 0;
1330 	} else {
1331 	    if (strncmp(basep, FLOPPY_NAME, sizeof (FLOPPY_NAME) - 1) == 0) {
1332 		/*
1333 		 * a floppy, convert rdiskette name to diskette name,
1334 		 * by skipping over the 'r' for raw diskette
1335 		 */
1336 		basep++;
1337 	    }
1338 
1339 	    /* not a ctds name, just copy it */
1340 	    (void) strlcpy(name, basep, size);
1341 	}
1342 }
1343 
1344 static char *
1345 get_byte_prop(char *prop_name, di_node_t node)
1346 {
1347 	int	cnt;
1348 	uchar_t	*bytes;
1349 	int	i;
1350 	char	str[MAXPATHLEN];
1351 
1352 	cnt = di_prop_lookup_bytes(DDI_DEV_T_ANY, node, prop_name, &bytes);
1353 	if (cnt < 1) {
1354 	    return (NULL);
1355 	}
1356 
1357 	str[0] = 0;
1358 	for (i = 0; i < cnt; i++) {
1359 	    char bstr[8];	/* a byte is only 2 hex chars + null */
1360 
1361 	    (void) snprintf(bstr, sizeof (bstr), "%.2x", bytes[i]);
1362 	    (void) strlcat(str, bstr, sizeof (str));
1363 	}
1364 	return (strdup(str));
1365 }
1366 
1367 static di_node_t
1368 get_parent_bus(di_node_t node, struct search_args *args)
1369 {
1370 	di_node_t pnode;
1371 
1372 	pnode = di_parent_node(node);
1373 	if (pnode == DI_NODE_NIL) {
1374 	    return (NULL);
1375 	}
1376 
1377 	if (bus_type(pnode, di_minor_next(pnode, NULL), args->ph) != NULL) {
1378 	    return (pnode);
1379 	}
1380 
1381 	return (get_parent_bus(pnode, args));
1382 }
1383 
1384 static int
1385 get_prom_int(char *prop_name, di_node_t node, di_prom_handle_t ph)
1386 {
1387 	int *n;
1388 
1389 	if (di_prom_prop_lookup_ints(ph, node, prop_name, &n) == 1) {
1390 	    return (*n);
1391 	}
1392 
1393 	return (0);
1394 }
1395 
1396 static char *
1397 get_prom_str(char *prop_name, di_node_t node, di_prom_handle_t ph)
1398 {
1399 	char *str;
1400 
1401 	if (di_prom_prop_lookup_strings(ph, node, prop_name, &str) == 1) {
1402 	    return (str);
1403 	}
1404 
1405 	return (NULL);
1406 }
1407 
1408 /*
1409  * Get one of the positive int or boolean properties.
1410  */
1411 static int
1412 get_prop(char *prop_name, di_node_t node)
1413 {
1414 	int num;
1415 	int *ip;
1416 
1417 	if ((num = di_prop_lookup_ints(DDI_DEV_T_ANY, node, prop_name, &ip))
1418 	    >= 0) {
1419 	    if (num == 0) {
1420 		/* boolean */
1421 		return (1);
1422 	    } else if (num == 1) {
1423 		/* single int */
1424 		return (*ip);
1425 	    }
1426 	}
1427 
1428 	return (-1);
1429 }
1430 
1431 static char *
1432 get_str_prop(char *prop_name, di_node_t node)
1433 {
1434 	char *str;
1435 
1436 	if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, prop_name, &str) == 1) {
1437 	    return (str);
1438 	}
1439 
1440 	return (NULL);
1441 }
1442 
1443 /*
1444  * Check if we have the drive in our list, based upon the device id, if the
1445  * drive has a device id, or the kernel name, if it doesn't have a device id.
1446  */
1447 static int
1448 have_disk(struct search_args *args, char *devidstr, char *kernel_name,
1449     disk_t **diskp)
1450 {
1451 	disk_t *listp;
1452 
1453 	*diskp = NULL;
1454 	listp = args->disk_listp;
1455 	if (devidstr != NULL) {
1456 	    if ((*diskp = get_disk_by_deviceid(listp, devidstr)) != NULL) {
1457 		return (1);
1458 	    }
1459 
1460 	} else {
1461 	    /* no devid, try matching the kernel names on the drives */
1462 	    while (listp != NULL) {
1463 		if (libdiskmgt_str_eq(kernel_name, listp->kernel_name)) {
1464 		    *diskp = listp;
1465 		    return (1);
1466 		}
1467 		listp = listp->next;
1468 	    }
1469 	}
1470 
1471 	return (0);
1472 }
1473 
1474 static char *
1475 bus_type(di_node_t node, di_minor_t minor, di_prom_handle_t ph)
1476 {
1477 	char	*type;
1478 	int	i;
1479 
1480 	type = get_prom_str("device_type", node, ph);
1481 	if (type == NULL) {
1482 	    type = di_node_name(node);
1483 	}
1484 
1485 	for (i = 0; bustypes[i]; i++) {
1486 	    if (libdiskmgt_str_eq(type, bustypes[i])) {
1487 		return (type);
1488 	    }
1489 	}
1490 
1491 	if (minor != NULL && strcmp(di_minor_nodetype(minor),
1492 	    DDI_NT_USB_ATTACHMENT_POINT) == 0) {
1493 	    return ("usb");
1494 	}
1495 
1496 	return (NULL);
1497 }
1498 
1499 static int
1500 is_cluster_disk(di_node_t node, di_minor_t minor)
1501 {
1502 	if (di_minor_spectype(minor) == S_IFCHR &&
1503 	    libdiskmgt_str_eq(di_minor_nodetype(minor), DDI_PSEUDO) &&
1504 	    libdiskmgt_str_eq(di_node_name(node), CLUSTER_DEV)) {
1505 	    return (1);
1506 	}
1507 
1508 	return (0);
1509 }
1510 
1511 /*
1512  * If the input name is in c[t]ds format then return 1, otherwise return 0.
1513  */
1514 static int
1515 is_ctds(char *name)
1516 {
1517 	char	*p;
1518 
1519 	p = name;
1520 
1521 	if (*p++ != 'c') {
1522 	    return (0);
1523 	}
1524 	/* skip controller digits */
1525 	while (isdigit(*p)) {
1526 	    p++;
1527 	}
1528 
1529 	/* handle optional target */
1530 	if (*p == 't') {
1531 	    p++;
1532 	    /* skip over target */
1533 	    while (isdigit(*p) || isupper(*p)) {
1534 		p++;
1535 	    }
1536 	}
1537 
1538 	if (*p++ != 'd') {
1539 	    return (0);
1540 	}
1541 	while (isdigit(*p)) {
1542 	    p++;
1543 	}
1544 
1545 	if (*p++ != 's') {
1546 	    return (0);
1547 	}
1548 
1549 	/* check the slice number */
1550 	while (isdigit(*p)) {
1551 	    p++;
1552 	}
1553 
1554 	if (*p != 0) {
1555 	    return (0);
1556 	}
1557 
1558 	return (1);
1559 }
1560 
1561 static int
1562 is_drive(di_minor_t minor)
1563 {
1564 	char	*type;
1565 	int	type_index;
1566 
1567 	type = di_minor_nodetype(minor);
1568 	type_index = 0;
1569 
1570 	while (disktypes[type_index] != NULL) {
1571 	    if (libdiskmgt_str_eq(type, disktypes[type_index])) {
1572 		return (1);
1573 	    }
1574 	    type_index++;
1575 	}
1576 
1577 	return (0);
1578 }
1579 
1580 static int
1581 is_zvol(di_node_t node, di_minor_t minor)
1582 {
1583 	if ((strncmp(di_node_name(node), ZFS_DRIVER, 3) == 0) &&
1584 	    di_minor_devt(minor))
1585 		return (1);
1586 	return (0);
1587 }
1588 
1589 static int
1590 is_HBA(di_node_t node, di_minor_t minor)
1591 {
1592 	char	*type;
1593 	char	*name;
1594 	int	type_index;
1595 
1596 	type = di_minor_nodetype(minor);
1597 	type_index = 0;
1598 
1599 	while (ctrltypes[type_index] != NULL) {
1600 	    if (libdiskmgt_str_eq(type, ctrltypes[type_index])) {
1601 		return (1);
1602 	    }
1603 	    type_index++;
1604 	}
1605 
1606 	name = di_node_name(node);
1607 	if (libdiskmgt_str_eq(type, DDI_PSEUDO) &&
1608 	    libdiskmgt_str_eq(name, "ide")) {
1609 	    return (1);
1610 	}
1611 
1612 	return (0);
1613 }
1614 
1615 static int
1616 new_alias(disk_t *diskp, char *kernel_name, char *devlink_path,
1617 	struct search_args *args)
1618 {
1619 	alias_t		*aliasp;
1620 	char		alias[MAXPATHLEN];
1621 	di_node_t	pnode;
1622 
1623 	aliasp = malloc(sizeof (alias_t));
1624 	if (aliasp == NULL) {
1625 	    return (ENOMEM);
1626 	}
1627 
1628 	aliasp->alias = NULL;
1629 	aliasp->kstat_name = NULL;
1630 	aliasp->wwn = NULL;
1631 	aliasp->devpaths = NULL;
1632 	aliasp->orig_paths = NULL;
1633 
1634 	get_disk_name_from_path(devlink_path, alias, sizeof (alias));
1635 
1636 	aliasp->alias = strdup(alias);
1637 	if (aliasp->alias == NULL) {
1638 	    cache_free_alias(aliasp);
1639 	    return (ENOMEM);
1640 	}
1641 
1642 	if (kernel_name != NULL) {
1643 	    aliasp->kstat_name = strdup(kernel_name);
1644 	    if (aliasp->kstat_name == NULL) {
1645 		cache_free_alias(aliasp);
1646 		return (ENOMEM);
1647 	    }
1648 	} else {
1649 	    aliasp->kstat_name = NULL;
1650 	}
1651 
1652 	aliasp->cluster = 0;
1653 	aliasp->lun = get_prop(DM_LUN, args->node);
1654 	aliasp->target = get_prop(DM_TARGET, args->node);
1655 	aliasp->wwn = get_byte_prop(WWN_PROP, args->node);
1656 
1657 	pnode = di_parent_node(args->node);
1658 	if (pnode != DI_NODE_NIL) {
1659 	    char prop_name[MAXPROPLEN];
1660 
1661 	    (void) snprintf(prop_name, sizeof (prop_name),
1662 		"target%d-sync-speed", aliasp->target);
1663 	    diskp->sync_speed = get_prop(prop_name, pnode);
1664 	    (void) snprintf(prop_name, sizeof (prop_name), "target%d-wide",
1665 		aliasp->target);
1666 	    diskp->wide = get_prop(prop_name, pnode);
1667 	}
1668 
1669 	if (new_devpath(aliasp, devlink_path) != 0) {
1670 	    cache_free_alias(aliasp);
1671 	    return (ENOMEM);
1672 	}
1673 
1674 	aliasp->next = diskp->aliases;
1675 	diskp->aliases = aliasp;
1676 
1677 	return (0);
1678 }
1679 
1680 /*
1681  * Append the new devpath to the end of the devpath list.  This is important
1682  * since we may want to use the order of the devpaths to match up the vtoc
1683  * entries.
1684  */
1685 static int
1686 new_devpath(alias_t *ap, char *devpath)
1687 {
1688 	slice_t	*newdp;
1689 	slice_t *alistp;
1690 
1691 	/*
1692 	 * First, search the alias list to be sure that this devpath is
1693 	 * not already there.
1694 	 */
1695 
1696 	for (alistp = ap->devpaths; alistp != NULL; alistp = alistp->next) {
1697 	    if (libdiskmgt_str_eq(alistp->devpath, devpath)) {
1698 		return (0);
1699 	    }
1700 	}
1701 
1702 	/*
1703 	 * Otherwise, not found so add this new devpath to the list.
1704 	 */
1705 
1706 	newdp = malloc(sizeof (slice_t));
1707 	if (newdp == NULL) {
1708 	    return (ENOMEM);
1709 	}
1710 
1711 	newdp->devpath = strdup(devpath);
1712 	if (newdp->devpath == NULL) {
1713 	    free(newdp);
1714 	    return (ENOMEM);
1715 	}
1716 	newdp->slice_num = -1;
1717 	newdp->next = NULL;
1718 
1719 	if (ap->devpaths == NULL) {
1720 	    ap->devpaths = newdp;
1721 	} else {
1722 	    /* append the devpath to the end of the list */
1723 	    slice_t	*dp;
1724 
1725 	    dp = ap->devpaths;
1726 	    while (dp->next != NULL) {
1727 		dp = dp->next;
1728 	    }
1729 
1730 	    dp->next = newdp;
1731 	}
1732 
1733 	return (0);
1734 }
1735 
1736 static path_t *
1737 new_path(controller_t *cp, disk_t *dp, di_node_t node, di_path_state_t st,
1738 	char *wwn)
1739 {
1740 	char		*devpath;
1741 	path_t		*pp;
1742 	di_minor_t	minor;
1743 
1744 	/* Special handling for fp attachment node. */
1745 	if (strcmp(di_node_name(node), "fp") == 0) {
1746 	    di_node_t pnode;
1747 
1748 	    pnode = di_parent_node(node);
1749 	    if (pnode != DI_NODE_NIL) {
1750 		node = pnode;
1751 	    }
1752 	}
1753 
1754 	devpath = di_devfs_path(node);
1755 
1756 	/* check if the path is already there */
1757 	pp = NULL;
1758 	if (cp->paths != NULL) {
1759 	    int i;
1760 
1761 	    for (i = 0; cp->paths[i]; i++) {
1762 		if (libdiskmgt_str_eq(devpath, cp->paths[i]->name)) {
1763 		    pp = cp->paths[i];
1764 		    break;
1765 		}
1766 	    }
1767 	}
1768 
1769 	if (pp != NULL) {
1770 	    /* the path exists, add this disk to it */
1771 
1772 	    di_devfs_path_free((void *) devpath);
1773 
1774 	    if (!add_disk2path(dp, pp, st, wwn)) {
1775 		return (NULL);
1776 	    }
1777 
1778 	    return (pp);
1779 	}
1780 
1781 	/* create a new path */
1782 
1783 	pp = calloc(1, sizeof (path_t));
1784 	if (pp == NULL) {
1785 	    di_devfs_path_free((void *) devpath);
1786 	    return (NULL);
1787 	}
1788 
1789 	pp->name = strdup(devpath);
1790 	di_devfs_path_free((void *) devpath);
1791 	if (pp->name == NULL) {
1792 	    cache_free_path(pp);
1793 	    return (NULL);
1794 	}
1795 
1796 	/* add the disk to the path */
1797 	if (!add_disk2path(dp, pp, st, wwn)) {
1798 	    return (NULL);
1799 	}
1800 
1801 	/* add the path to the controller */
1802 	if (add_ptr2array(pp, (void ***)&cp->paths) != 0) {
1803 	    cache_free_path(pp);
1804 	    return (NULL);
1805 	}
1806 
1807 	/* add the controller to the path */
1808 	pp->controller = cp;
1809 
1810 	minor = di_minor_next(node, NULL);
1811 	if (minor != NULL) {
1812 	    pp->ctype = ctype(node, minor);
1813 	} else {
1814 	    pp->ctype = DM_CTYPE_UNKNOWN;
1815 	}
1816 
1817 	return (pp);
1818 }
1819 
1820 /*
1821  * We pass in the current controller pointer (currp) so we can double check
1822  * that we aren't corrupting the list by removing the element we are on.  This
1823  * should never happen, but it doesn't hurt to double check.
1824  */
1825 static void
1826 remove_invalid_controller(char *name, controller_t *currp,
1827     struct search_args *args)
1828 {
1829 	controller_t *cp;
1830 	bus_t *bp;
1831 	controller_t *prevp;
1832 
1833 	bp = args->bus_listp;
1834 	while (bp != NULL) {
1835 	    int i;
1836 
1837 	    for (i = 0; bp->controllers[i]; i++) {
1838 		if (libdiskmgt_str_eq(bp->controllers[i]->name, name)) {
1839 		    int j;
1840 
1841 		    /* remove pointer to invalid controller (it is a path) */
1842 		    for (j = i; bp->controllers[j]; j++) {
1843 			bp->controllers[j] = bp->controllers[j + 1];
1844 		    }
1845 		}
1846 	    }
1847 	    bp = bp->next;
1848 	}
1849 
1850 	if (args->controller_listp == NULL) {
1851 	    return;
1852 	}
1853 
1854 	cp = args->controller_listp;
1855 	if (libdiskmgt_str_eq(cp->name, name)) {
1856 	    if (can_remove_controller(cp, currp)) {
1857 		args->controller_listp = cp->next;
1858 		cache_free_controller(cp);
1859 	    }
1860 	    return;
1861 	}
1862 
1863 	prevp = cp;
1864 	cp = cp->next;
1865 	while (cp != NULL) {
1866 	    if (libdiskmgt_str_eq(cp->name, name)) {
1867 		if (can_remove_controller(cp, currp)) {
1868 		    prevp->next = cp->next;
1869 		    cache_free_controller(cp);
1870 		}
1871 		return;
1872 	    }
1873 	    prevp = cp;
1874 	    cp = cp->next;
1875 	}
1876 }
1877 
1878 /*
1879  * This is the standard strstr code modified for case independence.
1880  */
1881 static char *
1882 str_case_index(register char *s1, register char *s2)
1883 {
1884 	uint_t s2len = strlen(s2); /* length of the second string */
1885 
1886 	/* If the length of the second string is 0, return the first arg. */
1887 	if (s2len == 0) {
1888 	    return (s1);
1889 	}
1890 
1891 	while (strlen(s1) >= s2len) {
1892 	    if (strncasecmp(s1, s2, s2len) == 0) {
1893 		return (s1);
1894 	    }
1895 	    s1++;
1896 	}
1897 	return (NULL);
1898 }
1899