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 * Copyright 2019 Joyent, Inc.
28 */
29
30#include    <sun_sas.h>
31
32/*
33 * Retrieves the attributes for a specific discovered port by WWN
34 */
35HBA_STATUS
36Sun_sasGetPortAttributesByWWN(HBA_HANDLE handle, HBA_WWN portWWN,
37    HBA_WWN domainPortWWN, PSMHBA_PORTATTRIBUTES attributes)
38{
39	const char		ROUTINE[] = "Sun_sasGetPortAttributesByWWN";
40	HBA_STATUS		status;
41	struct sun_sas_hba	*hba_ptr;
42	struct sun_sas_port	*hba_port_ptr, *hba_disco_port;
43	int			index, chkDomainPort = 0, domainFound = 0;
44
45	/* Validate the arguments */
46	if (attributes == NULL) {
47		log(LOG_DEBUG, ROUTINE, "NULL port attributes");
48		return (HBA_STATUS_ERROR_ARG);
49	}
50
51	if (wwnConversion(domainPortWWN.wwn) != 0) {
52		chkDomainPort = 1;
53	}
54
55	lock(&all_hbas_lock);
56	index = RetrieveIndex(handle);
57	lock(&open_handles_lock);
58	hba_ptr = RetrieveHandle(index);
59	if (hba_ptr == NULL) {
60		log(LOG_DEBUG, ROUTINE, "Invalid handle %08lx.", handle);
61		unlock(&open_handles_lock);
62		unlock(&all_hbas_lock);
63		return (HBA_STATUS_ERROR_INVALID_HANDLE);
64	}
65
66	/* Check for stale data */
67	status = verifyAdapter(hba_ptr);
68	if (status != HBA_STATUS_OK) {
69		log(LOG_DEBUG, ROUTINE, "Verify adapter failed");
70		unlock(&open_handles_lock);
71		unlock(&all_hbas_lock);
72		return (status);
73	}
74
75	if (hba_ptr->first_port == NULL) {
76		/* This is probably an internal failure of the library */
77		if (hba_ptr->device_path[0] != '\0') {
78			log(LOG_DEBUG, ROUTINE,
79			    "Internal failure:  Adapter %s contains "
80			    "no port data", hba_ptr->device_path);
81		} else {
82			log(LOG_DEBUG, ROUTINE,
83			    "Internal failure:  Adapter at index %d contains "
84			    "no port data", hba_ptr->index);
85		}
86		unlock(&open_handles_lock);
87		unlock(&all_hbas_lock);
88		return (HBA_STATUS_ERROR);
89	}
90
91	/* Loop over all Adapter ports */
92	for (hba_port_ptr = hba_ptr->first_port;
93	    hba_port_ptr != NULL;
94	    hba_port_ptr = hba_port_ptr->next) {
95		if (chkDomainPort) {
96			if (validateDomainAddress(hba_port_ptr,
97			    domainPortWWN) != HBA_STATUS_OK) {
98				continue;
99			} else
100				domainFound = 1;
101		}
102
103		if (wwnConversion(hba_port_ptr->port_attributes.
104		    PortSpecificAttribute.SASPort->LocalSASAddress.wwn) ==
105		    wwnConversion(portWWN.wwn)) {
106			/*
107			 * We should indicate an error if we enter here
108			 * without domainPortWWN set.
109			 */
110			if (chkDomainPort == 0) {
111				log(LOG_DEBUG, ROUTINE,
112				    "Domain Port WWN should be set when "
113				    "querying HBA port %016llx for "
114				    "handle %08lx",
115				    wwnConversion(portWWN.wwn), handle);
116				unlock(&open_handles_lock);
117				unlock(&all_hbas_lock);
118				return (HBA_STATUS_ERROR_ARG);
119			}
120			attributes->PortType =
121			    hba_port_ptr->port_attributes.PortType;
122			attributes->PortState =
123			    hba_port_ptr->port_attributes.PortState;
124			(void) strlcpy(attributes->OSDeviceName,
125			    hba_port_ptr->port_attributes.OSDeviceName,
126			    sizeof (attributes->OSDeviceName));
127			(void) memcpy(attributes->PortSpecificAttribute.SASPort,
128			    hba_port_ptr->port_attributes.PortSpecificAttribute.
129			    SASPort, sizeof (struct SMHBA_SAS_Port));
130
131			unlock(&open_handles_lock);
132			unlock(&all_hbas_lock);
133			return (HBA_STATUS_OK);
134		}
135
136		/* check to make sure there are devices attached to this port */
137		if (hba_port_ptr->first_attached_port != NULL) {
138
139			/* Loop over all discovered ports */
140			for (hba_disco_port = hba_port_ptr->first_attached_port;
141			    hba_disco_port != NULL;
142			    hba_disco_port = hba_disco_port->next) {
143				if (wwnConversion(hba_disco_port->
144				    port_attributes.PortSpecificAttribute.
145				    SASPort->LocalSASAddress.wwn) ==
146				    wwnConversion(portWWN.wwn)) {
147					attributes->PortType =
148					    hba_disco_port->port_attributes.
149					    PortType;
150					attributes->PortState =
151					    hba_disco_port->port_attributes.
152					    PortState;
153					(void) strlcpy(attributes->OSDeviceName,
154					    hba_disco_port->port_attributes.
155					    OSDeviceName,
156					    sizeof (attributes->OSDeviceName));
157					(void) memcpy(attributes->
158					    PortSpecificAttribute.SASPort,
159					    hba_disco_port->port_attributes.
160					    PortSpecificAttribute.SASPort,
161					    sizeof (struct SMHBA_SAS_Port));
162					unlock(&open_handles_lock);
163					unlock(&all_hbas_lock);
164					return (HBA_STATUS_OK);
165				}
166			}
167		}
168		if (chkDomainPort) {
169			log(LOG_DEBUG, ROUTINE,
170			    "Invalid Port WWN %016llx for handle %08lx",
171			    wwnConversion(portWWN.wwn), handle);
172			unlock(&open_handles_lock);
173			unlock(&all_hbas_lock);
174			return (HBA_STATUS_ERROR_ILLEGAL_WWN);
175		}
176	}
177	if (chkDomainPort && domainFound == 0) {
178		log(LOG_DEBUG, ROUTINE, "No Matching domain port"
179		    " (%16llx) for port (%16llx) for handle %08lx",
180		    wwnConversion(domainPortWWN.wwn),
181		    wwnConversion(portWWN.wwn),
182		    handle);
183	} else {
184		/* We enter here only when chkDomainPort == 0 */
185		log(LOG_DEBUG, ROUTINE,
186		    "Invalid Port WWN %016llx for handle %08lx",
187		    wwnConversion(portWWN.wwn), handle);
188	}
189	unlock(&open_handles_lock);
190	unlock(&all_hbas_lock);
191	return (HBA_STATUS_ERROR_ILLEGAL_WWN);
192}
193