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
TgtFCHBA(string path)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
getName()77 std::string TgtFCHBA::getName()
78 {
79 Trace log("TgtFCHBA::getName");
80 return (name);
81 }
82
getHBAAttributes()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
doForceLip()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
loadAdapters(vector<HBA * > & list)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