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 <sys/byteorder.h>
31 #include <sun_sas.h>
32
33 /*
34 * creates a handle each time Sun_sas_OpenAdapter() is called.
35 *
36 * a open_handle_struct was created to keep track of which handles are currently
37 * open. This prevents a user from using an old handle that corresponds to
38 * an hba that has already been closed.
39 */
40 HBA_HANDLE
CreateHandle(int adapterIndex)41 CreateHandle(int adapterIndex)
42 {
43 const char ROUTINE[] = "CreateHandle";
44 struct open_handle *new_open_handle;
45 HBA_UINT32 new_handle_index;
46 HBA_UINT8 max_handle_wrap = 0;
47
48 if (global_hba_head == NULL) {
49 log(LOG_DEBUG, ROUTINE,
50 "an error as occurred. global_hba_head is "
51 "NULL. Library may not be loaded yet.");
52 return (HANDLE_ERROR);
53 }
54
55 while (RetrieveIndex(open_handle_index) != -1) {
56 open_handle_index = open_handle_index + 1;
57 if (open_handle_index == 0) {
58 /*
59 * If open_handle_index wraps back to zero again,
60 * that means all handles are currently in use.
61 * Spec only allows for 16 bits of handles
62 */
63 if (max_handle_wrap == 1) {
64 log(LOG_DEBUG, ROUTINE,
65 "Max number of handles reached.");
66 return (HANDLE_ERROR);
67 }
68 open_handle_index = 1;
69 max_handle_wrap = 1;
70 }
71 }
72
73 new_handle_index = open_handle_index;
74 if ((new_open_handle = (struct open_handle *)calloc(1,
75 sizeof (struct open_handle))) == NULL) {
76 OUT_OF_MEMORY(ROUTINE);
77 return (HANDLE_ERROR);
78 }
79 (void) memset(new_open_handle, 0, sizeof (struct open_handle));
80 new_open_handle->adapterIndex = adapterIndex;
81 new_open_handle->handle = new_handle_index;
82
83 lock(&open_handles_lock);
84
85 /* add new open handle struct to the open_handles list */
86 if (global_hba_head->open_handles == NULL) {
87 global_hba_head->open_handles = new_open_handle;
88 } else {
89 new_open_handle->next = global_hba_head->open_handles;
90 global_hba_head->open_handles = new_open_handle;
91 }
92
93 unlock(&open_handles_lock);
94 open_handle_index = open_handle_index + 1;
95 if (open_handle_index == 0) {
96 open_handle_index = 1;
97 }
98
99 return (new_handle_index);
100 }
101
102 /*
103 * given a handle, returns the adapterIndex number.
104 *
105 * This functions checkes to see if the given handle corresponds to an open
106 * HBA. If it does, the adapterIndex is returned.
107 */
108 int
RetrieveIndex(HBA_HANDLE handle)109 RetrieveIndex(HBA_HANDLE handle)
110 {
111
112 struct open_handle *open_handle_ptr;
113
114 lock(&open_handles_lock);
115
116 open_handle_ptr = RetrieveOpenHandle(handle);
117
118 unlock(&open_handles_lock);
119 if (open_handle_ptr == NULL) {
120 return (-1);
121 }
122
123 return (open_handle_ptr->adapterIndex);
124 }
125 /*
126 * Given a handle, returns the open_handle structure
127 * The routine assumes that the open_handles_lock has already
128 * been taken.
129 */
130 struct open_handle *
RetrieveOpenHandle(HBA_HANDLE handle)131 RetrieveOpenHandle(HBA_HANDLE handle)
132 {
133
134 const char ROUTINE[] = "RetrieveOpenHandle";
135 struct open_handle *open_handle_ptr = NULL;
136
137 if (global_hba_head == NULL) {
138 log(LOG_DEBUG, ROUTINE, "No adapter is found.");
139 return (NULL);
140 }
141
142 for (open_handle_ptr = global_hba_head->open_handles;
143 open_handle_ptr != NULL;
144 open_handle_ptr = open_handle_ptr->next) {
145 if (open_handle_ptr->handle == handle) {
146 break;
147 }
148 }
149
150 return (open_handle_ptr);
151 }
152
153 /*
154 * Given an adapterIndex, this functions returns a pointer to the handle
155 * structure. This handle structure holds the hba's information
156 * Caller must take all_hbas_lock first.
157 */
158 struct sun_sas_hba *
RetrieveHandle(int index)159 RetrieveHandle(int index)
160 {
161 struct sun_sas_hba *hba_ptr = NULL;
162
163 for (hba_ptr = global_hba_head; hba_ptr != NULL;
164 hba_ptr = hba_ptr->next) {
165 if (hba_ptr->index == index)
166 break;
167 }
168
169 return (hba_ptr);
170 }
171
172 /*
173 * Given an adapterIndex, this functions returns a pointer to the handle
174 * structure and extracts it from the global list.
175 *
176 * all_hbas_lock must be taken already.
177 */
178 struct sun_sas_hba *
ExtractHandle(int index)179 ExtractHandle(int index)
180 {
181 struct sun_sas_hba *last = NULL;
182 struct sun_sas_hba *hba_ptr = NULL;
183
184 for (hba_ptr = global_hba_head;
185 hba_ptr != NULL;
186 last = hba_ptr, hba_ptr = hba_ptr->next) {
187 if (hba_ptr->index == index) {
188 if (last) {
189 last->next = hba_ptr->next;
190 } else {
191 /* Hmm, must be the head of the list. */
192 global_hba_head = hba_ptr->next;
193 }
194 hba_ptr->next = NULL; /* Zap it to be safe */
195 break;
196 }
197 }
198
199 return (hba_ptr);
200 }
201
202
203 /*
204 * Given an handle, this functions returns a pointer to the handle structure
205 * for that hba
206 *
207 * Caller must take all_hbas_lock first.
208 */
209 struct sun_sas_hba *
Retrieve_Sun_sasHandle(HBA_HANDLE handle)210 Retrieve_Sun_sasHandle(HBA_HANDLE handle)
211 {
212 const char ROUTINE[] = "Retrieve_Sun_sasHandle";
213 struct sun_sas_hba *handle_struct = NULL;
214 int index;
215
216 /* Retrieve fp device path from handle */
217 index = RetrieveIndex(handle);
218 if (index == -1) {
219 log(LOG_DEBUG, ROUTINE,
220 "handle could not be found.");
221 return (handle_struct);
222 }
223 lock(&open_handles_lock);
224 handle_struct = RetrieveHandle(index);
225 if (handle_struct == NULL) {
226 log(LOG_DEBUG, ROUTINE,
227 "could not find index in the handle list.");
228 unlock(&open_handles_lock);
229 return (handle_struct);
230 }
231 unlock(&open_handles_lock);
232
233 return (handle_struct);
234 }
235
236 /*
237 * Take a mutex lock. The routine will try, and if it fails,
238 * it will loop for a while and retry. If it fails many times,
239 * it will start writing to the log file.
240 */
241 void
lock(mutex_t * mp)242 lock(mutex_t *mp)
243 {
244 int status;
245 int loop = 0;
246 const char ROUTINE[] = "lock";
247
248 do {
249 loop++;
250 status = mutex_trylock(mp);
251 switch (status) {
252 case 0:
253 break;
254 case EFAULT:
255 log(LOG_DEBUG, ROUTINE,
256 "Lock failed: fault 0x%x", mp);
257 break;
258 case EINVAL:
259 log(LOG_DEBUG, ROUTINE,
260 "Lock failed: invalid 0x%x", mp);
261 break;
262 case EBUSY:
263 if (loop > DEADLOCK_WARNING) {
264 log(LOG_DEBUG, ROUTINE,
265 "Lock busy, possible deadlock:0x%x",
266 mp);
267 }
268 break;
269 case EOWNERDEAD:
270 log(LOG_DEBUG, ROUTINE,
271 "Lock failed: owner dead 0x%x",
272 mp);
273 break;
274 case ELOCKUNMAPPED:
275 log(LOG_DEBUG, ROUTINE,
276 "Lock failed: unmapped 0x%x",
277 mp);
278 break;
279 case ENOTRECOVERABLE:
280 log(LOG_DEBUG, ROUTINE,
281 "Lock failed: not recoverable 0x%x", mp);
282 break;
283 default:
284 if (loop > DEADLOCK_WARNING) {
285 log(LOG_DEBUG, ROUTINE,
286 "Lock failed: %s 0x%x",
287 strerror(status), mp);
288 break;
289 }
290 }
291
292 if (status) {
293 (void) sleep(LOCK_SLEEP);
294 }
295
296 } while (status);
297 }
298
299 /*
300 * Unlock a mutex lock.
301 */
302 void
unlock(mutex_t * mp)303 unlock(mutex_t *mp)
304 {
305 (void) mutex_unlock(mp);
306 }
307
308
309 /*
310 * Get the Port WWN of the first adapter port. This routine
311 * is used by the old V1 interfaces so that they can call
312 * the new V2 interfaces and exhibit the same behavior.
313 * In the event of error the WWN will be zero.
314 *
315 * This function will transition to PAA state but it will not
316 * verfiy whether data is stale or not
317 */
318 HBA_WWN
getFirstAdapterPortWWN(HBA_HANDLE handle)319 getFirstAdapterPortWWN(HBA_HANDLE handle)
320 {
321 const char ROUTINE[] = "getFirstAdapterPortWWN";
322 HBA_WWN pwwn = {0, 0, 0, 0, 0, 0, 0, 0};
323 struct sun_sas_hba *hba_ptr = NULL;
324 int index = 0;
325 HBA_STATUS status;
326
327 lock(&all_hbas_lock);
328 index = RetrieveIndex(handle);
329 lock(&open_handles_lock);
330 hba_ptr = RetrieveHandle(index);
331 if (hba_ptr == NULL) {
332 log(LOG_DEBUG, ROUTINE, "Invalid handle %08lx", handle);
333 unlock(&open_handles_lock);
334 unlock(&all_hbas_lock);
335 return (pwwn); /* zero WWN */
336 }
337
338 /* Check for stale data */
339 status = verifyAdapter(hba_ptr);
340 if (status != HBA_STATUS_OK) {
341 log(LOG_DEBUG, ROUTINE, "Verify adapter failed");
342 unlock(&open_handles_lock);
343 unlock(&all_hbas_lock);
344 return (pwwn);
345 }
346
347 if (hba_ptr->first_port == NULL) {
348 /* This is probably an internal failure of the library */
349 if (hba_ptr->device_path[0] != '\0') {
350 log(LOG_DEBUG, ROUTINE,
351 "Internal failure: Adapter %s contains no "
352 "port data", hba_ptr->device_path);
353 } else {
354 log(LOG_DEBUG, ROUTINE,
355 "Internal failure: Adapter at index %d contains "
356 " no support data", hba_ptr->index);
357 }
358 unlock(&open_handles_lock);
359 unlock(&all_hbas_lock);
360 return (pwwn); /* zero WWN */
361 }
362 /* Set the WWN now and return it */
363 pwwn = hba_ptr->first_port->port_attributes.PortSpecificAttribute.\
364 SASPort->LocalSASAddress;
365 unlock(&open_handles_lock);
366 unlock(&all_hbas_lock);
367
368 return (pwwn);
369 }
370
371 u_longlong_t
wwnConversion(uchar_t * wwn)372 wwnConversion(uchar_t *wwn)
373 {
374 u_longlong_t tmp;
375 (void) memcpy(&tmp, wwn, sizeof (u_longlong_t));
376 tmp = ntohll(tmp);
377 return (tmp);
378 }
379
380 /*
381 * Using ioctl to send uscsi command out
382 */
383 HBA_STATUS
send_uscsi_cmd(const char * devpath,struct uscsi_cmd * ucmd)384 send_uscsi_cmd(const char *devpath, struct uscsi_cmd *ucmd)
385 {
386 const char ROUTINE[] = "send_uscsi_cmd";
387 int fd;
388 HBA_STATUS ret;
389
390 /* set default timeout to 200 */
391 ucmd->uscsi_timeout = 200;
392
393 /* reset errno. */
394 errno = 0;
395 if ((fd = open(devpath, O_RDONLY | O_NDELAY)) == -1) {
396 log(LOG_DEBUG, ROUTINE,
397 "open devpath %s failed: %s", devpath, strerror(errno));
398 return (HBA_STATUS_ERROR);
399 }
400
401 if (ioctl(fd, USCSICMD, ucmd) == -1) {
402 if (errno == EBUSY) {
403 ret = HBA_STATUS_ERROR_BUSY;
404 } else if (errno == EAGAIN) {
405 ret = HBA_STATUS_ERROR_TRY_AGAIN;
406 } else {
407 ret = HBA_STATUS_ERROR;
408 }
409 log(LOG_DEBUG, ROUTINE,
410 "ioctl send uscsi to devpath: %s failed: %s",
411 devpath, strerror(errno));
412 (void) close(fd);
413 return (ret);
414 }
415
416 (void) close(fd);
417
418 return (HBA_STATUS_OK);
419 }
420
421 /*
422 * Check whether the given Domain Address is valid.
423 */
424 HBA_STATUS
validateDomainAddress(struct sun_sas_port * hba_port_ptr,HBA_WWN DomainAddr)425 validateDomainAddress(struct sun_sas_port *hba_port_ptr, HBA_WWN DomainAddr)
426 {
427 if (hba_port_ptr->first_phy != NULL &&
428 wwnConversion(hba_port_ptr->first_phy->
429 phy.domainPortWWN.wwn) ==
430 wwnConversion(DomainAddr.wwn)) {
431 return (HBA_STATUS_OK);
432 }
433 return (HBA_STATUS_ERROR);
434 }
435