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