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