xref: /titanic_51/usr/src/lib/libdiskmgt/common/findevs.c (revision 60c45ed01d4f99571d468c42f609d11a099fab1e)
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_next_phci(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 	new_array = (int *)calloc(cnt + 2, sizeof (int *));
777 	if (new_array == NULL) {
778 	    return (ENOMEM);
779 	}
780 
781 	/* copy the existing array */
782 	for (i = 0; i < cnt; i++) {
783 	    new_array[i] = pa[i];
784 	}
785 
786 	new_array[i] = p;
787 	new_array[i + 1] = -1;
788 
789 	free(pa);
790 	*parray = new_array;
791 
792 	return (0);
793 }
794 
795 static int
796 add_ptr2array(void *p, void ***parray)
797 {
798 	int		i;
799 	int		cnt;
800 	void		**pa;
801 	void		**new_array;
802 
803 	pa = *parray;
804 
805 	cnt = 0;
806 	if (pa != NULL) {
807 	    for (; pa[cnt]; cnt++);
808 	}
809 
810 	new_array = (void **)calloc(cnt + 2, sizeof (void *));
811 	if (new_array == NULL) {
812 	    return (ENOMEM);
813 	}
814 
815 	/* copy the existing array */
816 	for (i = 0; i < cnt; i++) {
817 	    new_array[i] = pa[i];
818 	}
819 
820 	new_array[i] = p;
821 	new_array[i + 1] = NULL;
822 
823 	free(pa);
824 	*parray = new_array;
825 
826 	return (0);
827 }
828 
829 /*
830  * This double checks that we aren't going to get into a bad situation.
831  * This function should never fail, but I just want to double check things.
832  */
833 static int
834 can_remove_controller(controller_t *cp, controller_t *currp)
835 {
836 	if (dm_debug) {
837 	    if (cp == currp) {
838 		(void) fprintf(stderr, "ERROR: remove current controller\n");
839 	    }
840 
841 	    if (cp->disks != NULL && cp->disks[0] != NULL) {
842 		(void) fprintf(stderr,
843 		    "ERROR: remove controller with disk ptrs\n");
844 	    }
845 
846 	    if (cp->paths != NULL && cp->paths[0] != NULL) {
847 		(void) fprintf(stderr,
848 		    "ERROR: remove controller with path ptrs\n");
849 	    }
850 	}
851 
852 	return (1);
853 }
854 
855 /*
856  * If we have a controller in the list that is really a path then we need to
857  * take that controller out of the list since nodes that are paths are not
858  * considered to be controllers.
859  */
860 static void
861 clean_paths(struct search_args *args)
862 {
863 	controller_t	*cp;
864 
865 	cp = args->controller_listp;
866 	while (cp != NULL) {
867 	    path_t	**pp;
868 
869 	    pp = cp->paths;
870 	    if (pp != NULL) {
871 		int i;
872 
873 		for (i = 0; pp[i]; i++) {
874 		    remove_invalid_controller(pp[i]->name, cp, args);
875 		}
876 	    }
877 	    cp = cp->next;
878 	}
879 }
880 
881 static disk_t *
882 create_disk(char *deviceid, char *kernel_name, struct search_args *args)
883 {
884 	disk_t	*diskp;
885 	char	*type;
886 	char	*prod_id;
887 	char	*vendor_id;
888 
889 	if (dm_debug) {
890 	    (void) fprintf(stderr, "INFO: create_disk %s\n", kernel_name);
891 	}
892 
893 	diskp = calloc(1, sizeof (disk_t));
894 	if (diskp == NULL) {
895 	    return (NULL);
896 	}
897 
898 	diskp->controllers = (controller_t **)
899 	    calloc(1, sizeof (controller_t *));
900 	if (diskp->controllers == NULL) {
901 	    cache_free_disk(diskp);
902 	    return (NULL);
903 	}
904 	diskp->controllers[0] = NULL;
905 
906 	diskp->devid = NULL;
907 	if (deviceid != NULL) {
908 	    if ((diskp->device_id = strdup(deviceid)) == NULL) {
909 		cache_free_disk(diskp);
910 		return (NULL);
911 	    }
912 
913 	    (void) devid_str_decode(deviceid, &(diskp->devid), NULL);
914 	}
915 
916 	if (kernel_name != NULL) {
917 	    diskp->kernel_name = strdup(kernel_name);
918 	    if (diskp->kernel_name == NULL) {
919 		cache_free_disk(diskp);
920 		return (NULL);
921 	    }
922 	}
923 
924 	diskp->paths = NULL;
925 	diskp->aliases = NULL;
926 
927 	diskp->cd_rom = 0;
928 	diskp->rpm = 0;
929 	type = di_minor_nodetype(args->minor);
930 
931 	prod_id = get_str_prop(PROD_ID_PROP, args->node);
932 	if (prod_id != NULL) {
933 	    if ((diskp->product_id = strdup(prod_id)) == NULL) {
934 		cache_free_disk(diskp);
935 		return (NULL);
936 	    }
937 	} else {
938 	    prod_id = get_str_prop(PROD_ID_USB_PROP, args->node);
939 	    if (prod_id != NULL) {
940 		if ((diskp->product_id = strdup(prod_id)) == NULL) {
941 		    cache_free_disk(diskp);
942 		    return (NULL);
943 		}
944 	    }
945 	}
946 
947 	vendor_id = get_str_prop(VENDOR_ID_PROP, args->node);
948 	if (vendor_id != NULL) {
949 	    if ((diskp->vendor_id = strdup(vendor_id)) == NULL) {
950 		cache_free_disk(diskp);
951 		return (NULL);
952 	    }
953 	} else {
954 	    vendor_id = get_str_prop(VENDOR_ID_PROP, args->node);
955 	    if (vendor_id != NULL) {
956 		if ((diskp->vendor_id = strdup(vendor_id)) == NULL) {
957 		    cache_free_disk(diskp);
958 		    return (NULL);
959 		}
960 	    }
961 	}
962 
963 	/*
964 	 * DVD, CD-ROM, CD-RW, MO, etc. are all reported as CD-ROMS.
965 	 * We try to use uscsi later to determine the real type.
966 	 * The cd_rom flag tells us that the kernel categorized the drive
967 	 * as a CD-ROM.  We leave the drv_type as UKNOWN for now.
968 	 * The combination of the cd_rom flag being set with the drv_type of
969 	 * unknown is what triggers the uscsi probe in drive.c.
970 	 */
971 	if (disk_is_cdrom(type)) {
972 	    diskp->drv_type = DM_DT_UNKNOWN;
973 	    diskp->cd_rom = 1;
974 	    diskp->removable = 1;
975 	} else if (libdiskmgt_str_eq(type, DDI_NT_FD)) {
976 	    diskp->drv_type = DM_DT_FLOPPY;
977 	    diskp->removable = 1;
978 	} else {
979 		/* not a "CD-ROM" or Floppy */
980 
981 	    diskp->removable = get_prop(REMOVABLE_PROP, args->node);
982 
983 	    if (diskp->removable == -1) {
984 		diskp->removable = 0;
985 #if defined(i386) || defined(__amd64)
986 		/*
987 		 * x86 does not have removable property.  Check for common
988 		 * removable drives, zip & jaz, and mark those correctly.
989 		 */
990 		if (vendor_id != NULL && prod_id != NULL) {
991 		    if (str_case_index(vendor_id, "iomega") != NULL) {
992 			if (str_case_index(prod_id, "jaz") != NULL) {
993 			    diskp->removable = 1;
994 			} else if (str_case_index(prod_id, "zip") != NULL) {
995 			    diskp->removable = 1;
996 			}
997 		    }
998 		}
999 #endif
1000 	    }
1001 
1002 	    if (diskp->removable) {
1003 		/*
1004 		 * For removable jaz or zip drives there is no way
1005 		 * to get the drive type unless media is inserted, so we
1006 		 * look at the product-id for a hint.
1007 		 */
1008 
1009 		diskp->drv_type = DM_DT_UNKNOWN;
1010 
1011 		if (prod_id != NULL) {
1012 		    if (str_case_index(prod_id, "jaz") != NULL) {
1013 			diskp->drv_type = DM_DT_JAZ;
1014 		    } else if (str_case_index(prod_id, "zip") != NULL) {
1015 			diskp->drv_type = DM_DT_ZIP;
1016 		    }
1017 		}
1018 	    } else {
1019 		diskp->drv_type = DM_DT_FIXED;
1020 	    }
1021 	}
1022 
1023 	diskp->next = args->disk_listp;
1024 	args->disk_listp = diskp;
1025 
1026 	return (diskp);
1027 }
1028 
1029 static char *
1030 ctype(di_node_t node, di_minor_t minor)
1031 {
1032 	char	*type;
1033 	char	*name;
1034 
1035 	type = di_minor_nodetype(minor);
1036 	name = di_node_name(node);
1037 
1038 	/* IDE disks use SCSI nexus as the type, so handle this special case */
1039 	if (libdiskmgt_str_eq(name, "ide")) {
1040 	    return (DM_CTYPE_ATA);
1041 	}
1042 
1043 	if (libdiskmgt_str_eq(di_minor_name(minor), "scsa2usb")) {
1044 	    return (DM_CTYPE_USB);
1045 	}
1046 
1047 	if (libdiskmgt_str_eq(type, DDI_NT_SCSI_NEXUS) ||
1048 	    libdiskmgt_str_eq(type, DDI_NT_SCSI_ATTACHMENT_POINT)) {
1049 	    return (DM_CTYPE_SCSI);
1050 	}
1051 
1052 	if (libdiskmgt_str_eq(type, DDI_NT_FC_ATTACHMENT_POINT)) {
1053 	    return (DM_CTYPE_FIBRE);
1054 	}
1055 
1056 	if (libdiskmgt_str_eq(type, DDI_NT_NEXUS) &&
1057 	    libdiskmgt_str_eq(name, "fp")) {
1058 	    return (DM_CTYPE_FIBRE);
1059 	}
1060 
1061 	if (libdiskmgt_str_eq(type, DDI_PSEUDO) &&
1062 	    libdiskmgt_str_eq(name, "ide")) {
1063 	    return (DM_CTYPE_ATA);
1064 	}
1065 
1066 	return (DM_CTYPE_UNKNOWN);
1067 }
1068 
1069 static boolean_t
1070 disk_is_cdrom(char *type)
1071 {
1072 
1073 	int		type_index;
1074 
1075 	for (type_index = 0; cdromtypes[type_index] != NULL; type_index++) {
1076 	    if (libdiskmgt_str_eq(type, cdromtypes[type_index])) {
1077 		return (B_TRUE);
1078 	    }
1079 	}
1080 
1081 	return (B_FALSE);
1082 }
1083 
1084 static alias_t *
1085 find_alias(disk_t *diskp, char *kernel_name)
1086 {
1087 	alias_t	*ap;
1088 
1089 	ap = diskp->aliases;
1090 	while (ap != NULL) {
1091 	    if (libdiskmgt_str_eq(ap->kstat_name, kernel_name)) {
1092 		return (ap);
1093 	    }
1094 	    ap = ap->next;
1095 	}
1096 
1097 	return (NULL);
1098 }
1099 
1100 static bus_t *
1101 find_bus(struct search_args *args, char *name)
1102 {
1103 	bus_t *listp;
1104 
1105 	listp = args->bus_listp;
1106 	while (listp != NULL) {
1107 	    if (libdiskmgt_str_eq(listp->name, name)) {
1108 		return (listp);
1109 	    }
1110 
1111 	    listp = listp->next;
1112 	}
1113 
1114 	return (NULL);
1115 }
1116 
1117 static controller_t *
1118 find_controller(struct search_args *args, char *name)
1119 {
1120 	controller_t *listp;
1121 
1122 	listp = args->controller_listp;
1123 	while (listp != NULL) {
1124 	    if (libdiskmgt_str_eq(listp->name, name)) {
1125 		return (listp);
1126 	    }
1127 
1128 	    listp = listp->next;
1129 	}
1130 
1131 	return (NULL);
1132 }
1133 
1134 static int
1135 fix_cluster_devpath(di_devlink_t devlink, void *arg)
1136 {
1137 	int			fd;
1138 	struct search_args	*args;
1139 	char			*devlink_path;
1140 	disk_t			*diskp = NULL;
1141 	alias_t			*ap = NULL;
1142 
1143 	/*
1144 	 * The devlink_path is of the form /dev/did/rdsk/d1s0.
1145 	 */
1146 
1147 	args =	(struct search_args *)arg;
1148 
1149 	/* Find the disk by the deviceid we read from the cluster disk. */
1150 	devlink_path = (char *)di_devlink_path(devlink);
1151 	if (devlink_path == NULL) {
1152 	    return (DI_WALK_CONTINUE);
1153 	}
1154 
1155 	if ((fd = open(devlink_path, O_RDONLY|O_NDELAY)) >= 0) {
1156 	    ddi_devid_t	devid;
1157 
1158 	    if (dm_debug > 1) {
1159 		(void) fprintf(stderr, "INFO:     cluster devpath %s\n",
1160 		    devlink_path);
1161 	    }
1162 
1163 	    if (devid_get(fd, &devid) == 0) {
1164 		char *minor;
1165 		char *devidstr;
1166 
1167 		minor = di_minor_name(args->minor);
1168 
1169 		if ((devidstr = devid_str_encode(devid, minor)) != NULL) {
1170 		    diskp = get_disk_by_deviceid(args->disk_listp, devidstr);
1171 
1172 			/*
1173 			 * This really shouldn't happen, since we should have
1174 			 * found all of the disks during our first pass through
1175 			 * the dev tree, but just in case...
1176 			 */
1177 			if (diskp == NULL) {
1178 			    if (dm_debug > 1) {
1179 				(void) fprintf(stderr,
1180 				    "INFO:     cluster create disk\n");
1181 			    }
1182 
1183 			    diskp = create_disk(devidstr, NULL, args);
1184 			    if (diskp == NULL) {
1185 				args->dev_walk_status = ENOMEM;
1186 			    }
1187 
1188 			    /* add the controller relationship */
1189 			    if (args->dev_walk_status == 0) {
1190 				if (add_disk2controller(diskp, args) != 0) {
1191 				    args->dev_walk_status = ENOMEM;
1192 				}
1193 			    }
1194 
1195 			    if (new_alias(diskp, NULL, devlink_path, args)
1196 				!= 0) {
1197 				args->dev_walk_status = ENOMEM;
1198 			    }
1199 			}
1200 
1201 			devid_str_free(devidstr);
1202 		}
1203 
1204 		devid_free(devid);
1205 	    }
1206 	    (void) close(fd);
1207 	}
1208 
1209 
1210 	if (diskp != NULL) {
1211 	    if (dm_debug > 1) {
1212 		(void) fprintf(stderr, "INFO:     cluster found disk\n");
1213 	    }
1214 
1215 	    ap = diskp->aliases;
1216 	}
1217 
1218 	if (ap != NULL) {
1219 	    /* NOTE: if ap->next != NULL have cluster disks w/ multiple paths */
1220 
1221 	    if (!ap->cluster) {
1222 		char	*basep;
1223 		char	*namep;
1224 		int	cnt = 0;
1225 		int	size;
1226 		char	alias[MAXPATHLEN];
1227 
1228 		/*
1229 		 * First time; save the /dev/rdsk devpaths and update the
1230 		 * alias info with the new alias name.
1231 		 */
1232 		ap->orig_paths = ap->devpaths;
1233 		ap->devpaths = NULL;
1234 
1235 		free(ap->alias);
1236 
1237 		/* get the new cluster alias name */
1238 		basep = strrchr(devlink_path, '/');
1239 		if (basep == NULL) {
1240 		    basep = devlink_path;
1241 		} else {
1242 		    basep++;
1243 		}
1244 
1245 		size = sizeof (alias) - 1;
1246 		namep = alias;
1247 		while (*basep != 0 && *basep != 's' && cnt < size) {
1248 		    *namep++ = *basep++;
1249 		    cnt++;
1250 		}
1251 		*namep = 0;
1252 
1253 		if ((ap->alias = strdup(alias)) == NULL) {
1254 		    args->dev_walk_status = ENOMEM;
1255 		}
1256 
1257 		ap->cluster = 1;
1258 	    }
1259 
1260 	    if (new_devpath(ap, devlink_path) != 0) {
1261 		args->dev_walk_status = ENOMEM;
1262 	    }
1263 	}
1264 
1265 	return (DI_WALK_CONTINUE);
1266 }
1267 
1268 /*
1269  * Check if we have the drive in our list, based upon the device id.
1270  * We got the device id from the dev tree walk.  This is encoded
1271  * using devid_str_encode(3DEVID).   In order to check the device ids we need
1272  * to use the devid_compare(3DEVID) function, so we need to decode the
1273  * string representation of the device id.
1274  */
1275 static disk_t *
1276 get_disk_by_deviceid(disk_t *listp, char *devidstr)
1277 {
1278 	ddi_devid_t	devid;
1279 
1280 	if (devidstr == NULL || devid_str_decode(devidstr, &devid, NULL) != 0) {
1281 	    return (NULL);
1282 	}
1283 
1284 	while (listp != NULL) {
1285 	    if (listp->devid != NULL &&
1286 		devid_compare(listp->devid, devid) == 0) {
1287 		break;
1288 	    }
1289 
1290 	    listp = listp->next;
1291 	}
1292 
1293 	devid_free(devid);
1294 
1295 	return (listp);
1296 }
1297 
1298 /*
1299  * Get the base disk name with no path prefix and no slice (if there is one).
1300  * The name parameter should be big enough to hold the name.
1301  * This handles diskette names ok (/dev/rdiskette0) since there is no slice,
1302  * and converts the raw diskette name.
1303  * But, we don't know how to strip off the slice from third party drive
1304  * names.  That just means that their drive name will include a slice on
1305  * it.
1306  */
1307 static void
1308 get_disk_name_from_path(char *path, char *name, int size)
1309 {
1310 	char		*basep;
1311 	int		cnt = 0;
1312 
1313 	basep = strrchr(path, '/');
1314 	if (basep == NULL) {
1315 	    basep = path;
1316 	} else {
1317 	    basep++;
1318 	}
1319 
1320 	size = size - 1;	/* leave room for terminating 0 */
1321 
1322 	if (is_ctds(basep)) {
1323 	    while (*basep != 0 && *basep != 's' && cnt < size) {
1324 		*name++ = *basep++;
1325 		cnt++;
1326 	    }
1327 	    *name = 0;
1328 	} else {
1329 	    if (strncmp(basep, FLOPPY_NAME, sizeof (FLOPPY_NAME) - 1) == 0) {
1330 		/*
1331 		 * a floppy, convert rdiskette name to diskette name,
1332 		 * by skipping over the 'r' for raw diskette
1333 		 */
1334 		basep++;
1335 	    }
1336 
1337 	    /* not a ctds name, just copy it */
1338 	    (void) strlcpy(name, basep, size);
1339 	}
1340 }
1341 
1342 static char *
1343 get_byte_prop(char *prop_name, di_node_t node)
1344 {
1345 	int	cnt;
1346 	uchar_t	*bytes;
1347 	int	i;
1348 	char	str[MAXPATHLEN];
1349 
1350 	cnt = di_prop_lookup_bytes(DDI_DEV_T_ANY, node, prop_name, &bytes);
1351 	if (cnt < 1) {
1352 	    return (NULL);
1353 	}
1354 
1355 	str[0] = 0;
1356 	for (i = 0; i < cnt; i++) {
1357 	    char bstr[8];	/* a byte is only 2 hex chars + null */
1358 
1359 	    (void) snprintf(bstr, sizeof (bstr), "%.2x", bytes[i]);
1360 	    (void) strlcat(str, bstr, sizeof (str));
1361 	}
1362 	return (strdup(str));
1363 }
1364 
1365 static di_node_t
1366 get_parent_bus(di_node_t node, struct search_args *args)
1367 {
1368 	di_node_t pnode;
1369 
1370 	pnode = di_parent_node(node);
1371 	if (pnode == DI_NODE_NIL) {
1372 	    return (NULL);
1373 	}
1374 
1375 	if (bus_type(pnode, di_minor_next(pnode, NULL), args->ph) != NULL) {
1376 	    return (pnode);
1377 	}
1378 
1379 	return (get_parent_bus(pnode, args));
1380 }
1381 
1382 static int
1383 get_prom_int(char *prop_name, di_node_t node, di_prom_handle_t ph)
1384 {
1385 	int *n;
1386 
1387 	if (di_prom_prop_lookup_ints(ph, node, prop_name, &n) == 1) {
1388 	    return (*n);
1389 	}
1390 
1391 	return (0);
1392 }
1393 
1394 static char *
1395 get_prom_str(char *prop_name, di_node_t node, di_prom_handle_t ph)
1396 {
1397 	char *str;
1398 
1399 	if (di_prom_prop_lookup_strings(ph, node, prop_name, &str) == 1) {
1400 	    return (str);
1401 	}
1402 
1403 	return (NULL);
1404 }
1405 
1406 /*
1407  * Get one of the positive int or boolean properties.
1408  */
1409 static int
1410 get_prop(char *prop_name, di_node_t node)
1411 {
1412 	int num;
1413 	int *ip;
1414 
1415 	if ((num = di_prop_lookup_ints(DDI_DEV_T_ANY, node, prop_name, &ip))
1416 	    >= 0) {
1417 	    if (num == 0) {
1418 		/* boolean */
1419 		return (1);
1420 	    } else if (num == 1) {
1421 		/* single int */
1422 		return (*ip);
1423 	    }
1424 	}
1425 
1426 	return (-1);
1427 }
1428 
1429 static char *
1430 get_str_prop(char *prop_name, di_node_t node)
1431 {
1432 	char *str;
1433 
1434 	if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, prop_name, &str) == 1) {
1435 	    return (str);
1436 	}
1437 
1438 	return (NULL);
1439 }
1440 
1441 /*
1442  * Check if we have the drive in our list, based upon the device id, if the
1443  * drive has a device id, or the kernel name, if it doesn't have a device id.
1444  */
1445 static int
1446 have_disk(struct search_args *args, char *devidstr, char *kernel_name,
1447     disk_t **diskp)
1448 {
1449 	disk_t *listp;
1450 
1451 	*diskp = NULL;
1452 	listp = args->disk_listp;
1453 	if (devidstr != NULL) {
1454 	    if ((*diskp = get_disk_by_deviceid(listp, devidstr)) != NULL) {
1455 		return (1);
1456 	    }
1457 
1458 	} else {
1459 	    /* no devid, try matching the kernel names on the drives */
1460 	    while (listp != NULL) {
1461 		if (libdiskmgt_str_eq(kernel_name, listp->kernel_name)) {
1462 		    *diskp = listp;
1463 		    return (1);
1464 		}
1465 		listp = listp->next;
1466 	    }
1467 	}
1468 
1469 	return (0);
1470 }
1471 
1472 static char *
1473 bus_type(di_node_t node, di_minor_t minor, di_prom_handle_t ph)
1474 {
1475 	char	*type;
1476 	int	i;
1477 
1478 	type = get_prom_str("device_type", node, ph);
1479 	if (type == NULL) {
1480 	    type = di_node_name(node);
1481 	}
1482 
1483 	for (i = 0; bustypes[i]; i++) {
1484 	    if (libdiskmgt_str_eq(type, bustypes[i])) {
1485 		return (type);
1486 	    }
1487 	}
1488 
1489 	if (minor != NULL && strcmp(di_minor_nodetype(minor),
1490 	    DDI_NT_USB_ATTACHMENT_POINT) == 0) {
1491 	    return ("usb");
1492 	}
1493 
1494 	return (NULL);
1495 }
1496 
1497 static int
1498 is_cluster_disk(di_node_t node, di_minor_t minor)
1499 {
1500 	if (di_minor_spectype(minor) == S_IFCHR &&
1501 	    libdiskmgt_str_eq(di_minor_nodetype(minor), DDI_PSEUDO) &&
1502 	    libdiskmgt_str_eq(di_node_name(node), CLUSTER_DEV)) {
1503 	    return (1);
1504 	}
1505 
1506 	return (0);
1507 }
1508 
1509 /*
1510  * If the input name is in c[t]ds format then return 1, otherwise return 0.
1511  */
1512 static int
1513 is_ctds(char *name)
1514 {
1515 	char	*p;
1516 
1517 	p = name;
1518 
1519 	if (*p++ != 'c') {
1520 	    return (0);
1521 	}
1522 	/* skip controller digits */
1523 	while (isdigit(*p)) {
1524 	    p++;
1525 	}
1526 
1527 	/* handle optional target */
1528 	if (*p == 't') {
1529 	    p++;
1530 	    /* skip over target */
1531 	    while (isdigit(*p) || isupper(*p)) {
1532 		p++;
1533 	    }
1534 	}
1535 
1536 	if (*p++ != 'd') {
1537 	    return (0);
1538 	}
1539 	while (isdigit(*p)) {
1540 	    p++;
1541 	}
1542 
1543 	if (*p++ != 's') {
1544 	    return (0);
1545 	}
1546 
1547 	/* check the slice number */
1548 	while (isdigit(*p)) {
1549 	    p++;
1550 	}
1551 
1552 	if (*p != 0) {
1553 	    return (0);
1554 	}
1555 
1556 	return (1);
1557 }
1558 
1559 static int
1560 is_drive(di_minor_t minor)
1561 {
1562 	char	*type;
1563 	int	type_index;
1564 
1565 	type = di_minor_nodetype(minor);
1566 	type_index = 0;
1567 
1568 	while (disktypes[type_index] != NULL) {
1569 	    if (libdiskmgt_str_eq(type, disktypes[type_index])) {
1570 		return (1);
1571 	    }
1572 	    type_index++;
1573 	}
1574 
1575 	return (0);
1576 }
1577 
1578 static int
1579 is_zvol(di_node_t node, di_minor_t minor)
1580 {
1581 	if ((strncmp(di_node_name(node), ZFS_DRIVER, 3) == 0) &&
1582 	    di_minor_devt(minor))
1583 		return (1);
1584 	return (0);
1585 }
1586 
1587 static int
1588 is_HBA(di_node_t node, di_minor_t minor)
1589 {
1590 	char	*type;
1591 	char	*name;
1592 	int	type_index;
1593 
1594 	type = di_minor_nodetype(minor);
1595 	type_index = 0;
1596 
1597 	while (ctrltypes[type_index] != NULL) {
1598 	    if (libdiskmgt_str_eq(type, ctrltypes[type_index])) {
1599 		return (1);
1600 	    }
1601 	    type_index++;
1602 	}
1603 
1604 	name = di_node_name(node);
1605 	if (libdiskmgt_str_eq(type, DDI_PSEUDO) &&
1606 	    libdiskmgt_str_eq(name, "ide")) {
1607 	    return (1);
1608 	}
1609 
1610 	return (0);
1611 }
1612 
1613 static int
1614 new_alias(disk_t *diskp, char *kernel_name, char *devlink_path,
1615 	struct search_args *args)
1616 {
1617 	alias_t		*aliasp;
1618 	char		alias[MAXPATHLEN];
1619 	di_node_t	pnode;
1620 
1621 	aliasp = malloc(sizeof (alias_t));
1622 	if (aliasp == NULL) {
1623 	    return (ENOMEM);
1624 	}
1625 
1626 	aliasp->alias = NULL;
1627 	aliasp->kstat_name = NULL;
1628 	aliasp->wwn = NULL;
1629 	aliasp->devpaths = NULL;
1630 	aliasp->orig_paths = NULL;
1631 
1632 	get_disk_name_from_path(devlink_path, alias, sizeof (alias));
1633 
1634 	aliasp->alias = strdup(alias);
1635 	if (aliasp->alias == NULL) {
1636 	    cache_free_alias(aliasp);
1637 	    return (ENOMEM);
1638 	}
1639 
1640 	if (kernel_name != NULL) {
1641 	    aliasp->kstat_name = strdup(kernel_name);
1642 	    if (aliasp->kstat_name == NULL) {
1643 		cache_free_alias(aliasp);
1644 		return (ENOMEM);
1645 	    }
1646 	} else {
1647 	    aliasp->kstat_name = NULL;
1648 	}
1649 
1650 	aliasp->cluster = 0;
1651 	aliasp->lun = get_prop(DM_LUN, args->node);
1652 	aliasp->target = get_prop(DM_TARGET, args->node);
1653 	aliasp->wwn = get_byte_prop(WWN_PROP, args->node);
1654 
1655 	pnode = di_parent_node(args->node);
1656 	if (pnode != DI_NODE_NIL) {
1657 	    char prop_name[MAXPROPLEN];
1658 
1659 	    (void) snprintf(prop_name, sizeof (prop_name),
1660 		"target%d-sync-speed", aliasp->target);
1661 	    diskp->sync_speed = get_prop(prop_name, pnode);
1662 	    (void) snprintf(prop_name, sizeof (prop_name), "target%d-wide",
1663 		aliasp->target);
1664 	    diskp->wide = get_prop(prop_name, pnode);
1665 	}
1666 
1667 	if (new_devpath(aliasp, devlink_path) != 0) {
1668 	    cache_free_alias(aliasp);
1669 	    return (ENOMEM);
1670 	}
1671 
1672 	aliasp->next = diskp->aliases;
1673 	diskp->aliases = aliasp;
1674 
1675 	return (0);
1676 }
1677 
1678 /*
1679  * Append the new devpath to the end of the devpath list.  This is important
1680  * since we may want to use the order of the devpaths to match up the vtoc
1681  * entries.
1682  */
1683 static int
1684 new_devpath(alias_t *ap, char *devpath)
1685 {
1686 	slice_t	*newdp;
1687 	slice_t *alistp;
1688 
1689 	/*
1690 	 * First, search the alias list to be sure that this devpath is
1691 	 * not already there.
1692 	 */
1693 
1694 	for (alistp = ap->devpaths; alistp != NULL; alistp = alistp->next) {
1695 	    if (libdiskmgt_str_eq(alistp->devpath, devpath)) {
1696 		return (0);
1697 	    }
1698 	}
1699 
1700 	/*
1701 	 * Otherwise, not found so add this new devpath to the list.
1702 	 */
1703 
1704 	newdp = malloc(sizeof (slice_t));
1705 	if (newdp == NULL) {
1706 	    return (ENOMEM);
1707 	}
1708 
1709 	newdp->devpath = strdup(devpath);
1710 	if (newdp->devpath == NULL) {
1711 	    free(newdp);
1712 	    return (ENOMEM);
1713 	}
1714 	newdp->slice_num = -1;
1715 	newdp->next = NULL;
1716 
1717 	if (ap->devpaths == NULL) {
1718 	    ap->devpaths = newdp;
1719 	} else {
1720 	    /* append the devpath to the end of the list */
1721 	    slice_t	*dp;
1722 
1723 	    dp = ap->devpaths;
1724 	    while (dp->next != NULL) {
1725 		dp = dp->next;
1726 	    }
1727 
1728 	    dp->next = newdp;
1729 	}
1730 
1731 	return (0);
1732 }
1733 
1734 static path_t *
1735 new_path(controller_t *cp, disk_t *dp, di_node_t node, di_path_state_t st,
1736 	char *wwn)
1737 {
1738 	char		*devpath;
1739 	path_t		*pp;
1740 	di_minor_t	minor;
1741 
1742 	/* Special handling for fp attachment node. */
1743 	if (strcmp(di_node_name(node), "fp") == 0) {
1744 	    di_node_t pnode;
1745 
1746 	    pnode = di_parent_node(node);
1747 	    if (pnode != DI_NODE_NIL) {
1748 		node = pnode;
1749 	    }
1750 	}
1751 
1752 	devpath = di_devfs_path(node);
1753 
1754 	/* check if the path is already there */
1755 	pp = NULL;
1756 	if (cp->paths != NULL) {
1757 	    int i;
1758 
1759 	    for (i = 0; cp->paths[i]; i++) {
1760 		if (libdiskmgt_str_eq(devpath, cp->paths[i]->name)) {
1761 		    pp = cp->paths[i];
1762 		    break;
1763 		}
1764 	    }
1765 	}
1766 
1767 	if (pp != NULL) {
1768 	    /* the path exists, add this disk to it */
1769 
1770 	    di_devfs_path_free((void *) devpath);
1771 
1772 	    if (!add_disk2path(dp, pp, st, wwn)) {
1773 		return (NULL);
1774 	    }
1775 
1776 	    return (pp);
1777 	}
1778 
1779 	/* create a new path */
1780 
1781 	pp = calloc(1, sizeof (path_t));
1782 	if (pp == NULL) {
1783 	    di_devfs_path_free((void *) devpath);
1784 	    return (NULL);
1785 	}
1786 
1787 	pp->name = strdup(devpath);
1788 	di_devfs_path_free((void *) devpath);
1789 	if (pp->name == NULL) {
1790 	    cache_free_path(pp);
1791 	    return (NULL);
1792 	}
1793 
1794 	/* add the disk to the path */
1795 	if (!add_disk2path(dp, pp, st, wwn)) {
1796 	    return (NULL);
1797 	}
1798 
1799 	/* add the path to the controller */
1800 	if (add_ptr2array(pp, (void ***)&cp->paths) != 0) {
1801 	    cache_free_path(pp);
1802 	    return (NULL);
1803 	}
1804 
1805 	/* add the controller to the path */
1806 	pp->controller = cp;
1807 
1808 	minor = di_minor_next(node, NULL);
1809 	if (minor != NULL) {
1810 	    pp->ctype = ctype(node, minor);
1811 	} else {
1812 	    pp->ctype = DM_CTYPE_UNKNOWN;
1813 	}
1814 
1815 	return (pp);
1816 }
1817 
1818 /*
1819  * We pass in the current controller pointer (currp) so we can double check
1820  * that we aren't corrupting the list by removing the element we are on.  This
1821  * should never happen, but it doesn't hurt to double check.
1822  */
1823 static void
1824 remove_invalid_controller(char *name, controller_t *currp,
1825     struct search_args *args)
1826 {
1827 	controller_t *cp;
1828 	bus_t *bp;
1829 	controller_t *prevp;
1830 
1831 	bp = args->bus_listp;
1832 	while (bp != NULL) {
1833 	    int i;
1834 
1835 	    for (i = 0; bp->controllers[i]; i++) {
1836 		if (libdiskmgt_str_eq(bp->controllers[i]->name, name)) {
1837 		    int j;
1838 
1839 		    /* remove pointer to invalid controller (it is a path) */
1840 		    for (j = i; bp->controllers[j]; j++) {
1841 			bp->controllers[j] = bp->controllers[j + 1];
1842 		    }
1843 		}
1844 	    }
1845 	    bp = bp->next;
1846 	}
1847 
1848 	if (args->controller_listp == NULL) {
1849 	    return;
1850 	}
1851 
1852 	cp = args->controller_listp;
1853 	if (libdiskmgt_str_eq(cp->name, name)) {
1854 	    if (can_remove_controller(cp, currp)) {
1855 		args->controller_listp = cp->next;
1856 		cache_free_controller(cp);
1857 	    }
1858 	    return;
1859 	}
1860 
1861 	prevp = cp;
1862 	cp = cp->next;
1863 	while (cp != NULL) {
1864 	    if (libdiskmgt_str_eq(cp->name, name)) {
1865 		if (can_remove_controller(cp, currp)) {
1866 		    prevp->next = cp->next;
1867 		    cache_free_controller(cp);
1868 		}
1869 		return;
1870 	    }
1871 	    prevp = cp;
1872 	    cp = cp->next;
1873 	}
1874 }
1875 
1876 /*
1877  * This is the standard strstr code modified for case independence.
1878  */
1879 static char *
1880 str_case_index(register char *s1, register char *s2)
1881 {
1882 	uint_t s2len = strlen(s2); /* length of the second string */
1883 
1884 	/* If the length of the second string is 0, return the first arg. */
1885 	if (s2len == 0) {
1886 	    return (s1);
1887 	}
1888 
1889 	while (strlen(s1) >= s2len) {
1890 	    if (strncasecmp(s1, s2, s2len) == 0) {
1891 		return (s1);
1892 	    }
1893 	    s1++;
1894 	}
1895 	return (NULL);
1896 }
1897