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