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
FCHBA(string path)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
getName()146 std::string FCHBA::getName() {
147 Trace log("FCHBA::getName");
148 return (name);
149 }
150
getHBAAttributes()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
doForceLip()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
npivGetHBAAttributes()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
loadAdapters(vector<HBA * > & list)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 adapters that VSL supports.");
451 }
452 delete (pathList);
453 }
454