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