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