1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sun_sas.h> 28 #include <sys/types.h> 29 #include <netinet/in.h> 30 #include <inttypes.h> 31 #include <ctype.h> 32 #include <sys/scsi/scsi_address.h> 33 #include <libdevid.h> 34 35 /* 36 * Get the preferred minor node for the given path. 37 * ":n" for tapes, ":c,raw" for disks, 38 * and ":0" for enclosures. 39 */ 40 static void 41 get_minor(char *devpath, char *minor) 42 { 43 const char ROUTINE[] = "get_minor"; 44 char fullpath[MAXPATHLEN]; 45 int fd; 46 47 if ((strstr(devpath, "/st@")) || (strstr(devpath, "/tape@"))) { 48 (void) strcpy(minor, ":n"); 49 } else if (strstr(devpath, "/smp@")) { 50 (void) strcpy(minor, ":smp"); 51 } else if ((strstr(devpath, "/ssd@")) || (strstr(devpath, "/sd@")) || 52 (strstr(devpath, "/disk@"))) { 53 (void) strcpy(minor, ":c,raw"); 54 } else if ((strstr(devpath, "/ses@")) || (strstr(devpath, 55 "/enclosure@"))) { 56 (void) snprintf(fullpath, MAXPATHLEN, "%s%s%s", DEVICES_DIR, 57 devpath, ":0"); 58 /* reset errno to 0 */ 59 errno = 0; 60 if ((fd = open(fullpath, O_RDONLY)) == -1) { 61 /* 62 * :0 minor doesn't exist. assume bound to sgen driver 63 * and :ses minor exist. 64 */ 65 if (errno == ENOENT) { 66 (void) strcpy(minor, ":ses"); 67 } 68 } else { 69 (void) strcpy(minor, ":0"); 70 (void) close(fd); 71 } 72 } else { 73 log(LOG_DEBUG, ROUTINE, "Unrecognized target (%s)", 74 devpath); 75 minor[0] = '\0'; 76 } 77 78 } 79 80 /* 81 * Free the attached port allocation. 82 */ 83 static void 84 free_attached_port(struct sun_sas_port *port_ptr) 85 { 86 struct sun_sas_port *tgt_port, *last_tgt_port; 87 struct ScsiEntryList *scsi_info = NULL, *last_scsi_info = NULL; 88 89 tgt_port = port_ptr->first_attached_port; 90 while (tgt_port != NULL) { 91 /* Free target mapping data list first. */ 92 scsi_info = tgt_port->scsiInfo; 93 while (scsi_info != NULL) { 94 last_scsi_info = scsi_info; 95 scsi_info = scsi_info->next; 96 free(last_scsi_info); 97 } 98 last_tgt_port = tgt_port; 99 tgt_port = tgt_port->next; 100 free(last_tgt_port->port_attributes.\ 101 PortSpecificAttribute.SASPort); 102 free(last_tgt_port); 103 } 104 105 port_ptr->first_attached_port = NULL; 106 port_ptr->port_attributes.PortSpecificAttribute.\ 107 SASPort->NumberofDiscoveredPorts = 0; 108 } 109 110 /* 111 * Fill domainPortWWN. 112 * should be called after completing discovered port discovery. 113 */ 114 void 115 fillDomainPortWWN(struct sun_sas_port *port_ptr) 116 { 117 const char ROUTINE[] = "fillDomainPortWWN"; 118 struct sun_sas_port *disco_port_ptr; 119 struct phy_info *phy_ptr; 120 uint64_t domainPort = 0; 121 struct ScsiEntryList *mapping_ptr; 122 123 for (disco_port_ptr = port_ptr->first_attached_port; 124 disco_port_ptr != NULL; disco_port_ptr = disco_port_ptr->next) { 125 if (disco_port_ptr->port_attributes.PortType == 126 HBA_PORTTYPE_SASEXPANDER && 127 wwnConversion(disco_port_ptr->port_attributes. 128 PortSpecificAttribute.SASPort-> 129 AttachedSASAddress.wwn) == 130 wwnConversion(port_ptr->port_attributes. 131 PortSpecificAttribute.SASPort-> 132 LocalSASAddress.wwn)) { 133 (void) memcpy(&domainPort, 134 disco_port_ptr->port_attributes. 135 PortSpecificAttribute. 136 SASPort->LocalSASAddress.wwn, 8); 137 break; 138 } 139 } 140 141 if (domainPort == 0) { 142 if (port_ptr->first_attached_port) { 143 /* 144 * there is no expander device attached on an HBA port 145 * domainPortWWN should not stay to 0 since multiple 146 * hba ports can have the same LocalSASAddres within 147 * the same HBA. 148 * Set the SAS address of direct attached target. 149 */ 150 if (wwnConversion(port_ptr->port_attributes. 151 PortSpecificAttribute.SASPort-> 152 LocalSASAddress.wwn) == 153 wwnConversion(port_ptr->first_attached_port-> 154 port_attributes.PortSpecificAttribute. 155 SASPort->AttachedSASAddress.wwn)) { 156 (void) memcpy(&domainPort, 157 port_ptr->first_attached_port-> 158 port_attributes.PortSpecificAttribute. 159 SASPort->LocalSASAddress.wwn, 8); 160 } else { 161 /* 162 * SAS address is not upstream connected. 163 * domainPortWWN stays as 0. 164 */ 165 log(LOG_DEBUG, ROUTINE, 166 "DomainPortWWN is not set. " 167 "Device(s) are visible on the HBA port " 168 "but there is no expander or directly " 169 "attached port with matching upsteam " 170 "attached SAS address for " 171 "HBA port (Local SAS Address: %016llx).", 172 wwnConversion(port_ptr->port_attributes. 173 PortSpecificAttribute. 174 SASPort->LocalSASAddress.wwn)); 175 return; 176 } 177 } else { 178 /* 179 * There existss an iport without properly configured 180 * child smp ndoes or child node or pathinfo. 181 * domainPortWWN stays as 0. 182 */ 183 log(LOG_DEBUG, ROUTINE, 184 "DomainPortWWN is not set. No properly " 185 "configured smp or directly attached port " 186 "found on HBA port(Local SAS Address: %016llx).", 187 wwnConversion(port_ptr->port_attributes. 188 PortSpecificAttribute. 189 SASPort->LocalSASAddress.wwn)); 190 return; 191 } 192 } 193 194 /* fill up phy info */ 195 for (phy_ptr = port_ptr->first_phy; phy_ptr != NULL; 196 phy_ptr = phy_ptr->next) { 197 (void) memcpy(phy_ptr->phy.domainPortWWN.wwn, &domainPort, 8); 198 } 199 200 /* fill up target mapping */ 201 for (disco_port_ptr = port_ptr->first_attached_port; 202 disco_port_ptr != NULL; disco_port_ptr = disco_port_ptr->next) { 203 for (mapping_ptr = disco_port_ptr->scsiInfo; 204 mapping_ptr != NULL; 205 mapping_ptr = mapping_ptr->next) { 206 (void) memcpy(mapping_ptr->entry.PortLun. 207 domainPortWWN.wwn, &domainPort, 8); 208 } 209 } 210 } 211 212 /* 213 * Finds attached device(target) from devinfo node. 214 */ 215 static HBA_STATUS 216 get_attached_devices_info(di_node_t node, struct sun_sas_port *port_ptr) 217 { 218 const char ROUTINE[] = "get_attached_devices_info"; 219 char *propStringData = NULL; 220 int *propIntData = NULL; 221 int64_t *propInt64Data = NULL; 222 scsi_lun_t samLun; 223 ddi_devid_t devid; 224 char *guidStr; 225 char *unit_address; 226 char *charptr; 227 char *devpath, link[MAXNAMELEN]; 228 char fullpath[MAXPATHLEN+1]; 229 char minorname[MAXNAMELEN+1]; 230 struct ScsiEntryList *mapping_ptr; 231 HBA_WWN SASAddress, AttachedSASAddress; 232 struct sun_sas_port *disco_port_ptr; 233 uint_t state = 0; 234 int portfound, rval, size; 235 int port_state = HBA_PORTSTATE_ONLINE; 236 uint64_t tmpAddr; 237 238 if (port_ptr == NULL) { 239 log(LOG_DEBUG, ROUTINE, "NULL port_ptr argument"); 240 return (HBA_STATUS_ERROR); 241 } 242 243 if ((devpath = di_devfs_path(node)) == NULL) { 244 log(LOG_DEBUG, ROUTINE, 245 "Device in device tree has no path. Skipping."); 246 return (HBA_STATUS_ERROR); 247 } 248 249 if ((di_instance(node) == -1) || di_retired(node)) { 250 log(LOG_DEBUG, ROUTINE, 251 "dev node (%s) returned instance of -1 or is retired. " 252 " Skipping.", devpath); 253 di_devfs_path_free(devpath); 254 return (HBA_STATUS_OK); 255 } 256 state = di_state(node); 257 /* when node is not attached and online, set the state to offline. */ 258 if (((state & DI_DRIVER_DETACHED) == DI_DRIVER_DETACHED) || 259 ((state & DI_DEVICE_OFFLINE) == DI_DEVICE_OFFLINE)) { 260 log(LOG_DEBUG, ROUTINE, 261 "dev node (%s) is either OFFLINE or DETACHED", 262 devpath); 263 port_state = HBA_PORTSTATE_OFFLINE; 264 } 265 266 /* add the "/devices" in the begining at the end */ 267 (void) snprintf(fullpath, sizeof (fullpath), "%s%s", 268 DEVICES_DIR, devpath); 269 270 (void) memset(&SASAddress, 0, sizeof (SASAddress)); 271 if ((unit_address = di_bus_addr(node)) != NULL) { 272 if ((charptr = strchr(unit_address, ',')) != NULL) { 273 *charptr = '\0'; 274 } 275 for (charptr = unit_address; *charptr != '\0'; charptr++) { 276 if (isxdigit(*charptr)) { 277 break; 278 } 279 } 280 if (*charptr != '\0') { 281 tmpAddr = htonll(strtoll(charptr, NULL, 16)); 282 (void) memcpy(&SASAddress.wwn[0], &tmpAddr, 8); 283 } else { 284 log(LOG_DEBUG, ROUTINE, 285 "No proper target port info on unit address of %s", 286 fullpath); 287 di_devfs_path_free(devpath); 288 return (HBA_STATUS_ERROR); 289 } 290 } else { 291 log(LOG_DEBUG, ROUTINE, 292 "Fail to get unit address of %s.", 293 fullpath); 294 di_devfs_path_free(devpath); 295 return (HBA_STATUS_ERROR); 296 } 297 298 (void) memset(&AttachedSASAddress, 0, sizeof (AttachedSASAddress)); 299 if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "attached-port", 300 &propStringData) != -1) { 301 for (charptr = propStringData; *charptr != '\0'; charptr++) { 302 if (isxdigit(*charptr)) { 303 break; 304 } 305 } 306 if (*charptr != '\0') { 307 tmpAddr = htonll(strtoll(charptr, NULL, 16)); 308 (void) memcpy(AttachedSASAddress.wwn, &tmpAddr, 8); 309 /* check the attached address of hba port. */ 310 if (memcmp(port_ptr->port_attributes. 311 PortSpecificAttribute.SASPort->LocalSASAddress.wwn, 312 &tmpAddr, 8) == 0) { 313 /* 314 * When attached-port is set from iport 315 * attached-port prop, we do the cross check 316 * with device's own SAS address. 317 * 318 * If not set, we store device's own SAS 319 * address to iport attached SAS address. 320 */ 321 if (wwnConversion(port_ptr->port_attributes. 322 PortSpecificAttribute.SASPort-> 323 AttachedSASAddress.wwn)) { 324 /* verify the Attaached SAS Addr. */ 325 if (memcmp(port_ptr->port_attributes. 326 PortSpecificAttribute.SASPort-> 327 AttachedSASAddress.wwn, 328 SASAddress.wwn, 8) != 0) { 329 /* indentation move begin. */ 330 log(LOG_DEBUG, ROUTINE, 331 "iport attached-port(%016llx) do not" 332 " match with level 1 Local" 333 " SAS address(%016llx).", 334 wwnConversion(port_ptr->port_attributes. 335 PortSpecificAttribute. 336 SASPort->AttachedSASAddress.wwn), 337 wwnConversion(SASAddress.wwn)); 338 di_devfs_path_free(devpath); 339 free_attached_port(port_ptr); 340 return (HBA_STATUS_ERROR); 341 /* indentation move ends. */ 342 } 343 } else { 344 (void) memcpy(port_ptr->port_attributes. 345 PortSpecificAttribute. 346 SASPort->AttachedSASAddress.wwn, 347 &SASAddress.wwn[0], 8); 348 } 349 } 350 } else { 351 log(LOG_DEBUG, ROUTINE, 352 "No proper attached SAS address value on device %s", 353 fullpath); 354 di_devfs_path_free(devpath); 355 free_attached_port(port_ptr); 356 return (HBA_STATUS_ERROR); 357 } 358 } else { 359 log(LOG_DEBUG, ROUTINE, 360 "Property AttachedSASAddress not found for device \"%s\"", 361 fullpath); 362 di_devfs_path_free(devpath); 363 free_attached_port(port_ptr); 364 return (HBA_STATUS_ERROR); 365 } 366 367 /* 368 * walk the disco list to make sure that there isn't a matching 369 * port and node wwn or a matching device path 370 */ 371 portfound = 0; 372 for (disco_port_ptr = port_ptr->first_attached_port; 373 disco_port_ptr != NULL; 374 disco_port_ptr = disco_port_ptr->next) { 375 if ((disco_port_ptr->port_attributes.PortState != 376 HBA_PORTSTATE_ERROR) && (memcmp(disco_port_ptr-> 377 port_attributes.PortSpecificAttribute. 378 SASPort->LocalSASAddress.wwn, SASAddress.wwn, 8) == 0)) { 379 /* 380 * found matching disco_port 381 * look for matching device path 382 */ 383 portfound = 1; 384 for (mapping_ptr = disco_port_ptr->scsiInfo; 385 mapping_ptr != NULL; 386 mapping_ptr = mapping_ptr->next) { 387 if (strstr(mapping_ptr-> entry.ScsiId. 388 OSDeviceName, devpath) != 0) { 389 log(LOG_DEBUG, ROUTINE, 390 "Found an already discovered " 391 "device %s.", fullpath); 392 di_devfs_path_free(devpath); 393 return (HBA_STATUS_OK); 394 } 395 } 396 if (portfound == 1) { 397 break; 398 } 399 } 400 } 401 402 if (portfound == 0) { 403 /* 404 * there are no matching SAS address. 405 * this must be a new device 406 */ 407 if ((disco_port_ptr = (struct sun_sas_port *)calloc(1, 408 sizeof (struct sun_sas_port))) == NULL) { 409 OUT_OF_MEMORY(ROUTINE); 410 di_devfs_path_free(devpath); 411 free_attached_port(port_ptr); 412 return (HBA_STATUS_ERROR); 413 } 414 415 if ((disco_port_ptr->port_attributes.PortSpecificAttribute.\ 416 SASPort = (struct SMHBA_SAS_Port *)calloc(1, 417 sizeof (struct SMHBA_SAS_Port))) == NULL) { 418 OUT_OF_MEMORY("add_hba_port_info"); 419 di_devfs_path_free(devpath); 420 free_attached_port(port_ptr); 421 return (HBA_STATUS_ERROR); 422 } 423 424 (void) memcpy(disco_port_ptr->port_attributes. 425 PortSpecificAttribute.SASPort->LocalSASAddress.wwn, 426 SASAddress.wwn, 8); 427 (void) memcpy(disco_port_ptr->port_attributes. 428 PortSpecificAttribute.SASPort->AttachedSASAddress.wwn, 429 AttachedSASAddress.wwn, 8); 430 431 /* Default to unknown until we figure out otherwise */ 432 rval = di_prop_lookup_strings(DDI_DEV_T_ANY, node, 433 "variant", &propStringData); 434 if (rval < 0) { 435 /* check if it is SMP target */ 436 charptr = di_driver_name(node); 437 if (charptr != NULL && (strncmp(charptr, "smp", 438 strlen(charptr)) == 0)) { 439 disco_port_ptr->port_attributes.PortType = 440 HBA_PORTTYPE_SASEXPANDER; 441 disco_port_ptr->port_attributes. 442 PortSpecificAttribute. 443 SASPort->PortProtocol = 444 HBA_SASPORTPROTOCOL_SMP; 445 if (lookupSMPLink(devpath, (char *)link) == 446 HBA_STATUS_OK) { 447 /* indentation changed here. */ 448 (void) strlcpy(disco_port_ptr->port_attributes. 449 OSDeviceName, link, 450 sizeof (disco_port_ptr->port_attributes.OSDeviceName)); 451 /* indentation change ends here. */ 452 } else { 453 /* indentation changed here. */ 454 get_minor(devpath, minorname); 455 (void) snprintf(fullpath, sizeof (fullpath), "%s%s%s", 456 DEVICES_DIR, devpath, minorname); 457 (void) strlcpy(disco_port_ptr->port_attributes. 458 OSDeviceName, fullpath, 459 sizeof (disco_port_ptr->port_attributes.OSDeviceName)); 460 /* indentation change ends here. */ 461 } 462 } else { 463 disco_port_ptr->port_attributes.PortType = 464 HBA_PORTTYPE_SASDEVICE; 465 disco_port_ptr->port_attributes.\ 466 PortSpecificAttribute.\ 467 SASPort->PortProtocol = 468 HBA_SASPORTPROTOCOL_SSP; 469 } 470 } else { 471 if ((strcmp(propStringData, "sata") == 0) || 472 (strcmp(propStringData, "atapi") == 0)) { 473 disco_port_ptr->port_attributes.PortType = 474 HBA_PORTTYPE_SATADEVICE; 475 disco_port_ptr->port_attributes.\ 476 PortSpecificAttribute.SASPort->PortProtocol 477 = HBA_SASPORTPROTOCOL_SATA; 478 } else { 479 log(LOG_DEBUG, ROUTINE, 480 "Unexpected variant prop value %s found on", 481 " device %s", propStringData, fullpath); 482 /* 483 * Port type will be 0 484 * which is not valid type. 485 */ 486 } 487 } 488 489 /* SMP device was handled already */ 490 if (disco_port_ptr->port_attributes.OSDeviceName[0] == '\0') { 491 /* indentation change due to ctysle check on sizeof. */ 492 size = sizeof (disco_port_ptr->port_attributes.OSDeviceName); 493 (void) strlcpy(disco_port_ptr->port_attributes. 494 OSDeviceName, fullpath, size); 495 } 496 497 /* add new discovered port into the list */ 498 499 if (port_ptr->first_attached_port == NULL) { 500 port_ptr->first_attached_port = disco_port_ptr; 501 disco_port_ptr->index = 0; 502 port_ptr->port_attributes.PortSpecificAttribute.\ 503 SASPort->NumberofDiscoveredPorts = 1; 504 } else { 505 disco_port_ptr->next = port_ptr->first_attached_port; 506 port_ptr->first_attached_port = disco_port_ptr; 507 disco_port_ptr->index = port_ptr->port_attributes.\ 508 PortSpecificAttribute.\ 509 SASPort->NumberofDiscoveredPorts; 510 port_ptr->port_attributes.PortSpecificAttribute.\ 511 SASPort->NumberofDiscoveredPorts++; 512 } 513 disco_port_ptr->port_attributes.PortState = port_state; 514 } 515 516 if (disco_port_ptr->port_attributes.PortType == 517 HBA_PORTTYPE_SASEXPANDER) { 518 /* No mapping data for expander device. return ok here. */ 519 di_devfs_path_free(devpath); 520 return (HBA_STATUS_OK); 521 } 522 523 if ((mapping_ptr = (struct ScsiEntryList *)calloc 524 (1, sizeof (struct ScsiEntryList))) == NULL) { 525 OUT_OF_MEMORY(ROUTINE); 526 di_devfs_path_free(devpath); 527 free_attached_port(port_ptr); 528 return (HBA_STATUS_ERROR); 529 } 530 531 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "lun", 532 &propIntData) != -1) { 533 mapping_ptr->entry.ScsiId.ScsiOSLun = *propIntData; 534 } else { 535 if ((charptr = strchr(unit_address, ',')) != NULL) { 536 charptr++; 537 mapping_ptr->entry.ScsiId.ScsiOSLun = 538 strtoull(charptr, NULL, 10); 539 } else { 540 log(LOG_DEBUG, ROUTINE, 541 "Failed to get LUN from the unit address of device " 542 " %s.", fullpath); 543 di_devfs_path_free(devpath); 544 free_attached_port(port_ptr); 545 return (HBA_STATUS_ERROR); 546 } 547 } 548 549 /* get TargetLun(SAM-LUN). */ 550 if (di_prop_lookup_int64(DDI_DEV_T_ANY, node, "lun64", 551 &propInt64Data) != -1) { 552 samLun = scsi_lun64_to_lun(*propInt64Data); 553 (void) memcpy(&mapping_ptr->entry.PortLun.TargetLun, 554 &samLun, 8); 555 } else { 556 log(LOG_DEBUG, "get_attached_devices_info", 557 "No lun64 prop found on device %s.", fullpath); 558 di_devfs_path_free(devpath); 559 free_attached_port(port_ptr); 560 return (HBA_STATUS_ERROR); 561 } 562 563 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, 564 "target", &propIntData) != -1) { 565 mapping_ptr->entry.ScsiId.ScsiTargetNumber = *propIntData; 566 } else { 567 mapping_ptr->entry.ScsiId.ScsiTargetNumber = di_instance(node); 568 } 569 570 /* get ScsiBusNumber */ 571 mapping_ptr->entry.ScsiId.ScsiBusNumber = port_ptr->cntlNumber; 572 573 (void) memcpy(mapping_ptr->entry.PortLun.PortWWN.wwn, 574 SASAddress.wwn, 8); 575 576 /* Store the devices path for now. We'll convert to /dev later */ 577 get_minor(devpath, minorname); 578 (void) snprintf(mapping_ptr->entry.ScsiId.OSDeviceName, 579 sizeof (mapping_ptr->entry.ScsiId.OSDeviceName), 580 "%s%s%s", DEVICES_DIR, devpath, minorname); 581 582 /* reset errno to 0 */ 583 errno = 0; 584 if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "devid", 585 &propStringData) != -1) { 586 if (devid_str_decode(propStringData, &devid, NULL) != -1) { 587 guidStr = devid_to_guid(devid); 588 if (guidStr != NULL) { 589 (void) strlcpy(mapping_ptr->entry.LUID.buffer, 590 guidStr, 256); 591 devid_free_guid(guidStr); 592 } else { 593 /* 594 * Note: 595 * if logical unit associated page 83 id 596 * descriptor is not avaialble for the device 597 * devid_to_guid returns NULl with errno 0. 598 */ 599 log(LOG_DEBUG, ROUTINE, 600 "failed to get devid guid on (%s) : %s", 601 devpath, strerror(errno)); 602 } 603 } else { 604 /* 605 * device may not support proper page 83 id descriptor. 606 * leave LUID attribute to NULL and continue. 607 */ 608 log(LOG_DEBUG, ROUTINE, 609 "failed to decode devid prop on (%s) : %s", 610 devpath, strerror(errno)); 611 } 612 } else { 613 /* leave LUID attribute to NULL and continue. */ 614 log(LOG_DEBUG, ROUTINE, 615 "failed to get devid prop on (%s) : %s", 616 devpath, strerror(errno)); 617 } 618 619 if (disco_port_ptr->scsiInfo == NULL) { 620 disco_port_ptr->scsiInfo = mapping_ptr; 621 } else { 622 mapping_ptr->next = disco_port_ptr->scsiInfo; 623 disco_port_ptr->scsiInfo = mapping_ptr; 624 } 625 626 di_devfs_path_free(devpath); 627 628 return (HBA_STATUS_OK); 629 } 630 631 /* 632 * Finds attached device(target) from pathinfo node. 633 */ 634 static HBA_STATUS 635 get_attached_paths_info(di_path_t path, struct sun_sas_port *port_ptr) 636 { 637 char ROUTINE[] = "get_attached_paths_info"; 638 char *propStringData = NULL; 639 int *propIntData = NULL; 640 int64_t *propInt64Data = NULL; 641 scsi_lun_t samLun; 642 ddi_devid_t devid; 643 char *guidStr; 644 char *unit_address; 645 char *charptr; 646 char *clientdevpath = NULL; 647 char *pathdevpath = NULL; 648 char fullpath[MAXPATHLEN+1]; 649 char minorname[MAXNAMELEN+1]; 650 struct ScsiEntryList *mapping_ptr; 651 HBA_WWN SASAddress, AttachedSASAddress; 652 struct sun_sas_port *disco_port_ptr; 653 di_path_state_t state = 0; 654 di_node_t clientnode; 655 int portfound, size; 656 int port_state = HBA_PORTSTATE_ONLINE; 657 uint64_t tmpAddr; 658 659 if (port_ptr == NULL) { 660 log(LOG_DEBUG, ROUTINE, "NULL port_ptr argument"); 661 return (HBA_STATUS_ERROR); 662 } 663 664 /* if not null, free before return. */ 665 pathdevpath = di_path_devfs_path(path); 666 667 state = di_path_state(path); 668 /* when node is not attached and online, set the state to offline. */ 669 if ((state == DI_PATH_STATE_OFFLINE) || 670 (state == DI_PATH_STATE_FAULT)) { 671 log(LOG_DEBUG, ROUTINE, 672 "path node (%s) is either OFFLINE or FAULT state", 673 pathdevpath ? pathdevpath : "(missing device path)"); 674 port_state = HBA_PORTSTATE_OFFLINE; 675 } 676 677 if (clientnode = di_path_client_node(path)) { 678 if (di_retired(clientnode)) { 679 log(LOG_DEBUG, ROUTINE, 680 "client node of path (%s) is retired. Skipping.", 681 pathdevpath ? pathdevpath : 682 "(missing device path)"); 683 if (pathdevpath) di_devfs_path_free(pathdevpath); 684 return (HBA_STATUS_OK); 685 } 686 if ((clientdevpath = di_devfs_path(clientnode)) == NULL) { 687 log(LOG_DEBUG, ROUTINE, 688 "Client device of path (%s) has no path. Skipping.", 689 pathdevpath ? pathdevpath : 690 "(missing device path)"); 691 if (pathdevpath) di_devfs_path_free(pathdevpath); 692 return (HBA_STATUS_ERROR); 693 } 694 } else { 695 log(LOG_DEBUG, ROUTINE, 696 "Failed to get client device from a path (%s).", 697 pathdevpath ? pathdevpath : 698 "(missing device path)"); 699 if (pathdevpath) di_devfs_path_free(pathdevpath); 700 return (HBA_STATUS_ERROR); 701 } 702 703 /* add the "/devices" in the begining and the :devctl at the end */ 704 (void) snprintf(fullpath, sizeof (fullpath), "%s%s", DEVICES_DIR, 705 clientdevpath); 706 707 (void) memset(&SASAddress, 0, sizeof (SASAddress)); 708 if ((unit_address = di_path_bus_addr(path)) != NULL) { 709 if ((charptr = strchr(unit_address, ',')) != NULL) { 710 *charptr = '\0'; 711 } 712 for (charptr = unit_address; *charptr != '\0'; charptr++) { 713 if (isxdigit(*charptr)) { 714 break; 715 } 716 } 717 if (charptr != '\0') { 718 tmpAddr = htonll(strtoll(charptr, NULL, 16)); 719 (void) memcpy(&SASAddress.wwn[0], &tmpAddr, 8); 720 } else { 721 log(LOG_DEBUG, ROUTINE, 722 "No proper target port info on unit address of " 723 "path (%s).", pathdevpath ? pathdevpath : 724 "(missing device path)"); 725 if (pathdevpath) di_devfs_path_free(pathdevpath); 726 di_devfs_path_free(clientdevpath); 727 return (HBA_STATUS_ERROR); 728 } 729 } else { 730 log(LOG_DEBUG, ROUTINE, "Fail to get unit address of path(%s).", 731 "path (%s).", pathdevpath ? pathdevpath : 732 "(missing device path)"); 733 if (pathdevpath) di_devfs_path_free(pathdevpath); 734 di_devfs_path_free(clientdevpath); 735 return (HBA_STATUS_ERROR); 736 } 737 738 (void) memset(&AttachedSASAddress, 0, sizeof (AttachedSASAddress)); 739 if (di_path_prop_lookup_strings(path, "attached-port", 740 &propStringData) != -1) { 741 for (charptr = propStringData; *charptr != '\0'; charptr++) { 742 if (isxdigit(*charptr)) { 743 break; 744 } 745 } 746 if (*charptr != '\0') { 747 tmpAddr = htonll(strtoll(charptr, NULL, 16)); 748 (void) memcpy(AttachedSASAddress.wwn, &tmpAddr, 8); 749 /* check the attached address of hba port. */ 750 if (memcmp(port_ptr->port_attributes. 751 PortSpecificAttribute.SASPort-> 752 LocalSASAddress.wwn, &tmpAddr, 8) == 0) { 753 if (wwnConversion(port_ptr->port_attributes. 754 PortSpecificAttribute.SASPort-> 755 AttachedSASAddress.wwn)) { 756 /* verify the attaached SAS Addr. */ 757 if (memcmp(port_ptr->port_attributes. 758 PortSpecificAttribute.SASPort-> 759 AttachedSASAddress.wwn, 760 SASAddress.wwn, 8) != 0) { 761 /* indentation move begin. */ 762 log(LOG_DEBUG, ROUTINE, 763 "iport attached-port(%016llx) do not" 764 " match with level 1 Local" 765 " SAS address(%016llx).", 766 wwnConversion(port_ptr->port_attributes. 767 PortSpecificAttribute. 768 SASPort->AttachedSASAddress.wwn), 769 wwnConversion(SASAddress.wwn)); 770 if (pathdevpath) 771 di_devfs_path_free(pathdevpath); 772 di_devfs_path_free(clientdevpath); 773 free_attached_port(port_ptr); 774 return (HBA_STATUS_ERROR); 775 /* indentation move ends. */ 776 } 777 } else { 778 /* store the Attaached SAS Addr. */ 779 (void) memcpy(port_ptr->port_attributes. 780 PortSpecificAttribute. 781 SASPort->AttachedSASAddress.wwn, 782 &SASAddress.wwn[0], 8); 783 } 784 } 785 } else { 786 log(LOG_DEBUG, ROUTINE, 787 "No proper attached SAS address value of path (%s)", 788 pathdevpath ? pathdevpath : 789 "(missing device path)"); 790 if (pathdevpath) di_devfs_path_free(pathdevpath); 791 di_devfs_path_free(clientdevpath); 792 free_attached_port(port_ptr); 793 return (HBA_STATUS_ERROR); 794 } 795 } else { 796 log(LOG_DEBUG, ROUTINE, 797 "Property attached-port not found for path (%s)", 798 pathdevpath ? pathdevpath : 799 "(missing device path)"); 800 if (pathdevpath) di_devfs_path_free(pathdevpath); 801 di_devfs_path_free(clientdevpath); 802 free_attached_port(port_ptr); 803 return (HBA_STATUS_ERROR); 804 } 805 806 /* 807 * walk the disco list to make sure that there isn't a matching 808 * port and node wwn or a matching device path 809 */ 810 portfound = 0; 811 for (disco_port_ptr = port_ptr->first_attached_port; 812 disco_port_ptr != NULL; 813 disco_port_ptr = disco_port_ptr->next) { 814 if ((disco_port_ptr->port_attributes.PortState != 815 HBA_PORTSTATE_ERROR) && 816 (memcmp(disco_port_ptr->port_attributes. 817 PortSpecificAttribute.SASPort->LocalSASAddress.wwn, 818 SASAddress.wwn, 8) == 0)) { 819 /* 820 * found matching disco_port 821 * look for matching device path 822 */ 823 portfound = 1; 824 for (mapping_ptr = disco_port_ptr->scsiInfo; 825 mapping_ptr != NULL; 826 mapping_ptr = mapping_ptr->next) { 827 if (strstr(mapping_ptr-> entry.ScsiId. 828 OSDeviceName, clientdevpath) != 0) { 829 log(LOG_DEBUG, ROUTINE, 830 "Found an already discovered " 831 "device %s.", clientdevpath); 832 if (pathdevpath) 833 di_devfs_path_free(pathdevpath); 834 di_devfs_path_free(clientdevpath); 835 return (HBA_STATUS_OK); 836 } 837 } 838 if (portfound == 1) { 839 break; 840 } 841 } 842 } 843 844 if (portfound == 0) { 845 /* 846 * there are no matching SAS address. 847 * this must be a new device 848 */ 849 if ((disco_port_ptr = (struct sun_sas_port *)calloc(1, 850 sizeof (struct sun_sas_port))) == NULL) { 851 OUT_OF_MEMORY(ROUTINE); 852 if (pathdevpath) di_devfs_path_free(pathdevpath); 853 di_devfs_path_free(clientdevpath); 854 free_attached_port(port_ptr); 855 return (HBA_STATUS_ERROR); 856 } 857 858 if ((disco_port_ptr->port_attributes.PortSpecificAttribute.\ 859 SASPort = (struct SMHBA_SAS_Port *)calloc(1, 860 sizeof (struct SMHBA_SAS_Port))) == NULL) { 861 OUT_OF_MEMORY("add_hba_port_info"); 862 if (pathdevpath) di_devfs_path_free(pathdevpath); 863 di_devfs_path_free(clientdevpath); 864 free_attached_port(port_ptr); 865 return (HBA_STATUS_ERROR); 866 } 867 868 (void) memcpy(disco_port_ptr->port_attributes. 869 PortSpecificAttribute. 870 SASPort->LocalSASAddress.wwn, SASAddress.wwn, 8); 871 (void) memcpy(disco_port_ptr->port_attributes. 872 PortSpecificAttribute. 873 SASPort->AttachedSASAddress.wwn, AttachedSASAddress.wwn, 8); 874 875 /* Default to unknown until we figure out otherwise */ 876 if (di_path_prop_lookup_strings(path, "variant", 877 &propStringData) != -1) { 878 if ((strcmp(propStringData, "sata") == 0) || 879 (strcmp(propStringData, "atapi") == 0)) { 880 disco_port_ptr->port_attributes.PortType = 881 HBA_PORTTYPE_SATADEVICE; 882 disco_port_ptr->port_attributes.\ 883 PortSpecificAttribute.SASPort->PortProtocol 884 = HBA_SASPORTPROTOCOL_SATA; 885 } else { 886 log(LOG_DEBUG, ROUTINE, 887 "Unexpected variant prop value %s found on", 888 " path (%s)", propStringData, 889 pathdevpath ? pathdevpath : 890 "(missing device path)"); 891 /* 892 * Port type will be 0 893 * which is not valid type. 894 */ 895 } 896 } else { 897 disco_port_ptr->port_attributes.PortType = 898 HBA_PORTTYPE_SASDEVICE; 899 disco_port_ptr->port_attributes.PortSpecificAttribute.\ 900 SASPort->PortProtocol = HBA_SASPORTPROTOCOL_SSP; 901 } 902 903 if (disco_port_ptr->port_attributes.OSDeviceName[0] == '\0') { 904 /* indentation change due to ctysle check on sizeof. */ 905 size = sizeof (disco_port_ptr->port_attributes.OSDeviceName); 906 if (pathdevpath != NULL) { 907 (void) strlcpy(disco_port_ptr->port_attributes. 908 OSDeviceName, pathdevpath, size); 909 } 910 } 911 912 /* add new discovered port into the list */ 913 if (port_ptr->first_attached_port == NULL) { 914 port_ptr->first_attached_port = disco_port_ptr; 915 disco_port_ptr->index = 0; 916 port_ptr->port_attributes.PortSpecificAttribute.\ 917 SASPort->NumberofDiscoveredPorts = 1; 918 } else { 919 disco_port_ptr->next = port_ptr->first_attached_port; 920 port_ptr->first_attached_port = disco_port_ptr; 921 disco_port_ptr->index = port_ptr->port_attributes.\ 922 PortSpecificAttribute.\ 923 SASPort->NumberofDiscoveredPorts; 924 port_ptr->port_attributes.PortSpecificAttribute.\ 925 SASPort->NumberofDiscoveredPorts++; 926 } 927 disco_port_ptr->port_attributes.PortState = port_state; 928 } 929 930 if ((mapping_ptr = (struct ScsiEntryList *)calloc 931 (1, sizeof (struct ScsiEntryList))) == NULL) { 932 OUT_OF_MEMORY(ROUTINE); 933 if (pathdevpath) di_devfs_path_free(pathdevpath); 934 di_devfs_path_free(clientdevpath); 935 free_attached_port(port_ptr); 936 return (HBA_STATUS_ERROR); 937 } 938 939 if (di_path_prop_lookup_ints(path, "lun", &propIntData) != -1) { 940 mapping_ptr->entry.ScsiId.ScsiOSLun = *propIntData; 941 } else { 942 if ((charptr = strchr(unit_address, ',')) != NULL) { 943 charptr++; 944 mapping_ptr->entry.ScsiId.ScsiOSLun = 945 strtoull(charptr, NULL, 10); 946 } else { 947 log(LOG_DEBUG, ROUTINE, 948 "Failed to get LUN from unit address of path(%s).", 949 pathdevpath ? pathdevpath : 950 "(missing device path)"); 951 if (pathdevpath) di_devfs_path_free(pathdevpath); 952 di_devfs_path_free(clientdevpath); 953 free_attached_port(port_ptr); 954 return (HBA_STATUS_ERROR); 955 } 956 } 957 958 /* Get TargetLun(SAM LUN). */ 959 if (di_path_prop_lookup_int64s(path, "lun64", &propInt64Data) != -1) { 960 samLun = scsi_lun64_to_lun(*propInt64Data); 961 (void) memcpy(&mapping_ptr->entry.PortLun.TargetLun, 962 &samLun, 8); 963 } else { 964 log(LOG_DEBUG, ROUTINE, "No lun64 prop found on path (%s)", 965 pathdevpath ? pathdevpath : 966 "(missing device path)"); 967 if (pathdevpath) di_devfs_path_free(pathdevpath); 968 di_devfs_path_free(clientdevpath); 969 free_attached_port(port_ptr); 970 return (HBA_STATUS_ERROR); 971 } 972 973 if (di_path_prop_lookup_ints(path, "target", &propIntData) != -1) { 974 mapping_ptr->entry.ScsiId.ScsiTargetNumber = *propIntData; 975 } else { 976 mapping_ptr->entry.ScsiId.ScsiTargetNumber = 977 di_path_instance(path); 978 } 979 980 /* get ScsiBusNumber */ 981 mapping_ptr->entry.ScsiId.ScsiBusNumber = port_ptr->cntlNumber; 982 983 (void) memcpy(mapping_ptr->entry.PortLun.PortWWN.wwn, 984 SASAddress.wwn, 8); 985 986 /* Store the devices path for now. We'll convert to /dev later */ 987 get_minor(clientdevpath, minorname); 988 (void) snprintf(mapping_ptr->entry.ScsiId.OSDeviceName, 989 sizeof (mapping_ptr->entry.ScsiId.OSDeviceName), 990 "%s%s%s", DEVICES_DIR, clientdevpath, minorname); 991 992 /* get luid. */ 993 errno = 0; /* reset errno to 0 */ 994 if (di_prop_lookup_strings(DDI_DEV_T_ANY, clientnode, "devid", 995 &propStringData) != -1) { 996 if (devid_str_decode(propStringData, &devid, NULL) != -1) { 997 guidStr = devid_to_guid(devid); 998 if (guidStr != NULL) { 999 (void) strlcpy(mapping_ptr->entry.LUID.buffer, 1000 guidStr, 1001 sizeof (mapping_ptr->entry.LUID.buffer)); 1002 devid_free_guid(guidStr); 1003 } else { 1004 /* 1005 * Note: 1006 * if logical unit associated page 83 id 1007 * descriptor is not avaialble for the device 1008 * devid_to_guid returns NULl with errno 0. 1009 */ 1010 log(LOG_DEBUG, ROUTINE, 1011 "failed to get devid guid on (%s)", 1012 " associated with path(%s) : %s", 1013 clientdevpath, 1014 pathdevpath ? pathdevpath : 1015 "(missing device path)", 1016 strerror(errno)); 1017 } 1018 } else { 1019 /* 1020 * device may not support proper page 83 id descriptor. 1021 * leave LUID attribute to NULL and continue. 1022 */ 1023 log(LOG_DEBUG, ROUTINE, 1024 "failed to decode devid prop on (%s)", 1025 " associated with path(%s) : %s", 1026 clientdevpath, 1027 pathdevpath ? pathdevpath : 1028 "(missing device path)", 1029 strerror(errno)); 1030 } 1031 } else { 1032 /* leave LUID attribute to NULL and continue. */ 1033 log(LOG_DEBUG, ROUTINE, "Failed to get devid on %s" 1034 " associated with path(%s) : %s", clientdevpath, 1035 pathdevpath ? pathdevpath : "(missing device path)", 1036 strerror(errno)); 1037 } 1038 1039 if (disco_port_ptr->scsiInfo == NULL) { 1040 disco_port_ptr->scsiInfo = mapping_ptr; 1041 } else { 1042 mapping_ptr->next = disco_port_ptr->scsiInfo; 1043 disco_port_ptr->scsiInfo = mapping_ptr; 1044 } 1045 1046 if (pathdevpath) di_devfs_path_free(pathdevpath); 1047 di_devfs_path_free(clientdevpath); 1048 1049 return (HBA_STATUS_OK); 1050 } 1051 1052 /* 1053 * walks the devinfo tree retrieving all hba information 1054 */ 1055 extern HBA_STATUS 1056 devtree_attached_devices(di_node_t node, struct sun_sas_port *port_ptr) 1057 { 1058 const char ROUTINE[] = "devtree_attached_devices"; 1059 di_node_t nodechild = DI_NODE_NIL; 1060 di_path_t path = DI_PATH_NIL; 1061 1062 /* child should be device */ 1063 if ((nodechild = di_child_node(node)) == DI_NODE_NIL) { 1064 log(LOG_DEBUG, ROUTINE, 1065 "No devinfo child on the HBA port node."); 1066 } 1067 1068 if ((path = di_path_phci_next_path(node, path)) == 1069 DI_PATH_NIL) { 1070 log(LOG_DEBUG, ROUTINE, 1071 "No pathinfo node on the HBA port node."); 1072 } 1073 1074 if ((nodechild == DI_NODE_NIL) && (path == DI_PATH_NIL)) { 1075 return (HBA_STATUS_OK); 1076 } 1077 1078 while (nodechild != DI_NODE_NIL) { 1079 if (get_attached_devices_info(nodechild, port_ptr) 1080 != HBA_STATUS_OK) { 1081 break; 1082 } 1083 nodechild = di_sibling_node(nodechild); 1084 } 1085 1086 1087 while (path != DI_PATH_NIL) { 1088 if (get_attached_paths_info(path, port_ptr) 1089 != HBA_STATUS_OK) { 1090 break; 1091 } 1092 path = di_path_phci_next_path(node, path); 1093 } 1094 1095 return (HBA_STATUS_OK); 1096 }