author | gw25295 |
Fri, 11 Apr 2008 18:36:28 -0700 | |
changeset 6423 | 437422a29d3a |
parent 2912 | 85ea316d9c18 |
child 6640 | c92ca9b95b9c |
permissions | -rw-r--r-- |
0 | 1 |
/* |
2 |
* CDDL HEADER START |
|
3 |
* |
|
4 |
* The contents of this file are subject to the terms of the |
|
2912
85ea316d9c18
PSARC 2005/399 Tamarack: Removable Media Enhancements in Solaris
artem
parents:
1415
diff
changeset
|
5 |
* Common Development and Distribution License (the "License"). |
85ea316d9c18
PSARC 2005/399 Tamarack: Removable Media Enhancements in Solaris
artem
parents:
1415
diff
changeset
|
6 |
* You may not use this file except in compliance with the License. |
0 | 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 |
/* |
|
6423 | 22 |
* Copyright 2008 Sun Microsystems, Inc. All rights reserved. |
0 | 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> |
|
6423 | 40 |
#include <sys/fs/zfs.h> |
0 | 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" |
|
1415 | 59 |
#define HOTPLUGGABLE_PROP "hotpluggable" |
0 | 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); |
|
6423 | 144 |
static int is_zvol(di_node_t node, di_minor_t minor); |
0 | 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 |
||
6423 | 573 |
} else if (di_minor_spectype(minor) == S_IFCHR && |
574 |
(is_drive(minor) || is_zvol(node, minor))) { |
|
0 | 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 { |
|
1415 | 979 |
/* not a "CD-ROM" or Floppy */ |
0 | 980 |
|
981 |
diskp->removable = get_prop(REMOVABLE_PROP, args->node); |
|
1415 | 982 |
|
983 |
if (diskp->removable == -1) { |
|
0 | 984 |
diskp->removable = 0; |
767 | 985 |
#if defined(i386) || defined(__amd64) |
0 | 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 |
|
6423 | 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 |
|
0 | 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 |
} |