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