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