110652SHyon.Kim@Sun.COM /*
210652SHyon.Kim@Sun.COM * CDDL HEADER START
310652SHyon.Kim@Sun.COM *
410652SHyon.Kim@Sun.COM * The contents of this file are subject to the terms of the
510652SHyon.Kim@Sun.COM * Common Development and Distribution License (the "License").
610652SHyon.Kim@Sun.COM * You may not use this file except in compliance with the License.
710652SHyon.Kim@Sun.COM *
810652SHyon.Kim@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910652SHyon.Kim@Sun.COM * or http://www.opensolaris.org/os/licensing.
1010652SHyon.Kim@Sun.COM * See the License for the specific language governing permissions
1110652SHyon.Kim@Sun.COM * and limitations under the License.
1210652SHyon.Kim@Sun.COM *
1310652SHyon.Kim@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
1410652SHyon.Kim@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510652SHyon.Kim@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
1610652SHyon.Kim@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
1710652SHyon.Kim@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
1810652SHyon.Kim@Sun.COM *
1910652SHyon.Kim@Sun.COM * CDDL HEADER END
2010652SHyon.Kim@Sun.COM */
2110652SHyon.Kim@Sun.COM
2210652SHyon.Kim@Sun.COM /*
23*12176SXun.Ni@Sun.COM * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2410652SHyon.Kim@Sun.COM */
2510652SHyon.Kim@Sun.COM
2610652SHyon.Kim@Sun.COM #include <sun_sas.h>
2710652SHyon.Kim@Sun.COM #include <sys/modctl.h>
2810652SHyon.Kim@Sun.COM #include <sys/types.h>
2910652SHyon.Kim@Sun.COM #include <netinet/in.h>
3010652SHyon.Kim@Sun.COM #include <inttypes.h>
3110652SHyon.Kim@Sun.COM #include <ctype.h>
3210652SHyon.Kim@Sun.COM
3310652SHyon.Kim@Sun.COM /* free hba port info for the given hba */
3410652SHyon.Kim@Sun.COM static void
free_hba_port(struct sun_sas_hba * hba_ptr)3510652SHyon.Kim@Sun.COM free_hba_port(struct sun_sas_hba *hba_ptr)
3610652SHyon.Kim@Sun.COM {
3710652SHyon.Kim@Sun.COM struct sun_sas_port *hba_port = NULL;
3810652SHyon.Kim@Sun.COM struct sun_sas_port *last_hba_port = NULL;
3910652SHyon.Kim@Sun.COM struct sun_sas_port *tgt_port = NULL;
4010652SHyon.Kim@Sun.COM struct sun_sas_port *last_tgt_port = NULL;
4110652SHyon.Kim@Sun.COM struct ScsiEntryList *scsi_info = NULL;
4210652SHyon.Kim@Sun.COM struct ScsiEntryList *last_scsi_info = NULL;
4310652SHyon.Kim@Sun.COM struct phy_info *phy_ptr = NULL;
4410652SHyon.Kim@Sun.COM struct phy_info *last_phy = NULL;
4510652SHyon.Kim@Sun.COM
4610652SHyon.Kim@Sun.COM /* Free the nested structures (port and attached port) */
4710652SHyon.Kim@Sun.COM hba_port = hba_ptr->first_port;
4810652SHyon.Kim@Sun.COM while (hba_port != NULL) {
4910652SHyon.Kim@Sun.COM /* Free discovered port structure list. */
5010652SHyon.Kim@Sun.COM tgt_port = hba_port->first_attached_port;
5110652SHyon.Kim@Sun.COM while (tgt_port != NULL) {
5210652SHyon.Kim@Sun.COM /* Free target mapping data list first. */
5310652SHyon.Kim@Sun.COM scsi_info = tgt_port->scsiInfo;
5410652SHyon.Kim@Sun.COM while (scsi_info != NULL) {
5510652SHyon.Kim@Sun.COM last_scsi_info = scsi_info;
5610652SHyon.Kim@Sun.COM scsi_info = scsi_info->next;
5710652SHyon.Kim@Sun.COM free(last_scsi_info);
5810652SHyon.Kim@Sun.COM }
5910652SHyon.Kim@Sun.COM last_tgt_port = tgt_port;
6010652SHyon.Kim@Sun.COM tgt_port = tgt_port->next;
6110652SHyon.Kim@Sun.COM free(last_tgt_port->port_attributes.\
6210652SHyon.Kim@Sun.COM PortSpecificAttribute.SASPort);
6310652SHyon.Kim@Sun.COM free(last_tgt_port);
6410652SHyon.Kim@Sun.COM }
6510652SHyon.Kim@Sun.COM hba_port->first_attached_port = NULL;
6610652SHyon.Kim@Sun.COM
6710652SHyon.Kim@Sun.COM phy_ptr = hba_port->first_phy;
6810652SHyon.Kim@Sun.COM while (phy_ptr != NULL) {
6910652SHyon.Kim@Sun.COM last_phy = phy_ptr;
7010652SHyon.Kim@Sun.COM phy_ptr = phy_ptr->next;
7110652SHyon.Kim@Sun.COM free(last_phy);
7210652SHyon.Kim@Sun.COM }
7310652SHyon.Kim@Sun.COM hba_port->first_phy = NULL;
7410652SHyon.Kim@Sun.COM
7510652SHyon.Kim@Sun.COM last_hba_port = hba_port;
7610652SHyon.Kim@Sun.COM hba_port = hba_port->next;
7710652SHyon.Kim@Sun.COM free(last_hba_port->port_attributes.\
7810652SHyon.Kim@Sun.COM PortSpecificAttribute.SASPort);
7910652SHyon.Kim@Sun.COM free(last_hba_port);
8010652SHyon.Kim@Sun.COM }
8110652SHyon.Kim@Sun.COM
8210652SHyon.Kim@Sun.COM hba_ptr->first_port = NULL;
8310652SHyon.Kim@Sun.COM }
8410652SHyon.Kim@Sun.COM
8510652SHyon.Kim@Sun.COM /*
8610652SHyon.Kim@Sun.COM * Internal routine for adding an HBA port
8710652SHyon.Kim@Sun.COM */
8810652SHyon.Kim@Sun.COM static HBA_STATUS
add_hba_port_info(di_node_t portNode,struct sun_sas_hba * hba_ptr,int protocol)8910652SHyon.Kim@Sun.COM add_hba_port_info(di_node_t portNode, struct sun_sas_hba *hba_ptr, int protocol)
9010652SHyon.Kim@Sun.COM {
9110652SHyon.Kim@Sun.COM const char ROUTINE[] = "add_hba_port_info";
9210652SHyon.Kim@Sun.COM struct sun_sas_port *port_ptr;
9310652SHyon.Kim@Sun.COM char *portDevpath;
9410652SHyon.Kim@Sun.COM int *propIntData;
9510652SHyon.Kim@Sun.COM char *propStringData;
9610652SHyon.Kim@Sun.COM uint64_t tmpAddr;
9710652SHyon.Kim@Sun.COM char *charptr, cntlLink[MAXPATHLEN] = {'\0'};
9810652SHyon.Kim@Sun.COM int rval;
9911243SHyon.Kim@Sun.COM di_node_t branchNode;
10010652SHyon.Kim@Sun.COM uint_t state = HBA_PORTSTATE_UNKNOWN;
10110652SHyon.Kim@Sun.COM
10210652SHyon.Kim@Sun.COM if (hba_ptr == NULL) {
10310652SHyon.Kim@Sun.COM log(LOG_DEBUG, ROUTINE,
10410652SHyon.Kim@Sun.COM "Sun_sas handle ptr set to NULL.");
10510652SHyon.Kim@Sun.COM return (HBA_STATUS_ERROR_ARG);
10610652SHyon.Kim@Sun.COM }
10710652SHyon.Kim@Sun.COM
10810652SHyon.Kim@Sun.COM if ((port_ptr = (struct sun_sas_port *)calloc(1,
10910652SHyon.Kim@Sun.COM sizeof (struct sun_sas_port))) == NULL) {
11010652SHyon.Kim@Sun.COM OUT_OF_MEMORY(ROUTINE);
11110652SHyon.Kim@Sun.COM return (HBA_STATUS_ERROR);
11210652SHyon.Kim@Sun.COM }
11310652SHyon.Kim@Sun.COM
11410652SHyon.Kim@Sun.COM if ((port_ptr->port_attributes.PortSpecificAttribute.SASPort =
11510652SHyon.Kim@Sun.COM (struct SMHBA_SAS_Port *)calloc(1, sizeof (struct SMHBA_SAS_Port)))
11610652SHyon.Kim@Sun.COM == NULL) {
11710652SHyon.Kim@Sun.COM OUT_OF_MEMORY(ROUTINE);
11810652SHyon.Kim@Sun.COM return (HBA_STATUS_ERROR);
11910652SHyon.Kim@Sun.COM }
12010652SHyon.Kim@Sun.COM
12110652SHyon.Kim@Sun.COM if ((portDevpath = di_devfs_path(portNode)) == NULL) {
12210652SHyon.Kim@Sun.COM log(LOG_DEBUG, ROUTINE,
12310652SHyon.Kim@Sun.COM "Unable to get device path from HBA Port Node.");
12410652SHyon.Kim@Sun.COM S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
12510652SHyon.Kim@Sun.COM S_FREE(port_ptr);
12610652SHyon.Kim@Sun.COM return (HBA_STATUS_ERROR);
12710652SHyon.Kim@Sun.COM }
12810652SHyon.Kim@Sun.COM
12911243SHyon.Kim@Sun.COM /*
13011243SHyon.Kim@Sun.COM * Let's take a branch snap shot for pulling attributes.
13111243SHyon.Kim@Sun.COM * The attribute change doesn't invalidate devinfo cache snapshot.
13211243SHyon.Kim@Sun.COM * Phy info prop and num-phys can be obsolate when the same hba
13311243SHyon.Kim@Sun.COM * connected to the same expander(SIM) thus phy numbers are increased.
13411243SHyon.Kim@Sun.COM * Also the phy number may get decreased when a connection is removed
13511243SHyon.Kim@Sun.COM * while the iport still exist through another connection.
13611243SHyon.Kim@Sun.COM */
13711243SHyon.Kim@Sun.COM branchNode = di_init(portDevpath, DINFOPROP);
13811243SHyon.Kim@Sun.COM if (branchNode == DI_NODE_NIL) {
13911243SHyon.Kim@Sun.COM /* something is wrong here. */
14011243SHyon.Kim@Sun.COM di_fini(branchNode);
14111243SHyon.Kim@Sun.COM log(LOG_DEBUG, ROUTINE,
14211243SHyon.Kim@Sun.COM "Unable to take devinfoi branch snapshot on HBA port \"%s\""
14311243SHyon.Kim@Sun.COM " due to %s", portDevpath, strerror(errno));
14411243SHyon.Kim@Sun.COM S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
14511243SHyon.Kim@Sun.COM S_FREE(port_ptr);
14611243SHyon.Kim@Sun.COM return (HBA_STATUS_ERROR);
14711243SHyon.Kim@Sun.COM }
14811243SHyon.Kim@Sun.COM
14910652SHyon.Kim@Sun.COM state = di_state(portNode);
15010652SHyon.Kim@Sun.COM if (((state & DI_DRIVER_DETACHED) == DI_DRIVER_DETACHED) ||
15110652SHyon.Kim@Sun.COM ((state & DI_DEVICE_OFFLINE) == DI_DEVICE_OFFLINE)) {
15210652SHyon.Kim@Sun.COM log(LOG_DEBUG, ROUTINE,
15310652SHyon.Kim@Sun.COM "HBA port node %s is either OFFLINE or DETACHED",
15410652SHyon.Kim@Sun.COM portDevpath);
15510652SHyon.Kim@Sun.COM port_ptr->port_attributes.PortState = HBA_PORTSTATE_OFFLINE;
15610652SHyon.Kim@Sun.COM } else {
15710652SHyon.Kim@Sun.COM port_ptr->port_attributes.PortState = HBA_PORTSTATE_ONLINE;
15810652SHyon.Kim@Sun.COM }
15910652SHyon.Kim@Sun.COM
16010652SHyon.Kim@Sun.COM port_ptr->port_attributes.PortType = HBA_PORTTYPE_SASDEVICE;
16110652SHyon.Kim@Sun.COM
16210652SHyon.Kim@Sun.COM (void) strlcpy(port_ptr->device_path, portDevpath, MAXPATHLEN + 1);
16310652SHyon.Kim@Sun.COM
16410652SHyon.Kim@Sun.COM if (lookupControllerLink(portDevpath, (char *)cntlLink) ==
16510652SHyon.Kim@Sun.COM HBA_STATUS_OK) {
16610652SHyon.Kim@Sun.COM (void) strlcpy(port_ptr->port_attributes.OSDeviceName, cntlLink,
16710652SHyon.Kim@Sun.COM sizeof (port_ptr->port_attributes.OSDeviceName));
16810652SHyon.Kim@Sun.COM if ((charptr = strrchr(cntlLink, '/')) != NULL) {
16910652SHyon.Kim@Sun.COM charptr++;
17010652SHyon.Kim@Sun.COM }
17110652SHyon.Kim@Sun.COM if (charptr[0] == 'c') {
17210652SHyon.Kim@Sun.COM port_ptr->cntlNumber = atoi(++charptr);
17310652SHyon.Kim@Sun.COM } else {
17410652SHyon.Kim@Sun.COM port_ptr->cntlNumber = -1;
17510652SHyon.Kim@Sun.COM }
17610652SHyon.Kim@Sun.COM } else {
17710652SHyon.Kim@Sun.COM (void) snprintf(port_ptr->port_attributes.OSDeviceName,
17810652SHyon.Kim@Sun.COM sizeof (port_ptr->port_attributes.OSDeviceName),
17910652SHyon.Kim@Sun.COM "%s%s%s", DEVICES_DIR, portDevpath, SCSI_SUFFIX);
18010652SHyon.Kim@Sun.COM }
18110652SHyon.Kim@Sun.COM
18210652SHyon.Kim@Sun.COM di_devfs_path_free(portDevpath);
18310652SHyon.Kim@Sun.COM
18410652SHyon.Kim@Sun.COM port_ptr->port_attributes.PortSpecificAttribute.
18510652SHyon.Kim@Sun.COM SASPort->PortProtocol = protocol;
18610652SHyon.Kim@Sun.COM
18711243SHyon.Kim@Sun.COM rval = di_prop_lookup_strings(DDI_DEV_T_ANY, branchNode,
18810652SHyon.Kim@Sun.COM "initiator-port", &propStringData);
18910652SHyon.Kim@Sun.COM if (rval < 0) {
19010652SHyon.Kim@Sun.COM log(LOG_DEBUG, ROUTINE,
19110652SHyon.Kim@Sun.COM "Unable to get initiator-port from HBA port node %s.",
19210652SHyon.Kim@Sun.COM port_ptr->port_attributes.OSDeviceName);
19311243SHyon.Kim@Sun.COM di_fini(branchNode);
19410652SHyon.Kim@Sun.COM S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
19510652SHyon.Kim@Sun.COM S_FREE(port_ptr);
19610652SHyon.Kim@Sun.COM return (HBA_STATUS_ERROR);
19710652SHyon.Kim@Sun.COM } else {
19810652SHyon.Kim@Sun.COM for (charptr = propStringData; *charptr != '\0'; charptr++) {
19910652SHyon.Kim@Sun.COM if (isxdigit(*charptr)) {
20010652SHyon.Kim@Sun.COM break;
20110652SHyon.Kim@Sun.COM }
20210652SHyon.Kim@Sun.COM }
20310652SHyon.Kim@Sun.COM if (*charptr != '\0') {
20410652SHyon.Kim@Sun.COM tmpAddr = htonll(strtoll(charptr, NULL, 16));
20510652SHyon.Kim@Sun.COM (void) memcpy(port_ptr->port_attributes.
20610652SHyon.Kim@Sun.COM PortSpecificAttribute.SASPort->LocalSASAddress.wwn,
20710652SHyon.Kim@Sun.COM &tmpAddr, 8);
20810652SHyon.Kim@Sun.COM } else {
20910652SHyon.Kim@Sun.COM log(LOG_DEBUG, ROUTINE,
21010652SHyon.Kim@Sun.COM "No proper intiator-port prop value on HBA port %s",
21110652SHyon.Kim@Sun.COM port_ptr->port_attributes.OSDeviceName);
21210652SHyon.Kim@Sun.COM }
21310652SHyon.Kim@Sun.COM }
21410652SHyon.Kim@Sun.COM
21511243SHyon.Kim@Sun.COM rval = di_prop_lookup_strings(DDI_DEV_T_ANY, branchNode,
21610652SHyon.Kim@Sun.COM "attached-port", &propStringData);
21710652SHyon.Kim@Sun.COM if (rval < 0) {
21810652SHyon.Kim@Sun.COM log(LOG_DEBUG, ROUTINE,
21910652SHyon.Kim@Sun.COM "Unable to get attached-port from HBA port node %s.",
22010652SHyon.Kim@Sun.COM port_ptr->port_attributes.OSDeviceName);
22111243SHyon.Kim@Sun.COM di_fini(branchNode);
22210652SHyon.Kim@Sun.COM S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
22310652SHyon.Kim@Sun.COM S_FREE(port_ptr);
22410652SHyon.Kim@Sun.COM return (HBA_STATUS_ERROR);
22510652SHyon.Kim@Sun.COM } else {
22610652SHyon.Kim@Sun.COM for (charptr = propStringData; *charptr != '\0'; charptr++) {
22710652SHyon.Kim@Sun.COM if (isxdigit(*charptr)) {
22810652SHyon.Kim@Sun.COM break;
22910652SHyon.Kim@Sun.COM }
23010652SHyon.Kim@Sun.COM }
23110652SHyon.Kim@Sun.COM if (*charptr != '\0') {
23210652SHyon.Kim@Sun.COM tmpAddr = htonll(strtoll(charptr, NULL, 16));
23310652SHyon.Kim@Sun.COM (void) memcpy(port_ptr->port_attributes.
23410652SHyon.Kim@Sun.COM PortSpecificAttribute.SASPort->
23510652SHyon.Kim@Sun.COM AttachedSASAddress.wwn, &tmpAddr, 8);
23610652SHyon.Kim@Sun.COM } else {
23710652SHyon.Kim@Sun.COM /* continue even if the attached port is NULL. */
23810652SHyon.Kim@Sun.COM log(LOG_DEBUG, ROUTINE,
23910652SHyon.Kim@Sun.COM "No proper attached-port prop value: "
24010652SHyon.Kim@Sun.COM "HBA port Local SAS Address(%016llx)",
24110652SHyon.Kim@Sun.COM wwnConversion(port_ptr->port_attributes.
24210652SHyon.Kim@Sun.COM PortSpecificAttribute.
24310652SHyon.Kim@Sun.COM SASPort->LocalSASAddress.wwn));
24410652SHyon.Kim@Sun.COM }
24510652SHyon.Kim@Sun.COM }
24610652SHyon.Kim@Sun.COM
24711243SHyon.Kim@Sun.COM rval = di_prop_lookup_ints(DDI_DEV_T_ANY, branchNode,
24810652SHyon.Kim@Sun.COM "num-phys", &propIntData);
24910652SHyon.Kim@Sun.COM if (rval < 0) {
25010652SHyon.Kim@Sun.COM log(LOG_DEBUG, ROUTINE,
25110652SHyon.Kim@Sun.COM "Unable to get NumberofPhys from HBA port %s.",
25210652SHyon.Kim@Sun.COM port_ptr->port_attributes.OSDeviceName);
25311243SHyon.Kim@Sun.COM di_fini(branchNode);
25410652SHyon.Kim@Sun.COM S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
25510652SHyon.Kim@Sun.COM S_FREE(port_ptr);
25610652SHyon.Kim@Sun.COM return (HBA_STATUS_ERROR);
25710652SHyon.Kim@Sun.COM } else {
25810652SHyon.Kim@Sun.COM port_ptr->port_attributes.PortSpecificAttribute.\
25910652SHyon.Kim@Sun.COM SASPort->NumberofPhys = *propIntData;
26010652SHyon.Kim@Sun.COM }
26110652SHyon.Kim@Sun.COM
26210652SHyon.Kim@Sun.COM if (port_ptr->port_attributes.PortSpecificAttribute.\
26310652SHyon.Kim@Sun.COM SASPort->NumberofPhys > 0) {
26411243SHyon.Kim@Sun.COM if (get_phy_info(branchNode, port_ptr) != HBA_STATUS_OK) {
26510652SHyon.Kim@Sun.COM log(LOG_DEBUG, ROUTINE,
26610652SHyon.Kim@Sun.COM "Failed to get phy info on HBA port %s.",
26710652SHyon.Kim@Sun.COM port_ptr->port_attributes.OSDeviceName);
26811243SHyon.Kim@Sun.COM di_fini(branchNode);
26910652SHyon.Kim@Sun.COM S_FREE(port_ptr->port_attributes.
27010652SHyon.Kim@Sun.COM PortSpecificAttribute.SASPort);
27110652SHyon.Kim@Sun.COM S_FREE(port_ptr);
27211243SHyon.Kim@Sun.COM return (HBA_STATUS_ERROR);
27310652SHyon.Kim@Sun.COM }
27410652SHyon.Kim@Sun.COM }
27510652SHyon.Kim@Sun.COM
27611243SHyon.Kim@Sun.COM /* now done with prop checking. remove branchNode. */
27711243SHyon.Kim@Sun.COM di_fini(branchNode);
27811243SHyon.Kim@Sun.COM
27911243SHyon.Kim@Sun.COM /* Construct discovered target port. */
28010652SHyon.Kim@Sun.COM if (devtree_attached_devices(portNode, port_ptr) != HBA_STATUS_OK) {
28110652SHyon.Kim@Sun.COM log(LOG_DEBUG, ROUTINE,
28210652SHyon.Kim@Sun.COM "Failed to get attached device info HBA port %s.",
28310652SHyon.Kim@Sun.COM port_ptr->port_attributes.OSDeviceName);
28410652SHyon.Kim@Sun.COM S_FREE(port_ptr->port_attributes.PortSpecificAttribute.SASPort);
28510652SHyon.Kim@Sun.COM S_FREE(port_ptr);
28611243SHyon.Kim@Sun.COM return (HBA_STATUS_ERROR);
28710652SHyon.Kim@Sun.COM }
28810652SHyon.Kim@Sun.COM
28910652SHyon.Kim@Sun.COM fillDomainPortWWN(port_ptr);
29010652SHyon.Kim@Sun.COM
29110652SHyon.Kim@Sun.COM /* add new port onto hba handle list */
29210652SHyon.Kim@Sun.COM if (hba_ptr->first_port == NULL) {
29310652SHyon.Kim@Sun.COM port_ptr->index = 0;
29410652SHyon.Kim@Sun.COM hba_ptr->first_port = port_ptr;
29510652SHyon.Kim@Sun.COM } else {
29610652SHyon.Kim@Sun.COM port_ptr->index = hba_ptr->first_port->index + 1;
29710652SHyon.Kim@Sun.COM port_ptr->next = hba_ptr->first_port;
29810652SHyon.Kim@Sun.COM hba_ptr->first_port = port_ptr;
29910652SHyon.Kim@Sun.COM }
30010652SHyon.Kim@Sun.COM
30110652SHyon.Kim@Sun.COM return (HBA_STATUS_OK);
30210652SHyon.Kim@Sun.COM }
30310652SHyon.Kim@Sun.COM
30410652SHyon.Kim@Sun.COM HBA_STATUS
refresh_hba(di_node_t hbaNode,struct sun_sas_hba * hba_ptr)30510652SHyon.Kim@Sun.COM refresh_hba(di_node_t hbaNode, struct sun_sas_hba *hba_ptr)
30610652SHyon.Kim@Sun.COM {
30710652SHyon.Kim@Sun.COM const char ROUTINE[] = "refresh_hba";
30810652SHyon.Kim@Sun.COM di_node_t portNode;
30910652SHyon.Kim@Sun.COM int protocol = 0;
31010652SHyon.Kim@Sun.COM int *propIntData;
31110652SHyon.Kim@Sun.COM
31210652SHyon.Kim@Sun.COM /*
31310652SHyon.Kim@Sun.COM * clean up existing hba port, discovered target, phy info.
31410652SHyon.Kim@Sun.COM * leave open handles intact.
31510652SHyon.Kim@Sun.COM */
31610652SHyon.Kim@Sun.COM free_hba_port(hba_ptr);
31710652SHyon.Kim@Sun.COM
31810652SHyon.Kim@Sun.COM if ((portNode = di_child_node(hbaNode)) == NULL) {
31910652SHyon.Kim@Sun.COM log(LOG_DEBUG, ROUTINE,
32010652SHyon.Kim@Sun.COM "HBA node doesn't have iport child.");
32110652SHyon.Kim@Sun.COM return (HBA_STATUS_ERROR);
32210652SHyon.Kim@Sun.COM }
32310652SHyon.Kim@Sun.COM
32410652SHyon.Kim@Sun.COM if ((di_prop_lookup_ints(DDI_DEV_T_ANY, hbaNode,
32510652SHyon.Kim@Sun.COM "supported-protocol", &propIntData)) == -1) {
32610652SHyon.Kim@Sun.COM log(LOG_DEBUG, ROUTINE,
32710652SHyon.Kim@Sun.COM "Unable to get supported-protocol from HBA node.");
32810652SHyon.Kim@Sun.COM } else {
32910652SHyon.Kim@Sun.COM protocol = *propIntData;
33010652SHyon.Kim@Sun.COM }
33110652SHyon.Kim@Sun.COM
33210652SHyon.Kim@Sun.COM while (portNode != DI_NODE_NIL) {
333*12176SXun.Ni@Sun.COM if (di_prop_lookup_ints(DDI_DEV_T_ANY, portNode,
334*12176SXun.Ni@Sun.COM "virtual-port", &propIntData) >= 0) {
335*12176SXun.Ni@Sun.COM if (*propIntData) {
336*12176SXun.Ni@Sun.COM /* ignore a virtual port. */
337*12176SXun.Ni@Sun.COM portNode = di_sibling_node(portNode);
338*12176SXun.Ni@Sun.COM continue;
339*12176SXun.Ni@Sun.COM }
340*12176SXun.Ni@Sun.COM }
34110652SHyon.Kim@Sun.COM if (add_hba_port_info(portNode, hba_ptr, protocol)
34210652SHyon.Kim@Sun.COM == HBA_STATUS_ERROR) {
34310652SHyon.Kim@Sun.COM S_FREE(hba_ptr->first_port);
34410652SHyon.Kim@Sun.COM S_FREE(hba_ptr);
34510652SHyon.Kim@Sun.COM return (HBA_STATUS_ERROR);
34610652SHyon.Kim@Sun.COM }
34710652SHyon.Kim@Sun.COM portNode = di_sibling_node(portNode);
34810652SHyon.Kim@Sun.COM }
34910652SHyon.Kim@Sun.COM
35010652SHyon.Kim@Sun.COM return (HBA_STATUS_OK);
35110652SHyon.Kim@Sun.COM }
35210652SHyon.Kim@Sun.COM
35310652SHyon.Kim@Sun.COM /*
35410652SHyon.Kim@Sun.COM * Discover information for one HBA in the device tree.
35510652SHyon.Kim@Sun.COM * The di_node_t argument should be a node with smhba-supported prop set
35610652SHyon.Kim@Sun.COM * to true.
35710652SHyon.Kim@Sun.COM * Without iport support, the devinfo node will represent one port hba.
35810652SHyon.Kim@Sun.COM * This routine assumes the locks have been taken.
35910652SHyon.Kim@Sun.COM */
36010652SHyon.Kim@Sun.COM HBA_STATUS
devtree_get_one_hba(di_node_t hbaNode)36110652SHyon.Kim@Sun.COM devtree_get_one_hba(di_node_t hbaNode)
36210652SHyon.Kim@Sun.COM {
36310652SHyon.Kim@Sun.COM const char ROUTINE[] = "devtree_get_one_hba";
36410652SHyon.Kim@Sun.COM char *propdata = NULL;
36510652SHyon.Kim@Sun.COM int *propIntData = NULL;
36610652SHyon.Kim@Sun.COM struct sun_sas_hba *new_hba, *hba_ptr;
36710652SHyon.Kim@Sun.COM char *hbaDevpath, *hba_driver;
36810652SHyon.Kim@Sun.COM int protocol = 0;
36910652SHyon.Kim@Sun.COM di_node_t portNode;
37010652SHyon.Kim@Sun.COM int hba_instance = -1;
37110652SHyon.Kim@Sun.COM
37210652SHyon.Kim@Sun.COM hba_instance = di_instance(hbaNode);
37310652SHyon.Kim@Sun.COM if (hba_instance == -1) {
37410652SHyon.Kim@Sun.COM log(LOG_DEBUG, ROUTINE,
37510652SHyon.Kim@Sun.COM "portNode has instance of -1");
37610652SHyon.Kim@Sun.COM return (DI_WALK_CONTINUE);
37710652SHyon.Kim@Sun.COM }
37810652SHyon.Kim@Sun.COM
37910652SHyon.Kim@Sun.COM if ((hbaDevpath = di_devfs_path(hbaNode)) == NULL) {
38010652SHyon.Kim@Sun.COM log(LOG_DEBUG, ROUTINE, "Unable to get "
38110652SHyon.Kim@Sun.COM "device path from hbaNode");
38210652SHyon.Kim@Sun.COM return (HBA_STATUS_ERROR);
38310652SHyon.Kim@Sun.COM }
38410652SHyon.Kim@Sun.COM
38510652SHyon.Kim@Sun.COM /* check to see if this is a repeat HBA */
38610652SHyon.Kim@Sun.COM if (global_hba_head) {
38710652SHyon.Kim@Sun.COM for (hba_ptr = global_hba_head;
38810652SHyon.Kim@Sun.COM hba_ptr != NULL;
38910652SHyon.Kim@Sun.COM hba_ptr = hba_ptr->next) {
39010652SHyon.Kim@Sun.COM if ((strncmp(hba_ptr->device_path, hbaDevpath,
39110652SHyon.Kim@Sun.COM strlen(hbaDevpath))) == 0) {
39210652SHyon.Kim@Sun.COM if (refresh_hba(hbaNode, hba_ptr) !=
39310652SHyon.Kim@Sun.COM HBA_STATUS_OK) {
39410652SHyon.Kim@Sun.COM log(LOG_DEBUG, ROUTINE, "Refresh failed"
39510652SHyon.Kim@Sun.COM " on hbaNode %s", hbaDevpath);
39610652SHyon.Kim@Sun.COM }
39710652SHyon.Kim@Sun.COM di_devfs_path_free(hbaDevpath);
39810652SHyon.Kim@Sun.COM return (HBA_STATUS_OK);
39910652SHyon.Kim@Sun.COM }
40010652SHyon.Kim@Sun.COM }
40110652SHyon.Kim@Sun.COM }
40210652SHyon.Kim@Sun.COM
40310652SHyon.Kim@Sun.COM /* this is a new hba */
40410652SHyon.Kim@Sun.COM if ((new_hba = (struct sun_sas_hba *)calloc(1,
40510652SHyon.Kim@Sun.COM sizeof (struct sun_sas_hba))) == NULL) {
40610652SHyon.Kim@Sun.COM OUT_OF_MEMORY(ROUTINE);
40710652SHyon.Kim@Sun.COM di_devfs_path_free(hbaDevpath);
40810652SHyon.Kim@Sun.COM return (HBA_STATUS_ERROR);
40910652SHyon.Kim@Sun.COM }
41010652SHyon.Kim@Sun.COM
41110652SHyon.Kim@Sun.COM (void) strlcpy(new_hba->device_path, hbaDevpath,
41210652SHyon.Kim@Sun.COM sizeof (new_hba->device_path));
41310652SHyon.Kim@Sun.COM di_devfs_path_free(hbaDevpath);
41410652SHyon.Kim@Sun.COM
41510652SHyon.Kim@Sun.COM (void) snprintf(new_hba->adapter_attributes.HBASymbolicName,
41610652SHyon.Kim@Sun.COM sizeof (new_hba->adapter_attributes.HBASymbolicName),
41710652SHyon.Kim@Sun.COM "%s%s", DEVICES_DIR, new_hba->device_path);
41810652SHyon.Kim@Sun.COM
41910652SHyon.Kim@Sun.COM /* Manufacturer */
42010652SHyon.Kim@Sun.COM if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
42110652SHyon.Kim@Sun.COM "Manufacturer", (char **)&propdata)) == -1) {
42210652SHyon.Kim@Sun.COM (void) strlcpy(new_hba->adapter_attributes.Manufacturer,
42310652SHyon.Kim@Sun.COM SUN_MICROSYSTEMS,
42410652SHyon.Kim@Sun.COM sizeof (new_hba->adapter_attributes.Manufacturer));
42510652SHyon.Kim@Sun.COM } else {
42610652SHyon.Kim@Sun.COM (void) strlcpy(new_hba->adapter_attributes.Manufacturer,
42710652SHyon.Kim@Sun.COM propdata,
42810652SHyon.Kim@Sun.COM sizeof (new_hba->adapter_attributes.Manufacturer));
42910652SHyon.Kim@Sun.COM }
43010652SHyon.Kim@Sun.COM
43110652SHyon.Kim@Sun.COM /* SerialNumber */
43210652SHyon.Kim@Sun.COM if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
43310652SHyon.Kim@Sun.COM "SerialNumber", (char **)&propdata)) == -1) {
43410652SHyon.Kim@Sun.COM new_hba->adapter_attributes.SerialNumber[0] = '\0';
43510652SHyon.Kim@Sun.COM } else {
43610652SHyon.Kim@Sun.COM (void) strlcpy(new_hba->adapter_attributes.SerialNumber,
43710652SHyon.Kim@Sun.COM propdata,
43810652SHyon.Kim@Sun.COM sizeof (new_hba->adapter_attributes.SerialNumber));
43910652SHyon.Kim@Sun.COM }
44010652SHyon.Kim@Sun.COM
44110652SHyon.Kim@Sun.COM /* Model */
44210652SHyon.Kim@Sun.COM if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
44310652SHyon.Kim@Sun.COM "ModelName", (char **)&propdata)) == -1) {
44410652SHyon.Kim@Sun.COM new_hba->adapter_attributes.Model[0] = '\0';
44510652SHyon.Kim@Sun.COM } else {
44610652SHyon.Kim@Sun.COM (void) strlcpy(new_hba->adapter_attributes.Model,
44710652SHyon.Kim@Sun.COM propdata,
44810652SHyon.Kim@Sun.COM sizeof (new_hba->adapter_attributes.Model));
44910652SHyon.Kim@Sun.COM }
45010652SHyon.Kim@Sun.COM
45110652SHyon.Kim@Sun.COM /* FirmwareVersion */
45210652SHyon.Kim@Sun.COM if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
45310652SHyon.Kim@Sun.COM "firmware-version", (char **)&propdata)) == -1) {
45410652SHyon.Kim@Sun.COM log(LOG_DEBUG, ROUTINE,
45510652SHyon.Kim@Sun.COM "Property \"%s\" not found for device \"%s\"",
45610652SHyon.Kim@Sun.COM "firmware-version", new_hba->device_path);
45710652SHyon.Kim@Sun.COM } else {
45810652SHyon.Kim@Sun.COM (void) strlcpy(new_hba->adapter_attributes.FirmwareVersion,
45910652SHyon.Kim@Sun.COM propdata,
46010652SHyon.Kim@Sun.COM sizeof (new_hba->adapter_attributes.FirmwareVersion));
46110652SHyon.Kim@Sun.COM }
46210652SHyon.Kim@Sun.COM
46310652SHyon.Kim@Sun.COM /* HardwareVersion */
46410652SHyon.Kim@Sun.COM if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
46510652SHyon.Kim@Sun.COM "hardware-version", (char **)&propdata)) == -1) {
46610652SHyon.Kim@Sun.COM log(LOG_DEBUG, ROUTINE,
46710652SHyon.Kim@Sun.COM "Property \"%s\" not found for device \"%s\"",
46810652SHyon.Kim@Sun.COM "hardware-version", new_hba->device_path);
46910652SHyon.Kim@Sun.COM } else {
47010652SHyon.Kim@Sun.COM (void) strlcpy(new_hba->adapter_attributes.HardwareVersion,
47110652SHyon.Kim@Sun.COM propdata,
47210652SHyon.Kim@Sun.COM sizeof (new_hba->adapter_attributes.HardwareVersion));
47310652SHyon.Kim@Sun.COM }
47410652SHyon.Kim@Sun.COM
47510652SHyon.Kim@Sun.COM /* DriverVersion */
47610652SHyon.Kim@Sun.COM if ((di_prop_lookup_strings(DDI_DEV_T_ANY, hbaNode,
47710652SHyon.Kim@Sun.COM "driver-version", (char **)&propdata)) == -1) {
47810652SHyon.Kim@Sun.COM log(LOG_DEBUG, ROUTINE,
47910652SHyon.Kim@Sun.COM "Property \"%s\" not found for device \"%s\"",
48010652SHyon.Kim@Sun.COM "driver-version", new_hba->device_path);
48110652SHyon.Kim@Sun.COM } else {
48210652SHyon.Kim@Sun.COM (void) strlcpy(new_hba->adapter_attributes.DriverVersion,
48310652SHyon.Kim@Sun.COM propdata,
48410652SHyon.Kim@Sun.COM sizeof (new_hba->adapter_attributes.DriverVersion));
48510652SHyon.Kim@Sun.COM }
48610652SHyon.Kim@Sun.COM
48710652SHyon.Kim@Sun.COM if ((di_prop_lookup_ints(DDI_DEV_T_ANY, hbaNode,
48810652SHyon.Kim@Sun.COM "supported-protocol", &propIntData)) == -1) {
48910652SHyon.Kim@Sun.COM log(LOG_DEBUG, ROUTINE,
49010652SHyon.Kim@Sun.COM "Unable to get supported-protocol from HBA node.");
49110652SHyon.Kim@Sun.COM } else {
49210652SHyon.Kim@Sun.COM protocol = *propIntData;
49310652SHyon.Kim@Sun.COM }
49410652SHyon.Kim@Sun.COM
49510652SHyon.Kim@Sun.COM /* We don't use these */
49610652SHyon.Kim@Sun.COM new_hba->adapter_attributes.OptionROMVersion[0] = '\0';
49710652SHyon.Kim@Sun.COM new_hba->adapter_attributes.RedundantOptionROMVersion[0] = '\0';
49810652SHyon.Kim@Sun.COM new_hba->adapter_attributes.RedundantFirmwareVersion[0] = '\0';
49910652SHyon.Kim@Sun.COM new_hba->adapter_attributes.VendorSpecificID = 0;
50010652SHyon.Kim@Sun.COM
50110652SHyon.Kim@Sun.COM if ((hba_driver = di_driver_name(hbaNode)) != NULL) {
50210652SHyon.Kim@Sun.COM (void) strlcpy(new_hba->adapter_attributes.DriverName,
50310652SHyon.Kim@Sun.COM hba_driver,
50410652SHyon.Kim@Sun.COM sizeof (new_hba->adapter_attributes.DriverName));
50510652SHyon.Kim@Sun.COM } else {
50610652SHyon.Kim@Sun.COM log(LOG_DEBUG, ROUTINE,
50710652SHyon.Kim@Sun.COM "HBA driver name not found for device \"%s\"",
50810652SHyon.Kim@Sun.COM new_hba->device_path);
50910652SHyon.Kim@Sun.COM }
51010652SHyon.Kim@Sun.COM
51110652SHyon.Kim@Sun.COM /*
51210652SHyon.Kim@Sun.COM * Name the adapter: like SUNW-pmcs-1
51310652SHyon.Kim@Sun.COM * Using di_instance number as the suffix for the name for persistent
51410652SHyon.Kim@Sun.COM * among rebooting.
51510652SHyon.Kim@Sun.COM */
51610652SHyon.Kim@Sun.COM (void) snprintf(new_hba->handle_name, HANDLE_NAME_LENGTH, "%s-%s-%d",
51710652SHyon.Kim@Sun.COM "SUNW", new_hba->adapter_attributes.DriverName, hba_instance);
51810652SHyon.Kim@Sun.COM
51910652SHyon.Kim@Sun.COM if ((portNode = di_child_node(hbaNode)) == NULL) {
52010652SHyon.Kim@Sun.COM log(LOG_DEBUG, ROUTINE,
52110652SHyon.Kim@Sun.COM "HBA driver doesn't have iport child. \"%s\"",
52210652SHyon.Kim@Sun.COM new_hba->device_path);
52310652SHyon.Kim@Sun.COM /* continue on with an hba without any port. */
52410652SHyon.Kim@Sun.COM new_hba->index = hba_count++;
52510652SHyon.Kim@Sun.COM
52610652SHyon.Kim@Sun.COM /*
52710652SHyon.Kim@Sun.COM * add newly created handle into global_hba_head list
52810652SHyon.Kim@Sun.COM */
52910652SHyon.Kim@Sun.COM if (global_hba_head != NULL) {
53010652SHyon.Kim@Sun.COM /*
53110652SHyon.Kim@Sun.COM * Make sure to move the open_handles list to back to
53210652SHyon.Kim@Sun.COM * the head if it's there (for refresh scenario)
53310652SHyon.Kim@Sun.COM */
53410652SHyon.Kim@Sun.COM if (global_hba_head->open_handles) {
53510652SHyon.Kim@Sun.COM new_hba->open_handles =
53610652SHyon.Kim@Sun.COM global_hba_head->open_handles;
53710652SHyon.Kim@Sun.COM global_hba_head->open_handles = NULL;
53810652SHyon.Kim@Sun.COM }
53910652SHyon.Kim@Sun.COM /* Now bump the new one to the head of the list */
54010652SHyon.Kim@Sun.COM new_hba->next = global_hba_head;
54110652SHyon.Kim@Sun.COM global_hba_head = new_hba;
54210652SHyon.Kim@Sun.COM } else {
54310652SHyon.Kim@Sun.COM global_hba_head = new_hba;
54410652SHyon.Kim@Sun.COM }
54510652SHyon.Kim@Sun.COM return (HBA_STATUS_OK);
54610652SHyon.Kim@Sun.COM }
54710652SHyon.Kim@Sun.COM
54810652SHyon.Kim@Sun.COM while (portNode != DI_NODE_NIL) {
549*12176SXun.Ni@Sun.COM if (di_prop_lookup_ints(DDI_DEV_T_ANY, portNode,
550*12176SXun.Ni@Sun.COM "virtual-port", &propIntData) >= 0) {
551*12176SXun.Ni@Sun.COM if (*propIntData) {
552*12176SXun.Ni@Sun.COM /* ignore a virtual port. */
553*12176SXun.Ni@Sun.COM portNode = di_sibling_node(portNode);
554*12176SXun.Ni@Sun.COM continue;
555*12176SXun.Ni@Sun.COM }
556*12176SXun.Ni@Sun.COM }
55710652SHyon.Kim@Sun.COM if (add_hba_port_info(portNode, new_hba, protocol)
55810652SHyon.Kim@Sun.COM == HBA_STATUS_ERROR) {
55910652SHyon.Kim@Sun.COM S_FREE(new_hba->first_port);
56010652SHyon.Kim@Sun.COM S_FREE(new_hba);
56110652SHyon.Kim@Sun.COM return (HBA_STATUS_ERROR);
56210652SHyon.Kim@Sun.COM }
56310652SHyon.Kim@Sun.COM portNode = di_sibling_node(portNode);
56410652SHyon.Kim@Sun.COM }
56510652SHyon.Kim@Sun.COM
56610652SHyon.Kim@Sun.COM new_hba->index = hba_count++;
56710652SHyon.Kim@Sun.COM
56810652SHyon.Kim@Sun.COM /*
56910652SHyon.Kim@Sun.COM * add newly created handle into global_hba_head list
57010652SHyon.Kim@Sun.COM */
57110652SHyon.Kim@Sun.COM if (global_hba_head != NULL) {
57210652SHyon.Kim@Sun.COM /*
57310652SHyon.Kim@Sun.COM * Make sure to move the open_handles list to back to the
57410652SHyon.Kim@Sun.COM * head if it's there (for refresh scenario)
57510652SHyon.Kim@Sun.COM */
57610652SHyon.Kim@Sun.COM if (global_hba_head->open_handles) {
57710652SHyon.Kim@Sun.COM new_hba->open_handles = global_hba_head->open_handles;
57810652SHyon.Kim@Sun.COM global_hba_head->open_handles = NULL;
57910652SHyon.Kim@Sun.COM }
58010652SHyon.Kim@Sun.COM /* Now bump the new one to the head of the list */
58110652SHyon.Kim@Sun.COM new_hba->next = global_hba_head;
58210652SHyon.Kim@Sun.COM global_hba_head = new_hba;
58310652SHyon.Kim@Sun.COM } else {
58410652SHyon.Kim@Sun.COM global_hba_head = new_hba;
58510652SHyon.Kim@Sun.COM }
58610652SHyon.Kim@Sun.COM
58710652SHyon.Kim@Sun.COM return (HBA_STATUS_OK);
58810652SHyon.Kim@Sun.COM }
58910652SHyon.Kim@Sun.COM
59010652SHyon.Kim@Sun.COM /*
59110652SHyon.Kim@Sun.COM * Discover information for all HBAs found on the system.
59210652SHyon.Kim@Sun.COM * The di_node_t argument should be the root of the device tree.
59310652SHyon.Kim@Sun.COM * This routine assumes the locks have been taken
59410652SHyon.Kim@Sun.COM */
59510652SHyon.Kim@Sun.COM static int
lookup_smhba_sas_hba(di_node_t node,void * arg)59610652SHyon.Kim@Sun.COM lookup_smhba_sas_hba(di_node_t node, void *arg)
59710652SHyon.Kim@Sun.COM {
59810652SHyon.Kim@Sun.COM const char ROUTINE[] = "lookup_smhba_sas_hba";
59910652SHyon.Kim@Sun.COM int *propData, rval;
60010652SHyon.Kim@Sun.COM walkarg_t *wa = (walkarg_t *)arg;
60110652SHyon.Kim@Sun.COM
60210652SHyon.Kim@Sun.COM /* Skip stub(instance -1) nodes */
60310652SHyon.Kim@Sun.COM if (IS_STUB_NODE(node)) {
60410652SHyon.Kim@Sun.COM log(LOG_DEBUG, ROUTINE, "Walk continue");
60510652SHyon.Kim@Sun.COM return (DI_WALK_CONTINUE);
60610652SHyon.Kim@Sun.COM }
60710652SHyon.Kim@Sun.COM
60810652SHyon.Kim@Sun.COM rval = di_prop_lookup_ints(DDI_DEV_T_ANY, node,
60910652SHyon.Kim@Sun.COM "sm-hba-supported", &propData);
61010652SHyon.Kim@Sun.COM if (rval >= 0) {
61110652SHyon.Kim@Sun.COM if (*propData) {
61210652SHyon.Kim@Sun.COM /* add the hba to the hba list */
61310652SHyon.Kim@Sun.COM if (devtree_get_one_hba(node) != HBA_STATUS_OK) {
61410652SHyon.Kim@Sun.COM *(wa->flag) = B_TRUE;
61510652SHyon.Kim@Sun.COM }
61610652SHyon.Kim@Sun.COM /* Found a node. No need to walk the child. */
61710652SHyon.Kim@Sun.COM log(LOG_DEBUG, ROUTINE, "Walk prunechild");
61810652SHyon.Kim@Sun.COM return (DI_WALK_PRUNECHILD);
61910652SHyon.Kim@Sun.COM }
62010652SHyon.Kim@Sun.COM }
62110652SHyon.Kim@Sun.COM
62210652SHyon.Kim@Sun.COM return (DI_WALK_CONTINUE);
62310652SHyon.Kim@Sun.COM }
62410652SHyon.Kim@Sun.COM
62510652SHyon.Kim@Sun.COM /*
62610652SHyon.Kim@Sun.COM * Discover information for all HBAs found on the system.
62710652SHyon.Kim@Sun.COM * The di_node_t argument should be the root of the device tree.
62810652SHyon.Kim@Sun.COM * This routine assumes the locks have been taken
62910652SHyon.Kim@Sun.COM */
63010652SHyon.Kim@Sun.COM HBA_STATUS
devtree_get_all_hbas(di_node_t root)63110652SHyon.Kim@Sun.COM devtree_get_all_hbas(di_node_t root)
63210652SHyon.Kim@Sun.COM {
63310652SHyon.Kim@Sun.COM const char ROUTINE[] = "devtree_get_all_hbas";
63410652SHyon.Kim@Sun.COM int rv, ret = HBA_STATUS_ERROR;
63510652SHyon.Kim@Sun.COM walkarg_t wa;
63610652SHyon.Kim@Sun.COM
63710652SHyon.Kim@Sun.COM wa.devpath = NULL;
63810652SHyon.Kim@Sun.COM if ((wa.flag = (boolean_t *)calloc(1,
63910652SHyon.Kim@Sun.COM sizeof (boolean_t))) == NULL) {
64010652SHyon.Kim@Sun.COM OUT_OF_MEMORY(ROUTINE);
64110652SHyon.Kim@Sun.COM return (HBA_STATUS_ERROR);
64210652SHyon.Kim@Sun.COM }
64310652SHyon.Kim@Sun.COM *wa.flag = B_FALSE;
64410652SHyon.Kim@Sun.COM rv = di_walk_node(root, DI_WALK_SIBFIRST, &wa, lookup_smhba_sas_hba);
64510652SHyon.Kim@Sun.COM
64610652SHyon.Kim@Sun.COM if (rv == 0) {
64710652SHyon.Kim@Sun.COM /*
64810652SHyon.Kim@Sun.COM * Now determine what status code to return, taking
64910652SHyon.Kim@Sun.COM * partial failure scenarios into consideration.
65010652SHyon.Kim@Sun.COM *
65110652SHyon.Kim@Sun.COM * If we have at least one working HBA, then we return an
65210652SHyon.Kim@Sun.COM * OK status. If we have no good HBAs, but at least one
65310652SHyon.Kim@Sun.COM * failed HBA, we return an ERROR status. If we have
65410652SHyon.Kim@Sun.COM * no HBAs and no failures, we return OK.
65510652SHyon.Kim@Sun.COM */
65610652SHyon.Kim@Sun.COM if (global_hba_head) {
65710652SHyon.Kim@Sun.COM /*
65810652SHyon.Kim@Sun.COM * We've got at least one HBA and possibly some
65910652SHyon.Kim@Sun.COM * failures.
66010652SHyon.Kim@Sun.COM */
66110652SHyon.Kim@Sun.COM ret = HBA_STATUS_OK;
66210652SHyon.Kim@Sun.COM } else if (*(wa.flag)) {
66310652SHyon.Kim@Sun.COM /* We have no HBAs but have failures */
66410652SHyon.Kim@Sun.COM ret = HBA_STATUS_ERROR;
66510652SHyon.Kim@Sun.COM } else {
66610652SHyon.Kim@Sun.COM /* We have no HBAs and no failures */
66710652SHyon.Kim@Sun.COM ret = HBA_STATUS_OK;
66810652SHyon.Kim@Sun.COM }
66910652SHyon.Kim@Sun.COM }
67010652SHyon.Kim@Sun.COM
67110652SHyon.Kim@Sun.COM
67210652SHyon.Kim@Sun.COM S_FREE(wa.flag);
67310652SHyon.Kim@Sun.COM
67410652SHyon.Kim@Sun.COM if (ret == HBA_STATUS_OK)
67510652SHyon.Kim@Sun.COM (void) registerSysevent();
67610652SHyon.Kim@Sun.COM
67710652SHyon.Kim@Sun.COM return (ret);
67810652SHyon.Kim@Sun.COM }
679