xref: /illumos-gate/usr/src/lib/sun_fc/common/FCHBAPort.cc (revision 5422785d352a2bb398daceab3d1898a8aa64d006)
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 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 
27 
28 #include <FCHBAPort.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/fibre-channel/fcio.h>
43 #include <sys/fibre-channel/ulp/fcp_util.h>
44 #include <sys/fibre-channel/ulp/fcsm.h>
45 #include <sys/fibre-channel/impl/fc_error.h>
46 #include <sys/fibre-channel/fc_appif.h>
47 #include <sys/scsi/generic/commands.h>
48 #include <sys/scsi/impl/commands.h>
49 #include <sys/scsi/impl/sense.h>
50 #include <sys/scsi/generic/inquiry.h>
51 #include <sys/scsi/generic/status.h>
52 #include <errno.h>
53 #include <FCHBANPIVPort.h>
54 
55 
56 using namespace std;
57 
58 const int FCHBAPort::MAX_FCIO_MSG_LEN = 256;
59 const string FCHBAPort::FCSM_DRIVER_PATH = "/devices/pseudo/fcsm@0:fcsm";
60 const string FCHBAPort::FCP_DRIVER_PATH	= "/devices/pseudo/fcp@0:fcp";
61 
62 /*
63  * Interpret the error code in the fcio_t structure
64  *
65  * message must be at least MAX_FCIO_MSG_LEN in length.
66  */
67 void
68 FCHBAPort::transportError(uint32_t fcio_errno, char *message) {
69 	Trace log("transportError");
70 	string fcioErrorString;
71 	if (message == NULL) {
72 	    log.internalError("NULL routine argument");
73 	    return;
74 	}
75 	switch (fcio_errno) {
76 	case (uint32_t)FC_FAILURE:
77 	    fcioErrorString = "general failure";
78 	    break;
79 	case (uint32_t)FC_FAILURE_SILENT:
80 	    fcioErrorString = "general failure but fail silently";
81 	    break;
82 	case FC_SUCCESS:
83 	    fcioErrorString = "successful completion";
84 	    break;
85 	case FC_CAP_ERROR:
86 	    fcioErrorString = "FCA capability error";
87 	    break;
88 	case FC_CAP_FOUND:
89 	    fcioErrorString = "FCA capability unsettable";
90 	    break;
91 	case FC_CAP_SETTABLE:
92 	    fcioErrorString = "FCA capability settable";
93 	    break;
94 	case FC_UNBOUND:
95 	    fcioErrorString = "unbound stuff";
96 	    break;
97 	case FC_NOMEM:
98 	    fcioErrorString = "allocation error";
99 	    break;
100 	case FC_BADPACKET:
101 	    fcioErrorString = "invalid packet specified/supplied";
102 	    break;
103 	case FC_OFFLINE:
104 	    fcioErrorString = "I/O resource unavailable";
105 	    break;
106 	case FC_OLDPORT:
107 	    fcioErrorString = "operation on non-loop port";
108 	    break;
109 	case FC_NO_MAP:
110 	    fcioErrorString = "requested map unavailable";
111 	    break;
112 	case FC_TRANSPORT_ERROR:
113 	    fcioErrorString = "unable to transport I/O";
114 	    break;
115 	case FC_ELS_FREJECT:
116 	    fcioErrorString = "ELS rejected by a Fabric";
117 	    break;
118 	case FC_ELS_PREJECT:
119 	    fcioErrorString = "ELS rejected by an N_port";
120 	    break;
121 	case FC_ELS_BAD:
122 	    fcioErrorString = "ELS rejected by FCA/fctl";
123 	    break;
124 	case FC_ELS_MALFORMED:
125 	    fcioErrorString = "poorly formed ELS request";
126 	    break;
127 	case FC_TOOMANY:
128 		fcioErrorString = "resource request too large";
129 	    break;
130 	case FC_UB_BADTOKEN:
131 	    fcioErrorString = "invalid unsolicited buffer token";
132 	    break;
133 	case FC_UB_ERROR:
134 	    fcioErrorString = "invalid unsol buf request";
135 	    break;
136 	case FC_UB_BUSY:
137 	    fcioErrorString = "buffer already in use";
138 	    break;
139 	case FC_BADULP:
140 	    fcioErrorString = "Unknown ulp";
141 	    break;
142 	case FC_BADTYPE:
143 	    fcioErrorString = "ULP not registered to handle this FC4 type";
144 	    break;
145 	case FC_UNCLAIMED:
146 	    fcioErrorString = "request or data not claimed";
147 	    break;
148 	case FC_ULP_SAMEMODULE:
149 	    fcioErrorString = "module already in use";
150 	    break;
151 	case FC_ULP_SAMETYPE:
152 	    fcioErrorString = "FC4 module already in use";
153 	    break;
154 	case FC_ABORTED:
155 	    fcioErrorString = "request aborted";
156 	    break;
157 	case FC_ABORT_FAILED:
158 	    fcioErrorString = "abort request failed";
159 	    break;
160 	case FC_BADEXCHANGE:
161 	    fcioErrorString = "exchange doesn�t exist";
162 	    break;
163 	case FC_BADWWN:
164 	    fcioErrorString = "WWN not recognized";
165 	    break;
166 	case FC_BADDEV:
167 	    fcioErrorString = "device unrecognized";
168 	    break;
169 	case FC_BADCMD:
170 	    fcioErrorString = "invalid command issued";
171 	    break;
172 	case FC_BADOBJECT:
173 	    fcioErrorString = "invalid object requested";
174 	    break;
175 	case FC_BADPORT:
176 	    fcioErrorString = "invalid port specified";
177 	    break;
178 	case FC_NOTTHISPORT:
179 	    fcioErrorString = "resource not at this port";
180 	    break;
181 	case FC_PREJECT:
182 	    fcioErrorString = "reject at remote N_Port";
183 	    break;
184 	case FC_FREJECT:
185 	    fcioErrorString = "reject at remote Fabric";
186 	    break;
187 	case FC_PBUSY:
188 	    fcioErrorString = "remote N_Port busy";
189 	    break;
190 	case FC_FBUSY:
191 	    fcioErrorString = "remote Fabric busy";
192 	    break;
193 	case FC_ALREADY:
194 	    fcioErrorString = "already logged in";
195 	    break;
196 	case FC_LOGINREQ:
197 	    fcioErrorString = "login required";
198 	    break;
199 	case FC_RESETFAIL:
200 	    fcioErrorString = "reset failed";
201 	    break;
202 	case FC_INVALID_REQUEST:
203 	    fcioErrorString = "request is invalid";
204 	    break;
205 	case FC_OUTOFBOUNDS:
206 	    fcioErrorString = "port number is out of bounds";
207 	    break;
208 	case FC_TRAN_BUSY:
209 	    fcioErrorString = "command transport busy";
210 	    break;
211 	case FC_STATEC_BUSY:
212 	    fcioErrorString = "port driver currently busy";
213 	    break;
214 	case FC_DEVICE_BUSY:
215 	    fcioErrorString = "transport working on this device";
216 	    break;
217 	case FC_DEVICE_NOT_TGT:
218 	    fcioErrorString = "device is not a SCSI target";
219 	    break;
220 	default:
221 	    snprintf(message, MAX_FCIO_MSG_LEN, "Unknown error code 0x%x",
222 		fcio_errno);
223 	    return;
224 	}
225 	snprintf(message, MAX_FCIO_MSG_LEN, "%s", fcioErrorString.c_str());
226 }
227 
228 static void
229 reportSense(struct scsi_extended_sense *sense, const char *routine) {
230 	Trace log("reportSense");
231 	string msg;
232 	if (!sense) {
233 	    log.internalError("NULL sense argument passed.");
234 	    return;
235 	}
236 	if (!routine) {
237 	    log.internalError("NULL routine argument passed.");
238 	    return;
239 	}
240 	log.genericIOError("SCSI FAILURE");
241 	switch (sense->es_key) {
242 	case KEY_NO_SENSE:
243 	    msg = "No sense";
244 	    break;
245 	case KEY_RECOVERABLE_ERROR:
246 	    msg = "Recoverable error";
247 	    break;
248 	case KEY_NOT_READY:
249 	    msg = "Not ready";
250 	    break;
251 	case KEY_MEDIUM_ERROR:
252 	    msg = "Medium error";
253 	    break;
254 	case KEY_HARDWARE_ERROR:
255 	    msg = "Hardware error";
256 	    break;
257 	case KEY_ILLEGAL_REQUEST:
258 	    msg = "Illegal request";
259 	    break;
260 	case KEY_UNIT_ATTENTION:
261 	    msg = "Unit attention";
262 	    break;
263 	case KEY_DATA_PROTECT:
264 	    msg = "Data protect";
265 	    break;
266 	case KEY_BLANK_CHECK:
267 	    msg = "Blank check";
268 	    break;
269 	case KEY_VENDOR_UNIQUE:
270 	    msg = "Vendor Unique";
271 	    break;
272 	case KEY_COPY_ABORTED:
273 	    msg = "Copy aborted";
274 	    break;
275 	case KEY_ABORTED_COMMAND:
276 	    msg = "Aborted command";
277 	    break;
278 	case KEY_EQUAL:
279 	    msg = "Equal";
280 	    break;
281 	case KEY_VOLUME_OVERFLOW:
282 	    msg = "Volume overflow";
283 	    break;
284 	case KEY_MISCOMPARE:
285 	    msg = "Miscompare";
286 	    break;
287 	case KEY_RESERVED:
288 	    msg = "Reserved";
289 	    break;
290 	default:
291 	    msg = "unknown sense key";
292 	}
293 	log.genericIOError("\tSense key: %s", msg.c_str());
294 	log.genericIOError("\tASC  = 0x%x", sense->es_add_code);
295 	log.genericIOError("\tASCQ = 0x%x", sense->es_qual_code);
296 }
297 
298 /*
299  * Issue a SCSI pass thru command.
300  * Returns a scsi status value.
301  */
302 void FCHBAPort::sendSCSIPassThru(struct fcp_scsi_cmd *fscsi,
303 	    HBA_UINT32 *responseSize, HBA_UINT32 *senseSize,
304 	    HBA_UINT8 *scsiStatus) {
305 	Trace log("FCHBAPort::sendSCSIPassThru");
306 	int		    fd;
307 	HBA_STATUS	    ret;
308 	int		    count;
309 	char		    fcioErrorString[MAX_FCIO_MSG_LEN] = "";
310 	hrtime_t	    start;
311 	hrtime_t	    end;
312 	int		    ioctl_errno;
313 	double		    duration;
314 	la_wwn_t	    wwn;
315 
316 	if (fscsi == NULL ||
317 		responseSize == NULL ||
318 		senseSize == NULL ||
319 		scsiStatus == NULL) {
320 	    throw BadArgumentException();
321 	}
322 
323 	memcpy(&wwn, fscsi->scsi_fc_pwwn.raw_wwn, sizeof (la_wwn_t));
324 	start = gethrtime();
325 	fscsi->scsi_fc_port_num	= instanceNumber;
326 
327 	fd = HBA::_open(FCP_DRIVER_PATH, O_RDONLY | O_NDELAY);
328 	count = 0;
329 	ioctl_errno = 0;
330 
331 	if (ioctl(fd, FCP_TGT_SEND_SCSI, fscsi) != 0) {
332 	    /* save off errno */
333 	    ioctl_errno = errno;
334 	    close(fd);
335 	    /*
336 	     * collect SCSI status first regrardless of the value.
337 	     * 0 is a good status so this should be okay
338 	     */
339 	    *scsiStatus = fscsi->scsi_bufstatus & STATUS_MASK;
340 	    transportError(fscsi->scsi_fc_status, fcioErrorString);
341 
342 	    /* Did we get a check condition? */
343 	    if ((fscsi->scsi_bufstatus & STATUS_MASK) == STATUS_CHECK) {
344 		*senseSize = fscsi->scsi_rqlen;
345 		throw CheckConditionException();
346 	    } else if (fscsi->scsi_fc_status == FC_DEVICE_NOT_TGT) {
347 		/*
348 		 * fcp driver returns FC_DEVICE_NOT_TGT when the node is not
349 		 * scsi-capable like remote hba nodes.
350 		 */
351 		throw NotATargetException();
352 	    } else if (fscsi->scsi_fc_status == FC_INVALID_LUN) {
353 		throw InvalidLUNException();
354 	    } else if (ioctl_errno == EBUSY) {
355 		throw BusyException();
356 	    } else if (ioctl_errno == EAGAIN) {
357 		throw TryAgainException();
358 	    } else if (ioctl_errno == ENOTSUP) {
359 		throw NotSupportedException();
360 	    } else if (ioctl_errno == ENOENT) {
361 		throw UnavailableException();
362 	    } else {
363 		throw IOError(this, wwnConversion(wwn.raw_wwn),
364 			fscsi->scsi_lun);
365 	    }
366 	} else {
367 		close(fd);
368 	    /* Just in case, check for a check-condition state */
369 	    if ((fscsi->scsi_bufstatus & STATUS_MASK) == STATUS_CHECK) {
370 		*scsiStatus = fscsi->scsi_bufstatus & STATUS_MASK;
371 		*senseSize = fscsi->scsi_rqlen;
372 		throw CheckConditionException();
373 	    }
374 	}
375 
376 	/* Record the response data */
377 	*scsiStatus = fscsi->scsi_bufstatus & STATUS_MASK;
378 	*responseSize = fscsi->scsi_buflen;
379 	*senseSize = fscsi->scsi_rqlen;
380 
381 	/* Do some quick duration calcuations */
382 	end = gethrtime();
383 	duration = end - start;
384 	duration /= HR_SECOND;
385 	log.debug("Total SCSI IO time for HBA %s "
386 	    "target %016llx was %.4f seconds", getPath().c_str(),
387 	    wwnConversion(wwn.raw_wwn), duration);
388 
389 #ifdef DEBUG
390 	/* Did we have any failure */
391 	if (ret != HBA_STATUS_OK) {
392 	    log.genericIOError(
393 		"Ioctl failed for device \"%s\" target %016llx."
394 		"  Errno: \"%s\"(%d), "
395 		"Transport: \"%s\", SCSI Status: 0x%x"
396 		"responseSize = %d, senseSize = %d",
397 		getPath().c_str(), wwnConversion(fscsi->scsi_fc_pwwn.raw_wwn),
398 		strerror(ioctl_errno), ioctl_errno, fcioErrorString,
399 		*scsiStatus, *responseSize, *senseSize);
400 	    /* We may or may not have sense data */
401 	    reportSense((struct scsi_extended_sense *)fscsi->scsi_rqbufaddr,
402 		ROUTINE);
403 	}
404 #endif
405 
406 }
407 
408 /*
409  * constructs the fcp_scsi_cmd struct for SCSI_Inquiry, SendReadCapacity, or
410  * SendReportLUNs
411  */
412 /*#include <fcio.h>
413 #include <fcp_util.h>*/
414 inline void
415 scsi_cmd_init(struct fcp_scsi_cmd *fscsi, const char *portname, void *reqbuf,
416 	    size_t req_len, void *responseBuffer, size_t resp_len,
417 	    void *senseBuffer, size_t sense_len) {
418 	Trace log("scsi_cmd_init");
419 	fscsi->scsi_fc_rspcode	= 0;
420 	fscsi->scsi_flags	= FCP_SCSI_READ;
421 	fscsi->scsi_timeout	= 10 /* sec */;
422 	fscsi->scsi_cdbbufaddr	= (char *)reqbuf;
423 	fscsi->scsi_cdblen	= (uint32_t) req_len;
424 	fscsi->scsi_bufaddr	= (char *)responseBuffer;
425 	fscsi->scsi_buflen	= (uint32_t) resp_len;
426 	fscsi->scsi_bufresid	= 0;
427 	fscsi->scsi_bufstatus	= 0;
428 	fscsi->scsi_rqbufaddr	= (char *)senseBuffer;
429 	fscsi->scsi_rqlen	= (uint32_t) sense_len;
430 	fscsi->scsi_rqresid	= 0;
431 }
432 
433 
434 FCHBAPort::FCHBAPort(string thePath) : HBAPort() {
435 	Trace log("FCHBAPort::FCHBAPort");
436 	log.debug("Initializing HBA port %s", thePath.c_str());
437 	fcio_t		fcio;
438 	int		size = 200;
439 	fc_hba_npiv_port_list_t	*pathList;
440 	bool		retry = false;
441 	int		bufSize;
442 
443 	try {
444 	    path = lookupControllerPath(thePath);
445 	    sscanf(path.c_str(), "/dev/cfg/c%d", &controllerNumber);
446 	} catch (...) {
447 	    log.debug("Unable to lookup controller path and number for %s",
448 		    thePath.c_str());
449 	    path = "/devices";
450 	    path += thePath;
451 	    path += ":fc";
452 	    controllerNumber = -1;
453 	}
454 
455 	// Fetch the minor number for later use
456 	struct stat sbuf;
457 	if (stat(path.c_str(), &sbuf) == -1) {
458 	    throw IOError("Unable to stat device path: " + path);
459 	}
460 	instanceNumber = minor(sbuf.st_rdev);
461 
462 	// This routine is not index based, so we can discard stateChange
463 	uint64_t tmp;
464 	HBA_PORTATTRIBUTES attrs = getPortAttributes(tmp);
465 	memcpy(&tmp, &attrs.PortWWN, 8);
466 	portWWN = ntohll(tmp);
467 	memcpy(&tmp, &attrs.NodeWWN, 8);
468 	nodeWWN = ntohll(tmp);
469 
470 	// For reference, here's how to dump WWN's through C++ streams.
471 	// cout << "\tPort WWN: " << hex << setfill('0') << setw(16) << portWWN
472 	// << endl;
473 	// cout << "\tNode WWN: " << hex << setfill('0') << setw(16) << nodeWWN
474 	// << endl;
475 
476 	// we should add code here to build NPIVPORT instance
477 	// Get Port's NPIV port list ( include nwwn and pwwn and path)
478 	memset((caddr_t)&fcio, 0, sizeof (fcio));
479 	fcio.fcio_cmd = FCIO_GET_NPIV_PORT_LIST;
480 	fcio.fcio_xfer = FCIO_XFER_READ;
481 	do {
482 		retry = false;
483 		bufSize = MAXPATHLEN * (size - 1) + (int) sizeof (fc_hba_npiv_port_list_t);
484 		pathList = (fc_hba_npiv_port_list_t *) new uchar_t[bufSize];
485 		pathList->numAdapters = size;
486 		fcio.fcio_olen = bufSize;
487 		fcio.fcio_obuf = (char *)pathList;
488 		fp_ioctl(getPath(), FCIO_CMD, &fcio);
489 		if (pathList->numAdapters > size) {
490 			log.debug("Buffer too small for number of NPIV Port.Retry.");
491 			size = pathList->numAdapters;
492 			retry = true;
493 			delete (pathList);
494 		}
495 	} while (retry);
496 	log.debug("Get %d npiv ports", pathList->numAdapters);
497 	// Make instance for each NPIV Port
498 	for ( int i = 0; i < pathList->numAdapters; i++) {
499 		try {
500 			addPort(new FCHBANPIVPort(pathList->hbaPaths[i]));
501 		} catch (...) {
502 			log.debug("Ignoring partial failure");
503 		}
504 	}
505 	delete (pathList);
506 }
507 
508 uint32_t FCHBAPort::deleteNPIVPort(uint64_t vportwwn) {
509 	Trace log("FCHBAPort::deleteNPIVPort");
510 	fcio_t  fcio;
511 	la_wwn_t        lawwn[1];
512 	int ret = 0;
513 
514 	memset(&fcio, 0, sizeof(fcio));
515 	uint64_t en_wwn = htonll(vportwwn);
516 	memcpy(&lawwn[0], &en_wwn, sizeof (en_wwn));
517 
518 	fcio.fcio_cmd = FCIO_DELETE_NPIV_PORT;
519 	fcio.fcio_xfer = FCIO_XFER_WRITE;
520 	fcio.fcio_ilen = sizeof (la_wwn_t) * 2;
521 	fcio.fcio_ibuf = (caddr_t)&lawwn;
522 
523 	fp_ioctl(getPath(), FCIO_CMD, &fcio);
524 
525 	return (ret);
526 }
527 
528 uint32_t FCHBAPort::createNPIVPort(uint64_t vnodewwn, uint64_t vportwwn, uint32_t vindex) {
529 	Trace log("FCHBAPort::createNPIVPort");
530 	fcio_t  fcio;
531 	la_wwn_t        lawwn[2];
532 	uint32_t vportindex = 0;
533 	HBA_NPIVCREATEENTRY	entrybuf;
534 
535 	memset(&fcio, 0, sizeof(fcio));
536 	uint64_t en_wwn = htonll(vnodewwn);
537 	memcpy(&entrybuf.VNodeWWN, &en_wwn, sizeof (en_wwn));
538 	en_wwn = htonll(vportwwn);
539 	memcpy(&entrybuf.VPortWWN, &en_wwn, sizeof (en_wwn));
540 	entrybuf.vindex = vindex;
541 
542 	fcio.fcio_cmd = FCIO_CREATE_NPIV_PORT;
543 	fcio.fcio_xfer = FCIO_XFER_READ;
544 	fcio.fcio_olen = sizeof (uint32_t);
545 	fcio.fcio_obuf = (caddr_t)&vportindex;
546 	fcio.fcio_ilen = sizeof (HBA_NPIVCREATEENTRY);
547 	fcio.fcio_ibuf = (caddr_t)&entrybuf;
548 
549 	fp_ioctl(getPath(), FCIO_CMD, &fcio);
550 
551 	return (vportindex);
552 }
553 
554 HBA_PORTNPIVATTRIBUTES FCHBAPort::getPortNPIVAttributes(uint64_t &stateChange) {
555 	Trace log("FCHBAPort::getPortNPIVAttributes");
556 
557 	HBA_PORTNPIVATTRIBUTES  attributes;
558 	fc_hba_port_npiv_attributes_t   attrs;
559 	fcio_t  fcio;
560 
561 	memset(&fcio, 0, sizeof(fcio));
562 	memset(&attributes, 0, sizeof(attributes));
563 
564 	fcio.fcio_cmd = FCIO_GET_ADAPTER_PORT_NPIV_ATTRIBUTES;
565 	fcio.fcio_olen = sizeof(attrs);
566 	fcio.fcio_xfer = FCIO_XFER_READ;
567 	fcio.fcio_obuf = (caddr_t)&attrs;
568 
569 	fp_ioctl(getPath(), FCIO_CMD, &fcio);
570 
571 	stateChange = attrs.lastChange;
572 	attributes.npivflag = attrs.npivflag;
573 	memcpy(&attributes.NodeWWN, &attrs.NodeWWN, 8);
574 	memcpy(&attributes.PortWWN, &attrs.PortWWN, 8);
575 	attributes.MaxNumberOfNPIVPorts = attrs.MaxNumberOfNPIVPorts;
576 	attributes.NumberOfNPIVPorts = attrs.NumberOfNPIVPorts;
577 
578 	return (attributes);
579 }
580 
581 HBA_PORTATTRIBUTES FCHBAPort::getPortAttributes(uint64_t &stateChange) {
582 	Trace log("FCHBAPort::getPortAttributes");
583 
584 	HBA_PORTATTRIBUTES		attributes;
585 	fcio_t			fcio;
586 	fc_hba_port_attributes_t    attrs;
587 
588 	memset(&fcio, 0, sizeof (fcio));
589 	memset(&attributes, 0, sizeof (attributes));
590 
591 	fcio.fcio_cmd = FCIO_GET_ADAPTER_PORT_ATTRIBUTES;
592 	fcio.fcio_olen = sizeof (attrs);
593 	fcio.fcio_xfer = FCIO_XFER_READ;
594 	fcio.fcio_obuf = (caddr_t)&attrs;
595 
596 	fp_ioctl(getPath(), FCIO_CMD, &fcio);
597 
598 	stateChange = attrs.lastChange;
599 
600 	attributes.PortFcId = attrs.PortFcId;
601 	attributes.PortType = attrs.PortType;
602 	attributes.PortState = attrs.PortState;
603 	attributes.PortSupportedClassofService = attrs.PortSupportedClassofService;
604 	attributes.PortSupportedSpeed = attrs.PortSupportedSpeed;
605 	attributes.PortSpeed = attrs.PortSpeed;
606 	attributes.PortMaxFrameSize = attrs.PortMaxFrameSize;
607 	attributes.NumberofDiscoveredPorts = attrs.NumberofDiscoveredPorts;
608 	memcpy(&attributes.NodeWWN, &attrs.NodeWWN, 8);
609 	memcpy(&attributes.PortWWN, &attrs.PortWWN, 8);
610 	memcpy(&attributes.FabricName, &attrs.FabricName, 8);
611 	memcpy(&attributes.PortSupportedFc4Types, &attrs.PortSupportedFc4Types, 32);
612 	memcpy(&attributes.PortActiveFc4Types, &attrs.PortActiveFc4Types, 32);
613 	memcpy(&attributes.PortSymbolicName, &attrs.PortSymbolicName, 256);
614 
615 	strncpy((char *)attributes.OSDeviceName, getPath().c_str(), 256);
616 	return (attributes);
617 }
618 
619 HBA_PORTATTRIBUTES FCHBAPort::getDiscoveredAttributes(
620 	    HBA_UINT32 discoveredport, uint64_t &stateChange) {
621 	Trace log("FCHBAPort::getDiscoverdAttributes(i)");
622 
623 	HBA_PORTATTRIBUTES		attributes;
624 	fcio_t			fcio;
625 	fc_hba_port_attributes_t    attrs;
626 
627 	memset(&fcio, 0, sizeof (fcio));
628 	memset(&attributes, 0, sizeof (attributes));
629 
630 	fcio.fcio_cmd = FCIO_GET_DISCOVERED_PORT_ATTRIBUTES;
631 	fcio.fcio_olen = sizeof (attrs);
632 	fcio.fcio_xfer = FCIO_XFER_READ;
633 	fcio.fcio_obuf = (caddr_t)&attrs;
634 	fcio.fcio_ilen = sizeof (discoveredport);
635 	fcio.fcio_ibuf = (caddr_t)&discoveredport;
636 
637 	fp_ioctl(getPath(), FCIO_CMD, &fcio);
638 
639 	stateChange = attrs.lastChange;
640 
641 	attributes.PortFcId = attrs.PortFcId;
642 	attributes.PortType = attrs.PortType;
643 	attributes.PortState = attrs.PortState;
644 	attributes.PortSupportedClassofService = attrs.PortSupportedClassofService;
645 	attributes.PortSupportedSpeed = attrs.PortSupportedSpeed;
646 	attributes.PortSpeed = attrs.PortSpeed;
647 	attributes.PortMaxFrameSize = attrs.PortMaxFrameSize;
648 	attributes.NumberofDiscoveredPorts = attrs.NumberofDiscoveredPorts;
649 	memcpy(&attributes.NodeWWN, &attrs.NodeWWN, 8);
650 	memcpy(&attributes.PortWWN, &attrs.PortWWN, 8);
651 	memcpy(&attributes.FabricName, &attrs.FabricName, 8);
652 	memcpy(&attributes.PortSupportedFc4Types, &attrs.PortSupportedFc4Types, 32);
653 	memcpy(&attributes.PortActiveFc4Types, &attrs.PortActiveFc4Types, 32);
654 	memcpy(&attributes.PortSymbolicName, &attrs.PortSymbolicName, 256);
655 
656 
657 	return (attributes);
658 }
659 
660 HBA_PORTATTRIBUTES FCHBAPort::getDiscoveredAttributes(
661 	    uint64_t wwn, uint64_t &stateChange) {
662 	Trace log("FCHBAPort::getDiscoverdAttributes(p)");
663 
664 	HBA_PORTATTRIBUTES attributes;
665 	fcio_t			fcio;
666 	fc_hba_port_attributes_t    attrs;
667 	la_wwn_t	lawwn;
668 
669 	memset(&fcio, 0, sizeof (fcio));
670 	memset(&attributes, 0, sizeof (attributes));
671 
672 	uint64_t en_wwn = htonll(wwn);
673 	memcpy(&lawwn, &en_wwn, sizeof (en_wwn));
674 
675 	fcio.fcio_cmd = FCIO_GET_PORT_ATTRIBUTES;
676 	fcio.fcio_olen = sizeof (attrs);
677 	fcio.fcio_xfer = FCIO_XFER_READ;
678 	fcio.fcio_obuf = (caddr_t)&attrs;
679 	fcio.fcio_ilen = sizeof (wwn);
680 	fcio.fcio_ibuf = (caddr_t)&lawwn;
681 
682 	fp_ioctl(getPath(), FCIO_CMD, &fcio);
683 
684 	stateChange = attrs.lastChange;
685 
686 	attributes.PortFcId = attrs.PortFcId;
687 	attributes.PortType = attrs.PortType;
688 	attributes.PortState = attrs.PortState;
689 	attributes.PortSupportedClassofService = attrs.PortSupportedClassofService;
690 	attributes.PortSupportedSpeed = attrs.PortSupportedSpeed;
691 	attributes.PortSpeed = attrs.PortSpeed;
692 	attributes.PortMaxFrameSize = attrs.PortMaxFrameSize;
693 	attributes.NumberofDiscoveredPorts = attrs.NumberofDiscoveredPorts;
694 	memcpy(&attributes.NodeWWN, &attrs.NodeWWN, 8);
695 	memcpy(&attributes.PortWWN, &attrs.PortWWN, 8);
696 	memcpy(&attributes.FabricName, &attrs.FabricName, 8);
697 	memcpy(&attributes.PortSupportedFc4Types, &attrs.PortSupportedFc4Types, 32);
698 	memcpy(&attributes.PortActiveFc4Types, &attrs.PortActiveFc4Types, 32);
699 	memcpy(&attributes.PortSymbolicName, &attrs.PortSymbolicName, 256);
700 
701 
702 	return (attributes);
703 }
704 
705 
706 void FCHBAPort::getTargetMappings(PHBA_FCPTARGETMAPPINGV2 userMappings) {
707 	Trace log("FCHBAPort::getTargetMappings");
708 	int				i, index;
709 	uint_t			total_entries = 0;
710 
711 	struct fcp_ioctl		fioctl;
712 	fc_hba_target_mappings_t    *mappings;
713 	int				fd;
714 	bool			zeroLength = false;
715 
716 
717 	if (userMappings == NULL) {
718 	    log.userError("Null mapping argument ");
719 	    throw BadArgumentException();
720 	}
721 
722 	/* It's possible they didn't give any space */
723 	if (userMappings->NumberOfEntries == 0) {
724 	    zeroLength = true;
725 	    userMappings->NumberOfEntries = 1;
726 		/* We have to give the driver at least one space */
727 	}
728 
729 	mappings = (fc_hba_target_mappings_t *)new uchar_t[
730 		(sizeof (fc_hba_mapping_entry_t)) *
731 		(userMappings->NumberOfEntries - 1) +
732 		sizeof (fc_hba_target_mappings_t)];
733 	if (mappings == NULL) {
734 	    log.noMemory();
735 	    throw InternalError();
736 	}
737 
738 
739 	fioctl.fp_minor = instanceNumber;
740 	fioctl.listlen = ((uint32_t) (sizeof (fc_hba_mapping_entry_t))) *
741 		(userMappings->NumberOfEntries - 1) +
742 		(uint32_t) sizeof (fc_hba_target_mappings_t);
743 	fioctl.list = (caddr_t)mappings;
744 
745 	fd = HBA::_open(FCP_DRIVER_PATH, O_RDONLY | O_NDELAY);
746 
747 	log.debug("Performing IOCTL to fetch mappings");
748 
749 	if (ioctl(fd, FCP_GET_TARGET_MAPPINGS, &fioctl) != 0) {
750 	    delete (mappings);
751 	    close(fd);
752 	    if (errno == EBUSY) {
753 		throw BusyException();
754 	    } else if (errno == EAGAIN) {
755 		throw TryAgainException();
756 	    } else if (errno == ENOTSUP) {
757 		throw NotSupportedException();
758 	    } else if (errno == ENOENT) {
759 		throw UnavailableException();
760 	    } else {
761 		throw IOError("Unable to fetch target mappings");
762 	    }
763 	}
764 
765 	close(fd);
766 	// Quickly iterate through and copy the data over to the client
767 	for (i = 0; i < userMappings->NumberOfEntries && !zeroLength &&
768 		    i < mappings->numLuns; i++) {
769 	    string raw = mappings->entries[i].targetDriver;
770 
771 
772 	    if (raw.length() <= 0) {
773 		log.internalError("Bad target mapping without path, truncating.");
774 		break;
775 	    }
776 	    /*
777 	     * Ideally, we'd like to ask some standard Solaris interface
778 	     * "What is the prefered minor node for this target?"
779 	     * but no such interface exists today.  So, for now,
780 	     * we just hard-code ":n" for tapes, ":c,raw" for disks,
781 	     * and ":0" for enclosures.
782 	     * Devices with other generic names will be presented through
783 	     * first matching /dev path.
784 	     */
785 	    if ((raw.find("/st@") != raw.npos) ||
786 		(raw.find("/tape@") != raw.npos)) {
787 		raw += ":n";
788 	    } else if ((raw.find("/ssd@") != raw.npos) ||
789 	    	(raw.find("/sd@") != raw.npos) ||
790 	   	(raw.find("/disk@") != raw.npos)) {
791 		raw += ":c,raw";
792 	    } else if ((raw.find("/ses@") != raw.npos) ||
793 	   	(raw.find("/enclosure@") != raw.npos)) {
794 		raw += ":0";
795 	    } else {
796 		log.debug(
797 	    "Unrecognized target driver (%s), using first matching /dev path",
798 		    raw.c_str());
799 	    }
800 	    snprintf(userMappings->entry[i].ScsiId.OSDeviceName,
801 		sizeof (userMappings->entry[i].ScsiId.OSDeviceName),
802 		"/devices%s", raw.c_str());
803 	    userMappings->entry[i].ScsiId.ScsiBusNumber =
804 		    controllerNumber;
805 	    userMappings->entry[i].ScsiId.ScsiTargetNumber =
806 		    mappings->entries[i].targetNumber;
807 	    userMappings->entry[i].ScsiId.ScsiOSLun =
808 		    mappings->entries[i].osLUN;
809 	    userMappings->entry[i].FcpId.FcId =
810 		    mappings->entries[i].d_id;
811 	    memcpy(userMappings->entry[i].FcpId.NodeWWN.wwn,
812 		    mappings->entries[i].NodeWWN.raw_wwn,
813 		    sizeof (la_wwn_t));
814 	    memcpy(userMappings->entry[i].FcpId.PortWWN.wwn,
815 		    mappings->entries[i].PortWWN.raw_wwn,
816 		    sizeof (la_wwn_t));
817 
818 	    userMappings->entry[i].FcpId.FcpLun =
819 		mappings->entries[i].samLUN;
820 
821 	    memcpy(userMappings->entry[i].LUID.buffer,
822 		    mappings->entries[i].guid,
823 		    sizeof (userMappings->entry[i].LUID.buffer));
824 	}
825 
826 	log.debug("Total mappings: %d %08x %08x",
827 	    mappings->numLuns, mappings->entries[i].osLUN, mappings->entries[i].samLUN);
828 
829 	// If everything is good, convert paths to sym-links
830 	if (mappings->numLuns > 0 && !zeroLength) {
831 	    if (userMappings->NumberOfEntries >= mappings->numLuns) {
832 		// User buffer is larger than needed. (All is good)
833 		userMappings->NumberOfEntries = mappings->numLuns;
834 		convertToShortNames(userMappings);
835 	    } else {
836 		// User buffer is non zero, but too small.  Don't bother with links
837 		userMappings->NumberOfEntries = mappings->numLuns;
838 		delete (mappings);
839 		throw MoreDataException();
840 	    }
841 	} else if (mappings->numLuns > 0) {
842 	    // Zero length buffer, but we've got mappings
843 	    userMappings->NumberOfEntries = mappings->numLuns;
844 	    delete (mappings);
845 	    throw MoreDataException();
846 	} else {
847 	    // No mappings, no worries
848 	    userMappings->NumberOfEntries = 0;
849 	    delete (mappings);
850 	    return;
851 	}
852 	delete (mappings);
853 }
854 
855 void FCHBAPort::getRNIDMgmtInfo(PHBA_MGMTINFO info) {
856 	Trace log("FCHBAPort::getRNIDMgmtInfo");
857 	HBA_STATUS		status = HBA_STATUS_OK;
858 	fc_rnid_t		rnid;
859 	fcio_t			fcio;
860 
861 
862 	if (info == NULL) {
863 	    log.userError("NULL port management info");
864 	    throw BadArgumentException();
865 	}
866 
867 	// Get the RNID information from the first port
868 	memset(&rnid, 0, sizeof (fc_rnid_t));
869 	memset((caddr_t)&fcio, 0, sizeof (fcio));
870 
871 	fcio.fcio_cmd =	FCIO_GET_NODE_ID;
872 	fcio.fcio_olen = sizeof (fc_rnid_t);
873 	fcio.fcio_xfer = FCIO_XFER_READ;
874 	fcio.fcio_obuf = (caddr_t)&rnid;
875 	fp_ioctl(getPath(), FCIO_CMD, &fcio);
876 
877 	// Copy out the struct members of rnid into PHBA_MGMTINFO struct
878 	memcpy(&info->wwn, &(rnid.global_id), sizeof (info->wwn));
879 	memcpy(&info->unittype, &(rnid.unit_type), sizeof (info->unittype));
880 	memcpy(&info->PortId, &(rnid.port_id), sizeof (info->PortId));
881 	memcpy(&info->NumberOfAttachedNodes, &(rnid.num_attached),
882 		sizeof (info->NumberOfAttachedNodes));
883 	memcpy(&info->IPVersion, &(rnid.ip_version), sizeof (info->IPVersion));
884 	memcpy(&info->UDPPort, &(rnid.udp_port), sizeof (info->UDPPort));
885 	memcpy(&info->IPAddress, &(rnid.ip_addr), sizeof (info->IPAddress));
886 	memcpy(&info->TopologyDiscoveryFlags, &(rnid.topo_flags),
887 		sizeof (info->TopologyDiscoveryFlags));
888 }
889 
890 void FCHBAPort::sendCTPassThru(void *requestBuffer, HBA_UINT32 requestSize,
891 	    void *responseBuffer, HBA_UINT32 *responseSize) {
892 	Trace log("FCHBAPort::sendCTPassThru");
893 	fcio_t			fcio;
894 	struct stat		sbuf;
895 	minor_t			minor_node;
896 	hrtime_t		start, end;
897 	double			duration;
898 
899 	// Validate the arguments
900 	if (requestBuffer == NULL) {
901 	    log.userError("NULL request buffer");
902 	    throw BadArgumentException();
903 	}
904 	if (responseBuffer == NULL) {
905 	    log.userError("NULL response buffer");
906 	    throw BadArgumentException();
907 	}
908 
909 	minor_node = instanceNumber;
910 
911 	// construct fcio struct
912 	memset(&fcio, 0, sizeof (fcio_t));
913 	fcio.fcio_cmd	= FCSMIO_CT_CMD;
914 	fcio.fcio_xfer	= FCIO_XFER_RW;
915 
916 	fcio.fcio_ilen	= requestSize;
917 	fcio.fcio_ibuf	= (char *)requestBuffer;
918 	fcio.fcio_olen	= *responseSize;
919 	fcio.fcio_obuf	= (char *)responseBuffer;
920 
921 	fcio.fcio_alen	= sizeof (minor_t);
922 	fcio.fcio_abuf	= (char *)&minor_node;
923 
924 
925 	start = gethrtime();
926 	fcsm_ioctl(FCSMIO_CMD, &fcio);
927 
928 	// Do some calculations on the duration of the ioctl.
929 	end = gethrtime();
930 	duration = end - start;
931 	duration /= HR_SECOND;
932 	log.debug(
933 	    "Total CTPASS ioctl call for HBA %s was %.4f seconds",
934 	    getPath().c_str(), duration);
935 }
936 
937 void FCHBAPort::sendRLS(uint64_t destWWN,
938 	    void		*pRspBuffer,
939 	    HBA_UINT32		*pRspBufferSize) {
940 	Trace log("FCHBAPort::sendRLS");
941 
942 	fcio_t		fcio;
943 	fc_portid_t		rls_req;
944 
945 
946 	// Validate the arguments
947 	if (pRspBuffer == NULL ||
948 		pRspBufferSize == NULL) {
949 	    log.userError("NULL hba");
950 	    throw BadArgumentException();
951 	}
952 
953 	// check to see if we are sending RLS to the HBA
954 	HBA_PORTATTRIBUTES attrs;
955 	uint64_t tmp;
956 	if (getPortWWN() == destWWN) {
957 	    attrs = getPortAttributes(tmp);
958 	} else {
959 	    attrs = getDiscoveredAttributes(destWWN, tmp);
960 	}
961 
962 	memcpy(&rls_req, &attrs.PortFcId,
963 	    sizeof (attrs.PortFcId));
964 
965 	memset((caddr_t)&fcio, 0, sizeof (fcio));
966 	fcio.fcio_cmd = FCIO_LINK_STATUS;
967 	fcio.fcio_ibuf = (caddr_t)&rls_req;
968 	fcio.fcio_ilen = sizeof (rls_req);
969 	fcio.fcio_xfer = FCIO_XFER_RW;
970 	fcio.fcio_flags = 0;
971 	fcio.fcio_cmd_flags = FCIO_CFLAGS_RLS_DEST_NPORT;
972 	fcio.fcio_obuf = (char *)new uchar_t[*pRspBufferSize];
973 	fcio.fcio_olen = *pRspBufferSize;
974 
975 	if (fcio.fcio_obuf == NULL) {
976 	    log.noMemory();
977 	    throw InternalError();
978 	}
979 
980 	fp_ioctl(getPath(), FCIO_CMD, &fcio);
981 	memcpy(pRspBuffer, fcio.fcio_obuf, *pRspBufferSize);
982 	if (fcio.fcio_obuf != NULL) {
983 	    delete(fcio.fcio_obuf);
984 	}
985 }
986 
987 void FCHBAPort::sendReportLUNs(uint64_t wwn,
988 	    void *responseBuffer, HBA_UINT32 *responseSize,
989 	    HBA_UINT8 *scsiStatus,
990 	    void *senseBuffer, HBA_UINT32 *senseSize) {
991 	Trace log("FCHBAPort::sendReportLUNs");
992 	struct	fcp_scsi_cmd	    fscsi;
993 	union	scsi_cdb	    scsi_rl_req;
994 	uint64_t		    targetWwn = htonll(wwn);
995 
996 	// Validate the arguments
997 	if (responseBuffer == NULL ||
998 		senseBuffer == NULL ||
999 		responseSize == NULL ||
1000 		senseSize == NULL) {
1001 	    throw BadArgumentException();
1002 	}
1003 
1004 	memset(&fscsi, 0, sizeof (fscsi));
1005 	memset(&scsi_rl_req, 0, sizeof (scsi_rl_req));
1006 	memcpy(fscsi.scsi_fc_pwwn.raw_wwn, &targetWwn, sizeof (la_wwn_t));
1007 
1008 	scsi_cmd_init(&fscsi, getPath().c_str(), &scsi_rl_req,
1009 		    sizeof (scsi_rl_req), responseBuffer, *responseSize,
1010 		    senseBuffer, *senseSize);
1011 
1012 	fscsi.scsi_lun = 0;
1013 	scsi_rl_req.scc_cmd = SCMD_REPORT_LUNS;
1014 	FORMG5COUNT(&scsi_rl_req, *responseSize);
1015 	sendSCSIPassThru(&fscsi, responseSize, senseSize, scsiStatus);
1016 }
1017 
1018 /*
1019  * arguments:
1020  *	wwn - remote target WWN where the SCSI Inquiry shall be sent
1021  *	fcLun - the SCSI LUN to which the SCSI Inquiry shall be sent
1022  *	cdb1 - the second byte of the CDB for the SCSI Inquiry
1023  *	cdb2 - the third byte of teh CDB for the SCSI Inquiry
1024  *	responseBuffer - shall be a pointer to a buffer to receive the SCSI
1025  *		Inquiry command response
1026  *	responseSize - a pointer to the size of the buffer to receive
1027  *		the SCSI Inquiry.
1028  *	scsiStatus - a pointer to a buffer to receive SCSI status
1029  *	senseBuffer - pointer to a buffer to receive SCSI sense data
1030  *	seneseSize - pointer to the size of the buffer to receive SCSI sense
1031  *		data
1032  */
1033 void FCHBAPort::sendScsiInquiry(uint64_t wwn, HBA_UINT64 fcLun,
1034 	    HBA_UINT8 cdb1, HBA_UINT8 cdb2, void *responseBuffer,
1035 	    HBA_UINT32 *responseSize, HBA_UINT8 *scsiStatus, void *senseBuffer,
1036 	    HBA_UINT32 *senseSize) {
1037 	Trace log("FCHBAPort::sendScsiInquiry");
1038 
1039 	struct	fcp_scsi_cmd	    fscsi;
1040 	union	scsi_cdb	    scsi_inq_req;
1041 	uint64_t		    targetWwn = htonll(wwn);
1042 
1043 	// Validate the arguments
1044 	if (responseBuffer == NULL ||
1045 		senseBuffer == NULL ||
1046 		responseSize == NULL ||
1047 		senseSize == NULL) {
1048 	    throw BadArgumentException();
1049 	}
1050 
1051 	memset(&fscsi, 0, sizeof (fscsi));
1052 	memset(&scsi_inq_req, 0, sizeof (scsi_inq_req));
1053 	memcpy(fscsi.scsi_fc_pwwn.raw_wwn, &targetWwn, sizeof (la_wwn_t));
1054 
1055 
1056 	scsi_cmd_init(&fscsi, getPath().c_str(), &scsi_inq_req,
1057 	    sizeof (scsi_inq_req), responseBuffer, *responseSize,
1058 	    senseBuffer, *senseSize);
1059 	fscsi.scsi_lun = fcLun;
1060 
1061 	scsi_inq_req.scc_cmd = SCMD_INQUIRY;
1062 	scsi_inq_req.g0_addr1 = cdb2;
1063 	scsi_inq_req.g0_addr2 = cdb1;
1064 	scsi_inq_req.g0_count0 = *responseSize;
1065 
1066 
1067 	sendSCSIPassThru(&fscsi, responseSize, senseSize, scsiStatus);
1068 }
1069 
1070 
1071 void FCHBAPort::sendReadCapacity(uint64_t pwwn,
1072 		HBA_UINT64 fcLun, void *responseBuffer,
1073 		HBA_UINT32 *responseSize, HBA_UINT8 *scsiStatus,
1074 		void *senseBuffer, HBA_UINT32 *senseSize) {
1075 	Trace log("FCHBAPort::sendReadCapacity");
1076 
1077 	struct fcp_scsi_cmd	    fscsi;
1078 	union scsi_cdb	    scsi_rc_req;
1079 	uint64_t		    targetWwn = htonll(pwwn);
1080 
1081 	// Validate the arguments
1082 	if (responseBuffer == NULL ||
1083 		senseBuffer == NULL ||
1084 		responseSize == NULL ||
1085 		senseSize == NULL ||
1086 		scsiStatus == NULL) {
1087 	    throw BadArgumentException();
1088 	}
1089 
1090 	memset(&fscsi, 0, sizeof (fscsi));
1091 	memset(&scsi_rc_req, 0, sizeof (scsi_rc_req));
1092 
1093 	scsi_cmd_init(&fscsi, getPath().c_str(), &scsi_rc_req,
1094 	    sizeof (scsi_rc_req), responseBuffer, *responseSize,
1095 	    senseBuffer, *senseSize);
1096 
1097 	memcpy(fscsi.scsi_fc_pwwn.raw_wwn, &targetWwn, sizeof (la_wwn_t));
1098 	fscsi.scsi_lun = fcLun;
1099 
1100 	scsi_rc_req.scc_cmd = SCMD_READ_CAPACITY;
1101 	scsi_rc_req.g1_reladdr = 0;
1102 
1103 	scsi_rc_req.g1_addr3 = 0;
1104 	scsi_rc_req.g1_count0	= 0;
1105 
1106 	sendSCSIPassThru(&fscsi, responseSize, senseSize, scsiStatus);
1107 }
1108 
1109 void FCHBAPort::sendRNID(uint64_t destwwn, HBA_UINT32 destfcid,
1110 			    HBA_UINT32 nodeIdDataFormat, void *pRspBuffer,
1111 			    HBA_UINT32 *RspBufferSize) {
1112 	Trace log("FCHBAPort::sendRNID");
1113 	int 			localportfound, remoteportfound, send;
1114 	fcio_t			fcio;
1115 
1116 	// Validate the arguments
1117 	if (pRspBuffer == NULL ||
1118 		RspBufferSize == NULL) {
1119 	    throw BadArgumentException();
1120 	}
1121 	// NodeIdDataFormat must be within the range of 0x00 and 0xff
1122 	if (nodeIdDataFormat > 0xff) {
1123 	    log.userError(
1124 		    "NodeIdDataFormat must be within the range of 0x00 "
1125 		    "and 0xFF");
1126 	    throw BadArgumentException();
1127 	}
1128 
1129 
1130 	remoteportfound = 0;
1131 	if (destfcid != 0) {
1132 	    try {
1133 		uint64_t tmp;
1134 		HBA_PORTATTRIBUTES attrs = getDiscoveredAttributes(destwwn,
1135 			tmp);
1136 		if (attrs.PortFcId == destfcid) {
1137 		    send = 1;
1138 		    remoteportfound = 1;
1139 		} else {
1140 		    send = 0;
1141 		    remoteportfound = 1;
1142 		}
1143 	    } catch (HBAException &e) {
1144 		/*
1145 		 * Send RNID if destination port not
1146 		 * present in the discovered ports table
1147 		 */
1148 	    }
1149 	    if (remoteportfound == 0) {
1150 		send = 1;
1151 	    }
1152 	} else {
1153 	    send = 1;
1154 	}
1155 
1156 	if (!send) {
1157 	    // Can we log something so we can figure out why?
1158 	    throw BadArgumentException();
1159 	}
1160 
1161 	memset((caddr_t)&fcio, 0, sizeof (fcio));
1162 	uint64_t netdestwwn = htonll(destwwn);
1163 	fcio.fcio_cmd = FCIO_SEND_NODE_ID;
1164 	fcio.fcio_xfer = FCIO_XFER_READ;
1165 	fcio.fcio_cmd_flags = nodeIdDataFormat;
1166 	fcio.fcio_ilen = sizeof (la_wwn_t);
1167 	fcio.fcio_ibuf = (caddr_t)&netdestwwn;
1168 	fcio.fcio_olen  = *RspBufferSize;
1169 	fcio.fcio_obuf  = (char *)new uchar_t[*RspBufferSize];
1170 
1171 
1172 	if (fcio.fcio_obuf == NULL) {
1173 	    log.noMemory();
1174 	    throw InternalError();
1175 	}
1176 
1177 	fp_ioctl(getPath(), FCIO_CMD, &fcio);
1178 
1179 	memcpy(pRspBuffer, fcio.fcio_obuf, *RspBufferSize);
1180 
1181 	if (fcio.fcio_obuf != NULL) {
1182 	    delete(fcio.fcio_obuf);
1183 	}
1184 }
1185 
1186 void FCHBAPort::setRNID(HBA_MGMTINFO info) {
1187 	Trace log("FCHBAPort::setRNID");
1188 	fc_rnid_t		rnid;
1189 	fcio_t			fcio;
1190 
1191 	memset(&rnid, 0, sizeof (fc_rnid_t));
1192 	memset((caddr_t)&fcio, 0, sizeof (fcio));
1193 
1194 
1195 	fcio.fcio_cmd = FCIO_SET_NODE_ID;
1196 	fcio.fcio_ilen = sizeof (fc_rnid_t);
1197 	fcio.fcio_xfer = FCIO_XFER_WRITE;
1198 	fcio.fcio_ibuf = (caddr_t)&rnid;
1199 
1200 
1201 	// Copy the HBA_MGMTINFO into fc_rnid_t struct
1202 	memcpy(&(rnid.unit_type), &(info.unittype), sizeof (rnid.unit_type));
1203 	memcpy(&(rnid.port_id), &(info.PortId), sizeof (rnid.port_id));
1204 	memcpy(&(rnid.global_id), &(info.wwn), sizeof (info.wwn));
1205 	memcpy(&(rnid.num_attached), &(info.NumberOfAttachedNodes),
1206 		sizeof (rnid.num_attached));
1207 	memcpy(&(rnid.ip_version), &(info.IPVersion), sizeof (rnid.ip_version));
1208 	memcpy(&(rnid.udp_port), &(info.UDPPort), sizeof (rnid.udp_port));
1209 	memcpy(&(rnid.ip_addr), &info.IPAddress, sizeof (rnid.ip_addr));
1210 	memcpy(&(rnid.topo_flags), &(info.TopologyDiscoveryFlags),
1211 		sizeof (rnid.topo_flags));
1212 
1213 	fp_ioctl(getPath(), FCIO_CMD, &fcio, O_NDELAY | O_RDONLY | O_EXCL);
1214 }
1215 
1216 void FCHBAPort::fp_ioctl(string path, int cmd, fcio_t *fcio, int openflag) {
1217 	Trace log("FCHBAPort::fp_ioctl with openflag");
1218 	char fcioErrorString[MAX_FCIO_MSG_LEN] = "";
1219 	int fd = HBA::_open(path, openflag);
1220 	try {
1221 	    int times = 0;
1222 	    HBA::_ioctl(fd, cmd, (uchar_t *)fcio);
1223 	    while (fcio->fcio_errno == FC_STATEC_BUSY) {
1224 		sleep(1);
1225 		HBA::_ioctl(fd, cmd, (uchar_t *)fcio);
1226 		if (times++ > 10) {
1227 			break;
1228 		}
1229 	    }
1230 	    close(fd);
1231 	    if (fcio->fcio_errno) {
1232 		throw IOError("IOCTL transport failure");
1233 	    }
1234 	} catch (...) {
1235 	    close(fd);
1236 	    transportError(fcio->fcio_errno, fcioErrorString);
1237 	    log.genericIOError("ioctl (0x%x) failed. Transport: \"%s\"", cmd,
1238 		    fcioErrorString);
1239 	    switch (fcio->fcio_errno) {
1240 	    case FC_BADWWN:
1241 		throw IllegalWWNException();
1242 	    case FC_BADPORT:
1243 		throw IllegalWWNException();
1244 	    case FC_OUTOFBOUNDS:
1245 		throw IllegalIndexException();
1246 	    case FC_PBUSY:
1247 	    case FC_FBUSY:
1248 	    case FC_TRAN_BUSY:
1249 	    case FC_STATEC_BUSY:
1250 	    case FC_DEVICE_BUSY:
1251 		throw BusyException();
1252 	    case FC_SUCCESS:
1253 	    default:
1254 		throw;
1255 	    }
1256 	}
1257 }
1258 
1259 void FCHBAPort::fp_ioctl(string path, int cmd, fcio_t *fcio) {
1260 	Trace log("FCHBAPort::fp_ioctl");
1261 	fp_ioctl(path, cmd, fcio, O_NDELAY | O_RDONLY);
1262 }
1263 
1264 void FCHBAPort::fcsm_ioctl(int cmd, fcio_t *fcio) {
1265 	// We use the same error handling as fp, so just re-use
1266 	fp_ioctl(FCSM_DRIVER_PATH, cmd, fcio);
1267 }
1268