xref: /illumos-gate/usr/src/lib/sun_fc/common/FCHBA.cc (revision 269e59f9a28bf47e0f463e64fc5af4a408b73b21)
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  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 
27 #include <unistd.h>
28 
29 #include <FCHBA.h>
30 #include <Exceptions.h>
31 #include <Trace.h>
32 #include <iostream>
33 #include <iomanip>
34 #include <cerrno>
35 #include <cstring>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include <unistd.h>
40 #include <stropts.h>
41 #include <sys/fibre-channel/fcio.h>
42 #include <sys/fibre-channel/ulp/fcsm.h>
43 #include <FCHBAPort.h>
44 #include <HBAList.h>
45 
46 #define EXCPT_RETRY_COUNT    10
47 
48 using namespace std;
49 const string FCHBA::FCSM_DRIVER_PATH = "/devices/pseudo/fcsm@0:fcsm";
50 const string FCHBA::FCSM_DRIVER_PKG	= "SUNWfcsm";
51 const int FCHBA::MAX_FCIO_MSG_LEN = 256;
52 
53 FCHBA::FCHBA(string path) : HBA() {
54     Trace log("FCHBA::FCHBA");
55     log.debug("Constructing new HBA (%s)", path.c_str());
56 
57     // Add first port
58     addPort(new FCHBAPort(path));
59 
60     name = "INTERNAL-FAILURE"; // Just in case things go wrong
61     try {
62 	HBA_ADAPTERATTRIBUTES attrs = getHBAAttributes();
63 	name = attrs.Manufacturer;
64 	name += "-";
65 	name += attrs.Model;
66 
67 	// Grab any other ports on this adapter
68 	for (int i = 1; i < attrs.NumberOfPorts; i++) {
69 	    fcio_t			fcio;
70 	    int			fd;
71 	    char		nextPath[MAXPATHLEN];
72 
73 	    log.debug("Fetching other port %d", i);
74 
75 	    // construct fcio struct
76 	    memset(&fcio, 0, sizeof (fcio_t));
77 	    memset(nextPath, 0, sizeof (nextPath));
78 	    fcio.fcio_cmd	= FCIO_GET_OTHER_ADAPTER_PORTS;
79 	    fcio.fcio_xfer	= FCIO_XFER_RW;
80 
81 	    fcio.fcio_olen	= MAXPATHLEN;
82 	    fcio.fcio_obuf	= (char *)nextPath;
83 	    fcio.fcio_ilen	= sizeof (i);
84 	    fcio.fcio_ibuf	= (char *)&i;
85 
86 	    // open the fcsm node so we can send the ioctl to
87 	    errno = 0;
88 	    HBAPort *port = getPortByIndex(0);
89 	    if ((fd = open(port->getPath().c_str(), O_NDELAY | O_RDONLY)) ==
90 		    -1) {
91 		log.debug("Unable to open %d opened (%s)", i,
92 		port->getPath().c_str());
93 		if (errno == EBUSY) {
94 		    throw BusyException();
95 		} else if (errno == EAGAIN) {
96 		    throw TryAgainException();
97 		} else if (errno == ENOTSUP) {
98 		    throw NotSupportedException();
99 		} else if (errno == ENOENT) {
100 		    throw UnavailableException();
101 		} else {
102 		    throw IOError("Unable to open FCSM driver");
103 		}
104 	    }
105 	    log.debug("Other port %d opened", i);
106 
107 	    errno = 0;
108 	    if (ioctl(fd, FCIO_CMD, &fcio) != 0) {
109 		// Interpret the fcio error code
110 		char fcioErrorString[MAX_FCIO_MSG_LEN] = "";
111 
112 		log.genericIOError(
113 		    "ADAPTER_LIST failed: "
114 		    "Errno: \"%s\"",
115 		    strerror(errno));
116 		close(fd);
117 		if (errno == EBUSY) {
118 		    throw BusyException();
119 		} else if (errno == EAGAIN) {
120 		    throw TryAgainException();
121 		} else if (errno == ENOTSUP) {
122 		    throw NotSupportedException();
123 		} else if (errno == ENOENT) {
124 		    throw UnavailableException();
125 		} else {
126 		    throw IOError("Unable to build HBA list");
127 		}
128 	    }
129 	    close(fd);
130 	    log.debug("About to add port %d (%s)", i, nextPath);
131 	    addPort(new FCHBAPort(nextPath));
132 	}
133     } catch (BusyException &e) {
134         throw e;
135     } catch (TryAgainException &e) {
136 	throw e;
137     } catch (UnavailableException &e) {
138 	throw e;
139     } catch (HBAException &e) {
140 	log.internalError(
141 		"Unable to construct HBA.");
142 	throw e;
143     }
144 }
145 
146 std::string FCHBA::getName() {
147     Trace log("FCHBA::getName");
148     return (name);
149 }
150 
151 HBA_ADAPTERATTRIBUTES FCHBA::getHBAAttributes() {
152     Trace log("FCHBA::getHBAAttributes");
153     int fd;
154 
155     errno = 0;
156     HBAPort *port = getPortByIndex(0);
157     if ((fd = open(port->getPath().c_str(), O_NDELAY | O_RDONLY)) == -1) {
158 	// Why did we fail?
159 	if (errno == EBUSY) {
160 	    throw BusyException();
161 	} else if (errno == EAGAIN) {
162 	    throw TryAgainException();
163 	} else if (errno == ENOTSUP) {
164 	    throw NotSupportedException();
165 	} else {
166 	    throw IOError(port);
167 	}
168     }
169 
170     HBA_ADAPTERATTRIBUTES attributes;
171     fcio_t			    fcio;
172     fc_hba_adapter_attributes_t	    attrs;
173 
174     memset(&fcio, 0, sizeof (fcio));
175 
176     fcio.fcio_cmd = FCIO_GET_ADAPTER_ATTRIBUTES;
177     fcio.fcio_olen = sizeof (attrs);
178     fcio.fcio_xfer = FCIO_XFER_READ;
179     fcio.fcio_obuf = (caddr_t)&attrs;
180 
181 
182     errno = 0;
183     if (ioctl(fd, FCIO_CMD, &fcio) != 0) {
184 	close(fd);
185 	if (errno == EBUSY) {
186 	    throw BusyException();
187 	} else if (errno == EAGAIN) {
188 	    throw TryAgainException();
189 	} else if (errno == ENOTSUP) {
190 	    throw NotSupportedException();
191 	} else {
192 	    throw IOError("Unable to fetch adapter attributes");
193 	}
194     }
195     close(fd);
196 
197     /* Now copy over the payload */
198     attributes.NumberOfPorts = attrs.NumberOfPorts;
199     attributes.VendorSpecificID = attrs.VendorSpecificID;
200     memcpy(attributes.Manufacturer, attrs.Manufacturer, 64);
201     memcpy(attributes.SerialNumber, attrs.SerialNumber, 64);
202     memcpy(attributes.Model, attrs.Model, 256);
203     memcpy(attributes.ModelDescription, attrs.ModelDescription, 256);
204     memcpy(attributes.NodeSymbolicName, attrs.NodeSymbolicName, 256);
205     memcpy(attributes.HardwareVersion, attrs.HardwareVersion, 256);
206     memcpy(attributes.DriverVersion, attrs.DriverVersion, 256);
207     memcpy(attributes.OptionROMVersion, attrs.OptionROMVersion, 256);
208     memcpy(attributes.FirmwareVersion, attrs.FirmwareVersion, 256);
209     memcpy(attributes.DriverName, attrs.DriverName, 256);
210     memcpy(&attributes.NodeWWN, &attrs.NodeWWN, 8);
211 
212     return (attributes);
213 }
214 
215 int FCHBA::doForceLip() {
216     Trace	 log("FCHBA::doForceLip");
217     int		 fd;
218     fcio_t	 fcio;
219     uint64_t	 wwn  = 0;
220     HBAPort	*port = getPortByIndex(0);
221 
222     errno = 0;
223     if ((fd = open(port->getPath().c_str(), O_RDONLY | O_EXCL)) == -1) {
224 	if (errno == EBUSY) {
225 	    throw BusyException();
226 	} else if (errno == EAGAIN) {
227 	    throw TryAgainException();
228 	} else if (errno == ENOTSUP) {
229 	    throw NotSupportedException();
230 	} else {
231 	    throw IOError(port);
232 	}
233     }
234 
235     memset(&fcio, 0, sizeof (fcio));
236     fcio.fcio_cmd = FCIO_RESET_LINK;
237     fcio.fcio_xfer = FCIO_XFER_WRITE;
238     fcio.fcio_ilen = sizeof (wwn);
239     fcio.fcio_ibuf = (caddr_t)&wwn;
240 
241     errno = 0;
242     if (ioctl(fd, FCIO_CMD, &fcio) != 0) {
243 	close(fd);
244 
245 	if (errno == EBUSY) {
246 	    throw BusyException();
247 	} else if (errno == EAGAIN) {
248 	    throw TryAgainException();
249 	} else if (errno == ENOTSUP) {
250 	    throw NotSupportedException();
251 	} else {
252 	    throw IOError("Unable to reinitialize the link");
253 	}
254     } else {
255         close(fd);
256 	return (fcio.fcio_errno);
257     }
258 }
259 
260 HBA_ADAPTERATTRIBUTES FCHBA::npivGetHBAAttributes() {
261 	Trace log("FCHBA::npivGetHBAAttributes");
262 	int fd;
263 
264 	errno = 0;
265 	HBAPort *port = getPortByIndex(0);
266 	if ((fd = open(port->getPath().c_str(), O_NDELAY | O_RDONLY)) == -1) {
267 		// Why did we fail?
268 		if (errno == EBUSY) {
269 			throw BusyException();
270 		} else if (errno == EAGAIN) {
271 			throw TryAgainException();
272 		} else if (errno == ENOTSUP) {
273 			throw NotSupportedException();
274 		} else {
275 			throw IOError(port);
276 		}
277 	}
278 
279 	HBA_ADAPTERATTRIBUTES attributes;
280 	fcio_t fcio;
281 	fc_hba_adapter_attributes_t attrs;
282 
283 	memset(&fcio, 0, sizeof (fcio));
284 	fcio.fcio_cmd = FCIO_NPIV_GET_ADAPTER_ATTRIBUTES;
285 	fcio.fcio_olen = sizeof (attrs);
286 	fcio.fcio_xfer = FCIO_XFER_READ;
287 	fcio.fcio_obuf = (caddr_t)&attrs;
288 	errno = 0;
289 
290 	if (ioctl(fd, FCIO_CMD, &fcio) != 0) {
291 		close(fd);
292 		if (errno == EBUSY) {
293 			throw BusyException();
294 		} else if (errno == EAGAIN) {
295 			throw TryAgainException();
296 		} else if (errno == ENOTSUP) {
297 			throw NotSupportedException();
298 		} else {
299 			throw IOError("Unable to fetch adapter attributes");
300 		}
301 	}
302 	close(fd);
303 
304 	/* Now copy over the payload */
305 	attributes.NumberOfPorts = attrs.NumberOfPorts;
306 	attributes.VendorSpecificID = attrs.VendorSpecificID;
307 	memcpy(attributes.Manufacturer, attrs.Manufacturer, 64);
308 	memcpy(attributes.SerialNumber, attrs.SerialNumber, 64);
309 	memcpy(attributes.Model, attrs.Model, 256);
310 	memcpy(attributes.ModelDescription, attrs.ModelDescription, 256);
311 	memcpy(attributes.NodeSymbolicName, attrs.NodeSymbolicName, 256);
312 	memcpy(attributes.HardwareVersion, attrs.HardwareVersion, 256);
313 	memcpy(attributes.DriverVersion, attrs.DriverVersion, 256);
314 	memcpy(attributes.OptionROMVersion, attrs.OptionROMVersion, 256);
315 	memcpy(attributes.FirmwareVersion, attrs.FirmwareVersion, 256);
316 	memcpy(attributes.DriverName, attrs.DriverName, 256);
317 	memcpy(&attributes.NodeWWN, &attrs.NodeWWN, 8);
318 
319 	return (attributes);
320 }
321 
322 void FCHBA::loadAdapters(vector<HBA*> &list) {
323     Trace log("FCHBA::loadAdapters");
324     fcio_t			fcio;
325     fc_hba_list_t		*pathList;
326     int			fd;
327     int			size = 64; // default first attempt
328     bool		retry = false;
329     struct stat		sb;
330     int bufSize;
331 
332     /* Before we do anything, let's see if FCSM is on the system */
333     errno = 0;
334     if (stat(FCSM_DRIVER_PATH.c_str(), &sb) != 0) {
335 	if (errno == ENOENT) {
336 	    log.genericIOError(
337 		"The %s driver is not present. Unable to issue "
338 		"CT commands. Please install the %s package.",
339 		FCSM_DRIVER_PATH.c_str(), FCSM_DRIVER_PKG.c_str());
340 	    throw NotSupportedException();
341 	} else {
342 	    log.genericIOError(
343 		"Can not stat the %s driver for reason \"%s\" "
344 		"Unable to issue CT commands.",
345 		FCSM_DRIVER_PATH.c_str(), strerror(errno));
346 	    throw IOError("Unable to stat FCSM driver");
347 	}
348     }
349 
350 
351     /* construct fcio struct */
352     memset(&fcio, 0, sizeof (fcio_t));
353     fcio.fcio_cmd	= FCSMIO_ADAPTER_LIST;
354     fcio.fcio_xfer	= FCIO_XFER_RW;
355 
356 
357     /* open the fcsm node so we can send the ioctl to */
358     errno = 0;
359     if ((fd = open(FCSM_DRIVER_PATH.c_str(), O_RDONLY)) < 0) {
360 	if (errno == EBUSY) {
361 	    throw BusyException();
362 	} else if (errno == EAGAIN) {
363 	    throw TryAgainException();
364 	} else if (errno == ENOTSUP) {
365 	    throw NotSupportedException();
366 	} else if (errno == ENOENT) {
367 	    throw UnavailableException();
368 	} else {
369 	    throw IOError("Unable to open FCSM driver");
370 	}
371     }
372 
373     do {
374 	retry = false;
375 	errno = 0;
376 	bufSize = MAXPATHLEN * size + (int) sizeof (fc_hba_list_t) - 1;
377 	pathList = (fc_hba_list_t *)new uchar_t[bufSize];
378 	pathList->numAdapters = size;
379 	fcio.fcio_olen	= bufSize;
380 	fcio.fcio_obuf	= (char *)pathList;
381 	if (ioctl(fd, FCSMIO_CMD, &fcio) != 0) {
382 	    /* Interpret the fcio error code */
383 	    char fcioErrorString[MAX_FCIO_MSG_LEN] = "";
384 
385 	    log.genericIOError(
386 		"ADAPTER_LIST failed: "
387 		"Errno: \"%s\"",
388 		strerror(errno));
389 	    delete (pathList);
390 	    close(fd);
391 	    if (errno == EBUSY) {
392 		throw BusyException();
393 	    } else if (errno == EAGAIN) {
394 		throw TryAgainException();
395 	    } else if (errno == ENOTSUP) {
396 		throw NotSupportedException();
397 	    } else if (errno == ENOENT) {
398 		throw UnavailableException();
399 	    } else {
400 		throw IOError("Unable to build HBA list");
401 	    }
402 	}
403 	if (pathList->numAdapters > size) {
404 	    log.debug(
405 		"Buffer too small for number of HBAs. Retrying.");
406 	    size = pathList->numAdapters;
407 	    retry = true;
408 	    delete (pathList);
409 	}
410     } while (retry);
411 
412     close(fd);
413     log.debug("Detected %d adapters", pathList->numAdapters);
414     for (int i = 0, times =0; i < pathList->numAdapters;) {
415 	try {
416 	    HBA *hba = new FCHBA(pathList->hbaPaths[i]);
417 	    list.insert(list.begin(), hba);
418 	    i++;
419 	} catch (BusyException &e) {
420             sleep(1);
421             if (times++ > EXCPT_RETRY_COUNT) {
422                 i++;
423                 times = 0;
424             }
425 	    continue;
426 	} catch (TryAgainException &e) {
427 	    sleep(1);
428 	    if (times++ > EXCPT_RETRY_COUNT) {
429 		i++;
430 		times = 0;
431 	    }
432 	    continue;
433 	} catch (UnavailableException &e) {
434 	    sleep(1);
435 	    if (times++ > EXCPT_RETRY_COUNT) {
436 		i++;
437 		times = 0;
438 	    }
439 	    continue;
440 	} catch (HBAException &e) {
441 	    i++;
442 	    times = 0;
443 	    log.debug(
444 		"Ignoring partial failure while loading an HBA");
445 	}
446     }
447     if (pathList->numAdapters > HBAList::HBA_MAX_PER_LIST) {
448 	delete(pathList);
449 	throw InternalError(
450 	    "Exceeds max number of adatpers that VSL supports.");
451     }
452     delete (pathList);
453 }
454