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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 }