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 
29 /*
30  * Retrieves the mapping between targets and OS SCSI information
31  */
32 HBA_STATUS
Sun_sasGetTargetMapping(HBA_HANDLE handle,HBA_WWN hbaPortWWN,HBA_WWN domainPortWWN,SMHBA_TARGETMAPPING * mapping)33 Sun_sasGetTargetMapping(HBA_HANDLE handle, HBA_WWN hbaPortWWN,
34     HBA_WWN domainPortWWN, SMHBA_TARGETMAPPING *mapping)
35 {
36 	const char		ROUTINE[] = "Sun_sasGetTargetMapping";
37 	int			i, index;
38 	int			hbaPortFound = 0;
39 	int			domainPortFound = 0;
40 	uint_t			total_entries = 0;
41 	struct  sun_sas_hba	*hba_ptr;
42 	struct  sun_sas_port	*hba_port_ptr, *hba_disco_port;
43 	struct	ScsiEntryList	*mapping_ptr;
44 
45 	if (mapping == NULL) {
46 		log(LOG_DEBUG, ROUTINE, "NULL mapping buffer");
47 		return (HBA_STATUS_ERROR_ARG);
48 	}
49 
50 	lock(&all_hbas_lock);
51 	index = RetrieveIndex(handle);
52 	lock(&open_handles_lock);
53 	hba_ptr = RetrieveHandle(index);
54 	if (hba_ptr == NULL) {
55 		log(LOG_DEBUG, ROUTINE, "Invalid handle %08lx.", handle);
56 		/* on error, need to set NumberOfEntries to 0 */
57 		mapping->NumberOfEntries = 0;
58 		unlock(&open_handles_lock);
59 		unlock(&all_hbas_lock);
60 		return (HBA_STATUS_ERROR_INVALID_HANDLE);
61 	}
62 
63 	/*
64 	 * We should indicate an error if no domainPortWWN passed in.
65 	 */
66 	if (wwnConversion(domainPortWWN.wwn) == 0) {
67 		log(LOG_DEBUG, ROUTINE, "domainPortWWN must be provided");
68 		mapping->NumberOfEntries = 0;
69 		unlock(&open_handles_lock);
70 		unlock(&all_hbas_lock);
71 		return (HBA_STATUS_ERROR_ARG);
72 	}
73 	/*
74 	 * walk through the list of ports for this hba and count up the number
75 	 * of discovered ports on each hba port
76 	 */
77 	i = 0;
78 	for (hba_port_ptr = hba_ptr->first_port; hba_port_ptr != NULL;
79 	    hba_port_ptr = hba_port_ptr->next) {
80 		if (hbaPortFound == 0) {
81 			if (wwnConversion(hba_port_ptr->port_attributes.
82 			    PortSpecificAttribute.SASPort->LocalSASAddress.wwn)
83 			    != wwnConversion(hbaPortWWN.wwn)) {
84 				/*
85 				 * Since all the ports under the same HBA have
86 				 * the same LocalSASAddress, we should break
87 				 * the loop once we find it dosn't match.
88 				 */
89 				break;
90 			} else {
91 				hbaPortFound = 1;
92 			}
93 		}
94 
95 		/*
96 		 * Check whether the domainPortWWN matches.
97 		 */
98 		if ((validateDomainAddress(hba_port_ptr, domainPortWWN))
99 		    != HBA_STATUS_OK) {
100 			continue;
101 		}
102 		domainPortFound = 1;
103 
104 		for (hba_disco_port = hba_port_ptr->first_attached_port;
105 		    hba_disco_port != NULL;
106 		    hba_disco_port = hba_disco_port->next) {
107 			for (mapping_ptr = hba_disco_port->scsiInfo;
108 			    mapping_ptr != NULL;
109 			    mapping_ptr = mapping_ptr->next) {
110 				/*
111 				 * Add the information as much as mapping
112 				 * can hold.
113 				 */
114 				if (wwnConversion(domainPortWWN.wwn) !=
115 				    wwnConversion(mapping_ptr->entry.
116 				    PortLun.domainPortWWN.wwn)) {
117 					continue;
118 				}
119 
120 				if (total_entries < mapping->NumberOfEntries) {
121 					(void) memcpy(&mapping->entry[i].ScsiId,
122 					    &mapping_ptr->entry.ScsiId,
123 					    sizeof (SMHBA_SCSIID));
124 					(void) memcpy(&mapping->entry[i].
125 					    PortLun, &mapping_ptr->entry.
126 					    PortLun, sizeof (SMHBA_PORTLUN));
127 					(void) memcpy(&mapping->entry[i].LUID,
128 					    &mapping_ptr->entry.LUID,
129 					    sizeof (SMHBA_LUID));
130 					i++;
131 				}
132 				total_entries++;
133 			}
134 		}
135 	}
136 
137 	/*
138 	 * check to make sure user has passed in an acceptable PortWWN for
139 	 * the given handle
140 	 */
141 	if (hbaPortFound == 0) {
142 		log(LOG_DEBUG, ROUTINE, "Unable to locate requested "
143 		    "HBA Port WWN %016llx on handle %08lx",
144 		    wwnConversion(hbaPortWWN.wwn), handle);
145 		unlock(&open_handles_lock);
146 		unlock(&all_hbas_lock);
147 		return (HBA_STATUS_ERROR_ILLEGAL_WWN);
148 	}
149 
150 	if (domainPortFound == 0) {
151 		log(LOG_DEBUG, ROUTINE, "No matching domain "
152 		    "port %016llx for port %016llx on handle "
153 		    "%08lx", wwnConversion(domainPortWWN.wwn),
154 		    wwnConversion(hbaPortWWN.wwn), handle);
155 		unlock(&open_handles_lock);
156 		unlock(&all_hbas_lock);
157 		return (HBA_STATUS_ERROR_ILLEGAL_WWN);
158 	}
159 
160 	if (total_entries > mapping->NumberOfEntries) {
161 		log(LOG_DEBUG, ROUTINE,
162 		    "total entries: %d: mapping->NumberofEntries: %d.",
163 		    total_entries, mapping->NumberOfEntries);
164 		mapping->NumberOfEntries = total_entries;
165 		unlock(&open_handles_lock);
166 		unlock(&all_hbas_lock);
167 		return (HBA_STATUS_ERROR_MORE_DATA);
168 	}
169 
170 	mapping->NumberOfEntries = total_entries;
171 
172 	/* convert devpath to dev link */
173 	convertDevpathToDevlink(mapping);
174 
175 	unlock(&open_handles_lock);
176 	unlock(&all_hbas_lock);
177 
178 	return (HBA_STATUS_OK);
179 }
180