xref: /illumos-gate/usr/src/lib/sun_sas/common/sun_sas.c (revision 00f453f4ebc211cb928f19a54d3f4edd61f43279)
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