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
48using namespace std;
49const string FCHBA::FCSM_DRIVER_PATH = "/devices/pseudo/fcsm@0:fcsm";
50const string FCHBA::FCSM_DRIVER_PKG	= "SUNWfcsm";
51const int FCHBA::MAX_FCIO_MSG_LEN = 256;
52
53FCHBA::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
146std::string FCHBA::getName() {
147    Trace log("FCHBA::getName");
148    return (name);
149}
150
151HBA_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
215int 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
260HBA_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
322void 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 adapters that VSL supports.");
451    }
452    delete (pathList);
453}
454