xref: /illumos-gate/usr/src/lib/sun_fc/common/TgtFCHBA.cc (revision 56f33205c9ed776c3c909e07d52e94610a675740)
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 <TgtFCHBA.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/fctio.h>
42 #include <sys/fibre-channel/impl/fc_error.h>
43 #include <TgtFCHBAPort.h>
44 #include <HBAList.h>
45 #include <sun_fc.h>
46 
47 using namespace std;
48 const string TgtFCHBA::FCT_DRIVER_PATH = "/devices/pseudo/fct@0:admin";
49 const string TgtFCHBA::FCT_ADAPTER_NAME_PREFIX = "/devices/pseudo/fct@0";
50 const string TgtFCHBA::FCT_DRIVER_PKG	= "SUNWfct";
51 const int TgtFCHBA::MAX_FCTIO_MSG_LEN = 256;
52 
53 TgtFCHBA::TgtFCHBA(string path) : HBA()
54 {
55     Trace log("TgtFCHBA::TgtFCHBA");
56     log.debug("Constructing new Target mode HBA (%s)", path.c_str());
57 
58     // Add a target FCHBA port. With fct driver architecuture, all target mode
59     // FCHBA will have a single port regardless of the multiport support on
60     // FCA layer.
61     addPort(new TgtFCHBAPort(path));
62     name = "INTERNAL-FAILURE"; // Just in case things go wrong
63     try {
64 	    HBA_ADAPTERATTRIBUTES attrs = getHBAAttributes();
65 	    name = attrs.Manufacturer;
66 	    name += "-";
67 	    name += attrs.Model;
68 	    name += "-Tgt";
69 
70     } catch (HBAException &e) {
71 	    log.debug(
72 		"Failed to get HBA attribute for %s", path.c_str());
73 	    throw e;
74     }
75 }
76 
77 std::string TgtFCHBA::getName()
78 {
79     Trace log("TgtFCHBA::getName");
80     return (name);
81 }
82 
83 HBA_ADAPTERATTRIBUTES TgtFCHBA::getHBAAttributes()
84 {
85     Trace log("TgtFCHBA::getHBAAttributes");
86     int fd;
87 
88     errno = 0;
89     HBAPort *port = getPortByIndex(0);
90 
91     HBA_ADAPTERATTRIBUTES attributes;
92     fctio_t			    fctio;
93     fc_tgt_hba_adapter_attributes_t	    attrs;
94     uint64_t	portwwn;
95 
96     if ((fd = open(FCT_DRIVER_PATH.c_str(), O_NDELAY | O_RDONLY)) == -1) {
97 	// Why did we fail?
98 	if (errno == EBUSY) {
99 	    throw BusyException();
100 	} else if (errno == EAGAIN) {
101 	    throw TryAgainException();
102 	} else if (errno == ENOTSUP) {
103 	    throw NotSupportedException();
104 	} else {
105 	    throw IOError(port);
106 	}
107     }
108 
109     try {
110 	    std::string path = port->getPath();
111 	    string::size_type offset = path.find_last_of(".");
112 	    if (offset >= 0) {
113 		string portwwnString = path.substr(offset+1);
114 		portwwn = strtoull(portwwnString.c_str(), NULL, 16);
115 	    }
116     } catch (...) {
117 	    throw BadArgumentException();
118     }
119 
120     uint64_t en_wwn = htonll(portwwn);
121 
122     memset(&fctio, 0, sizeof (fctio));
123     fctio.fctio_cmd = FCTIO_GET_ADAPTER_ATTRIBUTES;
124     fctio.fctio_olen = (uint32_t)(sizeof (attrs));
125     fctio.fctio_xfer = FCTIO_XFER_READ;
126     fctio.fctio_obuf = (uint64_t)(uintptr_t)&attrs;
127     fctio.fctio_ilen = 8;
128     fctio.fctio_ibuf = (uint64_t)(uintptr_t)&en_wwn;
129 
130     errno = 0;
131     if (ioctl(fd, FCTIO_CMD, &fctio) != 0) {
132 	close(fd);
133 	if (errno == EBUSY) {
134 	    throw BusyException();
135 	} else if (errno == EAGAIN) {
136 	    throw TryAgainException();
137 	} else if (errno == ENOTSUP) {
138 	    throw NotSupportedException();
139 	} else {
140 	    throw IOError("Unable to fetch adapter attributes");
141 	}
142     }
143     close(fd);
144 
145     /* Now copy over the payload */
146     attributes.NumberOfPorts = attrs.NumberOfPorts;
147     attributes.VendorSpecificID = attrs.VendorSpecificID;
148     memcpy(attributes.Manufacturer, attrs.Manufacturer, 64);
149     memcpy(attributes.SerialNumber, attrs.SerialNumber, 64);
150     memcpy(attributes.Model, attrs.Model, 256);
151     memcpy(attributes.ModelDescription, attrs.ModelDescription, 256);
152     memcpy(attributes.NodeSymbolicName, attrs.NodeSymbolicName, 256);
153     memcpy(attributes.HardwareVersion, attrs.HardwareVersion, 256);
154     memcpy(attributes.DriverVersion, attrs.DriverVersion, 256);
155     memcpy(attributes.OptionROMVersion, attrs.OptionROMVersion, 256);
156     memcpy(attributes.FirmwareVersion, attrs.FirmwareVersion, 256);
157     memcpy(attributes.DriverName, attrs.DriverName, 256);
158     memcpy(&attributes.NodeWWN, &attrs.NodeWWN, 8);
159 
160     return (attributes);
161 }
162 
163 int TgtFCHBA::doForceLip()
164 {
165     Trace	 log("TgtFCHBA::doForceLip");
166     int		 fd;
167     HBAPort	*port = getPortByIndex(0);
168     fctio_t	 fctio;
169     uint64_t	 portwwn;
170 
171     errno = 0;
172     if ((fd = open(FCT_DRIVER_PATH.c_str(), O_NDELAY | O_RDONLY)) == -1) {
173 	if (errno == EBUSY) {
174 	    throw BusyException();
175 	} else if (errno == EAGAIN) {
176 	    throw TryAgainException();
177 	} else if (errno == ENOTSUP) {
178 	    throw NotSupportedException();
179 	} else {
180 	    throw IOError(port);
181 	}
182     }
183 
184     try {
185 	    std::string path = port->getPath();
186 	    string::size_type offset = path.find_last_of(".");
187 	    if (offset >= 0) {
188 		string portwwnString = path.substr(offset+1);
189 		portwwn = strtoull(portwwnString.c_str(), NULL, 16);
190 	    }
191     } catch (...) {
192 	    throw BadArgumentException();
193     }
194 
195     uint64_t en_wwn = htonll(portwwn);
196     memset(&fctio, 0, sizeof (fctio));
197     fctio.fctio_cmd = FCTIO_FORCE_LIP;
198     fctio.fctio_xfer = FCTIO_XFER_READ;
199     fctio.fctio_ilen = 8;
200     fctio.fctio_ibuf = (uint64_t)(uintptr_t)&en_wwn;
201 
202     errno = 0;
203     if (ioctl(fd, FCTIO_CMD, &fctio) != 0) {
204 	close(fd);
205 	if (errno == EBUSY) {
206 	    throw BusyException();
207 	} else if (errno == EAGAIN) {
208 	    throw TryAgainException();
209 	} else if (errno == ENOTSUP) {
210 	    throw NotSupportedException();
211 	} else {
212 	    throw IOError("Unable to reinitialize the link");
213 	}
214     } else {
215 	close(fd);
216 	return ((int)fctio.fctio_errno);
217     }
218 }
219 
220 void TgtFCHBA::loadAdapters(vector<HBA*> &list)
221 {
222     Trace log("TgtFCHBA::loadAdapters");
223     fctio_t			fctio;
224     fc_tgt_hba_list_t		*tgthbaList;
225     int			fd;
226     int			size = 64; // default first attempt
227     bool		retry = false;
228     struct stat		sb;
229     int bufSize;
230     char wwnStr[17];
231 
232     /* Before we do anything, let's see if FCT is on the system */
233     errno = 0;
234     if (stat(FCT_DRIVER_PATH.c_str(), &sb) != 0) {
235 	if (errno == ENOENT) {
236 	    log.genericIOError(
237 		"The %s driver is not present."
238                 " Please install the %s package.",
239 		FCT_DRIVER_PATH.c_str(), FCT_DRIVER_PKG.c_str());
240 	    throw NotSupportedException();
241 	} else {
242 	    log.genericIOError(
243 		"Can not stat the %s driver for reason \"%s\" "
244 		"Unable to get target mode FC adapters.",
245 		FCT_DRIVER_PATH.c_str(), strerror(errno));
246 	    throw IOError("Unable to stat FCSM driver");
247 	}
248     }
249 
250 
251     /* construct fcio struct */
252     memset(&fctio, 0, sizeof (fctio_t));
253     fctio.fctio_cmd	= FCTIO_ADAPTER_LIST;
254     fctio.fctio_xfer	= FCTIO_XFER_RW;
255 
256     /* open the fcsm node so we can send the ioctl to */
257     errno = 0;
258     if ((fd = open(FCT_DRIVER_PATH.c_str(), O_RDONLY)) < 0) {
259 	if (errno == EBUSY) {
260 	    throw BusyException();
261 	} else if (errno == EAGAIN) {
262 	    throw TryAgainException();
263 	} else if (errno == ENOTSUP) {
264 	    throw NotSupportedException();
265 	} else if (errno == ENOENT) {
266 	    throw UnavailableException();
267 	} else {
268 	    throw IOError("Unable to open FCT driver");
269 	}
270     }
271 
272     do {
273 	retry = false;
274 	errno = 0;
275 	bufSize = 8 * (size - 1) + (int) sizeof (fc_tgt_hba_list_t);
276 	tgthbaList = (fc_tgt_hba_list_t *)new uchar_t[bufSize];
277 	tgthbaList->numPorts = size;
278 	fctio.fctio_olen	= bufSize;
279 	fctio.fctio_obuf	= (uint64_t)(uintptr_t)tgthbaList;
280 	if (ioctl(fd, FCTIO_CMD, &fctio) != 0) {
281 	    /* Interpret the fcio error code */
282 	    char fcioErrorString[MAX_FCTIO_MSG_LEN] = "";
283 
284 	    log.genericIOError(
285 		"TGT_ADAPTER_LIST failed: "
286 		"Errno: \"%s\"",
287 		strerror(errno));
288 	    delete (tgthbaList);
289 	    close(fd);
290 	    if (errno == EBUSY) {
291 		throw BusyException();
292 	    } else if (errno == EAGAIN) {
293 		throw TryAgainException();
294 	    } else if (errno == ENOTSUP) {
295 		throw NotSupportedException();
296 	    } else if (errno == ENOENT) {
297 		throw UnavailableException();
298 	    } else {
299 		throw IOError("Unable to build HBA list");
300 	    }
301 	}
302 	if (tgthbaList->numPorts > size) {
303 	    log.debug(
304 		"Buffer too small for number of target mode HBAs. Retrying.");
305 	    size = tgthbaList->numPorts;
306 	    retry = true;
307 	    delete (tgthbaList);
308 	}
309     } while (retry);
310 
311     close(fd);
312     log.debug("Detected %d target mode adapters", tgthbaList->numPorts);
313     for (int i = 0; i < tgthbaList->numPorts; i++) {
314 	try {
315 	    std::string hbapath = FCT_ADAPTER_NAME_PREFIX.c_str();
316 	    hbapath += ".";
317 	    // move the row with two dimentional uint8 array for WWN
318 	    uint64_t tmp = ntohll(*((uint64_t *)&tgthbaList->port_wwn[i][0]));
319 	    sprintf(wwnStr, "%llx", tmp);
320 	    hbapath += wwnStr;
321 
322 	    HBA *hba = new TgtFCHBA(hbapath);
323 	    list.insert(list.begin(), hba);
324 	} catch (...) {
325 	    log.debug(
326 		"Ignoring partial failure while loading an HBA");
327 	}
328     }
329     if (tgthbaList->numPorts > HBAList::HBA_MAX_PER_LIST) {
330 	delete(tgthbaList);
331 	throw InternalError(
332 	    "Exceeds max number of adatpers that VSL supports.");
333     }
334     delete (tgthbaList);
335 }
336