xref: /illumos-gate/usr/src/lib/sun_fc/common/FCHBA.cc (revision b31b5de1357c915fe7dab4d9646d9d84f9fe69bc)
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 2008 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 HBA_ADAPTERATTRIBUTES FCHBA::npivGetHBAAttributes() {
208 	Trace log("FCHBA::npivGetHBAAttributes");
209 	int fd;
210 
211 	errno = 0;
212 	HBAPort *port = getPortByIndex(0);
213 	if ((fd = open(port->getPath().c_str(), O_NDELAY | O_RDONLY)) == -1) {
214 		// Why did we fail?
215 		if (errno == EBUSY) {
216 			throw BusyException();
217 		} else if (errno == EAGAIN) {
218 			throw TryAgainException();
219 		} else if (errno == ENOTSUP) {
220 			throw NotSupportedException();
221 		} else {
222 			throw IOError(port);
223 		}
224 	}
225 
226 	HBA_ADAPTERATTRIBUTES attributes;
227 	fcio_t fcio;
228 	fc_hba_adapter_attributes_t attrs;
229 
230 	memset(&fcio, 0, sizeof (fcio));
231 	fcio.fcio_cmd = FCIO_NPIV_GET_ADAPTER_ATTRIBUTES;
232 	fcio.fcio_olen = sizeof (attrs);
233 	fcio.fcio_xfer = FCIO_XFER_READ;
234 	fcio.fcio_obuf = (caddr_t)&attrs;
235 	errno = 0;
236 
237 	if (ioctl(fd, FCIO_CMD, &fcio) != 0) {
238 		close(fd);
239 		if (errno == EBUSY) {
240 			throw BusyException();
241 		} else if (errno == EAGAIN) {
242 			throw TryAgainException();
243 		} else if (errno == ENOTSUP) {
244 			throw NotSupportedException();
245 		} else {
246 			throw IOError("Unable to fetch adapter attributes");
247 		}
248 	}
249 	close(fd);
250 
251 	/* Now copy over the payload */
252 	attributes.NumberOfPorts = attrs.NumberOfPorts;
253 	attributes.VendorSpecificID = attrs.VendorSpecificID;
254 	memcpy(attributes.Manufacturer, attrs.Manufacturer, 64);
255 	memcpy(attributes.SerialNumber, attrs.SerialNumber, 64);
256 	memcpy(attributes.Model, attrs.Model, 256);
257 	memcpy(attributes.ModelDescription, attrs.ModelDescription, 256);
258 	memcpy(attributes.NodeSymbolicName, attrs.NodeSymbolicName, 256);
259 	memcpy(attributes.HardwareVersion, attrs.HardwareVersion, 256);
260 	memcpy(attributes.DriverVersion, attrs.DriverVersion, 256);
261 	memcpy(attributes.OptionROMVersion, attrs.OptionROMVersion, 256);
262 	memcpy(attributes.FirmwareVersion, attrs.FirmwareVersion, 256);
263 	memcpy(attributes.DriverName, attrs.DriverName, 256);
264 	memcpy(&attributes.NodeWWN, &attrs.NodeWWN, 8);
265 
266 	return (attributes);
267 }
268 
269 void FCHBA::loadAdapters(vector<HBA*> &list) {
270     Trace log("FCHBA::loadAdapters");
271     fcio_t			fcio;
272     fc_hba_list_t		*pathList;
273     int			fd;
274     int			size = 64; // default first attempt
275     bool		retry = false;
276     struct stat		sb;
277     int bufSize;
278 
279     /* Before we do anything, let's see if FCSM is on the system */
280     errno = 0;
281     if (stat(FCSM_DRIVER_PATH.c_str(), &sb) != 0) {
282 	if (errno == ENOENT) {
283 	    log.genericIOError(
284 		"The %s driver is not present. Unable to issue "
285 		"CT commands. Please install the %s package.",
286 		FCSM_DRIVER_PATH.c_str(), FCSM_DRIVER_PKG.c_str());
287 	    throw NotSupportedException();
288 	} else {
289 	    log.genericIOError(
290 		"Can not stat the %s driver for reason \"%s\" "
291 		"Unable to issue CT commands.",
292 		FCSM_DRIVER_PATH.c_str(), strerror(errno));
293 	    throw IOError("Unable to stat FCSM driver");
294 	}
295     }
296 
297 
298     /* construct fcio struct */
299     memset(&fcio, 0, sizeof (fcio_t));
300     fcio.fcio_cmd	= FCSMIO_ADAPTER_LIST;
301     fcio.fcio_xfer	= FCIO_XFER_RW;
302 
303 
304     /* open the fcsm node so we can send the ioctl to */
305     errno = 0;
306     if ((fd = open(FCSM_DRIVER_PATH.c_str(), O_RDONLY)) < 0) {
307 	if (errno == EBUSY) {
308 	    throw BusyException();
309 	} else if (errno == EAGAIN) {
310 	    throw TryAgainException();
311 	} else if (errno == ENOTSUP) {
312 	    throw NotSupportedException();
313 	} else if (errno == ENOENT) {
314 	    throw UnavailableException();
315 	} else {
316 	    throw IOError("Unable to open FCSM driver");
317 	}
318     }
319 
320     do {
321 	retry = false;
322 	errno = 0;
323 	bufSize = MAXPATHLEN * size + (int) sizeof (fc_hba_list_t) - 1;
324 	pathList = (fc_hba_list_t *)new uchar_t[bufSize];
325 	pathList->numAdapters = size;
326 	fcio.fcio_olen	= bufSize;
327 	fcio.fcio_obuf	= (char *)pathList;
328 	if (ioctl(fd, FCSMIO_CMD, &fcio) != 0) {
329 	    /* Interpret the fcio error code */
330 	    char fcioErrorString[MAX_FCIO_MSG_LEN] = "";
331 
332 	    log.genericIOError(
333 		"ADAPTER_LIST failed: "
334 		"Errno: \"%s\"",
335 		strerror(errno));
336 	    delete (pathList);
337 	    close(fd);
338 	    if (errno == EBUSY) {
339 		throw BusyException();
340 	    } else if (errno == EAGAIN) {
341 		throw TryAgainException();
342 	    } else if (errno == ENOTSUP) {
343 		throw NotSupportedException();
344 	    } else if (errno == ENOENT) {
345 		throw UnavailableException();
346 	    } else {
347 		throw IOError("Unable to build HBA list");
348 	    }
349 	}
350 	if (pathList->numAdapters > size) {
351 	    log.debug(
352 		"Buffer too small for number of HBAs. Retrying.");
353 	    size = pathList->numAdapters;
354 	    retry = true;
355 	    delete (pathList);
356 	}
357     } while (retry);
358 
359     close(fd);
360     log.debug("Detected %d adapters", pathList->numAdapters);
361     for (int i = 0; i < pathList->numAdapters; i++) {
362 	try {
363 	    HBA *hba = new FCHBA(pathList->hbaPaths[i]);
364 	    list.insert(list.begin(), hba);
365 	} catch (...) {
366 	    log.debug(
367 		"Ignoring partial failure while loading an HBA");
368 	}
369     }
370     if (pathList->numAdapters > HBAList::HBA_MAX_PER_LIST) {
371 	delete(pathList);
372 	throw InternalError(
373 	    "Exceeds max number of adatpers that VSL supports.");
374     }
375     delete (pathList);
376 }
377