xref: /illumos-gate/usr/src/lib/sun_fc/common/TgtFCHBAPort.cc (revision e8921a52c53ee69f7b65f054d9b2e886139daa59)
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 
28 #include <TgtFCHBAPort.h>
29 #include <Exceptions.h>
30 #include <Trace.h>
31 #include <sun_fc.h>
32 #include <iostream>
33 #include <iomanip>
34 #include <sys/types.h>
35 #include <sys/mkdev.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <stropts.h>
40 #include <dirent.h>
41 #include <sys/fibre-channel/fc.h>
42 #include <sys/fctio.h>
43 #include <sys/fibre-channel/impl/fc_error.h>
44 #include <sys/fibre-channel/fc_appif.h>
45 #include <sys/scsi/generic/commands.h>
46 #include <sys/scsi/impl/commands.h>
47 #include <sys/scsi/impl/sense.h>
48 #include <sys/scsi/generic/inquiry.h>
49 #include <sys/scsi/generic/status.h>
50 #include <errno.h>
51 #include <cstdlib>
52 
53 
54 using namespace std;
55 
56 const int TgtFCHBAPort::MAX_FCTIO_MSG_LEN = 256;
57 const string TgtFCHBAPort::FCT_DRIVER_PATH = "/devices/pseudo/fct@0:admin";
58 
59 /*
60  * Interpret the error code in the fctio_t structure
61  *
62  * message must be at least MAX_FCTIO_MSG_LEN in length.
63  */
64 void
65 TgtFCHBAPort::transportError(uint32_t fctio_errno, char *message) {
66 	Trace log("transportError");
67 	string fcioErrorString;
68 	if (message == NULL) {
69 	    log.internalError("NULL routine argument");
70 	    return;
71 	}
72 	switch (fctio_errno) {
73 	case (uint32_t)FC_FAILURE:
74 	    fcioErrorString = "general failure";
75 	    break;
76 	case (uint32_t)FC_FAILURE_SILENT:
77 	    fcioErrorString = "general failure but fail silently";
78 	    break;
79 	case FC_SUCCESS:
80 	    fcioErrorString = "successful completion";
81 	    break;
82 	case FC_CAP_ERROR:
83 	    fcioErrorString = "FCA capability error";
84 	    break;
85 	case FC_CAP_FOUND:
86 	    fcioErrorString = "FCA capability unsettable";
87 	    break;
88 	case FC_CAP_SETTABLE:
89 	    fcioErrorString = "FCA capability settable";
90 	    break;
91 	case FC_UNBOUND:
92 	    fcioErrorString = "unbound stuff";
93 	    break;
94 	case FC_NOMEM:
95 	    fcioErrorString = "allocation error";
96 	    break;
97 	case FC_BADPACKET:
98 	    fcioErrorString = "invalid packet specified/supplied";
99 	    break;
100 	case FC_OFFLINE:
101 	    fcioErrorString = "I/O resource unavailable";
102 	    break;
103 	case FC_OLDPORT:
104 	    fcioErrorString = "operation on non-loop port";
105 	    break;
106 	case FC_NO_MAP:
107 	    fcioErrorString = "requested map unavailable";
108 	    break;
109 	case FC_TRANSPORT_ERROR:
110 	    fcioErrorString = "unable to transport I/O";
111 	    break;
112 	case FC_ELS_FREJECT:
113 	    fcioErrorString = "ELS rejected by a Fabric";
114 	    break;
115 	case FC_ELS_PREJECT:
116 	    fcioErrorString = "ELS rejected by an N_port";
117 	    break;
118 	case FC_ELS_BAD:
119 	    fcioErrorString = "ELS rejected by FCA/fctl";
120 	    break;
121 	case FC_ELS_MALFORMED:
122 	    fcioErrorString = "poorly formed ELS request";
123 	    break;
124 	case FC_TOOMANY:
125 		fcioErrorString = "resource request too large";
126 	    break;
127 	case FC_UB_BADTOKEN:
128 	    fcioErrorString = "invalid unsolicited buffer token";
129 	    break;
130 	case FC_UB_ERROR:
131 	    fcioErrorString = "invalid unsol buf request";
132 	    break;
133 	case FC_UB_BUSY:
134 	    fcioErrorString = "buffer already in use";
135 	    break;
136 	case FC_BADULP:
137 	    fcioErrorString = "Unknown ulp";
138 	    break;
139 	case FC_BADTYPE:
140 	    fcioErrorString = "ULP not registered to handle this FC4 type";
141 	    break;
142 	case FC_UNCLAIMED:
143 	    fcioErrorString = "request or data not claimed";
144 	    break;
145 	case FC_ULP_SAMEMODULE:
146 	    fcioErrorString = "module already in use";
147 	    break;
148 	case FC_ULP_SAMETYPE:
149 	    fcioErrorString = "FC4 module already in use";
150 	    break;
151 	case FC_ABORTED:
152 	    fcioErrorString = "request aborted";
153 	    break;
154 	case FC_ABORT_FAILED:
155 	    fcioErrorString = "abort request failed";
156 	    break;
157 	case FC_BADEXCHANGE:
158 	    fcioErrorString = "exchange doesn�t exist";
159 	    break;
160 	case FC_BADWWN:
161 	    fcioErrorString = "WWN not recognized";
162 	    break;
163 	case FC_BADDEV:
164 	    fcioErrorString = "device unrecognized";
165 	    break;
166 	case FC_BADCMD:
167 	    fcioErrorString = "invalid command issued";
168 	    break;
169 	case FC_BADOBJECT:
170 	    fcioErrorString = "invalid object requested";
171 	    break;
172 	case FC_BADPORT:
173 	    fcioErrorString = "invalid port specified";
174 	    break;
175 	case FC_NOTTHISPORT:
176 	    fcioErrorString = "resource not at this port";
177 	    break;
178 	case FC_PREJECT:
179 	    fcioErrorString = "reject at remote N_Port";
180 	    break;
181 	case FC_FREJECT:
182 	    fcioErrorString = "reject at remote Fabric";
183 	    break;
184 	case FC_PBUSY:
185 	    fcioErrorString = "remote N_Port busy";
186 	    break;
187 	case FC_FBUSY:
188 	    fcioErrorString = "remote Fabric busy";
189 	    break;
190 	case FC_ALREADY:
191 	    fcioErrorString = "already logged in";
192 	    break;
193 	case FC_LOGINREQ:
194 	    fcioErrorString = "login required";
195 	    break;
196 	case FC_RESETFAIL:
197 	    fcioErrorString = "reset failed";
198 	    break;
199 	case FC_INVALID_REQUEST:
200 	    fcioErrorString = "request is invalid";
201 	    break;
202 	case FC_OUTOFBOUNDS:
203 	    fcioErrorString = "port number is out of bounds";
204 	    break;
205 	case FC_TRAN_BUSY:
206 	    fcioErrorString = "command transport busy";
207 	    break;
208 	case FC_STATEC_BUSY:
209 	    fcioErrorString = "port driver currently busy";
210 	    break;
211 	case FC_DEVICE_BUSY:
212 	    fcioErrorString = "transport working on this device";
213 	    break;
214 	case FC_DEVICE_NOT_TGT:
215 	    fcioErrorString = "device is not a SCSI target";
216 	    break;
217 	default:
218 	    snprintf(message, MAX_FCTIO_MSG_LEN, "Unknown error code 0x%x",
219 		fctio_errno);
220 	    return;
221 	}
222 	snprintf(message, MAX_FCTIO_MSG_LEN, "%s", fcioErrorString.c_str());
223 }
224 
225 TgtFCHBAPort::TgtFCHBAPort(string thePath) : HBAPort() {
226 	Trace log("TgtFCHBAPort::TgtFCHBAPort");
227 	log.debug("Initializing HBA port %s", path.c_str());
228 	path = thePath;
229 
230 	// This routine is not index based, so we can discard stateChange
231 	uint64_t tmp;
232 	HBA_PORTATTRIBUTES attrs = getPortAttributes(tmp);
233 	memcpy(&tmp, &attrs.PortWWN, 8);
234 	portWWN = ntohll(tmp);
235 	memcpy(&tmp, &attrs.NodeWWN, 8);
236 	nodeWWN = ntohll(tmp);
237 
238 	// For reference, here's how to dump WWN's through C++ streams.
239 	// cout << "\tPort WWN: " << hex << setfill('0') << setw(16) << portWWN
240 	// << endl;
241 	// cout << "\tNode WWN: " << hex << setfill('0') << setw(16) << nodeWWN
242 	// << endl;
243 }
244 
245 HBA_PORTATTRIBUTES TgtFCHBAPort::getPortAttributes(uint64_t &stateChange) {
246 	Trace log("TgtFCHBAPort::getPortAttributes");
247 
248 	HBA_PORTATTRIBUTES	attributes;
249 	fctio_t			fctio;
250 	fc_tgt_hba_port_attributes_t    attrs;
251 
252 	memset(&fctio, 0, sizeof (fctio));
253 	memset(&attributes, 0, sizeof (attributes));
254 
255 	uint64_t portwwn = 0;
256 	try {
257 	    string::size_type offset = path.find_last_of(".");
258 	    if (offset >= 0) {
259 		string portwwnString = path.substr(offset+1);
260 		portwwn = strtoull(portwwnString.c_str(), NULL, 16);
261 	    }
262 	} catch (...) {
263 	    throw BadArgumentException();
264 	}
265 
266 	uint64_t en_wwn = htonll(portwwn);
267 
268 	fctio.fctio_cmd = FCTIO_GET_ADAPTER_PORT_ATTRIBUTES;
269 	fctio.fctio_ilen = 8;
270 	fctio.fctio_ibuf = (uint64_t)(uintptr_t)&en_wwn;
271 	fctio.fctio_xfer = FCTIO_XFER_READ;
272 	fctio.fctio_olen = (uint32_t)(sizeof (attrs));
273 	fctio.fctio_obuf = (uint64_t)(uintptr_t)&attrs;
274 
275 	fct_ioctl(FCTIO_CMD, &fctio);
276 
277 	stateChange = attrs.lastChange;
278 
279 	attributes.PortFcId = attrs.PortFcId;
280 	attributes.PortType = attrs.PortType;
281 	attributes.PortState = attrs.PortState;
282 	attributes.PortSupportedClassofService = attrs.PortSupportedClassofService;
283 	attributes.PortSupportedSpeed = attrs.PortSupportedSpeed;
284 	attributes.PortSpeed = attrs.PortSpeed;
285 	attributes.PortMaxFrameSize = attrs.PortMaxFrameSize;
286 	attributes.NumberofDiscoveredPorts = attrs.NumberofDiscoveredPorts;
287 	memcpy(&attributes.NodeWWN, &attrs.NodeWWN, 8);
288 	memcpy(&attributes.PortWWN, &attrs.PortWWN, 8);
289 	memcpy(&attributes.FabricName, &attrs.FabricName, 8);
290 	memcpy(&attributes.PortSupportedFc4Types, &attrs.PortSupportedFc4Types, 32);
291 	memcpy(&attributes.PortActiveFc4Types, &attrs.PortActiveFc4Types, 32);
292 	memcpy(&attributes.PortSymbolicName, &attrs.PortSymbolicName, 256);
293 
294 	strncpy((char *)attributes.OSDeviceName, "Not Applicable", 15);
295 	return (attributes);
296 }
297 
298 HBA_PORTATTRIBUTES TgtFCHBAPort::getDiscoveredAttributes(
299 	    HBA_UINT32 discoveredport, uint64_t &stateChange) {
300 	Trace log("TgtFCHBAPort::getDiscoverdAttributes(i)");
301 
302 	HBA_PORTATTRIBUTES		attributes;
303 	fctio_t			fctio;
304 	fc_tgt_hba_port_attributes_t    attrs;
305 
306 	memset(&fctio, 0, sizeof (fctio));
307 	memset(&attributes, 0, sizeof (attributes));
308 
309 	uint64_t portwwn = 0;
310 	try {
311 	    string::size_type offset = path.find_last_of(".");
312 	    if (offset >= 0) {
313 		string portwwnString = path.substr(offset+1);
314 		portwwn = strtoull(portwwnString.c_str(), NULL, 16);
315 	    }
316 	} catch (...) {
317 	    throw BadArgumentException();
318 	}
319 
320 	uint64_t en_wwn = htonll(portwwn);
321 
322 	fctio.fctio_cmd = FCTIO_GET_DISCOVERED_PORT_ATTRIBUTES;
323 	fctio.fctio_ilen = 8;
324 	fctio.fctio_ibuf = (uint64_t)(uintptr_t)&en_wwn;
325 	fctio.fctio_xfer = FCTIO_XFER_READ;
326 	fctio.fctio_olen = (uint32_t)(sizeof (attrs));
327 	fctio.fctio_obuf = (uint64_t)(uintptr_t)&attrs;
328 	fctio.fctio_alen = (uint32_t)(sizeof (discoveredport));
329 	fctio.fctio_abuf = (uint64_t)(uintptr_t)&discoveredport;
330 
331 	fct_ioctl(FCTIO_CMD, &fctio);
332 
333 	stateChange = attrs.lastChange;
334 
335 	attributes.PortFcId = attrs.PortFcId;
336 	attributes.PortType = attrs.PortType;
337 	attributes.PortState = attrs.PortState;
338 	attributes.PortSupportedClassofService = attrs.PortSupportedClassofService;
339 	attributes.PortSupportedSpeed = attrs.PortSupportedSpeed;
340 	attributes.PortSpeed = attrs.PortSpeed;
341 	attributes.PortMaxFrameSize = attrs.PortMaxFrameSize;
342 	attributes.NumberofDiscoveredPorts = attrs.NumberofDiscoveredPorts;
343 	memcpy(&attributes.NodeWWN, &attrs.NodeWWN, 8);
344 	memcpy(&attributes.PortWWN, &attrs.PortWWN, 8);
345 	memcpy(&attributes.FabricName, &attrs.FabricName, 8);
346 	memcpy(&attributes.PortSupportedFc4Types, &attrs.PortSupportedFc4Types, 32);
347 	memcpy(&attributes.PortActiveFc4Types, &attrs.PortActiveFc4Types, 32);
348 	memcpy(&attributes.PortSymbolicName, &attrs.PortSymbolicName, 256);
349 
350 
351 	return (attributes);
352 }
353 
354 HBA_PORTATTRIBUTES TgtFCHBAPort::getDiscoveredAttributes(
355 	    uint64_t wwn, uint64_t &stateChange) {
356 	Trace log("TgtFCHBAPort::getDiscoverdAttributes(p)");
357 
358 	HBA_PORTATTRIBUTES attributes;
359 	fctio_t			fctio;
360 	fc_tgt_hba_port_attributes_t    attrs;
361 
362 	memset(&fctio, 0, sizeof (fctio));
363 	memset(&attributes, 0, sizeof (attributes));
364 
365 	uint64_t en_wwn = htonll(wwn);
366 
367 	fctio.fctio_cmd = FCTIO_GET_PORT_ATTRIBUTES;
368 	fctio.fctio_olen = (uint32_t)(sizeof (attrs));
369 	fctio.fctio_xfer = FCTIO_XFER_READ;
370 	fctio.fctio_obuf = (uint64_t)(uintptr_t)&attrs;
371 	fctio.fctio_ilen = (uint32_t)(sizeof (wwn));
372 	fctio.fctio_ibuf = (uint64_t)(uintptr_t)&en_wwn;
373 
374 	fct_ioctl(FCTIO_CMD, &fctio);
375 
376 	stateChange = attrs.lastChange;
377 
378 	attributes.PortFcId = attrs.PortFcId;
379 	attributes.PortType = attrs.PortType;
380 	attributes.PortState = attrs.PortState;
381 	attributes.PortSupportedClassofService = attrs.PortSupportedClassofService;
382 	attributes.PortSupportedSpeed = attrs.PortSupportedSpeed;
383 	attributes.PortSpeed = attrs.PortSpeed;
384 	attributes.PortMaxFrameSize = attrs.PortMaxFrameSize;
385 	attributes.NumberofDiscoveredPorts = attrs.NumberofDiscoveredPorts;
386 	memcpy(&attributes.NodeWWN, &attrs.NodeWWN, 8);
387 	memcpy(&attributes.PortWWN, &attrs.PortWWN, 8);
388 	memcpy(&attributes.FabricName, &attrs.FabricName, 8);
389 	memcpy(&attributes.PortSupportedFc4Types, &attrs.PortSupportedFc4Types, 32);
390 	memcpy(&attributes.PortActiveFc4Types, &attrs.PortActiveFc4Types, 32);
391 	memcpy(&attributes.PortSymbolicName, &attrs.PortSymbolicName, 256);
392 
393 
394 	return (attributes);
395 }
396 
397 void TgtFCHBAPort::sendRLS(uint64_t destWWN,
398 	    void		*pRspBuffer,
399 	    HBA_UINT32		*pRspBufferSize) {
400 	Trace log("FCHBAPort::sendRLS");
401 
402 	fctio_t		fctio;
403 	// fc_hba_adapter_port_stats_t	fc_port_stat;
404 	uint64_t	en_portWWN;
405 	uint64_t	DestPortID;
406 
407 	// Validate the arguments
408 	if (pRspBuffer == NULL ||
409 		pRspBufferSize == NULL) {
410 	    log.userError("NULL hba");
411 	    throw BadArgumentException();
412 	}
413 
414 	// check to see if we are sending RLS to the HBA
415 	HBA_PORTATTRIBUTES attrs;
416 	uint64_t tmp;
417 	portWWN = getPortWWN();
418 	en_portWWN = htonll(portWWN);
419 
420 	/* The destWWN is either the adapter port or a discovered port. */
421 	memset(&fctio, 0, sizeof (fctio));
422 	fctio.fctio_cmd = FCTIO_GET_LINK_STATUS;
423 	fctio.fctio_ibuf = (uint64_t)(uintptr_t)&en_portWWN;
424 	fctio.fctio_ilen = (uint32_t)(sizeof (en_portWWN));
425 	if (portWWN != destWWN) {
426 	    attrs = getDiscoveredAttributes(destWWN, tmp);
427 	    DestPortID = (uint64_t)attrs.PortFcId;
428 	    fctio.fctio_abuf = (uint64_t)(uintptr_t)&DestPortID;
429 	    fctio.fctio_alen = (uint32_t)(sizeof (DestPortID));
430 	}
431 	fctio.fctio_xfer = FCTIO_XFER_READ;
432 	fctio.fctio_flags = 0;
433 	fctio.fctio_obuf = (uint64_t)(uintptr_t)new uchar_t[*pRspBufferSize];
434 	fctio.fctio_olen = *pRspBufferSize;
435 
436 	if (fctio.fctio_obuf == 0) {
437 	    log.noMemory();
438 	    throw InternalError();
439 	}
440 
441 	fct_ioctl(FCTIO_CMD, &fctio);
442 	memcpy(pRspBuffer, (uchar_t *)(uintptr_t)fctio.fctio_obuf,
443 	       *pRspBufferSize);
444 	if (fctio.fctio_obuf != 0) {
445 	    delete((uchar_t *)(uintptr_t)fctio.fctio_obuf);
446 	}
447 }
448 
449 /**
450  * @memo	    Validate that the port is still present in the system
451  * @exception	    UnavailableException if the port is not present
452  * @version	    1.7
453  *
454  * @doc		    If the port is still present on the system, the routine
455  *		    will return normally.  If the port is not present
456  *		    an exception will be thrown.
457  */
458 void TgtFCHBAPort::validatePresent() {
459 	Trace log("TgtFCHBAPort::validatePresent");
460 	// We already got the adapter list through the ioctl
461 	// so calling it again to validate it is too expensive.
462 }
463 
464 void TgtFCHBAPort::fct_ioctl(int cmd, fctio_t *fctio) {
465 	Trace log("TgtFCHBAPort::fct_ioctl");
466 	char fcioErrorString[MAX_FCTIO_MSG_LEN] = "";
467 	int fd = HBA::_open(FCT_DRIVER_PATH, O_NDELAY | O_RDONLY);
468 	try {
469 	    HBA::_ioctl(fd, cmd, (uchar_t *)fctio);
470 	    close(fd);
471 	    if (fctio->fctio_errno) {
472 		throw IOError("IOCTL transport failure");
473 	    }
474 	} catch (...) {
475 	    close(fd);
476 	    transportError(fctio->fctio_errno, fcioErrorString);
477 	    log.genericIOError("ioctl (0x%x) failed. Transport: \"%s\"", cmd,
478 		    fcioErrorString);
479 	    switch (fctio->fctio_errno) {
480 	    case FC_BADWWN:
481 		throw IllegalWWNException();
482 	    case FC_BADPORT:
483 		throw IllegalWWNException();
484 	    case FC_OUTOFBOUNDS:
485 		throw IllegalIndexException();
486 	    case FC_PBUSY:
487 	    case FC_FBUSY:
488 	    case FC_TRAN_BUSY:
489 	    case FC_STATEC_BUSY:
490 	    case FC_DEVICE_BUSY:
491 		throw BusyException();
492 	    case FC_SUCCESS:
493 	    default:
494 		throw;
495 	    }
496 	}
497 }
498