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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
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.
13 *
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]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /* implementation specific to scsi nodes probing */
30
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"
46
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
52
53 #define SCSI_INITIATOR_ID 7
54 #define DRV_TYPE_DSK 1
55 #define DRV_TYPE_TAPE 2
56 #define NUM_DSK_TARGS 15
57 /*
58 * No support for wide tapes for now.
59 * If required wide support, set this to 8
60 * See st.conf.
61 */
62 #define NUM_TAPE_TARGS 7
63
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
69
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
81 };
82
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"
87
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;
95
96 typedef struct node {
97 struct node *next;
98 cfga_list_data_t *data;
99 } node_t;
100
101 typedef struct linked_list {
102 node_t *first;
103 int num_nodes;
104 } plist_t;
105
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;
114
115 static plist_t *scsi_list = NULL;
116 static cfga_list_data_t *cfglist = NULL;
117 static int nlist = 0;
118
119 static void
free_list(plist_t * list)120 free_list(plist_t *list)
121 {
122 node_t *tmp = NULL, *tmp1 = NULL;
123
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;
132 }
133 }
134
135 /*
136 * This routine gets the list of scsi controllers present
137 */
138 static cfga_err_t
populate_controllers_list(plist_t * cntrl_list,cfga_list_data_t * list,int num)139 populate_controllers_list(plist_t *cntrl_list, cfga_list_data_t *list, int num)
140 {
141 int i;
142 node_t *nodeptr = NULL;
143 cfga_list_data_t *temp = NULL;
144
145 if (cntrl_list == NULL || list == NULL) {
146 return (CFGA_ATTR_INVAL);
147 }
148
149 cntrl_list->first = NULL;
150 cntrl_list->num_nodes = 0;
151
152 if (num == 0) {
153 return (CFGA_OK);
154 }
155
156 for (i = 0; i < num; i++) {
157 if (strcmp(list[i].ap_type, SCSI_SLOT) != 0) {
158 continue;
159 }
160
161 /* scsi controller */
162 temp = (cfga_list_data_t *)malloc(sizeof (cfga_list_data_t));
163 if (temp == NULL) {
164 return (CFGA_ERROR);
165 }
166 (void) memcpy(temp, &list[i], sizeof (cfga_list_data_t));
167
168 nodeptr = (node_t *)malloc(sizeof (node_t));
169 if (nodeptr == NULL) {
170 free(temp);
171 return (CFGA_ERROR);
172 }
173 nodeptr->data = temp;
174 nodeptr->next = NULL;
175
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++;
184 }
185 }
186 return (CFGA_OK);
187 }
188
189 picl_errno_t
scsi_info_init()190 scsi_info_init()
191 {
192 cfga_err_t ap_list_err;
193
194 ap_list_err = config_list_ext(0, NULL, &cfglist, &nlist, NULL,
195 NULL, NULL, CFGA_FLAG_LIST_ALL);
196
197 if (ap_list_err != CFGA_OK) {
198 if (ap_list_err == CFGA_NOTSUPP) {
199 return (PICL_SUCCESS);
200 } else {
201 return (PICL_FAILURE);
202 }
203 }
204
205 scsi_list = (plist_t *)malloc(sizeof (plist_t));
206 if (scsi_list == NULL) {
207 free(cfglist);
208 return (PICL_NOSPACE);
209 }
210
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);
216 }
217 return (PICL_SUCCESS);
218 }
219
220 void
scsi_info_fini()221 scsi_info_fini()
222 {
223 free(cfglist);
224 free_list(scsi_list);
225 free(scsi_list);
226 }
227
228 /*
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
232 */
233 static picl_errno_t
find_scsi_controller(char * devfs_path,plist_t * list,char * ap_id)234 find_scsi_controller(char *devfs_path, plist_t *list, char *ap_id)
235 {
236 node_t *tmp = NULL;
237 char *lasts = NULL;
238 char *token = NULL;
239 char path[MAXPATHLEN];
240
241 if (devfs_path == NULL || ap_id == NULL) {
242 return (PICL_INVALIDARG);
243 }
244 (void) snprintf((char *)path, sizeof (path), "/devices%s", devfs_path);
245
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;
254 }
255
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);
260 }
261 tmp = tmp->next;
262 }
263 return (PICL_NODENOTFOUND);
264 }
265
266 /*
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.
270 */
271 picl_errno_t
get_scsislot_name(char * devfs_path,char * bus_addr,char * name)272 get_scsislot_name(char *devfs_path, char *bus_addr, char *name)
273 {
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];
281
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);
286 }
287
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);
294 }
295
296 if (list.num_nodes <= 0) {
297 free(cfgalist);
298 return (PICL_NODENOTFOUND);
299 }
300
301 if ((rc = find_scsi_controller(devfs_path, &list,
302 controller)) != PICL_SUCCESS) {
303 free(cfgalist);
304 free_list(&list);
305 return (rc);
306 }
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);
313 }
314
315 /*
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
324 *
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.
330 */
331 static void
get_bus_addr(char * scsi_loc,char ** bus_addr)332 get_bus_addr(char *scsi_loc, char **bus_addr)
333 {
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];
339
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;
346
347 while (scsi_dirlink_names[i] && !len) {
348 len = strspn(ap, scsi_dirlink_names[i++]);
349 /*
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.
353 */
354 if (len && strstr(ap, scsi_dirlink_names[i-1]))
355 break;
356 len = 0;
357 }
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;
367 }
368 }
369 ap += len;
370 if (strlen(ap) && parse_link) {
371
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");
376 }
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++;
387 }
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);
398 }
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);
404 }
405 }
406
407 /*
408 * This routine determines all the scsi nodes under a FRU and
409 * creates a subtree of all the scsi nodes with basic properties.
410 */
411 static picl_errno_t
dyn_probe_for_scsi_frus(frutree_frunode_t * frup,cfga_list_data_t * cfgalist,plist_t * list,int numlist)412 dyn_probe_for_scsi_frus(frutree_frunode_t *frup, cfga_list_data_t *cfgalist,
413 plist_t *list, int numlist)
414 {
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];
421
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;
431
432 }
433 (void) snprintf(controller_name, sizeof (controller_name),
434 "%s::", curr->data->ap_log_id);
435
436 for (i = 0; i < numlist; i++) {
437 if (strcmp(cfgalist[i].ap_type, SCSI_SLOT) == 0) {
438 continue;
439 }
440 if (strstr(cfgalist[i].ap_log_id,
441 controller_name) == NULL) {
442 continue;
443 }
444 /* check if device is under fru */
445 if (strstr(cfgalist[i].ap_phys_id, path) == NULL) {
446 continue;
447 }
448
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;
455 }
456 get_bus_addr(cfgalist[i].ap_log_id, &bus_addr);
457 if (bus_addr == NULL) {
458 continue;
459 }
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);
467 }
468 }
469 curr = curr->next;
470 }
471 return (PICL_SUCCESS);
472 }
473
474 /*
475 * data used here is cached information (cfglist, nlist)
476 */
477 static picl_errno_t
cache_probe_for_scsi_frus(frutree_frunode_t * frup)478 cache_probe_for_scsi_frus(frutree_frunode_t *frup)
479 {
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;
486
487 /* for each controller in the list, find if disk/fru is present */
488 if (scsi_list == NULL) {
489 return (PICL_SUCCESS);
490 }
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;
499 }
500 (void) snprintf(controller_name, sizeof (controller_name),
501 "%s::", curr->data->ap_log_id);
502
503 for (i = 0; i < nlist; i++) {
504 if (strcmp(cfglist[i].ap_type, SCSI_SLOT) == 0) {
505 continue;
506 }
507 if (strstr(cfglist[i].ap_log_id,
508 controller_name) == NULL) {
509 continue;
510 }
511 /* check if the device is under fru */
512 if (strstr(cfglist[i].ap_phys_id, path) == NULL) {
513 continue;
514 }
515
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;
522 }
523 get_bus_addr(cfglist[i].ap_log_id, &bus_addr);
524 if (bus_addr == NULL) {
525 continue;
526 }
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);
534 }
535 }
536 curr = curr->next;
537 }
538 return (PICL_SUCCESS);
539 }
540
541 /*
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.
551 */
552 static boolean_t
is_node_present(scsi_info_t * scsi_info,char * devfs_path,int target)553 is_node_present(scsi_info_t *scsi_info, char *devfs_path, int target)
554 {
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;
561
562 if (scsi_info == NULL) {
563 return (B_FALSE);
564 }
565
566 if (scsi_info->list == NULL) {
567 return (B_FALSE);
568 }
569
570 (void) snprintf(path, sizeof (path), "/devices%s", devfs_path);
571
572 curr = scsi_info->list->first;
573 while (curr != NULL) {
574
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;
581 }
582
583 if (strstr(path, token) == NULL) {
584 /* this controller is not of interest */
585 curr = curr->next;
586 continue;
587 }
588
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;
595 }
596
597 if (strstr(scsi_info->cfgalist[i].ap_log_id,
598 controller) == NULL) {
599 continue;
600 }
601
602 get_bus_addr(scsi_info->cfgalist[i].ap_phys_id,
603 &bus_addr);
604 /*
605 * compare with target value
606 */
607 if (bus_addr == NULL) {
608 return (B_TRUE);
609 }
610 if (strtoul(bus_addr, NULL, 16) == target) {
611 /*
612 * this device is already represented
613 * in fru tree
614 */
615 free(bus_addr);
616 return (B_TRUE);
617 }
618 free(bus_addr);
619 }
620 curr = curr->next;
621 }
622 return (B_FALSE);
623 }
624
625 static di_prop_t
get_prop_by_name(di_node_t node,char * name)626 get_prop_by_name(di_node_t node, char *name)
627 {
628 di_prop_t prop = DI_PROP_NIL;
629 char *prop_name = NULL;
630
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);
637 }
638 }
639 prop = di_prop_next(node, prop);
640 }
641 return (DI_PROP_NIL);
642 }
643
644 static int
get_geoaddr(picl_nodehdl_t nodeh,void * c_args)645 get_geoaddr(picl_nodehdl_t nodeh, void *c_args)
646 {
647 picl_errno_t rc;
648 uint8_t *geo_addr = NULL;
649 char slot_type[PICL_PROPNAMELEN_MAX];
650
651 if (c_args == NULL)
652 return (PICL_INVALIDARG);
653 geo_addr = (uint8_t *)c_args;
654
655 if ((rc = ptree_get_propval_by_name(nodeh, PICL_PROP_SLOT_TYPE,
656 slot_type, sizeof (slot_type))) != PICL_SUCCESS) {
657 return (rc);
658 }
659
660 if (strcmp(slot_type, SANIBEL_SCSI_SLOT) == 0 ||
661 strcmp(slot_type, SANIBEL_IDE_SLOT) == 0) {
662 *geo_addr = *geo_addr + 1;
663 }
664 return (PICL_WALK_CONTINUE);
665 }
666
667 static int
frutree_get_geoaddr(frutree_frunode_t * frup)668 frutree_get_geoaddr(frutree_frunode_t *frup)
669 {
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);
674 }
675 return (geo_addr);
676 }
677
678 static int
probe_disks(di_node_t node,void * arg)679 probe_disks(di_node_t node, void *arg)
680 {
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];
693
694 if (arg == NULL)
695 return (DI_WALK_TERMINATE);
696
697 data = *(scsi_info_t **)arg;
698 if (data == NULL) {
699 return (DI_WALK_TERMINATE);
700 }
701
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);
708 }
709 }
710
711 while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
712 nodetype = di_minor_nodetype(minor);
713 if (nodetype == NULL) {
714 continue;
715 }
716
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;
730 }
731
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;
737 }
738 if (drv_name == NULL || bus_addr == NULL) {
739 di_devfs_path_free(devfs_path);
740 continue;
741 }
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);
751 }
752 }
753
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);
758 }
759
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));
775 }
776
777 } else {
778 (void) strncpy(slot_type, SANIBEL_UNKNOWN_SLOT,
779 sizeof (slot_type));
780 }
781
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);
786 }
787 /* increment the geo_addr */
788 data->geo_addr++;
789 } else {
790 di_devfs_path_free(devfs_path);
791 continue;
792 }
793 return (DI_WALK_CONTINUE);
794 }
795 return (DI_WALK_CONTINUE);
796 }
797
798 static picl_errno_t
probe_scsi_in_libdevinfo(frutree_frunode_t * frup,cfga_list_data_t * cfgalist,plist_t * list,int num_list,boolean_t compare_cfgadm)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)
801 {
802 di_node_t rnode;
803 scsi_info_t *scsi_data = NULL;
804
805 if (frup == NULL) {
806 return (PICL_FAILURE);
807 }
808
809 rnode = di_init(frup->fru_path, DINFOCPYALL);
810 if (rnode == DI_NODE_NIL) {
811 return (PICL_FAILURE);
812 }
813
814 scsi_data = (scsi_info_t *)malloc(sizeof (scsi_info_t));
815 if (scsi_data == NULL) {
816 di_fini(rnode);
817 return (PICL_NOSPACE);
818 }
819
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);
831 }
832
833 free(scsi_data);
834 di_fini(rnode);
835 return (PICL_SUCCESS);
836 }
837
838 picl_errno_t
probe_for_scsi_frus(frutree_frunode_t * frup)839 probe_for_scsi_frus(frutree_frunode_t *frup)
840 {
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;
846
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);
850
851 if (ap_list_err != CFGA_OK) {
852 rc = probe_scsi_in_libdevinfo(frup, NULL, NULL,
853 0, B_FALSE);
854 return (rc);
855 }
856
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);
866 }
867
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);
875 }
876 /*
877 * we have to fetch cfgadm, look for scsi controllers
878 * dynamically
879 */
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);
896 }
897 return (rc);
898 }
899 }
900