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