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