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 }