cmd: remove sparc-only virtinfo
[unleashed.git] / usr / src / cmd / picl / plugins / sun4u / snowbird / frutree / piclscsi.c
blob25280a5644a924e0c6522d54320d158ee5fc309d
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 /* implementation specific to scsi nodes probing */
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <syslog.h>
34 #include <stdlib.h>
35 #include <sys/param.h>
36 #include <config_admin.h>
37 #include <string.h>
38 #include <strings.h>
39 #include <picl.h>
40 #include <picltree.h>
41 #include <libintl.h>
42 #include <libdevinfo.h>
43 #include <sys/types.h>
44 #include <picldefs.h>
45 #include "piclfrutree.h"
47 #define SCSI_SLOT "scsi-bus"
48 #define SCSI_LOC_FORMAT "t%dd0"
49 #define TARGET "target"
50 #define CLASS "class"
51 #define BUF_SIZE 256
53 #define SCSI_INITIATOR_ID 7
54 #define DRV_TYPE_DSK 1
55 #define DRV_TYPE_TAPE 2
56 #define NUM_DSK_TARGS 15
58 * No support for wide tapes for now.
59 * If required wide support, set this to 8
60 * See st.conf.
62 #define NUM_TAPE_TARGS 7
64 #define DIRLINK_DSK "dsk"
65 #define DIRLINK_RMT "rmt"
66 #define DRV_SCSI_DSK "sd"
67 #define DRV_SCSI_TAPE "st"
68 #define NULL_ENTRY 0
70 /* currently supported directory strings for SCSI FRUs in cfgadm APs */
71 static char *scsi_dirlink_names[] = { DIRLINK_DSK, DIRLINK_RMT, NULL_ENTRY};
72 /* currently supported SCSI FRU drivers */
73 static struct scsi_drv_info {
74 char *drv_name;
75 uint8_t num_targets;
76 uint8_t drv_type;
77 } scsi_drv[] = {
78 DRV_SCSI_DSK, NUM_DSK_TARGS, DRV_TYPE_DSK,
79 DRV_SCSI_TAPE, NUM_TAPE_TARGS, DRV_TYPE_TAPE,
80 NULL_ENTRY, NULL_ENTRY, NULL_ENTRY
83 /* the following defs are based on defines in scsi cfgadm plugin */
84 #define CDROM "CD-ROM"
85 #define RMM "tape"
86 #define DISK "disk"
88 extern boolean_t is_location_present_in_subtree(frutree_frunode_t *,
89 const char *, const char *);
90 extern picl_errno_t create_children(frutree_frunode_t *, char *, char *,
91 int, char *, boolean_t);
92 extern char *strtok_r(char *s1, const char *s2, char **lasts);
93 extern boolean_t frutree_connects_initiated;
94 extern int frutree_debug;
96 typedef struct node {
97 struct node *next;
98 cfga_list_data_t *data;
99 } node_t;
101 typedef struct linked_list {
102 node_t *first;
103 int num_nodes;
104 } plist_t;
106 typedef struct scsi_info {
107 frutree_frunode_t *frup;
108 cfga_list_data_t *cfgalist;
109 plist_t *list;
110 int num_list;
111 boolean_t compare_cfgadm;
112 int geo_addr;
113 } scsi_info_t;
115 static plist_t *scsi_list = NULL;
116 static cfga_list_data_t *cfglist = NULL;
117 static int nlist = 0;
119 static void
120 free_list(plist_t *list)
122 node_t *tmp = NULL, *tmp1 = NULL;
124 if (list == NULL)
125 return;
126 tmp = list->first;
127 while (tmp != NULL) {
128 free(tmp->data);
129 tmp1 = tmp->next;
130 free(tmp);
131 tmp = tmp1;
136 * This routine gets the list of scsi controllers present
138 static cfga_err_t
139 populate_controllers_list(plist_t *cntrl_list, cfga_list_data_t *list, int num)
141 int i;
142 node_t *nodeptr = NULL;
143 cfga_list_data_t *temp = NULL;
145 if (cntrl_list == NULL || list == NULL) {
146 return (CFGA_ATTR_INVAL);
149 cntrl_list->first = NULL;
150 cntrl_list->num_nodes = 0;
152 if (num == 0) {
153 return (CFGA_OK);
156 for (i = 0; i < num; i++) {
157 if (strcmp(list[i].ap_type, SCSI_SLOT) != 0) {
158 continue;
161 /* scsi controller */
162 temp = (cfga_list_data_t *)malloc(sizeof (cfga_list_data_t));
163 if (temp == NULL) {
164 return (CFGA_ERROR);
166 (void) memcpy(temp, &list[i], sizeof (cfga_list_data_t));
168 nodeptr = (node_t *)malloc(sizeof (node_t));
169 if (nodeptr == NULL) {
170 free(temp);
171 return (CFGA_ERROR);
173 nodeptr->data = temp;
174 nodeptr->next = NULL;
176 /* append to the list */
177 if (cntrl_list->first == NULL) {
178 cntrl_list->first = nodeptr;
179 cntrl_list->num_nodes++;
180 } else {
181 nodeptr->next = cntrl_list->first;
182 cntrl_list->first = nodeptr;
183 cntrl_list->num_nodes++;
186 return (CFGA_OK);
189 picl_errno_t
190 scsi_info_init()
192 cfga_err_t ap_list_err;
194 ap_list_err = config_list_ext(0, NULL, &cfglist, &nlist, NULL,
195 NULL, NULL, CFGA_FLAG_LIST_ALL);
197 if (ap_list_err != CFGA_OK) {
198 if (ap_list_err == CFGA_NOTSUPP) {
199 return (PICL_SUCCESS);
200 } else {
201 return (PICL_FAILURE);
205 scsi_list = (plist_t *)malloc(sizeof (plist_t));
206 if (scsi_list == NULL) {
207 free(cfglist);
208 return (PICL_NOSPACE);
211 ap_list_err = populate_controllers_list(scsi_list, cfglist, nlist);
212 if (ap_list_err != CFGA_OK) {
213 free(cfglist);
214 free(scsi_list);
215 return (PICL_FAILURE);
217 return (PICL_SUCCESS);
220 void
221 scsi_info_fini()
223 free(cfglist);
224 free_list(scsi_list);
225 free(scsi_list);
229 * This routine searches the controllers list to find the mapping based
230 * on given devfs_path.
231 * caller should allocate memory for ap_id
233 static picl_errno_t
234 find_scsi_controller(char *devfs_path, plist_t *list, char *ap_id)
236 node_t *tmp = NULL;
237 char *lasts = NULL;
238 char *token = NULL;
239 char path[MAXPATHLEN];
241 if (devfs_path == NULL || ap_id == NULL) {
242 return (PICL_INVALIDARG);
244 (void) snprintf((char *)path, sizeof (path), "/devices%s", devfs_path);
246 tmp = list->first;
247 while (tmp != NULL) {
248 lasts = tmp->data->ap_phys_id;
249 token = (char *)strtok_r(lasts, (const char *)":",
250 (char **)&lasts);
251 if (token == NULL) {
252 tmp = tmp->next;
253 continue;
256 if (strcmp(path, token) == 0) { /* match found */
257 (void) strncpy(ap_id, tmp->data->ap_log_id,
258 sizeof (ap_id));
259 return (PICL_SUCCESS);
261 tmp = tmp->next;
263 return (PICL_NODENOTFOUND);
267 * This routine dynamically determines the cfgadm attachment point
268 * for a given devfspath and target id.
269 * memory for name should be allocated by the caller.
271 picl_errno_t
272 get_scsislot_name(char *devfs_path, char *bus_addr, char *name)
274 picl_errno_t rc;
275 int target_id = 0;
276 int numlist;
277 plist_t list;
278 cfga_err_t ap_list_err;
279 cfga_list_data_t *cfgalist = NULL;
280 char controller[MAXPATHLEN];
282 ap_list_err = config_list_ext(0, NULL, &cfgalist,
283 &numlist, NULL, NULL, NULL, CFGA_FLAG_LIST_ALL);
284 if (ap_list_err != CFGA_OK) {
285 return (PICL_NODENOTFOUND);
288 ap_list_err = populate_controllers_list(&list, cfgalist,
289 numlist);
290 if (ap_list_err != CFGA_OK) {
291 free_list(&list);
292 free(cfgalist);
293 return (PICL_NODENOTFOUND);
296 if (list.num_nodes <= 0) {
297 free(cfgalist);
298 return (PICL_NODENOTFOUND);
301 if ((rc = find_scsi_controller(devfs_path, &list,
302 controller)) != PICL_SUCCESS) {
303 free(cfgalist);
304 free_list(&list);
305 return (rc);
307 target_id = strtol(bus_addr, (char **)NULL, 16);
308 (void) sprintf(name, "%s::dsk/%st%dd0", controller,
309 controller, target_id);
310 free(cfgalist);
311 free_list(&list);
312 return (PICL_SUCCESS);
316 * Arg scsi_loc can be any of the following forms appearing in cfgadm output
317 * c0::dsk/c0t0d0
318 * c1::sd56
319 * c2::rmt/0
320 * c3::st41
321 * dsk/c1t1d0
322 * rmt/1
323 * /devices/pci@1f,0/pci@1,1/scsi@2:scsi::dsk/c0t0d0
325 * On return, bus_addr contains the target id of the device.
326 * Please note that currently the target id is computed. It is better
327 * to eventually change this to getting from libdevinfo.
328 * Also, please note that SCSI_INITIATOR_ID should not
329 * be hardcoded, but should be dynamically retrieved from an OBP property.
331 static void
332 get_bus_addr(char *scsi_loc, char **bus_addr)
334 char *ap, *token, *p, *ap_idp;
335 int len = 0, i = 0;
336 char parse_link = 0;
337 char addr[BUF_SIZE], ap_id[BUF_SIZE];
338 char fileinfo[BUF_SIZE], ap_id_link[BUF_SIZE];
340 (void) strncpy(ap_id, scsi_loc, sizeof (ap_id));
341 ap = strrchr(ap_id, ':');
342 if (!ap)
343 ap = ap_idp = ap_id;
344 else
345 ap_idp = ++ap;
347 while (scsi_dirlink_names[i] && !len) {
348 len = strspn(ap, scsi_dirlink_names[i++]);
350 * strspn may return positive len even when there is no
351 * complete string matches!!! hence the following check is
352 * necessary. So ensure the string match.
354 if (len && strstr(ap, scsi_dirlink_names[i-1]))
355 break;
356 len = 0;
358 if (len)
359 parse_link = 1;
360 else {
361 i = 0;
362 while (scsi_drv[i].drv_name && !len) {
363 len = strspn(ap, scsi_drv[i++].drv_name);
364 if (len && strstr(ap, scsi_drv[i-1].drv_name))
365 break;
366 len = 0;
369 ap += len;
370 if (strlen(ap) && parse_link) {
372 /* slice 0 must be present in the system */
373 if (strstr(ap, "/c")) {
374 if (strstr(ap, "s0") == NULL)
375 (void) strcat(ap, "s0");
377 /* get the devlink and read the target id from minor node */
378 (void) snprintf(ap_id_link, sizeof (ap_id_link), "/dev/%s",
379 ap_idp);
380 (void) bzero(fileinfo, sizeof (fileinfo));
381 if (readlink(ap_id_link, fileinfo, sizeof (fileinfo)) < 0)
382 return;
383 if (!fileinfo[0])
384 return;
385 ap = strrchr(fileinfo, '@');
386 ap++;
388 token = (char *)strtok_r(ap, ",", &p);
389 (void) strncpy(addr, token, sizeof (addr));
390 if (!parse_link) {
391 int drv_inst = atoi(token);
392 int tmp_targ_id = drv_inst % scsi_drv[i-1].num_targets;
393 int targ_id = scsi_drv[i-1].drv_type == DRV_TYPE_DSK ?
394 (tmp_targ_id < SCSI_INITIATOR_ID ?
395 tmp_targ_id : tmp_targ_id+1):
396 DRV_TYPE_TAPE ? tmp_targ_id : drv_inst;
397 (void) snprintf(addr, sizeof (addr), "%d", targ_id);
399 if (strlen(addr)) {
400 *bus_addr = (char *)malloc(strlen(addr)+1);
401 if ((*bus_addr) == NULL)
402 return;
403 (void) strcpy((char *)*bus_addr, addr);
408 * This routine determines all the scsi nodes under a FRU and
409 * creates a subtree of all the scsi nodes with basic properties.
411 static picl_errno_t
412 dyn_probe_for_scsi_frus(frutree_frunode_t *frup, cfga_list_data_t *cfgalist,
413 plist_t *list, int numlist)
415 picl_errno_t rc;
416 int i, geo_addr = 0;
417 node_t *curr = NULL;
418 char *bus_addr = NULL;
419 char path[MAXPATHLEN];
420 char controller_name[MAXPATHLEN];
422 /* for each controller in the list, find if disk/fru is present */
423 curr = list->first;
424 while (curr != NULL) {
425 /* compare the path */
426 (void) snprintf((char *)path, sizeof (path), "/devices%s",
427 frup->fru_path);
428 if (strstr(curr->data->ap_phys_id, path) == NULL) {
429 curr = curr->next;
430 continue;
433 (void) snprintf(controller_name, sizeof (controller_name),
434 "%s::", curr->data->ap_log_id);
436 for (i = 0; i < numlist; i++) {
437 if (strcmp(cfgalist[i].ap_type, SCSI_SLOT) == 0) {
438 continue;
440 if (strstr(cfgalist[i].ap_log_id,
441 controller_name) == NULL) {
442 continue;
444 /* check if device is under fru */
445 if (strstr(cfgalist[i].ap_phys_id, path) == NULL) {
446 continue;
449 /* we found a scsi fru */
450 geo_addr++;
451 /* check if the device is present in subtree */
452 if (is_location_present_in_subtree(frup,
453 cfgalist[i].ap_log_id, path) == B_TRUE) {
454 continue;
456 get_bus_addr(cfgalist[i].ap_log_id, &bus_addr);
457 if (bus_addr == NULL) {
458 continue;
460 rc = create_children(frup, cfgalist[i].ap_log_id,
461 bus_addr, geo_addr, SANIBEL_SCSI_SLOT, B_TRUE);
462 free(bus_addr);
463 if (rc != PICL_SUCCESS) {
464 FRUTREE_DEBUG3(FRUTREE_INIT, "SUNW_frutree:"
465 "Error in creating node %s under %s(error=%d)",
466 cfgalist[i].ap_log_id, frup->name, rc);
469 curr = curr->next;
471 return (PICL_SUCCESS);
475 * data used here is cached information (cfglist, nlist)
477 static picl_errno_t
478 cache_probe_for_scsi_frus(frutree_frunode_t *frup)
480 int i, geo_addr = 0;
481 picl_errno_t rc;
482 node_t *curr = NULL;
483 char path[MAXPATHLEN];
484 char controller_name[MAXPATHLEN];
485 char *bus_addr = NULL;
487 /* for each controller in the list, find if disk/fru is present */
488 if (scsi_list == NULL) {
489 return (PICL_SUCCESS);
491 curr = scsi_list->first;
492 while (curr != NULL) {
493 /* compare the path */
494 (void) snprintf((char *)path, sizeof (path), "/devices%s",
495 frup->fru_path);
496 if (strstr(curr->data->ap_phys_id, path) == NULL) {
497 curr = curr->next;
498 continue;
500 (void) snprintf(controller_name, sizeof (controller_name),
501 "%s::", curr->data->ap_log_id);
503 for (i = 0; i < nlist; i++) {
504 if (strcmp(cfglist[i].ap_type, SCSI_SLOT) == 0) {
505 continue;
507 if (strstr(cfglist[i].ap_log_id,
508 controller_name) == NULL) {
509 continue;
511 /* check if the device is under fru */
512 if (strstr(cfglist[i].ap_phys_id, path) == NULL) {
513 continue;
516 /* we found a scsi fru */
517 geo_addr++;
518 /* check if the device is present in subtree */
519 if (is_location_present_in_subtree(frup,
520 cfglist[i].ap_log_id, path) == B_TRUE) {
521 continue;
523 get_bus_addr(cfglist[i].ap_log_id, &bus_addr);
524 if (bus_addr == NULL) {
525 continue;
527 rc = create_children(frup, cfglist[i].ap_log_id,
528 bus_addr, geo_addr, SANIBEL_SCSI_SLOT, B_TRUE);
529 free(bus_addr);
530 if (rc != PICL_SUCCESS) {
531 FRUTREE_DEBUG3(FRUTREE_INIT, "SUNW_frutree:"
532 "Error in creating node %s under %s(error=%d)",
533 cfglist[i].ap_log_id, frup->name, rc);
536 curr = curr->next;
538 return (PICL_SUCCESS);
542 * This routine checks if the node (scsi device) is present in cfgadm data
543 * Algorithm:
544 * 1. traverse thru list of controllers and find
545 * the controller of interest
546 * 2. go thru list of devices under controller and compare if the target is same
547 * 3. if yes
548 * - device is already represented
549 * 4. if No
550 * - The node must be repreented in PICL tree.
552 static boolean_t
553 is_node_present(scsi_info_t *scsi_info, char *devfs_path, int target)
555 node_t *curr = NULL;
556 char path[MAXPATHLEN];
557 char controller[MAXPATHLEN];
558 char *bus_addr = NULL;
559 char *lasts = NULL, *token = NULL;
560 int i = 0;
562 if (scsi_info == NULL) {
563 return (B_FALSE);
566 if (scsi_info->list == NULL) {
567 return (B_FALSE);
570 (void) snprintf(path, sizeof (path), "/devices%s", devfs_path);
572 curr = scsi_info->list->first;
573 while (curr != NULL) {
575 lasts = curr->data->ap_phys_id;
576 token = (char *)strtok_r(lasts, (const char *)":",
577 (char **)&lasts);
578 if (token == NULL) {
579 curr = curr->next;
580 continue;
583 if (strstr(path, token) == NULL) {
584 /* this controller is not of interest */
585 curr = curr->next;
586 continue;
589 (void) snprintf(controller, sizeof (controller), "%s::",
590 curr->data->ap_log_id);
591 for (i = 0; i < scsi_info->num_list; i++) {
592 if (strcmp(scsi_info->cfgalist[i].ap_type,
593 SCSI_SLOT) == 0) {
594 continue;
597 if (strstr(scsi_info->cfgalist[i].ap_log_id,
598 controller) == NULL) {
599 continue;
602 get_bus_addr(scsi_info->cfgalist[i].ap_phys_id,
603 &bus_addr);
605 * compare with target value
607 if (bus_addr == NULL) {
608 return (B_TRUE);
610 if (strtoul(bus_addr, NULL, 16) == target) {
612 * this device is already represented
613 * in fru tree
615 free(bus_addr);
616 return (B_TRUE);
618 free(bus_addr);
620 curr = curr->next;
622 return (B_FALSE);
625 static di_prop_t
626 get_prop_by_name(di_node_t node, char *name)
628 di_prop_t prop = DI_PROP_NIL;
629 char *prop_name = NULL;
631 prop = di_prop_next(node, DI_PROP_NIL);
632 while (prop != DI_PROP_NIL) {
633 prop_name = di_prop_name(prop);
634 if (prop_name != NULL) {
635 if (strcmp(prop_name, name) == 0) {
636 return (prop);
639 prop = di_prop_next(node, prop);
641 return (DI_PROP_NIL);
644 static int
645 get_geoaddr(picl_nodehdl_t nodeh, void *c_args)
647 picl_errno_t rc;
648 uint8_t *geo_addr = NULL;
649 char slot_type[PICL_PROPNAMELEN_MAX];
651 if (c_args == NULL)
652 return (PICL_INVALIDARG);
653 geo_addr = (uint8_t *)c_args;
655 if ((rc = ptree_get_propval_by_name(nodeh, PICL_PROP_SLOT_TYPE,
656 slot_type, sizeof (slot_type))) != PICL_SUCCESS) {
657 return (rc);
660 if (strcmp(slot_type, SANIBEL_SCSI_SLOT) == 0 ||
661 strcmp(slot_type, SANIBEL_IDE_SLOT) == 0) {
662 *geo_addr = *geo_addr + 1;
664 return (PICL_WALK_CONTINUE);
667 static int
668 frutree_get_geoaddr(frutree_frunode_t *frup)
670 int geo_addr = 1;
671 if (ptree_walk_tree_by_class(frup->frunodeh, PICL_CLASS_LOCATION,
672 &geo_addr, get_geoaddr) != PICL_SUCCESS) {
673 return (geo_addr);
675 return (geo_addr);
678 static int
679 probe_disks(di_node_t node, void *arg)
681 di_prop_t prop;
682 picl_errno_t rc;
683 int *target_val = NULL;
684 char *nodetype = NULL;
685 char *devfs_path = NULL;
686 char *bus_addr = NULL;
687 char *drv_name = NULL;
688 scsi_info_t *data = NULL;
689 di_minor_t minor = DI_MINOR_NIL;
690 char *class = NULL;
691 char node_name[BUF_SIZE];
692 char slot_type[PICL_PROPNAMELEN_MAX];
694 if (arg == NULL)
695 return (DI_WALK_TERMINATE);
697 data = *(scsi_info_t **)arg;
698 if (data == NULL) {
699 return (DI_WALK_TERMINATE);
702 /* initialize the geo_addr value */
703 if (data->geo_addr == 0) {
704 if (data->compare_cfgadm == B_FALSE) {
705 data->geo_addr = 1;
706 } else {
707 data->geo_addr = frutree_get_geoaddr(data->frup);
711 while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
712 nodetype = di_minor_nodetype(minor);
713 if (nodetype == NULL) {
714 continue;
717 if (strcmp(nodetype, DDI_NT_BLOCK_CHAN) == 0 ||
718 strcmp(nodetype, DDI_NT_BLOCK_WWN) == 0) {
719 (void) snprintf(node_name, sizeof (node_name),
720 "%s%d", DISK, data->geo_addr);
721 } else if (strcmp(nodetype, DDI_NT_TAPE) == 0) {
722 (void) snprintf(node_name, sizeof (node_name),
723 "%s%d", RMM, data->geo_addr);
724 } else if (strcmp(nodetype, DDI_NT_CD) == 0 ||
725 strcmp(nodetype, DDI_NT_CD_CHAN) == 0) {
726 (void) snprintf(node_name, sizeof (node_name),
727 "%s%d", CDROM, data->geo_addr);
728 } else {
729 continue;
732 devfs_path = di_devfs_path(node);
733 drv_name = di_driver_name(node);
734 bus_addr = di_bus_addr(node);
735 if (devfs_path == NULL) {
736 continue;
738 if (drv_name == NULL || bus_addr == NULL) {
739 di_devfs_path_free(devfs_path);
740 continue;
742 prop = get_prop_by_name(node, TARGET);
743 if (prop != DI_PROP_NIL) {
744 di_prop_ints(prop, &target_val);
745 if (data->compare_cfgadm) {
746 /* check if node is present in cfgadm data */
747 if (is_node_present(data, devfs_path,
748 *target_val) == B_TRUE) {
749 di_devfs_path_free(devfs_path);
750 return (DI_WALK_CONTINUE);
754 di_devfs_path_free(devfs_path);
755 prop = get_prop_by_name(node, CLASS);
756 if (prop != DI_PROP_NIL) {
757 di_prop_strings(prop, &class);
760 /* determine the slot type based on class code */
761 if (class != NULL) {
762 if (strcmp(class, DEVICE_CLASS_SCSI) == 0) {
763 (void) strncpy(slot_type,
764 SANIBEL_SCSI_SLOT,
765 sizeof (slot_type));
766 } else if (strcmp(class,
767 DEVICE_CLASS_IDE) == 0) {
768 (void) strncpy(slot_type,
769 SANIBEL_IDE_SLOT,
770 sizeof (slot_type));
771 } else {
772 (void) strncpy(slot_type,
773 SANIBEL_UNKNOWN_SLOT,
774 sizeof (slot_type));
777 } else {
778 (void) strncpy(slot_type, SANIBEL_UNKNOWN_SLOT,
779 sizeof (slot_type));
782 if ((rc = create_children(data->frup, node_name,
783 bus_addr, data->geo_addr, slot_type,
784 B_FALSE)) != PICL_SUCCESS) {
785 return (rc);
787 /* increment the geo_addr */
788 data->geo_addr++;
789 } else {
790 di_devfs_path_free(devfs_path);
791 continue;
793 return (DI_WALK_CONTINUE);
795 return (DI_WALK_CONTINUE);
798 static picl_errno_t
799 probe_scsi_in_libdevinfo(frutree_frunode_t *frup, cfga_list_data_t *cfgalist,
800 plist_t *list, int num_list, boolean_t compare_cfgadm)
802 di_node_t rnode;
803 scsi_info_t *scsi_data = NULL;
805 if (frup == NULL) {
806 return (PICL_FAILURE);
809 rnode = di_init(frup->fru_path, DINFOCPYALL);
810 if (rnode == DI_NODE_NIL) {
811 return (PICL_FAILURE);
814 scsi_data = (scsi_info_t *)malloc(sizeof (scsi_info_t));
815 if (scsi_data == NULL) {
816 di_fini(rnode);
817 return (PICL_NOSPACE);
820 scsi_data->frup = frup;
821 scsi_data->cfgalist = cfgalist;
822 scsi_data->list = list;
823 scsi_data->num_list = num_list;
824 scsi_data->compare_cfgadm = compare_cfgadm;
825 scsi_data->geo_addr = 0;
826 if (di_walk_node(rnode, DI_WALK_CLDFIRST, &scsi_data,
827 probe_disks) != 0) {
828 free(scsi_data);
829 di_fini(rnode);
830 return (PICL_FAILURE);
833 free(scsi_data);
834 di_fini(rnode);
835 return (PICL_SUCCESS);
838 picl_errno_t
839 probe_for_scsi_frus(frutree_frunode_t *frup)
841 int numlist;
842 picl_errno_t rc;
843 plist_t list;
844 cfga_err_t ap_list_err;
845 cfga_list_data_t *cfgalist = NULL;
847 if (frutree_connects_initiated == B_TRUE) { /* probing after hotswap */
848 ap_list_err = config_list_ext(0, NULL, &cfgalist,
849 &numlist, NULL, NULL, NULL, CFGA_FLAG_LIST_ALL);
851 if (ap_list_err != CFGA_OK) {
852 rc = probe_scsi_in_libdevinfo(frup, NULL, NULL,
853 0, B_FALSE);
854 return (rc);
857 /* get list of all controllers in the system */
858 ap_list_err = populate_controllers_list(&list, cfgalist,
859 numlist);
860 if (ap_list_err != CFGA_OK) {
861 free_list(&list);
862 free(cfgalist);
863 rc = probe_scsi_in_libdevinfo(frup, NULL, NULL,
864 0, B_FALSE);
865 return (rc);
868 /* no controllers found */
869 if (list.num_nodes <= 0) {
870 free_list(&list);
871 free(cfgalist);
872 rc = probe_scsi_in_libdevinfo(frup, NULL, NULL,
873 0, B_FALSE);
874 return (rc);
877 * we have to fetch cfgadm, look for scsi controllers
878 * dynamically
880 (void) dyn_probe_for_scsi_frus(frup, cfgalist, &list, numlist);
881 rc = probe_scsi_in_libdevinfo(frup, cfgalist, &list,
882 numlist, B_TRUE);
883 free_list(&list);
884 free(cfgalist);
885 return (rc);
886 } else {
887 /* during initialization */
888 /* use the cached cfgadm data */
889 rc = cache_probe_for_scsi_frus(frup);
890 if (scsi_list && scsi_list->num_nodes > 0) {
891 rc = probe_scsi_in_libdevinfo(frup, cfglist,
892 scsi_list, nlist, B_TRUE);
893 } else {
894 rc = probe_scsi_in_libdevinfo(frup, NULL,
895 NULL, 0, B_FALSE);
897 return (rc);