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  * Copyright 2012 Garrett D'Amore <garrett@damore.org>.  All rights reserved.
  27  */
  28 /*
  29  * Fibre channel Transport Library (fctl)
  30  *
  31  * Function naming conventions:
  32  *              Functions called from ULPs begin with fc_ulp_
  33  *              Functions called from FCAs begin with fc_fca_
  34  *              Internal functions begin with fctl_
  35  *
  36  * Fibre channel packet layout:
  37  *        +---------------------+<--------+
  38  *        |                     |         |
  39  *        | ULP Packet private  |         |
  40  *        |                     |         |
  41  *        +---------------------+         |
  42  *        |                     |---------+
  43  *        |  struct  fc_packet  |---------+
  44  *        |                     |         |
  45  *        +---------------------+<--------+
  46  *        |                     |
  47  *        | FCA Packet private  |
  48  *        |                     |
  49  *        +---------------------+
  50  *
  51  * So you  loved  the  ascii  art ?  It's  strongly  desirable  to  cache
  52  * allocate the entire packet in one common  place.  So we define a set a
  53  * of rules.  In a  contiguous  block of memory,  the top  portion of the
  54  * block points to ulp packet  private  area, next follows the  fc_packet
  55  * structure used  extensively by all the consumers and what follows this
  56  * is the FCA packet private.  Note that given a packet  structure, it is
  57  * possible  to get to the  ULP  and  FCA  Packet  private  fields  using
  58  * ulp_private and fca_private fields (which hold pointers) respectively.
  59  *
  60  * It should be noted with a grain of salt that ULP Packet  private  size
  61  * varies  between two different  ULP types, So this poses a challenge to
  62  * compute the correct  size of the whole block on a per port basis.  The
  63  * transport  layer  doesn't have a problem in dealing with  FCA   packet
  64  * private  sizes as it is the sole  manager of ports  underneath.  Since
  65  * it's not a good idea to cache allocate  different  sizes of memory for
  66  * different ULPs and have the ability to choose from one of these caches
  67  * based on ULP type during every packet  allocation,  the transport some
  68  * what  wisely (?)  hands off this job of cache  allocation  to the ULPs
  69  * themselves.
  70  *
  71  * That means FCAs need to make their  packet  private size  known to the
  72  * transport   to  pass  it  up  to  the   ULPs.  This  is  done   during
  73  * fc_fca_attach().  And the transport passes this size up to ULPs during
  74  * fc_ulp_port_attach() of each ULP.
  75  *
  76  * This  leaves  us with  another  possible  question;  How  are  packets
  77  * allocated for ELS's started by the transport  itself ?  Well, the port
  78  * driver  during  attach  time, cache  allocates  on a per port basis to
  79  * handle ELSs too.
  80  */
  81 
  82 #include <sys/note.h>
  83 #include <sys/types.h>
  84 #include <sys/varargs.h>
  85 #include <sys/param.h>
  86 #include <sys/errno.h>
  87 #include <sys/uio.h>
  88 #include <sys/buf.h>
  89 #include <sys/modctl.h>
  90 #include <sys/open.h>
  91 #include <sys/kmem.h>
  92 #include <sys/poll.h>
  93 #include <sys/conf.h>
  94 #include <sys/cmn_err.h>
  95 #include <sys/stat.h>
  96 #include <sys/ddi.h>
  97 #include <sys/sunddi.h>
  98 #include <sys/promif.h>
  99 #include <sys/byteorder.h>
 100 #include <sys/fibre-channel/fc.h>
 101 #include <sys/fibre-channel/impl/fc_ulpif.h>
 102 #include <sys/fibre-channel/impl/fc_fcaif.h>
 103 #include <sys/fibre-channel/impl/fctl_private.h>
 104 #include <sys/fibre-channel/impl/fc_portif.h>
 105 
 106 /* These are referenced by fp.c!  */
 107 int did_table_size = D_ID_HASH_TABLE_SIZE;
 108 int pwwn_table_size = PWWN_HASH_TABLE_SIZE;
 109 
 110 static fc_ulp_module_t  *fctl_ulp_modules;
 111 static fc_fca_port_t    *fctl_fca_portlist;
 112 static fc_ulp_list_t    *fctl_ulp_list;
 113 
 114 static char fctl_greeting[] =
 115         "fctl: %s ULP same type (0x%x) as existing module.\n";
 116 
 117 static char *fctl_undefined = "Undefined";
 118 
 119 /*
 120  * This lock protects the fc_ulp_module_t linked list (i.e. mod_next field)
 121  */
 122 
 123 static krwlock_t fctl_ulp_lock;
 124 
 125 /*
 126  * The fctl_mod_ports_lock protects the mod_ports element in the
 127  * fc_ulp_ports_t structure
 128  */
 129 
 130 static krwlock_t fctl_mod_ports_lock;
 131 
 132 /*
 133  * fctl_port_lock protects the linked list of local port structures
 134  * (fctl_fca_portlist).  When walking the list, this lock must be obtained
 135  * prior to any local port locks.
 136  */
 137 
 138 static kmutex_t fctl_port_lock;
 139 static kmutex_t fctl_ulp_list_mutex;
 140 
 141 static fctl_nwwn_list_t         *fctl_nwwn_hash_table;
 142 static kmutex_t                 fctl_nwwn_hash_mutex;
 143 int fctl_nwwn_table_size = NWWN_HASH_TABLE_SIZE;
 144 
 145 #define FCTL_VERSION            "20090729-1.70"
 146 #define FCTL_NAME_VERSION       "SunFC Transport v" FCTL_VERSION
 147 
 148 char *fctl_version = FCTL_NAME_VERSION;
 149 
 150 extern struct mod_ops mod_miscops;
 151 
 152 static struct modlmisc modlmisc = {
 153         &mod_miscops,                       /* type of module */
 154         FCTL_NAME_VERSION               /* Module name */
 155 };
 156 
 157 static struct modlinkage modlinkage = {
 158         MODREV_1, (void *)&modlmisc, NULL
 159 };
 160 
 161 static struct bus_ops fctl_fca_busops = {
 162         BUSO_REV,
 163         nullbusmap,                     /* bus_map */
 164         NULL,                           /* bus_get_intrspec */
 165         NULL,                           /* bus_add_intrspec */
 166         NULL,                           /* bus_remove_intrspec */
 167         i_ddi_map_fault,                /* bus_map_fault */
 168         NULL,                           /* bus_dma_map */
 169         ddi_dma_allochdl,               /* bus_dma_allochdl */
 170         ddi_dma_freehdl,                /* bus_dma_freehdl */
 171         ddi_dma_bindhdl,                /* bus_dma_bindhdl */
 172         ddi_dma_unbindhdl,              /* bus_unbindhdl */
 173         ddi_dma_flush,                  /* bus_dma_flush */
 174         ddi_dma_win,                    /* bus_dma_win */
 175         ddi_dma_mctl,                   /* bus_dma_ctl */
 176         fctl_fca_bus_ctl,               /* bus_ctl */
 177         ddi_bus_prop_op,                /* bus_prop_op */
 178         NULL,                           /* bus_get_eventcookie */
 179         NULL,                           /* bus_add_eventcall */
 180         NULL,                           /* bus_remove_event */
 181         NULL,                           /* bus_post_event */
 182         NULL,                           /* bus_intr_ctl */
 183         NULL,                           /* bus_config */
 184         NULL,                           /* bus_unconfig */
 185         NULL,                           /* bus_fm_init */
 186         NULL,                           /* bus_fm_fini */
 187         NULL,                           /* bus_fm_access_enter */
 188         NULL,                           /* bus_fm_access_exit */
 189         NULL,                           /* bus_power */
 190         NULL
 191 };
 192 
 193 struct kmem_cache *fctl_job_cache;
 194 
 195 static fc_errmap_t fc_errlist [] = {
 196         { FC_FAILURE,           "Operation failed"                      },
 197         { FC_SUCCESS,           "Operation success"                     },
 198         { FC_CAP_ERROR,         "Capability error"                      },
 199         { FC_CAP_FOUND,         "Capability found"                      },
 200         { FC_CAP_SETTABLE,      "Capability settable"                   },
 201         { FC_UNBOUND,           "Port not bound"                        },
 202         { FC_NOMEM,             "No memory"                             },
 203         { FC_BADPACKET,         "Bad packet"                            },
 204         { FC_OFFLINE,           "Port offline"                          },
 205         { FC_OLDPORT,           "Old Port"                              },
 206         { FC_NO_MAP,            "No map available"                      },
 207         { FC_TRANSPORT_ERROR,   "Transport error"                       },
 208         { FC_ELS_FREJECT,       "ELS Frejected"                         },
 209         { FC_ELS_PREJECT,       "ELS PRejected"                         },
 210         { FC_ELS_BAD,           "Bad ELS request"                       },
 211         { FC_ELS_MALFORMED,     "Malformed ELS request"                 },
 212         { FC_TOOMANY,           "Too many commands"                     },
 213         { FC_UB_BADTOKEN,       "Bad Unsolicited buffer token"          },
 214         { FC_UB_ERROR,          "Unsolicited buffer error"              },
 215         { FC_UB_BUSY,           "Unsolicited buffer busy"               },
 216         { FC_BADULP,            "Bad ULP"                               },
 217         { FC_BADTYPE,           "Bad Type"                              },
 218         { FC_UNCLAIMED,         "Not Claimed"                           },
 219         { FC_ULP_SAMEMODULE,    "Same ULP Module"                       },
 220         { FC_ULP_SAMETYPE,      "Same ULP Type"                         },
 221         { FC_ABORTED,           "Command Aborted"                       },
 222         { FC_ABORT_FAILED,      "Abort Failed"                          },
 223         { FC_BADEXCHANGE,       "Bad Exchange"                          },
 224         { FC_BADWWN,            "Bad World Wide Name"                   },
 225         { FC_BADDEV,            "Bad Device"                            },
 226         { FC_BADCMD,            "Bad Command"                           },
 227         { FC_BADOBJECT,         "Bad Object"                            },
 228         { FC_BADPORT,           "Bad Port"                              },
 229         { FC_NOTTHISPORT,       "Not on this Port"                      },
 230         { FC_PREJECT,           "Operation Prejected"                   },
 231         { FC_FREJECT,           "Operation Frejected"                   },
 232         { FC_PBUSY,             "Operation Pbusyed"                     },
 233         { FC_FBUSY,             "Operation Fbusyed"                     },
 234         { FC_ALREADY,           "Already done"                          },
 235         { FC_LOGINREQ,          "PLOGI Required"                        },
 236         { FC_RESETFAIL,         "Reset operation failed"                },
 237         { FC_INVALID_REQUEST,   "Invalid Request"                       },
 238         { FC_OUTOFBOUNDS,       "Out of Bounds"                         },
 239         { FC_TRAN_BUSY,         "Command transport Busy"                },
 240         { FC_STATEC_BUSY,       "State change Busy"                     },
 241         { FC_DEVICE_BUSY,       "Port driver is working on this device" }
 242 };
 243 
 244 fc_pkt_reason_t remote_stop_reasons [] = {
 245         { FC_REASON_ABTS,       "Abort Sequence"        },
 246         { FC_REASON_ABTX,       "Abort Exchange"        },
 247         { FC_REASON_INVALID,    NULL                    }
 248 };
 249 
 250 fc_pkt_reason_t general_reasons [] = {
 251         { FC_REASON_HW_ERROR,           "Hardware Error"                },
 252         { FC_REASON_SEQ_TIMEOUT,        "Sequence Timeout"              },
 253         { FC_REASON_ABORTED,            "Aborted"                       },
 254         { FC_REASON_ABORT_FAILED,       "Abort Failed"                  },
 255         { FC_REASON_NO_CONNECTION,      "No Connection"                 },
 256         { FC_REASON_XCHG_DROPPED,       "Exchange Dropped"              },
 257         { FC_REASON_ILLEGAL_FRAME,      "Illegal Frame"                 },
 258         { FC_REASON_ILLEGAL_LENGTH,     "Illegal Length"                },
 259         { FC_REASON_UNSUPPORTED,        "Unsuported"                    },
 260         { FC_REASON_RX_BUF_TIMEOUT,     "Receive Buffer Timeout"        },
 261         { FC_REASON_FCAL_OPN_FAIL,      "FC AL Open Failed"             },
 262         { FC_REASON_OVERRUN,            "Over run"                      },
 263         { FC_REASON_QFULL,              "Queue Full"                    },
 264         { FC_REASON_ILLEGAL_REQ,        "Illegal Request",              },
 265         { FC_REASON_PKT_BUSY,           "Busy"                          },
 266         { FC_REASON_OFFLINE,            "Offline"                       },
 267         { FC_REASON_BAD_XID,            "Bad Exchange Id"               },
 268         { FC_REASON_XCHG_BSY,           "Exchange Busy"                 },
 269         { FC_REASON_NOMEM,              "No Memory"                     },
 270         { FC_REASON_BAD_SID,            "Bad S_ID"                      },
 271         { FC_REASON_NO_SEQ_INIT,        "No Sequence Initiative"        },
 272         { FC_REASON_DIAG_BUSY,          "Diagnostic Busy"               },
 273         { FC_REASON_DMA_ERROR,          "DMA Error"                     },
 274         { FC_REASON_CRC_ERROR,          "CRC Error"                     },
 275         { FC_REASON_ABORT_TIMEOUT,      "Abort Timeout"                 },
 276         { FC_REASON_FCA_UNIQUE,         "FCA Unique"                    },
 277         { FC_REASON_INVALID,            NULL                            }
 278 };
 279 
 280 fc_pkt_reason_t rjt_reasons [] = {
 281         { FC_REASON_INVALID_D_ID,       "Invalid D_ID"                  },
 282         { FC_REASON_INVALID_S_ID,       "Invalid S_ID"                  },
 283         { FC_REASON_TEMP_UNAVAILABLE,   "Temporarily Unavailable"       },
 284         { FC_REASON_PERM_UNAVAILABLE,   "Permamnently Unavailable"      },
 285         { FC_REASON_CLASS_NOT_SUPP,     "Class Not Supported",          },
 286         { FC_REASON_DELIMTER_USAGE_ERROR,
 287             "Delimeter Usage Error"             },
 288         { FC_REASON_TYPE_NOT_SUPP,      "Type Not Supported"            },
 289         { FC_REASON_INVALID_LINK_CTRL,  "Invalid Link Control"          },
 290         { FC_REASON_INVALID_R_CTL,      "Invalid R_CTL"                 },
 291         { FC_REASON_INVALID_F_CTL,      "Invalid F_CTL"                 },
 292         { FC_REASON_INVALID_OX_ID,      "Invalid OX_ID"                 },
 293         { FC_REASON_INVALID_RX_ID,      "Invalid RX_ID"                 },
 294         { FC_REASON_INVALID_SEQ_ID,     "Invalid Sequence ID"           },
 295         { FC_REASON_INVALID_DF_CTL,     "Invalid DF_CTL"                },
 296         { FC_REASON_INVALID_SEQ_CNT,    "Invalid Sequence count"        },
 297         { FC_REASON_INVALID_PARAM,      "Invalid Parameter"             },
 298         { FC_REASON_EXCH_ERROR,         "Exchange Error"                },
 299         { FC_REASON_PROTOCOL_ERROR,     "Protocol Error"                },
 300         { FC_REASON_INCORRECT_LENGTH,   "Incorrect Length"              },
 301         { FC_REASON_UNEXPECTED_ACK,     "Unexpected Ack"                },
 302         { FC_REASON_UNEXPECTED_LR,      "Unexpected Link reset"         },
 303         { FC_REASON_LOGIN_REQUIRED,     "Login Required"                },
 304         { FC_REASON_EXCESSIVE_SEQS,     "Excessive Sequences"
 305             " Attempted"                        },
 306         { FC_REASON_EXCH_UNABLE,        "Exchange incapable"            },
 307         { FC_REASON_ESH_NOT_SUPP,       "Expiration Security Header "
 308             "Not Supported"                     },
 309         { FC_REASON_NO_FABRIC_PATH,     "No Fabric Path"                },
 310         { FC_REASON_VENDOR_UNIQUE,      "Vendor Unique"                 },
 311         { FC_REASON_INVALID,            NULL                            }
 312 };
 313 
 314 fc_pkt_reason_t n_port_busy_reasons [] = {
 315         { FC_REASON_PHYSICAL_BUSY,              "Physical Busy"         },
 316         { FC_REASON_N_PORT_RESOURCE_BSY,        "Resource Busy"         },
 317         { FC_REASON_N_PORT_VENDOR_UNIQUE,       "Vendor Unique"         },
 318         { FC_REASON_INVALID,                    NULL                    }
 319 };
 320 
 321 fc_pkt_reason_t f_busy_reasons [] = {
 322         { FC_REASON_FABRIC_BSY,         "Fabric Busy"                   },
 323         { FC_REASON_N_PORT_BSY,         "N_Port Busy"                   },
 324         { FC_REASON_INVALID,            NULL                            }
 325 };
 326 
 327 fc_pkt_reason_t ls_ba_rjt_reasons [] = {
 328         { FC_REASON_INVALID_LA_CODE,    "Invalid Link Application Code" },
 329         { FC_REASON_LOGICAL_ERROR,      "Logical Error"                 },
 330         { FC_REASON_LOGICAL_BSY,        "Logical Busy"                  },
 331         { FC_REASON_PROTOCOL_ERROR_RJT, "Protocol Error Reject"         },
 332         { FC_REASON_CMD_UNABLE,         "Unable to Perform Command"     },
 333         { FC_REASON_CMD_UNSUPPORTED,    "Unsupported Command"           },
 334         { FC_REASON_VU_RJT,             "Vendor Unique"                 },
 335         { FC_REASON_INVALID,            NULL                            }
 336 };
 337 
 338 fc_pkt_reason_t fs_rjt_reasons [] = {
 339         { FC_REASON_FS_INVALID_CMD,     "Invalid Command"               },
 340         { FC_REASON_FS_INVALID_VER,     "Invalid Version"               },
 341         { FC_REASON_FS_LOGICAL_ERR,     "Logical Error"                 },
 342         { FC_REASON_FS_INVALID_IUSIZE,  "Invalid IU Size"               },
 343         { FC_REASON_FS_LOGICAL_BUSY,    "Logical Busy"                  },
 344         { FC_REASON_FS_PROTOCOL_ERR,    "Protocol Error"                },
 345         { FC_REASON_FS_CMD_UNABLE,      "Unable to Perform Command"     },
 346         { FC_REASON_FS_CMD_UNSUPPORTED, "Unsupported Command"           },
 347         { FC_REASON_FS_VENDOR_UNIQUE,   "Vendor Unique"                 },
 348         { FC_REASON_INVALID,            NULL                            }
 349 };
 350 
 351 fc_pkt_action_t n_port_busy_actions [] = {
 352         { FC_ACTION_SEQ_TERM_RETRY,     "Retry terminated Sequence"     },
 353         { FC_ACTION_SEQ_ACTIVE_RETRY,   "Retry Active Sequence"         },
 354         { FC_REASON_INVALID,            NULL                            }
 355 };
 356 
 357 fc_pkt_action_t rjt_timeout_actions [] = {
 358         { FC_ACTION_RETRYABLE,          "Retryable"                     },
 359         { FC_ACTION_NON_RETRYABLE,      "Non Retryable"                 },
 360         { FC_REASON_INVALID,            NULL                            }
 361 };
 362 
 363 fc_pkt_expln_t ba_rjt_explns [] = {
 364         { FC_EXPLN_NONE,                "No Explanation"                },
 365         { FC_EXPLN_INVALID_OX_RX_ID,    "Invalid X_ID"                  },
 366         { FC_EXPLN_SEQ_ABORTED,         "Sequence Aborted"              },
 367         { FC_EXPLN_INVALID,             NULL                            }
 368 };
 369 
 370 fc_pkt_error_t fc_pkt_errlist[] = {
 371         {
 372                 FC_PKT_SUCCESS,
 373                 "Operation Success",
 374                 NULL,
 375                 NULL,
 376                 NULL
 377         },
 378         {       FC_PKT_REMOTE_STOP,
 379             "Remote Stop",
 380             remote_stop_reasons,
 381             NULL,
 382             NULL
 383         },
 384         {
 385                 FC_PKT_LOCAL_RJT,
 386                 "Local Reject",
 387                 general_reasons,
 388                 rjt_timeout_actions,
 389                 NULL
 390         },
 391         {
 392                 FC_PKT_NPORT_RJT,
 393                 "N_Port Reject",
 394                 rjt_reasons,
 395                 rjt_timeout_actions,
 396                 NULL
 397         },
 398         {
 399                 FC_PKT_FABRIC_RJT,
 400                 "Fabric Reject",
 401                 rjt_reasons,
 402                 rjt_timeout_actions,
 403                 NULL
 404         },
 405         {
 406                 FC_PKT_LOCAL_BSY,
 407                 "Local Busy",
 408                 general_reasons,
 409                 NULL,
 410                 NULL,
 411         },
 412         {
 413                 FC_PKT_TRAN_BSY,
 414                 "Transport Busy",
 415                 general_reasons,
 416                 NULL,
 417                 NULL,
 418         },
 419         {
 420                 FC_PKT_NPORT_BSY,
 421                 "N_Port Busy",
 422                 n_port_busy_reasons,
 423                 n_port_busy_actions,
 424                 NULL
 425         },
 426         {
 427                 FC_PKT_FABRIC_BSY,
 428                 "Fabric Busy",
 429                 f_busy_reasons,
 430                 NULL,
 431                 NULL,
 432         },
 433         {
 434                 FC_PKT_LS_RJT,
 435                 "Link Service Reject",
 436                 ls_ba_rjt_reasons,
 437                 NULL,
 438                 NULL,
 439         },
 440         {
 441                 FC_PKT_BA_RJT,
 442                 "Basic Reject",
 443                 ls_ba_rjt_reasons,
 444                 NULL,
 445                 ba_rjt_explns,
 446         },
 447         {
 448                 FC_PKT_TIMEOUT,
 449                 "Timeout",
 450                 general_reasons,
 451                 rjt_timeout_actions,
 452                 NULL
 453         },
 454         {
 455                 FC_PKT_FS_RJT,
 456                 "Fabric Switch Reject",
 457                 fs_rjt_reasons,
 458                 NULL,
 459                 NULL
 460         },
 461         {
 462                 FC_PKT_TRAN_ERROR,
 463                 "Packet Transport error",
 464                 general_reasons,
 465                 NULL,
 466                 NULL
 467         },
 468         {
 469                 FC_PKT_FAILURE,
 470                 "Packet Failure",
 471                 general_reasons,
 472                 NULL,
 473                 NULL
 474         },
 475         {
 476                 FC_PKT_PORT_OFFLINE,
 477                 "Port Offline",
 478                 NULL,
 479                 NULL,
 480                 NULL
 481         },
 482         {
 483                 FC_PKT_ELS_IN_PROGRESS,
 484                 "ELS is in Progress",
 485                 NULL,
 486                 NULL,
 487                 NULL
 488         }
 489 };
 490 
 491 int
 492 _init()
 493 {
 494         int rval;
 495 
 496         rw_init(&fctl_ulp_lock, NULL, RW_DRIVER, NULL);
 497         rw_init(&fctl_mod_ports_lock, NULL, RW_DRIVER, NULL);
 498         mutex_init(&fctl_port_lock, NULL, MUTEX_DRIVER, NULL);
 499         mutex_init(&fctl_nwwn_hash_mutex, NULL, MUTEX_DRIVER, NULL);
 500 
 501         fctl_nwwn_hash_table = kmem_zalloc(sizeof (*fctl_nwwn_hash_table) *
 502             fctl_nwwn_table_size, KM_SLEEP);
 503 
 504         fctl_ulp_modules = NULL;
 505         fctl_fca_portlist = NULL;
 506 
 507         fctl_job_cache = kmem_cache_create("fctl_cache",
 508             sizeof (job_request_t), 8, fctl_cache_constructor,
 509             fctl_cache_destructor, NULL, NULL, NULL, 0);
 510 
 511         if (fctl_job_cache == NULL) {
 512                 kmem_free(fctl_nwwn_hash_table,
 513                     sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size);
 514                 mutex_destroy(&fctl_nwwn_hash_mutex);
 515                 mutex_destroy(&fctl_port_lock);
 516                 rw_destroy(&fctl_ulp_lock);
 517                 rw_destroy(&fctl_mod_ports_lock);
 518                 return (ENOMEM);
 519         }
 520 
 521         if ((rval = mod_install(&modlinkage)) != 0) {
 522                 kmem_cache_destroy(fctl_job_cache);
 523                 kmem_free(fctl_nwwn_hash_table,
 524                     sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size);
 525                 mutex_destroy(&fctl_nwwn_hash_mutex);
 526                 mutex_destroy(&fctl_port_lock);
 527                 rw_destroy(&fctl_ulp_lock);
 528                 rw_destroy(&fctl_mod_ports_lock);
 529         }
 530 
 531         return (rval);
 532 }
 533 
 534 
 535 /*
 536  * The mod_uninstall code doesn't call _fini when
 537  * there is living dependent module on fctl. So
 538  * there is no need to be extra careful here ?
 539  */
 540 int
 541 _fini()
 542 {
 543         int rval;
 544 
 545         if ((rval = mod_remove(&modlinkage)) != 0) {
 546                 return (rval);
 547         }
 548 
 549         kmem_cache_destroy(fctl_job_cache);
 550         kmem_free(fctl_nwwn_hash_table,
 551             sizeof (*fctl_nwwn_hash_table) * fctl_nwwn_table_size);
 552         mutex_destroy(&fctl_nwwn_hash_mutex);
 553         mutex_destroy(&fctl_port_lock);
 554         rw_destroy(&fctl_ulp_lock);
 555         rw_destroy(&fctl_mod_ports_lock);
 556 
 557         return (rval);
 558 }
 559 
 560 
 561 int
 562 _info(struct modinfo *modinfo_p)
 563 {
 564         return (mod_info(&modlinkage, modinfo_p));
 565 }
 566 
 567 
 568 /* ARGSUSED */
 569 static int
 570 fctl_cache_constructor(void *buf, void *cdarg, int kmflag)
 571 {
 572         job_request_t *job = (job_request_t *)buf;
 573 
 574         mutex_init(&job->job_mutex, NULL, MUTEX_DRIVER, NULL);
 575         sema_init(&job->job_fctl_sema, 0, NULL, SEMA_DEFAULT, NULL);
 576         sema_init(&job->job_port_sema, 0, NULL, SEMA_DEFAULT, NULL);
 577 
 578         return (0);
 579 }
 580 
 581 
 582 /* ARGSUSED */
 583 static void
 584 fctl_cache_destructor(void *buf, void *cdarg)
 585 {
 586         job_request_t *job = (job_request_t *)buf;
 587 
 588         sema_destroy(&job->job_fctl_sema);
 589         sema_destroy(&job->job_port_sema);
 590         mutex_destroy(&job->job_mutex);
 591 }
 592 
 593 
 594 /*
 595  * fc_ulp_add:
 596  *              Add a ULP module
 597  *
 598  * Return Codes:
 599  *              FC_ULP_SAMEMODULE
 600  *              FC_SUCCESS
 601  *              FC_FAILURE
 602  *
 603  *   fc_ulp_add  prints  a warning message if there is  already a
 604  *   similar ULP type  attached and this is unlikely to change as
 605  *   we trudge along.  Further, this  function  returns a failure
 606  *   code if the same  module  attempts to add more than once for
 607  *   the same FC-4 type.
 608  */
 609 int
 610 fc_ulp_add(fc_ulp_modinfo_t *ulp_info)
 611 {
 612         fc_ulp_module_t *mod;
 613         fc_ulp_module_t *prev;
 614         job_request_t   *job;
 615         fc_ulp_list_t   *new;
 616         fc_fca_port_t   *fca_port;
 617         int             ntry = 0;
 618 
 619         ASSERT(ulp_info != NULL);
 620 
 621         /*
 622          * Make sure ulp_rev matches fctl version.
 623          * Whenever non-private data structure or non-static interface changes,
 624          * we should use an increased FCTL_ULP_MODREV_# number here and in all
 625          * ulps to prevent version mismatch.
 626          */
 627         if (ulp_info->ulp_rev != FCTL_ULP_MODREV_4) {
 628                 cmn_err(CE_WARN, "fctl: ULP %s version mismatch;"
 629                     " ULP %s would not be loaded", ulp_info->ulp_name,
 630                     ulp_info->ulp_name);
 631                 return (FC_BADULP);
 632         }
 633 
 634         new = kmem_zalloc(sizeof (*new), KM_SLEEP);
 635         ASSERT(new != NULL);
 636 
 637         mutex_enter(&fctl_ulp_list_mutex);
 638         new->ulp_info = ulp_info;
 639         if (fctl_ulp_list != NULL) {
 640                 new->ulp_next = fctl_ulp_list;
 641         }
 642         fctl_ulp_list = new;
 643         mutex_exit(&fctl_ulp_list_mutex);
 644 
 645         while (rw_tryenter(&fctl_ulp_lock, RW_WRITER) == 0) {
 646                 delay(drv_usectohz(1000000));
 647                 if (ntry++ > FC_ULP_ADD_RETRY_COUNT) {
 648                         fc_ulp_list_t   *list;
 649                         fc_ulp_list_t   *last;
 650                         mutex_enter(&fctl_ulp_list_mutex);
 651                         for (last = NULL, list = fctl_ulp_list; list != NULL;
 652                             list = list->ulp_next) {
 653                                 if (list->ulp_info == ulp_info) {
 654                                         break;
 655                                 }
 656                                 last = list;
 657                         }
 658 
 659                         if (list) {
 660                                 if (last) {
 661                                         last->ulp_next = list->ulp_next;
 662                                 } else {
 663                                         fctl_ulp_list = list->ulp_next;
 664                                 }
 665                                 kmem_free(list, sizeof (*list));
 666                         }
 667                         mutex_exit(&fctl_ulp_list_mutex);
 668                         cmn_err(CE_WARN, "fctl: ULP %s unable to load",
 669                             ulp_info->ulp_name);
 670                         return (FC_FAILURE);
 671                 }
 672         }
 673 
 674         for (mod = fctl_ulp_modules, prev = NULL; mod; mod = mod->mod_next) {
 675                 ASSERT(mod->mod_info != NULL);
 676 
 677                 if (ulp_info == mod->mod_info &&
 678                     ulp_info->ulp_type == mod->mod_info->ulp_type) {
 679                         rw_exit(&fctl_ulp_lock);
 680                         return (FC_ULP_SAMEMODULE);
 681                 }
 682 
 683                 if (ulp_info->ulp_type == mod->mod_info->ulp_type) {
 684                         cmn_err(CE_NOTE, fctl_greeting, ulp_info->ulp_name,
 685                             ulp_info->ulp_type);
 686                 }
 687                 prev = mod;
 688         }
 689 
 690         mod = kmem_zalloc(sizeof (*mod), KM_SLEEP);
 691         mod->mod_info = ulp_info;
 692         mod->mod_next = NULL;
 693 
 694         if (prev) {
 695                 prev->mod_next = mod;
 696         } else {
 697                 fctl_ulp_modules = mod;
 698         }
 699 
 700         /*
 701          * Schedule a job to each port's job_handler
 702          * thread to attach their ports with this ULP.
 703          */
 704         mutex_enter(&fctl_port_lock);
 705         for (fca_port = fctl_fca_portlist; fca_port != NULL;
 706             fca_port = fca_port->port_next) {
 707                 job = fctl_alloc_job(JOB_ATTACH_ULP, JOB_TYPE_FCTL_ASYNC,
 708                     NULL, NULL, KM_SLEEP);
 709 
 710                 fctl_enque_job(fca_port->port_handle, job);
 711         }
 712         mutex_exit(&fctl_port_lock);
 713 
 714         rw_exit(&fctl_ulp_lock);
 715 
 716         return (FC_SUCCESS);
 717 }
 718 
 719 
 720 /*
 721  * fc_ulp_remove
 722  *      Remove a ULP module
 723  *
 724  * A misbehaving ULP may call this routine while I/Os are in progress.
 725  * Currently there is no mechanism to detect it to fail such a request.
 726  *
 727  * Return Codes:
 728  *              FC_SUCCESS
 729  *              FC_FAILURE
 730  */
 731 int
 732 fc_ulp_remove(fc_ulp_modinfo_t *ulp_info)
 733 {
 734         fc_ulp_module_t *mod;
 735         fc_ulp_list_t   *list;
 736         fc_ulp_list_t   *last;
 737         fc_ulp_module_t *prev;
 738 
 739         mutex_enter(&fctl_ulp_list_mutex);
 740 
 741         for (last = NULL, list = fctl_ulp_list; list != NULL;
 742             list = list->ulp_next) {
 743                 if (list->ulp_info == ulp_info) {
 744                         break;
 745                 }
 746                 last = list;
 747         }
 748 
 749         if (list) {
 750                 if (last) {
 751                         last->ulp_next = list->ulp_next;
 752                 } else {
 753                         fctl_ulp_list = list->ulp_next;
 754                 }
 755                 kmem_free(list, sizeof (*list));
 756         }
 757 
 758         mutex_exit(&fctl_ulp_list_mutex);
 759 
 760         rw_enter(&fctl_ulp_lock, RW_WRITER);
 761 
 762         for (mod = fctl_ulp_modules, prev = NULL; mod != NULL;
 763             mod = mod->mod_next) {
 764                 if (mod->mod_info == ulp_info) {
 765                         break;
 766                 }
 767                 prev = mod;
 768         }
 769 
 770         if (mod) {
 771                 fc_ulp_ports_t *next;
 772 
 773                 if (prev) {
 774                         prev->mod_next = mod->mod_next;
 775                 } else {
 776                         fctl_ulp_modules = mod->mod_next;
 777                 }
 778 
 779                 rw_enter(&fctl_mod_ports_lock, RW_WRITER);
 780 
 781                 while ((next = mod->mod_ports) != NULL) {
 782                         mod->mod_ports = next->port_next;
 783                         fctl_dealloc_ulp_port(next);
 784                 }
 785 
 786                 rw_exit(&fctl_mod_ports_lock);
 787                 rw_exit(&fctl_ulp_lock);
 788 
 789                 kmem_free(mod, sizeof (*mod));
 790 
 791                 return (FC_SUCCESS);
 792         }
 793         rw_exit(&fctl_ulp_lock);
 794 
 795         return (FC_FAILURE);
 796 }
 797 
 798 
 799 /*
 800  * The callers typically cache allocate the packet, complete the
 801  * DMA setup for pkt_cmd and pkt_resp fields of the packet and
 802  * call this function to see if the FCA is interested in doing
 803  * its own intialization. For example, socal may like to initialize
 804  * the soc_hdr which is pointed to by the pkt_fca_private field
 805  * and sitting right below fc_packet_t in memory.
 806  *
 807  * The caller is required to ensure that pkt_pd is populated with the
 808  * handle that it was given when the transport notified it about the
 809  * device this packet is associated with.  If there is no associated
 810  * device, pkt_pd must be set to NULL.  A non-NULL pkt_pd will cause an
 811  * increment of the reference count for said pd.  When the packet is freed,
 812  * the reference count will be decremented.  This reference count, in
 813  * combination with the PD_GIVEN_TO_ULPS flag guarantees that the pd
 814  * will not wink out of existence while there is a packet outstanding.
 815  *
 816  * This function and fca_init_pkt must not perform any operations that
 817  * would result in a call back to the ULP, as the ULP may be required
 818  * to hold a mutex across this call to ensure that the pd in question
 819  * won't go away prior the call to fc_ulp_transport.
 820  *
 821  * ULPs are responsible for using the handles they are given during state
 822  * change callback processing in a manner that ensures consistency.  That
 823  * is, they must be aware that they could be processing a state change
 824  * notification that tells them the device associated with a particular
 825  * handle has gone away at the same time they are being asked to
 826  * initialize a packet using that handle. ULPs must therefore ensure
 827  * that their state change processing and packet initialization code
 828  * paths are sufficiently synchronized to avoid the use of an
 829  * invalidated handle in any fc_packet_t struct that is passed to the
 830  * fc_ulp_init_packet() function.
 831  */
 832 int
 833 fc_ulp_init_packet(opaque_t port_handle, fc_packet_t *pkt, int sleep)
 834 {
 835         int rval;
 836         fc_local_port_t *port = port_handle;
 837         fc_remote_port_t *pd;
 838 
 839         ASSERT(pkt != NULL);
 840 
 841         pd = pkt->pkt_pd;
 842 
 843         /* Call the FCA driver's fca_init_pkt entry point function. */
 844         rval = port->fp_fca_tran->fca_init_pkt(port->fp_fca_handle, pkt, sleep);
 845 
 846         if ((rval == FC_SUCCESS) && (pd != NULL)) {
 847                 /*
 848                  * A !NULL pd here must still be a valid
 849                  * reference to the fc_remote_port_t.
 850                  */
 851                 mutex_enter(&pd->pd_mutex);
 852                 ASSERT(pd->pd_ref_count >= 0);
 853                 pd->pd_ref_count++;
 854                 mutex_exit(&pd->pd_mutex);
 855         }
 856 
 857         return (rval);
 858 }
 859 
 860 
 861 /*
 862  * This function is called before destroying the cache allocated
 863  * fc_packet to free up (and uninitialize) any resource specially
 864  * allocated by the FCA driver during tran_init_pkt().
 865  *
 866  * If the pkt_pd field in the given fc_packet_t struct is not NULL, then
 867  * the pd_ref_count reference count is decremented for the indicated
 868  * fc_remote_port_t struct.
 869  */
 870 int
 871 fc_ulp_uninit_packet(opaque_t port_handle, fc_packet_t *pkt)
 872 {
 873         int rval;
 874         fc_local_port_t *port = port_handle;
 875         fc_remote_port_t *pd;
 876 
 877         ASSERT(pkt != NULL);
 878 
 879         pd = pkt->pkt_pd;
 880 
 881         /* Call the FCA driver's fca_un_init_pkt entry point function */
 882         rval = port->fp_fca_tran->fca_un_init_pkt(port->fp_fca_handle, pkt);
 883 
 884         if ((rval == FC_SUCCESS) && (pd != NULL)) {
 885                 mutex_enter(&pd->pd_mutex);
 886 
 887                 ASSERT(pd->pd_ref_count > 0);
 888                 pd->pd_ref_count--;
 889 
 890                 /*
 891                  * If at this point the state of this fc_remote_port_t
 892                  * struct is PORT_DEVICE_INVALID, it probably means somebody
 893                  * is cleaning up old (e.g. retried) packets. If the
 894                  * pd_ref_count has also dropped to zero, it's time to
 895                  * deallocate this fc_remote_port_t struct.
 896                  */
 897                 if (pd->pd_state == PORT_DEVICE_INVALID &&
 898                     pd->pd_ref_count == 0) {
 899                         fc_remote_node_t *node = pd->pd_remote_nodep;
 900 
 901                         mutex_exit(&pd->pd_mutex);
 902 
 903                         /*
 904                          * Also deallocate the associated fc_remote_node_t
 905                          * struct if it has no other associated
 906                          * fc_remote_port_t structs.
 907                          */
 908                         if ((fctl_destroy_remote_port(port, pd) == 0) &&
 909                             (node != NULL)) {
 910                                 fctl_destroy_remote_node(node);
 911                         }
 912                         return (rval);
 913                 }
 914 
 915                 mutex_exit(&pd->pd_mutex);
 916         }
 917 
 918         return (rval);
 919 }
 920 
 921 
 922 int
 923 fc_ulp_getportmap(opaque_t port_handle, fc_portmap_t **map, uint32_t *len,
 924     int flag)
 925 {
 926         int             job_code;
 927         fc_local_port_t *port;
 928         job_request_t   *job;
 929         fc_portmap_t    *tmp_map;
 930         uint32_t        tmp_len;
 931         fc_portmap_t    *change_list = NULL;
 932         uint32_t        listlen = 0;
 933 
 934         port = port_handle;
 935 
 936         mutex_enter(&port->fp_mutex);
 937         if (port->fp_statec_busy) {
 938                 mutex_exit(&port->fp_mutex);
 939                 return (FC_STATEC_BUSY);
 940         }
 941 
 942         if (FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) {
 943                 mutex_exit(&port->fp_mutex);
 944                 return (FC_OFFLINE);
 945         }
 946 
 947         if (port->fp_dev_count && (port->fp_dev_count ==
 948             port->fp_total_devices)) {
 949                 mutex_exit(&port->fp_mutex);
 950                 fctl_fillout_map(port, &change_list, &listlen, 1, 1, 0);
 951                 if (listlen > *len) {
 952                         tmp_map = (fc_portmap_t *)kmem_zalloc(
 953                             listlen * sizeof (fc_portmap_t), KM_NOSLEEP);
 954                         if (tmp_map == NULL) {
 955                                 return (FC_NOMEM);
 956                         }
 957                         if (*map) {
 958                                 kmem_free(*map, (*len) * sizeof (fc_portmap_t));
 959                         }
 960                         *map = tmp_map;
 961                 }
 962                 if (change_list) {
 963                         bcopy(change_list, *map,
 964                             listlen * sizeof (fc_portmap_t));
 965                         kmem_free(change_list, listlen * sizeof (fc_portmap_t));
 966                 }
 967                 *len = listlen;
 968         } else {
 969                 mutex_exit(&port->fp_mutex);
 970 
 971                 switch (flag) {
 972                 case FC_ULP_PLOGI_DONTCARE:
 973                         job_code = JOB_PORT_GETMAP;
 974                         break;
 975 
 976                 case FC_ULP_PLOGI_PRESERVE:
 977                         job_code = JOB_PORT_GETMAP_PLOGI_ALL;
 978                         break;
 979 
 980                 default:
 981                         return (FC_INVALID_REQUEST);
 982                 }
 983                 /*
 984                  * Submit a job request to the job handler
 985                  * thread to get the map and wait
 986                  */
 987                 job = fctl_alloc_job(job_code, 0, NULL, NULL, KM_SLEEP);
 988                 job->job_private = (opaque_t)map;
 989                 job->job_arg = (opaque_t)len;
 990                 fctl_enque_job(port, job);
 991 
 992                 fctl_jobwait(job);
 993                 /*
 994                  * The result of the last I/O operation is
 995                  * in job_code. We don't care to look at it
 996                  * Rather we look at the number of devices
 997                  * that are found to fill out the map for
 998                  * ULPs.
 999                  */
1000                 fctl_dealloc_job(job);
1001         }
1002 
1003         /*
1004          * If we're here, we're returning a map to the caller, which means
1005          * we'd better make sure every pd in that map has the
1006          * PD_GIVEN_TO_ULPS flag set.
1007          */
1008 
1009         tmp_len = *len;
1010         tmp_map = *map;
1011 
1012         while (tmp_len-- != 0) {
1013                 if (tmp_map->map_state != PORT_DEVICE_INVALID) {
1014                         fc_remote_port_t *pd =
1015                             (fc_remote_port_t *)tmp_map->map_pd;
1016                         mutex_enter(&pd->pd_mutex);
1017                         pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
1018                         mutex_exit(&pd->pd_mutex);
1019                 }
1020                 tmp_map++;
1021         }
1022 
1023         return (FC_SUCCESS);
1024 }
1025 
1026 
1027 int
1028 fc_ulp_login(opaque_t port_handle, fc_packet_t **ulp_pkt, uint32_t listlen)
1029 {
1030         int                     rval = FC_SUCCESS;
1031         int                     job_flags;
1032         uint32_t                count;
1033         fc_packet_t             **tmp_array;
1034         job_request_t           *job;
1035         fc_local_port_t         *port = port_handle;
1036         fc_ulp_rscn_info_t      *rscnp =
1037             (fc_ulp_rscn_info_t *)(ulp_pkt[0])->pkt_ulp_rscn_infop;
1038 
1039         /*
1040          * If the port is OFFLINE, or if the port driver is
1041          * being SUSPENDED/PM_SUSPENDED/DETACHED, block all
1042          * PLOGI operations
1043          */
1044         mutex_enter(&port->fp_mutex);
1045         if (port->fp_statec_busy) {
1046                 mutex_exit(&port->fp_mutex);
1047                 return (FC_STATEC_BUSY);
1048         }
1049 
1050         if ((FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) ||
1051             (port->fp_soft_state &
1052             (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) {
1053                 mutex_exit(&port->fp_mutex);
1054                 return (FC_OFFLINE);
1055         }
1056 
1057         /*
1058          * If the rscn count in the packet is not the same as the rscn count
1059          * in the fc_local_port_t, then one or more new RSCNs has occurred.
1060          */
1061         if ((rscnp != NULL) &&
1062             (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) &&
1063             (rscnp->ulp_rscn_count != port->fp_rscn_count)) {
1064                 mutex_exit(&port->fp_mutex);
1065                 return (FC_DEVICE_BUSY_NEW_RSCN);
1066         }
1067 
1068         mutex_exit(&port->fp_mutex);
1069 
1070         tmp_array = kmem_zalloc(sizeof (*tmp_array) * listlen, KM_SLEEP);
1071         for (count = 0; count < listlen; count++) {
1072                 tmp_array[count] = ulp_pkt[count];
1073         }
1074 
1075         job_flags = ((ulp_pkt[0]->pkt_tran_flags) & FC_TRAN_NO_INTR)
1076             ? 0 : JOB_TYPE_FCTL_ASYNC;
1077 
1078 #ifdef  DEBUG
1079         {
1080                 int next;
1081                 int count;
1082                 int polled;
1083 
1084                 polled = ((ulp_pkt[0]->pkt_tran_flags) &
1085                     FC_TRAN_NO_INTR) ? 0 : JOB_TYPE_FCTL_ASYNC;
1086 
1087                 for (count = 0; count < listlen; count++) {
1088                         next = ((ulp_pkt[count]->pkt_tran_flags)
1089                             & FC_TRAN_NO_INTR) ? 0 : JOB_TYPE_FCTL_ASYNC;
1090                         ASSERT(next == polled);
1091                 }
1092         }
1093 #endif
1094 
1095         job = fctl_alloc_job(JOB_PLOGI_GROUP, job_flags, NULL, NULL, KM_SLEEP);
1096         job->job_ulp_pkts = tmp_array;
1097         job->job_ulp_listlen = listlen;
1098 
1099         while (listlen--) {
1100                 fc_packet_t *pkt;
1101 
1102                 pkt = tmp_array[listlen];
1103                 if (pkt->pkt_pd == NULL) {
1104                         pkt->pkt_state = FC_PKT_SUCCESS;
1105                         continue;
1106                 }
1107 
1108                 mutex_enter(&pkt->pkt_pd->pd_mutex);
1109                 if (pkt->pkt_pd->pd_flags == PD_ELS_IN_PROGRESS ||
1110                     pkt->pkt_pd->pd_flags == PD_ELS_MARK) {
1111                         /*
1112                          * Set the packet state and let the port
1113                          * driver call the completion routine
1114                          * from its thread
1115                          */
1116                         mutex_exit(&pkt->pkt_pd->pd_mutex);
1117                         pkt->pkt_state = FC_PKT_ELS_IN_PROGRESS;
1118                         continue;
1119                 }
1120 
1121                 if (pkt->pkt_pd->pd_state == PORT_DEVICE_INVALID ||
1122                     pkt->pkt_pd->pd_type == PORT_DEVICE_OLD) {
1123                         mutex_exit(&pkt->pkt_pd->pd_mutex);
1124                         pkt->pkt_state = FC_PKT_LOCAL_RJT;
1125                         continue;
1126                 }
1127                 mutex_exit(&pkt->pkt_pd->pd_mutex);
1128                 pkt->pkt_state = FC_PKT_SUCCESS;
1129         }
1130 
1131         fctl_enque_job(port, job);
1132 
1133         if (!(job_flags & JOB_TYPE_FCTL_ASYNC)) {
1134                 fctl_jobwait(job);
1135                 rval = job->job_result;
1136                 fctl_dealloc_job(job);
1137         }
1138 
1139         return (rval);
1140 }
1141 
1142 
1143 opaque_t
1144 fc_ulp_get_remote_port(opaque_t port_handle, la_wwn_t *pwwn, int *error,
1145     int create)
1146 {
1147         fc_local_port_t         *port;
1148         job_request_t           *job;
1149         fc_remote_port_t        *pd;
1150 
1151         port = port_handle;
1152         pd = fctl_get_remote_port_by_pwwn(port, pwwn);
1153 
1154         if (pd != NULL) {
1155                 *error = FC_SUCCESS;
1156                 /*
1157                  * A ULP now knows about this pd, so mark it
1158                  */
1159                 mutex_enter(&pd->pd_mutex);
1160                 pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
1161                 mutex_exit(&pd->pd_mutex);
1162                 return (pd);
1163         }
1164 
1165         mutex_enter(&port->fp_mutex);
1166         if (FC_IS_TOP_SWITCH(port->fp_topology) && create) {
1167                 uint32_t        d_id;
1168                 fctl_ns_req_t   *ns_cmd;
1169 
1170                 mutex_exit(&port->fp_mutex);
1171 
1172                 job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP);
1173 
1174                 if (job == NULL) {
1175                         *error = FC_NOMEM;
1176                         return (pd);
1177                 }
1178 
1179                 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gid_pn_t),
1180                     sizeof (ns_resp_gid_pn_t), sizeof (ns_resp_gid_pn_t),
1181                     0, KM_SLEEP);
1182 
1183                 if (ns_cmd == NULL) {
1184                         fctl_dealloc_job(job);
1185                         *error = FC_NOMEM;
1186                         return (pd);
1187                 }
1188                 ns_cmd->ns_cmd_code = NS_GID_PN;
1189                 ((ns_req_gid_pn_t *)(ns_cmd->ns_cmd_buf))->pwwn = *pwwn;
1190 
1191                 job->job_result = FC_SUCCESS;
1192                 job->job_private = (void *)ns_cmd;
1193                 job->job_counter = 1;
1194                 fctl_enque_job(port, job);
1195                 fctl_jobwait(job);
1196 
1197                 if (job->job_result != FC_SUCCESS) {
1198                         *error = job->job_result;
1199                         fctl_free_ns_cmd(ns_cmd);
1200                         fctl_dealloc_job(job);
1201                         return (pd);
1202                 }
1203                 d_id = ((ns_resp_gid_pn_t *)ns_cmd->ns_data_buf)->pid.port_id;
1204                 fctl_free_ns_cmd(ns_cmd);
1205 
1206                 ns_cmd = fctl_alloc_ns_cmd(sizeof (ns_req_gan_t),
1207                     sizeof (ns_resp_gan_t), 0, FCTL_NS_CREATE_DEVICE,
1208                     KM_SLEEP);
1209                 ASSERT(ns_cmd != NULL);
1210 
1211                 ns_cmd->ns_gan_max = 1;
1212                 ns_cmd->ns_cmd_code = NS_GA_NXT;
1213                 ns_cmd->ns_gan_sid = FCTL_GAN_START_ID;
1214                 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.port_id = d_id - 1;
1215                 ((ns_req_gan_t *)(ns_cmd->ns_cmd_buf))->pid.priv_lilp_posit = 0;
1216 
1217                 job->job_result = FC_SUCCESS;
1218                 job->job_private = (void *)ns_cmd;
1219                 job->job_counter = 1;
1220                 fctl_enque_job(port, job);
1221                 fctl_jobwait(job);
1222 
1223                 fctl_free_ns_cmd(ns_cmd);
1224                 if (job->job_result != FC_SUCCESS) {
1225                         *error = job->job_result;
1226                         fctl_dealloc_job(job);
1227                         return (pd);
1228                 }
1229                 fctl_dealloc_job(job);
1230 
1231                 /*
1232                  * Check if the port device is created now.
1233                  */
1234                 pd = fctl_get_remote_port_by_pwwn(port, pwwn);
1235 
1236                 if (pd == NULL) {
1237                         *error = FC_FAILURE;
1238                 } else {
1239                         *error = FC_SUCCESS;
1240 
1241                         /*
1242                          * A ULP now knows about this pd, so mark it
1243                          */
1244                         mutex_enter(&pd->pd_mutex);
1245                         pd->pd_aux_flags |= PD_GIVEN_TO_ULPS;
1246                         mutex_exit(&pd->pd_mutex);
1247                 }
1248         } else {
1249                 mutex_exit(&port->fp_mutex);
1250                 *error = FC_FAILURE;
1251         }
1252 
1253         return (pd);
1254 }
1255 
1256 
1257 /*
1258  * If a NS object exists in the host and query is performed
1259  * on that object, we should retrieve it from our basket
1260  * and return it right here, there by saving a request going
1261  * all the up to the Name Server.
1262  */
1263 int
1264 fc_ulp_port_ns(opaque_t port_handle, opaque_t pd, fc_ns_cmd_t *ns_req)
1265 {
1266         int             rval;
1267         int             fabric;
1268         job_request_t   *job;
1269         fctl_ns_req_t   *ns_cmd;
1270         fc_local_port_t *port = port_handle;
1271 
1272         mutex_enter(&port->fp_mutex);
1273         fabric = FC_IS_TOP_SWITCH(port->fp_topology) ? 1 : 0;
1274         mutex_exit(&port->fp_mutex);
1275 
1276         /*
1277          * Name server query can't be performed for devices not in Fabric
1278          */
1279         if (!fabric && pd) {
1280                 return (FC_BADOBJECT);
1281         }
1282 
1283         if (FC_IS_CMD_A_REG(ns_req->ns_cmd)) {
1284                 if (pd == NULL) {
1285                         rval = fctl_update_host_ns_values(port, ns_req);
1286                         if (rval != FC_SUCCESS) {
1287                                 return (rval);
1288                         }
1289                 } else {
1290                         /*
1291                          * Guess what, FC-GS-2 currently prohibits (not
1292                          * in the strongest language though) setting of
1293                          * NS object values by other ports. But we might
1294                          * get that changed to at least accommodate setting
1295                          * symbolic node/port names - But if disks/tapes
1296                          * were going to provide a method to set these
1297                          * values directly (which in turn might register
1298                          * with the NS when they come up; yep, for that
1299                          * to happen the disks will have to be very well
1300                          * behaved Fabric citizen) we won't need to
1301                          * register the symbolic port/node names for
1302                          * other ports too (rather send down SCSI commands
1303                          * to the devices to set the names)
1304                          *
1305                          * Be that as it may, let's continue to fail
1306                          * registration requests for other ports. period.
1307                          */
1308                         return (FC_BADOBJECT);
1309                 }
1310 
1311                 if (!fabric) {
1312                         return (FC_SUCCESS);
1313                 }
1314         } else if (!fabric) {
1315                 return (fctl_retrieve_host_ns_values(port, ns_req));
1316         }
1317 
1318         job = fctl_alloc_job(JOB_NS_CMD, 0, NULL, NULL, KM_SLEEP);
1319         ASSERT(job != NULL);
1320 
1321         ns_cmd = fctl_alloc_ns_cmd(ns_req->ns_req_len,
1322             ns_req->ns_resp_len, ns_req->ns_resp_len, 0, KM_SLEEP);
1323         ASSERT(ns_cmd != NULL);
1324         ns_cmd->ns_cmd_code = ns_req->ns_cmd;
1325         bcopy(ns_req->ns_req_payload, ns_cmd->ns_cmd_buf,
1326             ns_req->ns_req_len);
1327 
1328         job->job_private = (void *)ns_cmd;
1329         fctl_enque_job(port, job);
1330         fctl_jobwait(job);
1331         rval = job->job_result;
1332 
1333         if (ns_req->ns_resp_len >= ns_cmd->ns_data_len) {
1334                 bcopy(ns_cmd->ns_data_buf, ns_req->ns_resp_payload,
1335                     ns_cmd->ns_data_len);
1336         }
1337         bcopy(&ns_cmd->ns_resp_hdr, &ns_req->ns_resp_hdr,
1338             sizeof (fc_ct_header_t));
1339 
1340         fctl_free_ns_cmd(ns_cmd);
1341         fctl_dealloc_job(job);
1342 
1343         return (rval);
1344 }
1345 
1346 
1347 int
1348 fc_ulp_transport(opaque_t port_handle, fc_packet_t *pkt)
1349 {
1350         int                     rval;
1351         fc_local_port_t         *port;
1352         fc_remote_port_t        *pd, *newpd;
1353         fc_ulp_rscn_info_t      *rscnp =
1354             (fc_ulp_rscn_info_t *)pkt->pkt_ulp_rscn_infop;
1355 
1356         port = port_handle;
1357 
1358         if (pkt->pkt_tran_flags & FC_TRAN_DUMPING) {
1359                 return (port->fp_fca_tran->fca_transport(
1360                     port->fp_fca_handle, pkt));
1361         }
1362 
1363         mutex_enter(&port->fp_mutex);
1364         if (port->fp_statec_busy) {
1365                 mutex_exit(&port->fp_mutex);
1366                 return (FC_STATEC_BUSY);
1367         }
1368 
1369         /* A locus of race conditions */
1370         if (((FC_PORT_STATE_MASK(port->fp_state)) == FC_STATE_OFFLINE) ||
1371             (port->fp_soft_state &
1372             (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) {
1373                 mutex_exit(&port->fp_mutex);
1374                 return (FC_OFFLINE);
1375         }
1376 
1377         /*
1378          * If the rscn count in the packet is not the same as the rscn count
1379          * in the fc_local_port_t, then one or more new RSCNs has occurred.
1380          */
1381         if ((rscnp != NULL) &&
1382             (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) &&
1383             (rscnp->ulp_rscn_count != port->fp_rscn_count)) {
1384                 mutex_exit(&port->fp_mutex);
1385                 return (FC_DEVICE_BUSY_NEW_RSCN);
1386         }
1387 
1388         pd = pkt->pkt_pd;
1389         if (pd) {
1390                 if (pd->pd_type == PORT_DEVICE_OLD ||
1391                     pd->pd_state == PORT_DEVICE_INVALID) {
1392 
1393                         newpd = fctl_get_remote_port_by_pwwn_mutex_held(port,
1394                             &pd->pd_port_name);
1395 
1396                         /*
1397                          * The remote port (pd) in the packet is no longer
1398                          * usable, as the old pd still exists we can use the
1399                          * WWN to check if we have a current pd for the device
1400                          * we want. Either way we continue with the old logic
1401                          * whether we have a new pd or not, as the new pd
1402                          * could be bad, or have become unusable.
1403                          */
1404                         if ((newpd) && (newpd != pd)) {
1405 
1406                                 /*
1407                                  * There is a better remote port (pd) to try,
1408                                  * so we need to fix the reference counts, etc.
1409                                  */
1410                                 mutex_enter(&newpd->pd_mutex);
1411                                 newpd->pd_ref_count++;
1412                                 pkt->pkt_pd = newpd;
1413                                 mutex_exit(&newpd->pd_mutex);
1414 
1415                                 mutex_enter(&pd->pd_mutex);
1416                                 pd->pd_ref_count--;
1417                                 if ((pd->pd_state == PORT_DEVICE_INVALID) &&
1418                                     (pd->pd_ref_count == 0)) {
1419                                         fc_remote_node_t *node =
1420                                             pd->pd_remote_nodep;
1421 
1422                                         mutex_exit(&pd->pd_mutex);
1423                                         mutex_exit(&port->fp_mutex);
1424 
1425                                         /*
1426                                          * This will create another PD hole
1427                                          * where we have a reference to a pd,
1428                                          * but someone else could remove it.
1429                                          */
1430                                         if ((fctl_destroy_remote_port(port, pd)
1431                                             == 0) && (node != NULL)) {
1432                                                 fctl_destroy_remote_node(node);
1433                                         }
1434                                         mutex_enter(&port->fp_mutex);
1435                                 } else {
1436                                         mutex_exit(&pd->pd_mutex);
1437                                 }
1438                                 pd = newpd;
1439                         }
1440                 }
1441 
1442                 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
1443                         rval = (pd->pd_state == PORT_DEVICE_VALID) ?
1444                             FC_LOGINREQ : FC_BADDEV;
1445                         mutex_exit(&port->fp_mutex);
1446                         return (rval);
1447                 }
1448 
1449                 if (pd->pd_flags != PD_IDLE) {
1450                         mutex_exit(&port->fp_mutex);
1451                         return (FC_DEVICE_BUSY);
1452                 }
1453 
1454                 if (pd->pd_type == PORT_DEVICE_OLD ||
1455                     pd->pd_state == PORT_DEVICE_INVALID) {
1456                         mutex_exit(&port->fp_mutex);
1457                         return (FC_BADDEV);
1458                 }
1459 
1460         } else if (FC_IS_REAL_DEVICE(pkt->pkt_cmd_fhdr.d_id)) {
1461                 mutex_exit(&port->fp_mutex);
1462                 return (FC_BADPACKET);
1463         }
1464         mutex_exit(&port->fp_mutex);
1465 
1466         return (port->fp_fca_tran->fca_transport(port->fp_fca_handle, pkt));
1467 }
1468 
1469 
1470 int
1471 fc_ulp_issue_els(opaque_t port_handle, fc_packet_t *pkt)
1472 {
1473         int                     rval;
1474         fc_local_port_t         *port = port_handle;
1475         fc_remote_port_t        *pd;
1476         fc_ulp_rscn_info_t      *rscnp =
1477             (fc_ulp_rscn_info_t *)pkt->pkt_ulp_rscn_infop;
1478 
1479         /*
1480          * If the port is OFFLINE, or if the port driver is
1481          * being SUSPENDED/PM_SUSPENDED/DETACHED, block all
1482          * ELS operations
1483          */
1484         mutex_enter(&port->fp_mutex);
1485         if ((FC_PORT_STATE_MASK(port->fp_state) == FC_STATE_OFFLINE) ||
1486             (port->fp_soft_state &
1487             (FP_SOFT_IN_DETACH | FP_SOFT_SUSPEND | FP_SOFT_POWER_DOWN))) {
1488                 mutex_exit(&port->fp_mutex);
1489                 return (FC_OFFLINE);
1490         }
1491 
1492         if (port->fp_statec_busy) {
1493                 mutex_exit(&port->fp_mutex);
1494                 return (FC_STATEC_BUSY);
1495         }
1496 
1497         /*
1498          * If the rscn count in the packet is not the same as the rscn count
1499          * in the fc_local_port_t, then one or more new RSCNs has occurred.
1500          */
1501         if ((rscnp != NULL) &&
1502             (rscnp->ulp_rscn_count != FC_INVALID_RSCN_COUNT) &&
1503             (rscnp->ulp_rscn_count != port->fp_rscn_count)) {
1504                 mutex_exit(&port->fp_mutex);
1505                 return (FC_DEVICE_BUSY_NEW_RSCN);
1506         }
1507 
1508         mutex_exit(&port->fp_mutex);
1509 
1510         if ((pd = pkt->pkt_pd) != NULL) {
1511                 mutex_enter(&pd->pd_mutex);
1512                 if (pd->pd_state != PORT_DEVICE_LOGGED_IN) {
1513                         rval = (pd->pd_state == PORT_DEVICE_VALID) ?
1514                             FC_LOGINREQ : FC_BADDEV;
1515                         mutex_exit(&pd->pd_mutex);
1516                         return (rval);
1517                 }
1518 
1519                 if (pd->pd_flags != PD_IDLE) {
1520                         mutex_exit(&pd->pd_mutex);
1521                         return (FC_DEVICE_BUSY);
1522                 }
1523                 if (pd->pd_type == PORT_DEVICE_OLD ||
1524                     pd->pd_state == PORT_DEVICE_INVALID) {
1525                         mutex_exit(&pd->pd_mutex);
1526                         return (FC_BADDEV);
1527                 }
1528                 mutex_exit(&pd->pd_mutex);
1529         }
1530 
1531         return (port->fp_fca_tran->fca_els_send(port->fp_fca_handle, pkt));
1532 }
1533 
1534 
1535 int
1536 fc_ulp_uballoc(opaque_t port_handle, uint32_t *count, uint32_t size,
1537     uint32_t type, uint64_t *tokens)
1538 {
1539         fc_local_port_t *port = port_handle;
1540 
1541         return (port->fp_fca_tran->fca_ub_alloc(port->fp_fca_handle,
1542             tokens, size, count, type));
1543 }
1544 
1545 
1546 int
1547 fc_ulp_ubfree(opaque_t port_handle, uint32_t count, uint64_t *tokens)
1548 {
1549         fc_local_port_t *port = port_handle;
1550 
1551         return (port->fp_fca_tran->fca_ub_free(port->fp_fca_handle,
1552             count, tokens));
1553 }
1554 
1555 
1556 int
1557 fc_ulp_ubrelease(opaque_t port_handle, uint32_t count, uint64_t *tokens)
1558 {
1559         fc_local_port_t *port = port_handle;
1560 
1561         return (port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
1562             count, tokens));
1563 }
1564 
1565 
1566 int
1567 fc_ulp_abort(opaque_t port_handle, fc_packet_t *pkt, int flags)
1568 {
1569         fc_local_port_t *port = port_handle;
1570 
1571         return (port->fp_fca_tran->fca_abort(port->fp_fca_handle, pkt, flags));
1572 }
1573 
1574 
1575 /*
1576  * Submit an asynchronous request to the job handler if the sleep
1577  * flag is set to KM_NOSLEEP, as such calls could have been made
1578  * in interrupt contexts, and the goal is to avoid busy waiting,
1579  * blocking on a conditional variable, a semaphore or any of the
1580  * synchronization primitives. A noticeable draw back with this
1581  * asynchronous request is that an FC_SUCCESS is returned long
1582  * before the reset is complete (successful or not).
1583  */
1584 int
1585 fc_ulp_linkreset(opaque_t port_handle, la_wwn_t *pwwn, int sleep)
1586 {
1587         int             rval;
1588         fc_local_port_t *port;
1589         job_request_t   *job;
1590 
1591         port = port_handle;
1592         /*
1593          * Many a times, this function is called from interrupt
1594          * contexts and there have been several dead locks and
1595          * hangs - One of the simplest work arounds is to fib
1596          * if a RESET is in progress.
1597          */
1598         mutex_enter(&port->fp_mutex);
1599         if (port->fp_soft_state & FP_SOFT_IN_LINK_RESET) {
1600                 mutex_exit(&port->fp_mutex);
1601                 return (FC_SUCCESS);
1602         }
1603 
1604         /*
1605          * Ward off this reset if a state change is in progress.
1606          */
1607         if (port->fp_statec_busy) {
1608                 mutex_exit(&port->fp_mutex);
1609                 return (FC_STATEC_BUSY);
1610         }
1611         port->fp_soft_state |= FP_SOFT_IN_LINK_RESET;
1612         mutex_exit(&port->fp_mutex);
1613 
1614         if (fctl_busy_port(port) != 0) {
1615                 mutex_enter(&port->fp_mutex);
1616                 port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET;
1617                 mutex_exit(&port->fp_mutex);
1618                 return (FC_FAILURE);
1619         }
1620 
1621         if (sleep == KM_SLEEP) {
1622                 job = fctl_alloc_job(JOB_LINK_RESET, 0, NULL, NULL, sleep);
1623                 ASSERT(job != NULL);
1624 
1625                 job->job_private = (void *)pwwn;
1626                 job->job_counter = 1;
1627                 fctl_enque_job(port, job);
1628                 fctl_jobwait(job);
1629 
1630                 mutex_enter(&port->fp_mutex);
1631                 port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET;
1632                 mutex_exit(&port->fp_mutex);
1633 
1634                 fctl_idle_port(port);
1635 
1636                 rval = job->job_result;
1637                 fctl_dealloc_job(job);
1638         } else {
1639                 job = fctl_alloc_job(JOB_LINK_RESET, JOB_TYPE_FCTL_ASYNC,
1640                     fctl_link_reset_done, port, sleep);
1641                 if (job == NULL) {
1642                         mutex_enter(&port->fp_mutex);
1643                         port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET;
1644                         mutex_exit(&port->fp_mutex);
1645                         fctl_idle_port(port);
1646                         return (FC_NOMEM);
1647                 }
1648                 job->job_private = (void *)pwwn;
1649                 job->job_counter = 1;
1650                 fctl_priority_enque_job(port, job);
1651                 rval = FC_SUCCESS;
1652         }
1653 
1654         return (rval);
1655 }
1656 
1657 
1658 int
1659 fc_ulp_port_reset(opaque_t port_handle, uint32_t cmd)
1660 {
1661         int             rval = FC_SUCCESS;
1662         fc_local_port_t *port = port_handle;
1663 
1664         switch (cmd) {
1665         case FC_RESET_PORT:
1666                 rval = port->fp_fca_tran->fca_reset(
1667                     port->fp_fca_handle, FC_FCA_LINK_RESET);
1668                 break;
1669 
1670         case FC_RESET_ADAPTER:
1671                 rval = port->fp_fca_tran->fca_reset(
1672                     port->fp_fca_handle, FC_FCA_RESET);
1673                 break;
1674 
1675         case FC_RESET_DUMP:
1676                 rval = port->fp_fca_tran->fca_reset(
1677                     port->fp_fca_handle, FC_FCA_CORE);
1678                 break;
1679 
1680         case FC_RESET_CRASH:
1681                 rval = port->fp_fca_tran->fca_reset(
1682                     port->fp_fca_handle, FC_FCA_RESET_CORE);
1683                 break;
1684 
1685         default:
1686                 rval = FC_FAILURE;
1687         }
1688 
1689         return (rval);
1690 }
1691 
1692 
1693 int
1694 fc_ulp_get_port_login_params(opaque_t port_handle, la_els_logi_t *login_params)
1695 {
1696         fc_local_port_t *port = port_handle;
1697 
1698         /* Copy the login parameters */
1699         *login_params = port->fp_service_params;
1700         return (FC_SUCCESS);
1701 }
1702 
1703 
1704 int
1705 fc_ulp_get_port_instance(opaque_t port_handle)
1706 {
1707         fc_local_port_t *port = port_handle;
1708 
1709         return (port->fp_instance);
1710 }
1711 
1712 
1713 opaque_t
1714 fc_ulp_get_port_handle(int port_instance)
1715 {
1716         opaque_t        port_handle = NULL;
1717         fc_fca_port_t   *cur;
1718 
1719         mutex_enter(&fctl_port_lock);
1720         for (cur = fctl_fca_portlist; cur; cur = cur->port_next) {
1721                 if (cur->port_handle->fp_instance == port_instance) {
1722                         port_handle = (opaque_t)cur->port_handle;
1723                         break;
1724                 }
1725         }
1726         mutex_exit(&fctl_port_lock);
1727 
1728         return (port_handle);
1729 }
1730 
1731 
1732 int
1733 fc_ulp_error(int fc_errno, char **errmsg)
1734 {
1735         return (fctl_error(fc_errno, errmsg));
1736 }
1737 
1738 
1739 int
1740 fc_ulp_pkt_error(fc_packet_t *pkt, char **state, char **reason,
1741     char **action, char **expln)
1742 {
1743         return (fctl_pkt_error(pkt, state, reason, action, expln));
1744 }
1745 
1746 
1747 /*
1748  * If an ULP by the specified name exists, return FC_SUCCESS, else FC_FAILURE
1749  */
1750 int
1751 fc_ulp_is_name_present(caddr_t ulp_name)
1752 {
1753         int             rval = FC_FAILURE;
1754         fc_ulp_list_t   *list;
1755 
1756         mutex_enter(&fctl_ulp_list_mutex);
1757         for (list = fctl_ulp_list; list != NULL; list = list->ulp_next) {
1758                 if (strcmp(list->ulp_info->ulp_name, ulp_name) == 0) {
1759                         rval = FC_SUCCESS;
1760                         break;
1761                 }
1762         }
1763         mutex_exit(&fctl_ulp_list_mutex);
1764 
1765         return (rval);
1766 }
1767 
1768 
1769 /*
1770  * Return port WWN for a port Identifier
1771  */
1772 int
1773 fc_ulp_get_pwwn_by_did(opaque_t port_handle, fc_portid_t d_id, la_wwn_t *pwwn)
1774 {
1775         int                     rval = FC_FAILURE;
1776         fc_remote_port_t        *pd;
1777         fc_local_port_t         *port = port_handle;
1778 
1779         pd = fctl_get_remote_port_by_did(port, d_id.port_id);
1780         if (pd != NULL) {
1781                 mutex_enter(&pd->pd_mutex);
1782                 *pwwn = pd->pd_port_name;
1783                 mutex_exit(&pd->pd_mutex);
1784                 rval = FC_SUCCESS;
1785         }
1786 
1787         return (rval);
1788 }
1789 
1790 
1791 /*
1792  * Return a port map for a port WWN
1793  */
1794 int
1795 fc_ulp_pwwn_to_portmap(opaque_t port_handle, la_wwn_t *bytes, fc_portmap_t *map)
1796 {
1797         fc_local_port_t         *port = port_handle;
1798         fc_remote_node_t        *node;
1799         fc_remote_port_t        *pd;
1800 
1801         pd = fctl_get_remote_port_by_pwwn(port, bytes);
1802         if (pd == NULL) {
1803                 return (FC_FAILURE);
1804         }
1805 
1806         mutex_enter(&pd->pd_mutex);
1807         map->map_pwwn = pd->pd_port_name;
1808         map->map_did = pd->pd_port_id;
1809         map->map_hard_addr = pd->pd_hard_addr;
1810         map->map_state = pd->pd_state;
1811         map->map_type = pd->pd_type;
1812         map->map_flags = 0;
1813 
1814         ASSERT(map->map_type <= PORT_DEVICE_DELETE);
1815 
1816         bcopy(pd->pd_fc4types, map->map_fc4_types, sizeof (pd->pd_fc4types));
1817 
1818         node = pd->pd_remote_nodep;
1819         mutex_exit(&pd->pd_mutex);
1820 
1821         if (node) {
1822                 mutex_enter(&node->fd_mutex);
1823                 map->map_nwwn = node->fd_node_name;
1824                 mutex_exit(&node->fd_mutex);
1825         }
1826         map->map_pd = pd;
1827 
1828         return (FC_SUCCESS);
1829 }
1830 
1831 
1832 opaque_t
1833 fc_ulp_get_fca_device(opaque_t port_handle, fc_portid_t d_id)
1834 {
1835         fc_local_port_t *port = port_handle;
1836 
1837         if (port->fp_fca_tran->fca_get_device == NULL) {
1838                 return (NULL);
1839         }
1840 
1841         return (port->fp_fca_tran->fca_get_device(port->fp_fca_handle, d_id));
1842 }
1843 
1844 
1845 int
1846 fc_ulp_port_notify(opaque_t port_handle, uint32_t cmd)
1847 {
1848         int             rval = FC_SUCCESS;
1849         fc_local_port_t *port = port_handle;
1850 
1851         if (port->fp_fca_tran->fca_notify) {
1852                 mutex_enter(&port->fp_mutex);
1853                 switch (cmd) {
1854                 case FC_NOTIFY_TARGET_MODE:
1855                         port->fp_options |= FP_TARGET_MODE;
1856                         break;
1857                 case FC_NOTIFY_NO_TARGET_MODE:
1858                         port->fp_options &= ~FP_TARGET_MODE;
1859                         break;
1860                 }
1861                 mutex_exit(&port->fp_mutex);
1862                 rval = port->fp_fca_tran->fca_notify(port->fp_fca_handle, cmd);
1863         }
1864 
1865         return (rval);
1866 }
1867 
1868 
1869 void
1870 fc_ulp_disable_relogin(opaque_t *fc_port, la_wwn_t *pwwn)
1871 {
1872         fc_remote_port_t *pd =
1873             fctl_get_remote_port_by_pwwn((fc_local_port_t *)fc_port, pwwn);
1874 
1875         if (pd) {
1876                 mutex_enter(&pd->pd_mutex);
1877                 pd->pd_aux_flags |= PD_DISABLE_RELOGIN;
1878                 mutex_exit(&pd->pd_mutex);
1879         }
1880 }
1881 
1882 
1883 void
1884 fc_ulp_enable_relogin(opaque_t *fc_port, la_wwn_t *pwwn)
1885 {
1886         fc_remote_port_t *pd =
1887             fctl_get_remote_port_by_pwwn((fc_local_port_t *)fc_port, pwwn);
1888 
1889         if (pd) {
1890                 mutex_enter(&pd->pd_mutex);
1891                 pd->pd_aux_flags &= ~PD_DISABLE_RELOGIN;
1892                 mutex_exit(&pd->pd_mutex);
1893         }
1894 }
1895 
1896 
1897 /*
1898  * fc_fca_init
1899  *              Overload the FCA bus_ops vector in its dev_ops with
1900  *              fctl_fca_busops to handle all the INITchilds for "sf"
1901  *              in one common place.
1902  *
1903  *              Should be called from FCA _init routine.
1904  */
1905 void
1906 fc_fca_init(struct dev_ops *fca_devops_p)
1907 {
1908         fca_devops_p->devo_bus_ops = &fctl_fca_busops;
1909 }
1910 
1911 
1912 /*
1913  * fc_fca_attach
1914  */
1915 int
1916 fc_fca_attach(dev_info_t *fca_dip, fc_fca_tran_t *tran)
1917 {
1918         /*
1919          * When we are in a position to offer downward compatibility
1920          * we should change the following check to allow lower revision
1921          * of FCAs; But we aren't there right now.
1922          */
1923         if (tran->fca_version != FCTL_FCA_MODREV_5) {
1924                 const char *name = ddi_driver_name(fca_dip);
1925 
1926                 ASSERT(name != NULL);
1927 
1928                 cmn_err(CE_WARN, "fctl: FCA %s version mismatch"
1929                     " please upgrade %s", name, name);
1930                 return (DDI_FAILURE);
1931         }
1932 
1933         ddi_set_driver_private(fca_dip, (caddr_t)tran);
1934         return (DDI_SUCCESS);
1935 }
1936 
1937 
1938 /*
1939  * fc_fca_detach
1940  */
1941 int
1942 fc_fca_detach(dev_info_t *fca_dip)
1943 {
1944         ddi_set_driver_private(fca_dip, NULL);
1945         return (DDI_SUCCESS);
1946 }
1947 
1948 
1949 /*
1950  * Check if the frame is a Link response Frame; Handle all cases (P_RJT,
1951  * F_RJT, P_BSY, F_BSY fall into this category). Check also for some Basic
1952  * Link Service responses such as BA_RJT and Extended Link Service response
1953  * such as LS_RJT. If the response is a Link_Data Frame or something that
1954  * this function doesn't understand return FC_FAILURE; Otherwise, fill out
1955  * various fields (state, action, reason, expln) from the response gotten
1956  * in the packet and return FC_SUCCESS.
1957  */
1958 int
1959 fc_fca_update_errors(fc_packet_t *pkt)
1960 {
1961         int ret = FC_SUCCESS;
1962 
1963         switch (pkt->pkt_resp_fhdr.r_ctl) {
1964         case R_CTL_P_RJT: {
1965                 uint32_t prjt;
1966 
1967                 prjt = pkt->pkt_resp_fhdr.ro;
1968                 pkt->pkt_state = FC_PKT_NPORT_RJT;
1969                 pkt->pkt_action = (prjt & 0xFF000000) >> 24;
1970                 pkt->pkt_reason = (prjt & 0xFF0000) >> 16;
1971                 break;
1972         }
1973 
1974         case R_CTL_F_RJT: {
1975                 uint32_t frjt;
1976 
1977                 frjt = pkt->pkt_resp_fhdr.ro;
1978                 pkt->pkt_state = FC_PKT_FABRIC_RJT;
1979                 pkt->pkt_action = (frjt & 0xFF000000) >> 24;
1980                 pkt->pkt_reason = (frjt & 0xFF0000) >> 16;
1981                 break;
1982         }
1983 
1984         case R_CTL_P_BSY: {
1985                 uint32_t pbsy;
1986 
1987                 pbsy = pkt->pkt_resp_fhdr.ro;
1988                 pkt->pkt_state = FC_PKT_NPORT_BSY;
1989                 pkt->pkt_action = (pbsy & 0xFF000000) >> 24;
1990                 pkt->pkt_reason = (pbsy & 0xFF0000) >> 16;
1991                 break;
1992         }
1993 
1994         case R_CTL_F_BSY_LC:
1995         case R_CTL_F_BSY_DF: {
1996                 uchar_t fbsy;
1997 
1998                 fbsy = pkt->pkt_resp_fhdr.type;
1999                 pkt->pkt_state = FC_PKT_FABRIC_BSY;
2000                 pkt->pkt_reason = (fbsy & 0xF0) >> 4;
2001                 break;
2002         }
2003 
2004         case R_CTL_LS_BA_RJT: {
2005                 uint32_t brjt;
2006 
2007                 brjt = *(uint32_t *)pkt->pkt_resp;
2008                 pkt->pkt_state = FC_PKT_BA_RJT;
2009                 pkt->pkt_reason = (brjt & 0xFF0000) >> 16;
2010                 pkt->pkt_expln = (brjt & 0xFF00) >> 8;
2011                 break;
2012         }
2013 
2014         case R_CTL_ELS_RSP: {
2015                 la_els_rjt_t *lsrjt;
2016 
2017                 lsrjt = (la_els_rjt_t *)pkt->pkt_resp;
2018                 if (lsrjt->ls_code.ls_code == LA_ELS_RJT) {
2019                         pkt->pkt_state = FC_PKT_LS_RJT;
2020                         pkt->pkt_reason = lsrjt->reason;
2021                         pkt->pkt_action = lsrjt->action;
2022                         break;
2023                 }
2024                 /* FALLTHROUGH */
2025         }
2026 
2027         default:
2028                 ret = FC_FAILURE;
2029                 break;
2030         }
2031 
2032         return (ret);
2033 }
2034 
2035 
2036 int
2037 fc_fca_error(int fc_errno, char **errmsg)
2038 {
2039         return (fctl_error(fc_errno, errmsg));
2040 }
2041 
2042 
2043 int
2044 fc_fca_pkt_error(fc_packet_t *pkt, char **state, char **reason,
2045     char **action, char **expln)
2046 {
2047         return (fctl_pkt_error(pkt, state, reason, action, expln));
2048 }
2049 
2050 
2051 /*
2052  * WWN to string goodie. Unpredictable results will happen
2053  * if enough memory isn't supplied in str argument. If you
2054  * are wondering how much does this routine need, it is just
2055  * (2 * WWN size + 1). So for a WWN size of 8 bytes the str
2056  * argument should have atleast 17 bytes allocated.
2057  */
2058 void
2059 fc_wwn_to_str(la_wwn_t *wwn, caddr_t str)
2060 {
2061         int count;
2062 
2063         for (count = 0; count < FCTL_WWN_SIZE(wwn); count++, str += 2) {
2064                 (void) sprintf(str, "%02x", wwn->raw_wwn[count]);
2065         }
2066         *str = '\0';
2067 }
2068 
2069 #define FC_ATOB(x)      (((x) >= '0' && (x) <= '9') ? ((x) - '0') :       \
2070                         ((x) >= 'a' && (x) <= 'f') ?                      \
2071                         ((x) - 'a' + 10) : ((x) - 'A' + 10))
2072 
2073 void
2074 fc_str_to_wwn(caddr_t str, la_wwn_t *wwn)
2075 {
2076         int count = 0;
2077         uchar_t byte;
2078 
2079         while (*str) {
2080                 byte = FC_ATOB(*str);
2081                 str++;
2082                 byte = byte << 4 | FC_ATOB(*str);
2083                 str++;
2084                 wwn->raw_wwn[count++] = byte;
2085         }
2086 }
2087 
2088 /*
2089  * FCA driver's intercepted bus control operations.
2090  */
2091 static int
2092 fctl_fca_bus_ctl(dev_info_t *fca_dip, dev_info_t *rip,
2093     ddi_ctl_enum_t op, void *arg, void *result)
2094 {
2095         switch (op) {
2096         case DDI_CTLOPS_REPORTDEV:
2097                 break;
2098 
2099         case DDI_CTLOPS_IOMIN:
2100                 break;
2101 
2102         case DDI_CTLOPS_INITCHILD:
2103                 return (fctl_initchild(fca_dip, (dev_info_t *)arg));
2104 
2105         case DDI_CTLOPS_UNINITCHILD:
2106                 return (fctl_uninitchild(fca_dip, (dev_info_t *)arg));
2107 
2108         default:
2109                 return (ddi_ctlops(fca_dip, rip, op, arg, result));
2110         }
2111 
2112         return (DDI_SUCCESS);
2113 }
2114 
2115 
2116 /*
2117  * FCAs indicate the maximum number of ports supported in their
2118  * tran structure. Fail the INITCHILD if the child port number
2119  * is any greater than the maximum number of ports supported
2120  * by the FCA.
2121  */
2122 static int
2123 fctl_initchild(dev_info_t *fca_dip, dev_info_t *port_dip)
2124 {
2125         int             rval;
2126         int             port_no;
2127         int             port_len;
2128         char            name[20];
2129         fc_fca_tran_t   *tran;
2130         dev_info_t      *dip;
2131         int             portprop;
2132 
2133         port_len = sizeof (port_no);
2134 
2135         /* physical port do not has this property */
2136         portprop = ddi_prop_get_int(DDI_DEV_T_ANY, port_dip,
2137             DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
2138             "phyport-instance", -1);
2139 
2140         if ((portprop == -1) && ndi_dev_is_persistent_node(port_dip)) {
2141                 /*
2142                  * Clear any addr bindings created by fcode interpreter
2143                  * in devi_last_addr so that a ndi_devi_find should never
2144                  * return this fcode node.
2145                  */
2146                 ddi_set_name_addr(port_dip, NULL);
2147                 return (DDI_FAILURE);
2148         }
2149 
2150         rval = ddi_prop_op(DDI_DEV_T_ANY, port_dip, PROP_LEN_AND_VAL_BUF,
2151             DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port",
2152             (caddr_t)&port_no, &port_len);
2153 
2154         if (rval != DDI_SUCCESS) {
2155                 return (DDI_FAILURE);
2156         }
2157 
2158         tran = (fc_fca_tran_t *)ddi_get_driver_private(fca_dip);
2159         ASSERT(tran != NULL);
2160 
2161         (void) sprintf((char *)name, "%x,0", port_no);
2162         ddi_set_name_addr(port_dip, name);
2163 
2164         dip = ndi_devi_find(fca_dip, ddi_binding_name(port_dip), name);
2165 
2166         /*
2167          * Even though we never initialize FCode nodes of fp, such a node
2168          * could still be there after a DR operation. There will only be
2169          * one FCode node, so if this is the one, clear it and issue a
2170          * ndi_devi_find again.
2171          */
2172         if ((portprop == -1) && dip && ndi_dev_is_persistent_node(dip)) {
2173                 ddi_set_name_addr(dip, NULL);
2174                 dip = ndi_devi_find(fca_dip, ddi_binding_name(port_dip), name);
2175         }
2176 
2177         if ((portprop == -1) && dip && (dip != port_dip)) {
2178                 /*
2179                  * Here we have a duplicate .conf entry. Clear the addr
2180                  * set previously and return failure.
2181                  */
2182                 ddi_set_name_addr(port_dip, NULL);
2183                 return (DDI_FAILURE);
2184         }
2185 
2186         return (DDI_SUCCESS);
2187 }
2188 
2189 
2190 /* ARGSUSED */
2191 static int
2192 fctl_uninitchild(dev_info_t *fca_dip, dev_info_t *port_dip)
2193 {
2194         ddi_set_name_addr(port_dip, NULL);
2195         return (DDI_SUCCESS);
2196 }
2197 
2198 
2199 static dev_info_t *
2200 fctl_findchild(dev_info_t *pdip, char *cname, char *caddr)
2201 {
2202         dev_info_t *dip;
2203         char *addr;
2204 
2205         ASSERT(cname != NULL && caddr != NULL);
2206         /* ASSERT(DEVI_BUSY_OWNED(pdip)); */
2207 
2208         for (dip = ddi_get_child(pdip); dip != NULL;
2209             dip = ddi_get_next_sibling(dip)) {
2210                 if (strcmp(cname, ddi_node_name(dip)) != 0) {
2211                         continue;
2212                 }
2213 
2214                 if ((addr = ddi_get_name_addr(dip)) == NULL) {
2215                         if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
2216                             DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
2217                             "bus-addr", &addr) == DDI_PROP_SUCCESS) {
2218                                 if (strcmp(caddr, addr) == 0) {
2219                                         ddi_prop_free(addr);
2220                                         return (dip);
2221                                 }
2222                                 ddi_prop_free(addr);
2223                         }
2224                 } else {
2225                         if (strcmp(caddr, addr) == 0) {
2226                                 return (dip);
2227                         }
2228                 }
2229         }
2230 
2231         return (NULL);
2232 }
2233 
2234 int
2235 fctl_check_npiv_portindex(dev_info_t *dip, int vindex)
2236 {
2237         int i, instance;
2238         fc_local_port_t *port;
2239 
2240         instance = ddi_get_instance(dip);
2241         port = (fc_local_port_t *)fc_ulp_get_port_handle(instance);
2242         if ((!port) || (vindex <= 0) || (vindex >= FC_NPIV_MAX_PORT)) {
2243                 return (0);
2244         }
2245 
2246         i = vindex-1;
2247         mutex_enter(&port->fp_mutex);
2248         if (port->fp_npiv_portindex[i] == 0) {
2249                 mutex_exit(&port->fp_mutex);
2250                 return (vindex);
2251         }
2252         mutex_exit(&port->fp_mutex);
2253         return (0);
2254 }
2255 
2256 int
2257 fctl_get_npiv_portindex(dev_info_t *dip)
2258 {
2259         int i, instance;
2260         fc_local_port_t *port;
2261 
2262         instance = ddi_get_instance(dip);
2263         port = (fc_local_port_t *)fc_ulp_get_port_handle(instance);
2264         if (!port) {
2265                 return (0);
2266         }
2267 
2268         mutex_enter(&port->fp_mutex);
2269         for (i = 0; i < FC_NPIV_MAX_PORT; i++) {
2270                 if (port->fp_npiv_portindex[i] == 0) {
2271                         mutex_exit(&port->fp_mutex);
2272                         return (i+1);
2273                 }
2274         }
2275         mutex_exit(&port->fp_mutex);
2276         return (0);
2277 }
2278 
2279 
2280 void
2281 fctl_set_npiv_portindex(dev_info_t *dip, int index)
2282 {
2283         int instance;
2284         fc_local_port_t *port;
2285 
2286         instance = ddi_get_instance(dip);
2287         port = (fc_local_port_t *)fc_ulp_get_port_handle(instance);
2288         if (!port) {
2289                 return;
2290         }
2291         mutex_enter(&port->fp_mutex);
2292         port->fp_npiv_portindex[index - 1] = 1;
2293         mutex_exit(&port->fp_mutex);
2294 }
2295 
2296 
2297 int
2298 fctl_fca_create_npivport(dev_info_t *parent,
2299     dev_info_t *phydip, char *nname, char *pname, uint32_t *vindex)
2300 {
2301         int rval = 0, devstrlen;
2302         char    *devname, *cname, *caddr, *devstr;
2303         dev_info_t      *child = NULL;
2304         int             portnum;
2305 
2306         if (*vindex == 0) {
2307                 portnum = fctl_get_npiv_portindex(phydip);
2308                 *vindex = portnum;
2309         } else {
2310                 portnum = fctl_check_npiv_portindex(phydip, *vindex);
2311         }
2312 
2313         if (portnum == 0) {
2314                 cmn_err(CE_WARN,
2315                     "Cann't find valid port index, fail to create devnode");
2316                 return (NDI_FAILURE);
2317         }
2318 
2319         devname = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
2320         (void) sprintf(devname, "fp@%x,0", portnum);
2321         devstrlen = strlen(devname) + 1;
2322         devstr = i_ddi_strdup(devname, KM_SLEEP);
2323         i_ddi_parse_name(devstr, &cname, &caddr, NULL);
2324 
2325         if (fctl_findchild(parent, cname, caddr) != NULL) {
2326                 rval = NDI_FAILURE;
2327                 goto freememory;
2328         }
2329 
2330         ndi_devi_alloc_sleep(parent, cname, DEVI_PSEUDO_NODEID, &child);
2331         if (child == NULL) {
2332                 cmn_err(CE_WARN,
2333                     "fctl_create_npiv_port fail to create new devinfo");
2334                 rval = NDI_FAILURE;
2335                 goto freememory;
2336         }
2337 
2338         if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
2339             "bus-addr", caddr) != DDI_PROP_SUCCESS) {
2340                 cmn_err(CE_WARN, "fctl%d: prop update bus-addr %s@%s failed",
2341                     ddi_get_instance(parent), cname, caddr);
2342                 (void) ndi_devi_free(child);
2343                 rval = NDI_FAILURE;
2344                 goto freememory;
2345         }
2346 
2347         if (strlen(nname) != 0) {
2348                 if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
2349                     "node-name", nname) != DDI_PROP_SUCCESS) {
2350                         (void) ndi_devi_free(child);
2351                         rval = NDI_FAILURE;
2352                         goto freememory;
2353                 }
2354         }
2355 
2356         if (strlen(pname) != 0) {
2357                 if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
2358                     "port-name", pname) != DDI_PROP_SUCCESS) {
2359                         (void) ndi_devi_free(child);
2360                         rval = NDI_FAILURE;
2361                         goto freememory;
2362                 }
2363         }
2364 
2365         if (ddi_prop_update_int(DDI_DEV_T_NONE, child,
2366             "port", portnum) != DDI_PROP_SUCCESS) {
2367                 cmn_err(CE_WARN, "fp%d: prop_update port %s@%s failed",
2368                     ddi_get_instance(parent), cname, caddr);
2369                 (void) ndi_devi_free(child);
2370                 rval = NDI_FAILURE;
2371                 goto freememory;
2372         }
2373 
2374         if (ddi_prop_update_int(DDI_DEV_T_NONE, child,
2375             "phyport-instance", ddi_get_instance(phydip)) != DDI_PROP_SUCCESS) {
2376                 cmn_err(CE_WARN,
2377                     "fp%d: prop_update phyport-instance %s@%s failed",
2378                     ddi_get_instance(parent), cname, caddr);
2379                 (void) ndi_devi_free(child);
2380                 rval = NDI_FAILURE;
2381                 goto freememory;
2382         }
2383 
2384         rval = ndi_devi_online(child, NDI_ONLINE_ATTACH);
2385         if (rval != NDI_SUCCESS) {
2386                 cmn_err(CE_WARN, "fp%d: online_driver %s failed",
2387                     ddi_get_instance(parent), cname);
2388                 rval = NDI_FAILURE;
2389                 goto freememory;
2390         }
2391 
2392         fctl_set_npiv_portindex(phydip, portnum);
2393 freememory:
2394         kmem_free(devstr, devstrlen);
2395         kmem_free(devname, MAXNAMELEN);
2396 
2397         return (rval);
2398 }
2399 
2400 
2401 void
2402 fctl_add_port(fc_local_port_t *port)
2403 {
2404         fc_fca_port_t *new;
2405 
2406         new = kmem_zalloc(sizeof (*new), KM_SLEEP);
2407 
2408         mutex_enter(&fctl_port_lock);
2409         new->port_handle = port;
2410         new->port_next = fctl_fca_portlist;
2411         fctl_fca_portlist = new;
2412         mutex_exit(&fctl_port_lock);
2413 }
2414 
2415 
2416 void
2417 fctl_remove_port(fc_local_port_t *port)
2418 {
2419         fc_ulp_module_t         *mod;
2420         fc_fca_port_t           *prev;
2421         fc_fca_port_t           *list;
2422         fc_ulp_ports_t          *ulp_port;
2423 
2424         rw_enter(&fctl_ulp_lock, RW_WRITER);
2425         rw_enter(&fctl_mod_ports_lock, RW_WRITER);
2426 
2427         for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
2428                 ulp_port = fctl_get_ulp_port(mod, port);
2429                 if (ulp_port == NULL) {
2430                         continue;
2431                 }
2432 
2433                 ASSERT((ulp_port->port_dstate & ULP_PORT_ATTACH) == 0);
2434 
2435                 (void) fctl_remove_ulp_port(mod, port);
2436         }
2437 
2438         rw_exit(&fctl_mod_ports_lock);
2439         rw_exit(&fctl_ulp_lock);
2440 
2441         mutex_enter(&fctl_port_lock);
2442 
2443         list = fctl_fca_portlist;
2444         prev = NULL;
2445         while (list != NULL) {
2446                 if (list->port_handle == port) {
2447                         if (prev == NULL) {
2448                                 fctl_fca_portlist = list->port_next;
2449                         } else {
2450                                 prev->port_next = list->port_next;
2451                         }
2452                         kmem_free(list, sizeof (*list));
2453                         break;
2454                 }
2455                 prev = list;
2456                 list = list->port_next;
2457         }
2458         mutex_exit(&fctl_port_lock);
2459 }
2460 
2461 
2462 void
2463 fctl_attach_ulps(fc_local_port_t *port, fc_attach_cmd_t cmd,
2464     struct modlinkage *linkage)
2465 {
2466         int                     rval;
2467         uint32_t                s_id;
2468         uint32_t                state;
2469         fc_ulp_module_t         *mod;
2470         fc_ulp_port_info_t      info;
2471         fc_ulp_ports_t          *ulp_port;
2472 
2473         ASSERT(!MUTEX_HELD(&port->fp_mutex));
2474 
2475         info.port_linkage = linkage;
2476         info.port_dip = port->fp_port_dip;
2477         info.port_handle = (opaque_t)port;
2478         info.port_dma_behavior = port->fp_dma_behavior;
2479         info.port_fcp_dma = port->fp_fcp_dma;
2480         info.port_acc_attr = port->fp_fca_tran->fca_acc_attr;
2481         info.port_fca_pkt_size = port->fp_fca_tran->fca_pkt_size;
2482         info.port_reset_action = port->fp_reset_action;
2483 
2484         mutex_enter(&port->fp_mutex);
2485 
2486         /*
2487          * It is still possible that another thread could have gotten
2488          * into the detach process before we got here.
2489          */
2490         if (port->fp_soft_state & FP_SOFT_IN_DETACH) {
2491                 mutex_exit(&port->fp_mutex);
2492                 return;
2493         }
2494 
2495         s_id = port->fp_port_id.port_id;
2496         if (port->fp_statec_busy) {
2497                 info.port_state = port->fp_bind_state;
2498         } else {
2499                 info.port_state = port->fp_state;
2500         }
2501 
2502         switch (state = FC_PORT_STATE_MASK(info.port_state)) {
2503         case FC_STATE_LOOP:
2504         case FC_STATE_NAMESERVICE:
2505                 info.port_state &= ~state;
2506                 info.port_state |= FC_STATE_ONLINE;
2507                 break;
2508 
2509         default:
2510                 break;
2511         }
2512         ASSERT((info.port_state & FC_STATE_LOOP) == 0);
2513 
2514         info.port_flags = port->fp_topology;
2515         info.port_pwwn = port->fp_service_params.nport_ww_name;
2516         info.port_nwwn = port->fp_service_params.node_ww_name;
2517         mutex_exit(&port->fp_mutex);
2518 
2519         rw_enter(&fctl_ulp_lock, RW_READER);
2520         rw_enter(&fctl_mod_ports_lock, RW_WRITER);
2521 
2522         for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
2523                 if ((port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) &&
2524                     (mod->mod_info->ulp_type == FC_TYPE_IS8802_SNAP)) {
2525                         /*
2526                          * We don't support IP over FC on FCOE HBA
2527                          */
2528                         continue;
2529                 }
2530 
2531                 if ((ulp_port = fctl_get_ulp_port(mod, port)) == NULL) {
2532                         ulp_port = fctl_add_ulp_port(mod, port, KM_SLEEP);
2533                         ASSERT(ulp_port != NULL);
2534 
2535                         mutex_enter(&ulp_port->port_mutex);
2536                         ulp_port->port_statec = ((info.port_state &
2537                             FC_STATE_ONLINE) ? FC_ULP_STATEC_ONLINE :
2538                             FC_ULP_STATEC_OFFLINE);
2539                         mutex_exit(&ulp_port->port_mutex);
2540                 }
2541         }
2542 
2543         rw_downgrade(&fctl_mod_ports_lock);
2544 
2545         for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
2546                 if ((port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) &&
2547                     (mod->mod_info->ulp_type == FC_TYPE_IS8802_SNAP)) {
2548                         /*
2549                          * We don't support IP over FC on FCOE HBA
2550                          */
2551                         continue;
2552                 }
2553 
2554                 ulp_port = fctl_get_ulp_port(mod, port);
2555                 ASSERT(ulp_port != NULL);
2556 
2557                 if (fctl_pre_attach(ulp_port, cmd) == FC_FAILURE) {
2558                         continue;
2559                 }
2560 
2561                 fctl_init_dma_attr(port, mod, &info);
2562 
2563                 rval = mod->mod_info->ulp_port_attach(
2564                     mod->mod_info->ulp_handle, &info, cmd, s_id);
2565 
2566                 fctl_post_attach(mod, ulp_port, cmd, rval);
2567 
2568                 if (rval == FC_SUCCESS && cmd == FC_CMD_ATTACH &&
2569                     strcmp(mod->mod_info->ulp_name, "fcp") == 0) {
2570                         ASSERT(ddi_get_driver_private(info.port_dip) != NULL);
2571                 }
2572         }
2573 
2574         rw_exit(&fctl_mod_ports_lock);
2575         rw_exit(&fctl_ulp_lock);
2576 }
2577 
2578 
2579 static int
2580 fctl_pre_attach(fc_ulp_ports_t *ulp_port, fc_attach_cmd_t cmd)
2581 {
2582         int rval = FC_SUCCESS;
2583 
2584         mutex_enter(&ulp_port->port_mutex);
2585 
2586         switch (cmd) {
2587         case FC_CMD_ATTACH:
2588                 if (ulp_port->port_dstate & ULP_PORT_ATTACH) {
2589                         rval = FC_FAILURE;
2590                 }
2591                 break;
2592 
2593         case FC_CMD_RESUME:
2594                 ASSERT((ulp_port->port_dstate & ULP_PORT_POWER_DOWN) == 0);
2595                 if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) ||
2596                     !(ulp_port->port_dstate & ULP_PORT_SUSPEND)) {
2597                         rval = FC_FAILURE;
2598                 }
2599                 break;
2600 
2601         case FC_CMD_POWER_UP:
2602                 if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) ||
2603                     !(ulp_port->port_dstate & ULP_PORT_POWER_DOWN)) {
2604                         rval = FC_FAILURE;
2605                 }
2606                 break;
2607         }
2608 
2609         if (rval == FC_SUCCESS) {
2610                 ulp_port->port_dstate |= ULP_PORT_BUSY;
2611         }
2612         mutex_exit(&ulp_port->port_mutex);
2613 
2614         return (rval);
2615 }
2616 
2617 
2618 static void
2619 fctl_post_attach(fc_ulp_module_t *mod, fc_ulp_ports_t *ulp_port,
2620     fc_attach_cmd_t cmd, int rval)
2621 {
2622         int     be_chatty;
2623 
2624         ASSERT(cmd == FC_CMD_ATTACH || cmd == FC_CMD_RESUME ||
2625             cmd == FC_CMD_POWER_UP);
2626 
2627         mutex_enter(&ulp_port->port_mutex);
2628         ulp_port->port_dstate &= ~ULP_PORT_BUSY;
2629 
2630         be_chatty = (rval == FC_FAILURE_SILENT) ? 0 : 1;
2631 
2632         if (rval != FC_SUCCESS) {
2633                 caddr_t         op;
2634                 fc_local_port_t *port = ulp_port->port_handle;
2635 
2636                 mutex_exit(&ulp_port->port_mutex);
2637 
2638                 switch (cmd) {
2639                 case FC_CMD_ATTACH:
2640                         op = "attach";
2641                         break;
2642 
2643                 case FC_CMD_RESUME:
2644                         op = "resume";
2645                         break;
2646 
2647                 case FC_CMD_POWER_UP:
2648                         op = "power up";
2649                         break;
2650                 }
2651 
2652                 if (be_chatty) {
2653                         cmn_err(CE_WARN, "!fctl(%d): %s failed for %s",
2654                             port->fp_instance, op, mod->mod_info->ulp_name);
2655                 }
2656 
2657                 return;
2658         }
2659 
2660         switch (cmd) {
2661         case FC_CMD_ATTACH:
2662                 ulp_port->port_dstate |= ULP_PORT_ATTACH;
2663                 break;
2664 
2665         case FC_CMD_RESUME:
2666                 ulp_port->port_dstate &= ~ULP_PORT_SUSPEND;
2667                 break;
2668 
2669         case FC_CMD_POWER_UP:
2670                 ulp_port->port_dstate &= ~ULP_PORT_POWER_DOWN;
2671                 break;
2672         }
2673         mutex_exit(&ulp_port->port_mutex);
2674 }
2675 
2676 
2677 int
2678 fctl_detach_ulps(fc_local_port_t *port, fc_detach_cmd_t cmd,
2679     struct modlinkage *linkage)
2680 {
2681         int                     rval = FC_SUCCESS;
2682         fc_ulp_module_t         *mod;
2683         fc_ulp_port_info_t      info;
2684         fc_ulp_ports_t          *ulp_port;
2685 
2686         ASSERT(!MUTEX_HELD(&port->fp_mutex));
2687 
2688         info.port_linkage = linkage;
2689         info.port_dip = port->fp_port_dip;
2690         info.port_handle = (opaque_t)port;
2691         info.port_acc_attr = port->fp_fca_tran->fca_acc_attr;
2692         info.port_fca_pkt_size = port->fp_fca_tran->fca_pkt_size;
2693 
2694         rw_enter(&fctl_ulp_lock, RW_READER);
2695         rw_enter(&fctl_mod_ports_lock, RW_READER);
2696 
2697         for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
2698                 if ((ulp_port = fctl_get_ulp_port(mod, port)) == NULL) {
2699                         continue;
2700                 }
2701 
2702                 if (fctl_pre_detach(ulp_port, cmd) != FC_SUCCESS) {
2703                         continue;
2704                 }
2705 
2706                 fctl_init_dma_attr(port, mod, &info);
2707 
2708                 rval = mod->mod_info->ulp_port_detach(
2709                     mod->mod_info->ulp_handle, &info, cmd);
2710 
2711                 fctl_post_detach(mod, ulp_port, cmd, rval);
2712 
2713                 if (rval != FC_SUCCESS) {
2714                         break;
2715                 }
2716 
2717                 if (cmd == FC_CMD_DETACH && strcmp(mod->mod_info->ulp_name,
2718                     "fcp") == 0) {
2719                         ASSERT(ddi_get_driver_private(info.port_dip) == NULL);
2720                 }
2721 
2722                 mutex_enter(&ulp_port->port_mutex);
2723                 ulp_port->port_statec = FC_ULP_STATEC_DONT_CARE;
2724                 mutex_exit(&ulp_port->port_mutex);
2725         }
2726 
2727         rw_exit(&fctl_mod_ports_lock);
2728         rw_exit(&fctl_ulp_lock);
2729 
2730         return (rval);
2731 }
2732 
2733 static  void
2734 fctl_init_dma_attr(fc_local_port_t *port, fc_ulp_module_t *mod,
2735     fc_ulp_port_info_t  *info)
2736 {
2737 
2738         if ((strcmp(mod->mod_info->ulp_name, "fcp") == 0) ||
2739             (strcmp(mod->mod_info->ulp_name, "ltct") == 0)) {
2740                 info->port_cmd_dma_attr =
2741                     port->fp_fca_tran->fca_dma_fcp_cmd_attr;
2742                 info->port_data_dma_attr =
2743                     port->fp_fca_tran->fca_dma_fcp_data_attr;
2744                 info->port_resp_dma_attr =
2745                     port->fp_fca_tran->fca_dma_fcp_rsp_attr;
2746         } else if (strcmp(mod->mod_info->ulp_name, "fcsm") == 0) {
2747                 info->port_cmd_dma_attr =
2748                     port->fp_fca_tran->fca_dma_fcsm_cmd_attr;
2749                 info->port_data_dma_attr =
2750                     port->fp_fca_tran->fca_dma_attr;
2751                 info->port_resp_dma_attr =
2752                     port->fp_fca_tran->fca_dma_fcsm_rsp_attr;
2753         } else if (strcmp(mod->mod_info->ulp_name, "fcip") == 0) {
2754                 info->port_cmd_dma_attr =
2755                     port->fp_fca_tran->fca_dma_fcip_cmd_attr;
2756                 info->port_data_dma_attr =
2757                     port->fp_fca_tran->fca_dma_attr;
2758                 info->port_resp_dma_attr =
2759                     port->fp_fca_tran->fca_dma_fcip_rsp_attr;
2760         } else {
2761                 info->port_cmd_dma_attr = info->port_data_dma_attr =
2762                     info->port_resp_dma_attr =
2763                     port->fp_fca_tran->fca_dma_attr; /* default */
2764         }
2765 }
2766 
2767 static int
2768 fctl_pre_detach(fc_ulp_ports_t *ulp_port, fc_detach_cmd_t cmd)
2769 {
2770         int rval = FC_SUCCESS;
2771 
2772         mutex_enter(&ulp_port->port_mutex);
2773 
2774         switch (cmd) {
2775         case FC_CMD_DETACH:
2776                 if ((ulp_port->port_dstate & ULP_PORT_ATTACH) == 0) {
2777                         rval = FC_FAILURE;
2778                 }
2779                 break;
2780 
2781         case FC_CMD_SUSPEND:
2782                 if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) ||
2783                     ulp_port->port_dstate & ULP_PORT_SUSPEND) {
2784                         rval = FC_FAILURE;
2785                 }
2786                 break;
2787 
2788         case FC_CMD_POWER_DOWN:
2789                 if (!(ulp_port->port_dstate & ULP_PORT_ATTACH) ||
2790                     ulp_port->port_dstate & ULP_PORT_POWER_DOWN) {
2791                         rval = FC_FAILURE;
2792                 }
2793                 break;
2794         }
2795 
2796         if (rval == FC_SUCCESS) {
2797                 ulp_port->port_dstate |= ULP_PORT_BUSY;
2798         }
2799         mutex_exit(&ulp_port->port_mutex);
2800 
2801         return (rval);
2802 }
2803 
2804 
2805 static void
2806 fctl_post_detach(fc_ulp_module_t *mod, fc_ulp_ports_t *ulp_port,
2807     fc_detach_cmd_t cmd, int rval)
2808 {
2809         ASSERT(cmd == FC_CMD_DETACH || cmd == FC_CMD_SUSPEND ||
2810             cmd == FC_CMD_POWER_DOWN);
2811 
2812         mutex_enter(&ulp_port->port_mutex);
2813         ulp_port->port_dstate &= ~ULP_PORT_BUSY;
2814 
2815         if (rval != FC_SUCCESS) {
2816                 caddr_t         op;
2817                 fc_local_port_t *port = ulp_port->port_handle;
2818 
2819                 mutex_exit(&ulp_port->port_mutex);
2820 
2821                 switch (cmd) {
2822                 case FC_CMD_DETACH:
2823                         op = "detach";
2824                         break;
2825 
2826                 case FC_CMD_SUSPEND:
2827                         op = "suspend";
2828                         break;
2829 
2830                 case FC_CMD_POWER_DOWN:
2831                         op = "power down";
2832                         break;
2833                 }
2834 
2835                 cmn_err(CE_WARN, "!fctl(%d): %s failed for %s",
2836                     port->fp_instance, op, mod->mod_info->ulp_name);
2837 
2838                 return;
2839         }
2840 
2841         switch (cmd) {
2842         case FC_CMD_DETACH:
2843                 ulp_port->port_dstate &= ~ULP_PORT_ATTACH;
2844                 break;
2845 
2846         case FC_CMD_SUSPEND:
2847                 ulp_port->port_dstate |= ULP_PORT_SUSPEND;
2848                 break;
2849 
2850         case FC_CMD_POWER_DOWN:
2851                 ulp_port->port_dstate |= ULP_PORT_POWER_DOWN;
2852                 break;
2853         }
2854         mutex_exit(&ulp_port->port_mutex);
2855 }
2856 
2857 
2858 static fc_ulp_ports_t *
2859 fctl_add_ulp_port(fc_ulp_module_t *ulp_module, fc_local_port_t *port_handle,
2860     int sleep)
2861 {
2862         fc_ulp_ports_t *last;
2863         fc_ulp_ports_t *next;
2864         fc_ulp_ports_t *new;
2865 
2866         ASSERT(RW_READ_HELD(&fctl_ulp_lock));
2867         ASSERT(RW_WRITE_HELD(&fctl_mod_ports_lock));
2868 
2869         last = NULL;
2870         next = ulp_module->mod_ports;
2871 
2872         while (next != NULL) {
2873                 last = next;
2874                 next = next->port_next;
2875         }
2876 
2877         new = fctl_alloc_ulp_port(sleep);
2878         if (new == NULL) {
2879                 return (new);
2880         }
2881 
2882         new->port_handle = port_handle;
2883         if (last == NULL) {
2884                 ulp_module->mod_ports = new;
2885         } else {
2886                 last->port_next = new;
2887         }
2888 
2889         return (new);
2890 }
2891 
2892 
2893 static fc_ulp_ports_t *
2894 fctl_alloc_ulp_port(int sleep)
2895 {
2896         fc_ulp_ports_t *new;
2897 
2898         new = kmem_zalloc(sizeof (*new), sleep);
2899         if (new == NULL) {
2900                 return (new);
2901         }
2902         mutex_init(&new->port_mutex, NULL, MUTEX_DRIVER, NULL);
2903 
2904         return (new);
2905 }
2906 
2907 
2908 static int
2909 fctl_remove_ulp_port(struct ulp_module *ulp_module,
2910     fc_local_port_t *port_handle)
2911 {
2912         fc_ulp_ports_t *last;
2913         fc_ulp_ports_t *next;
2914 
2915         ASSERT(RW_WRITE_HELD(&fctl_ulp_lock));
2916         ASSERT(RW_WRITE_HELD(&fctl_mod_ports_lock));
2917 
2918         last = NULL;
2919         next = ulp_module->mod_ports;
2920 
2921         while (next != NULL) {
2922                 if (next->port_handle == port_handle) {
2923                         if (next->port_dstate & ULP_PORT_ATTACH) {
2924                                 return (FC_FAILURE);
2925                         }
2926                         break;
2927                 }
2928                 last = next;
2929                 next = next->port_next;
2930         }
2931 
2932         if (next != NULL) {
2933                 ASSERT((next->port_dstate & ULP_PORT_ATTACH) == 0);
2934 
2935                 if (last == NULL) {
2936                         ulp_module->mod_ports = next->port_next;
2937                 } else {
2938                         last->port_next = next->port_next;
2939                 }
2940                 fctl_dealloc_ulp_port(next);
2941 
2942                 return (FC_SUCCESS);
2943         } else {
2944                 return (FC_FAILURE);
2945         }
2946 }
2947 
2948 
2949 static void
2950 fctl_dealloc_ulp_port(fc_ulp_ports_t *next)
2951 {
2952         mutex_destroy(&next->port_mutex);
2953         kmem_free(next, sizeof (*next));
2954 }
2955 
2956 
2957 static fc_ulp_ports_t *
2958 fctl_get_ulp_port(struct ulp_module *ulp_module, fc_local_port_t *port_handle)
2959 {
2960         fc_ulp_ports_t *next;
2961 
2962         ASSERT(RW_LOCK_HELD(&fctl_ulp_lock));
2963         ASSERT(RW_LOCK_HELD(&fctl_mod_ports_lock));
2964 
2965         for (next = ulp_module->mod_ports; next != NULL;
2966             next = next->port_next) {
2967                 if (next->port_handle == port_handle) {
2968                         return (next);
2969                 }
2970         }
2971 
2972         return (NULL);
2973 }
2974 
2975 
2976 /*
2977  * Pass state change notfications on to registered ULPs.
2978  *
2979  * Can issue wakeups to client callers who might be waiting for completions
2980  * on other threads.
2981  *
2982  * Caution: will silently deallocate any fc_remote_port_t and/or
2983  * fc_remote_node_t structs it finds that are not in use.
2984  */
2985 void
2986 fctl_ulp_statec_cb(void *arg)
2987 {
2988         uint32_t                s_id;
2989         uint32_t                new_state;
2990         fc_local_port_t         *port;
2991         fc_ulp_ports_t          *ulp_port;
2992         fc_ulp_module_t         *mod;
2993         fc_port_clist_t         *clist = (fc_port_clist_t *)arg;
2994 
2995         ASSERT(clist != NULL);
2996 
2997         port = clist->clist_port;
2998 
2999         mutex_enter(&port->fp_mutex);
3000         s_id = port->fp_port_id.port_id;
3001         mutex_exit(&port->fp_mutex);
3002 
3003         switch (clist->clist_state) {
3004         case FC_STATE_ONLINE:
3005                 new_state = FC_ULP_STATEC_ONLINE;
3006                 break;
3007 
3008         case FC_STATE_OFFLINE:
3009                 if (clist->clist_len) {
3010                         new_state = FC_ULP_STATEC_OFFLINE_TIMEOUT;
3011                 } else {
3012                         new_state = FC_ULP_STATEC_OFFLINE;
3013                 }
3014                 break;
3015 
3016         default:
3017                 new_state = FC_ULP_STATEC_DONT_CARE;
3018                 break;
3019         }
3020 
3021 #ifdef  DEBUG
3022         /*
3023          * sanity check for presence of OLD devices in the hash lists
3024          */
3025         if (clist->clist_size) {
3026                 int                     count;
3027                 fc_remote_port_t        *pd;
3028 
3029                 ASSERT(clist->clist_map != NULL);
3030                 for (count = 0; count < clist->clist_len; count++) {
3031                         if (clist->clist_map[count].map_state ==
3032                             PORT_DEVICE_INVALID) {
3033                                 la_wwn_t        pwwn;
3034                                 fc_portid_t     d_id;
3035 
3036                                 pd = clist->clist_map[count].map_pd;
3037                                 if (pd != NULL) {
3038                                         mutex_enter(&pd->pd_mutex);
3039                                         pwwn = pd->pd_port_name;
3040                                         d_id = pd->pd_port_id;
3041                                         mutex_exit(&pd->pd_mutex);
3042 
3043                                         pd = fctl_get_remote_port_by_pwwn(port,
3044                                             &pwwn);
3045 
3046                                         ASSERT(pd != clist->clist_map[count].
3047                                             map_pd);
3048 
3049                                         pd = fctl_get_remote_port_by_did(port,
3050                                             d_id.port_id);
3051                                         ASSERT(pd != clist->clist_map[count].
3052                                             map_pd);
3053                                 }
3054                         }
3055                 }
3056         }
3057 #endif
3058 
3059         /*
3060          * Check for duplicate map entries
3061          */
3062         if (clist->clist_size) {
3063                 int                     count;
3064                 fc_remote_port_t        *pd1, *pd2;
3065 
3066                 ASSERT(clist->clist_map != NULL);
3067                 for (count = 0; count < clist->clist_len-1; count++) {
3068                         int count2;
3069 
3070                         pd1 = clist->clist_map[count].map_pd;
3071                         if (pd1 == NULL) {
3072                                 continue;
3073                         }
3074 
3075                         for (count2 = count+1;
3076                             count2 < clist->clist_len;
3077                             count2++) {
3078 
3079                                 pd2 = clist->clist_map[count2].map_pd;
3080                                 if (pd2 == NULL) {
3081                                         continue;
3082                                 }
3083 
3084                                 if (pd1 == pd2) {
3085                                         clist->clist_map[count].map_flags |=
3086                                             PORT_DEVICE_DUPLICATE_MAP_ENTRY;
3087                                         break;
3088                                 }
3089                         }
3090                 }
3091         }
3092 
3093 
3094         rw_enter(&fctl_ulp_lock, RW_READER);
3095         for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
3096                 rw_enter(&fctl_mod_ports_lock, RW_READER);
3097                 ulp_port = fctl_get_ulp_port(mod, port);
3098                 rw_exit(&fctl_mod_ports_lock);
3099 
3100                 if (ulp_port == NULL) {
3101                         continue;
3102                 }
3103 
3104                 mutex_enter(&ulp_port->port_mutex);
3105                 if (FCTL_DISALLOW_CALLBACKS(ulp_port->port_dstate)) {
3106                         mutex_exit(&ulp_port->port_mutex);
3107                         continue;
3108                 }
3109 
3110                 switch (ulp_port->port_statec) {
3111                 case FC_ULP_STATEC_DONT_CARE:
3112                         if (ulp_port->port_statec != new_state) {
3113                                 ulp_port->port_statec = new_state;
3114                         }
3115                         break;
3116 
3117                 case FC_ULP_STATEC_ONLINE:
3118                 case FC_ULP_STATEC_OFFLINE:
3119                         if (ulp_port->port_statec == new_state) {
3120                                 mutex_exit(&ulp_port->port_mutex);
3121                                 continue;
3122                         }
3123                         ulp_port->port_statec = new_state;
3124                         break;
3125 
3126                 case FC_ULP_STATEC_OFFLINE_TIMEOUT:
3127                         if (ulp_port->port_statec == new_state ||
3128                             new_state == FC_ULP_STATEC_OFFLINE) {
3129                                 mutex_exit(&ulp_port->port_mutex);
3130                                 continue;
3131                         }
3132                         ulp_port->port_statec = new_state;
3133                         break;
3134 
3135                 default:
3136                         ASSERT(0);
3137                         break;
3138                 }
3139 
3140                 mod->mod_info->ulp_statec_callback(
3141                     mod->mod_info->ulp_handle, (opaque_t)port,
3142                     clist->clist_state, clist->clist_flags,
3143                     clist->clist_map, clist->clist_len, s_id);
3144 
3145                 mutex_exit(&ulp_port->port_mutex);
3146         }
3147         rw_exit(&fctl_ulp_lock);
3148 
3149         if (clist->clist_size) {
3150                 int                     count;
3151                 fc_remote_node_t        *node;
3152                 fc_remote_port_t        *pd;
3153 
3154                 ASSERT(clist->clist_map != NULL);
3155                 for (count = 0; count < clist->clist_len; count++) {
3156 
3157                         if ((pd = clist->clist_map[count].map_pd) == NULL) {
3158                                 continue;
3159                         }
3160 
3161                         mutex_enter(&pd->pd_mutex);
3162 
3163                         pd->pd_ref_count--;
3164                         ASSERT(pd->pd_ref_count >= 0);
3165 
3166                         if (clist->clist_map[count].map_state !=
3167                             PORT_DEVICE_INVALID) {
3168                                 mutex_exit(&pd->pd_mutex);
3169                                 continue;
3170                         }
3171 
3172                         node = pd->pd_remote_nodep;
3173                         pd->pd_aux_flags &= ~PD_GIVEN_TO_ULPS;
3174 
3175                         mutex_exit(&pd->pd_mutex);
3176 
3177                         /*
3178                          * This fc_remote_port_t is no longer referenced
3179                          * by any ULPs. Deallocate it if its pd_ref_count
3180                          * has reached zero.
3181                          */
3182                         if ((fctl_destroy_remote_port(port, pd) == 0) &&
3183                             (node != NULL)) {
3184                                 fctl_destroy_remote_node(node);
3185                         }
3186                 }
3187 
3188                 kmem_free(clist->clist_map,
3189                     sizeof (*(clist->clist_map)) * clist->clist_size);
3190         }
3191 
3192         if (clist->clist_wait) {
3193                 mutex_enter(&clist->clist_mutex);
3194                 clist->clist_wait = 0;
3195                 cv_signal(&clist->clist_cv);
3196                 mutex_exit(&clist->clist_mutex);
3197         } else {
3198                 kmem_free(clist, sizeof (*clist));
3199         }
3200 }
3201 
3202 
3203 /*
3204  * Allocate an fc_remote_node_t struct to represent a remote node for the
3205  * given nwwn.  This will also add the nwwn to the global nwwn table.
3206  *
3207  * Returns a pointer to the newly-allocated struct.  Returns NULL if
3208  * the kmem_zalloc fails or if the enlist_wwn attempt fails.
3209  */
3210 fc_remote_node_t *
3211 fctl_create_remote_node(la_wwn_t *nwwn, int sleep)
3212 {
3213         fc_remote_node_t *rnodep;
3214 
3215         if ((rnodep = kmem_zalloc(sizeof (*rnodep), sleep)) == NULL) {
3216                 return (NULL);
3217         }
3218 
3219         mutex_init(&rnodep->fd_mutex, NULL, MUTEX_DRIVER, NULL);
3220 
3221         rnodep->fd_node_name = *nwwn;
3222         rnodep->fd_flags = FC_REMOTE_NODE_VALID;
3223         rnodep->fd_numports = 1;
3224 
3225         if (fctl_enlist_nwwn_table(rnodep, sleep) != FC_SUCCESS) {
3226                 mutex_destroy(&rnodep->fd_mutex);
3227                 kmem_free(rnodep, sizeof (*rnodep));
3228                 return (NULL);
3229         }
3230 
3231         return (rnodep);
3232 }
3233 
3234 /*
3235  * Deconstruct and free the given fc_remote_node_t struct (remote node struct).
3236  * Silently skips the deconstruct/free if there are any fc_remote_port_t
3237  * (remote port device) structs still referenced by the given
3238  * fc_remote_node_t struct.
3239  */
3240 void
3241 fctl_destroy_remote_node(fc_remote_node_t *rnodep)
3242 {
3243         mutex_enter(&rnodep->fd_mutex);
3244 
3245         /*
3246          * Look at the count and linked list of of remote ports
3247          * (fc_remote_port_t structs); bail if these indicate that
3248          * given fc_remote_node_t may be in use.
3249          */
3250         if (rnodep->fd_numports != 0 || rnodep->fd_portlistp) {
3251                 mutex_exit(&rnodep->fd_mutex);
3252                 return;
3253         }
3254 
3255         mutex_exit(&rnodep->fd_mutex);
3256 
3257         mutex_destroy(&rnodep->fd_mutex);
3258         kmem_free(rnodep, sizeof (*rnodep));
3259 }
3260 
3261 
3262 /*
3263  * Add the given fc_remote_node_t to the global fctl_nwwn_hash_table[]. This
3264  * uses the nwwn in the fd_node_name.raw_wwn of the given struct.
3265  * This only fails if the kmem_zalloc fails.  This does not check for a
3266  * unique or pre-existing nwwn in the fctl_nwwn_hash_table[].
3267  * This is only called from fctl_create_remote_node().
3268  */
3269 int
3270 fctl_enlist_nwwn_table(fc_remote_node_t *rnodep, int sleep)
3271 {
3272         int                     index;
3273         fctl_nwwn_elem_t        *new;
3274         fctl_nwwn_list_t        *head;
3275 
3276         ASSERT(!MUTEX_HELD(&rnodep->fd_mutex));
3277 
3278         if ((new = kmem_zalloc(sizeof (*new), sleep)) == NULL) {
3279                 return (FC_FAILURE);
3280         }
3281 
3282         mutex_enter(&fctl_nwwn_hash_mutex);
3283         new->fne_nodep = rnodep;
3284 
3285         mutex_enter(&rnodep->fd_mutex);
3286         ASSERT(fctl_is_wwn_zero(&rnodep->fd_node_name) == FC_FAILURE);
3287         index = HASH_FUNC(WWN_HASH_KEY(rnodep->fd_node_name.raw_wwn),
3288             fctl_nwwn_table_size);
3289         mutex_exit(&rnodep->fd_mutex);
3290 
3291         head = &fctl_nwwn_hash_table[index];
3292 
3293         /* Link it in at the head of the hash list */
3294         new->fne_nextp = head->fnl_headp;
3295         head->fnl_headp = new;
3296 
3297         mutex_exit(&fctl_nwwn_hash_mutex);
3298 
3299         return (FC_SUCCESS);
3300 }
3301 
3302 
3303 /*
3304  * Remove the given fc_remote_node_t from the global fctl_nwwn_hash_table[].
3305  * This uses the nwwn in the fd_node_name.raw_wwn of the given struct.
3306  */
3307 void
3308 fctl_delist_nwwn_table(fc_remote_node_t *rnodep)
3309 {
3310         int                     index;
3311         fctl_nwwn_list_t        *head;
3312         fctl_nwwn_elem_t        *elem;
3313         fctl_nwwn_elem_t        *prev;
3314 
3315         ASSERT(MUTEX_HELD(&fctl_nwwn_hash_mutex));
3316         ASSERT(MUTEX_HELD(&rnodep->fd_mutex));
3317 
3318         index = HASH_FUNC(WWN_HASH_KEY(rnodep->fd_node_name.raw_wwn),
3319             fctl_nwwn_table_size);
3320 
3321         head = &fctl_nwwn_hash_table[index];
3322         elem = head->fnl_headp;
3323         prev = NULL;
3324 
3325         while (elem != NULL) {
3326                 if (elem->fne_nodep == rnodep) {
3327                         /*
3328                          * Found it -- unlink it from the list & decrement
3329                          * the count for the hash chain.
3330                          */
3331                         if (prev == NULL) {
3332                                 head->fnl_headp = elem->fne_nextp;
3333                         } else {
3334                                 prev->fne_nextp = elem->fne_nextp;
3335                         }
3336                         break;
3337                 }
3338                 prev = elem;
3339                 elem = elem->fne_nextp;
3340         }
3341 
3342         if (elem != NULL) {
3343                 kmem_free(elem, sizeof (*elem));
3344         }
3345 }
3346 
3347 
3348 /*
3349  * Returns a reference to an fc_remote_node_t struct for the given node_wwn.
3350  * Looks in the global fctl_nwwn_hash_table[]. Identical to the
3351  * fctl_lock_remote_node_by_nwwn() function, except that this does NOT increment
3352  * the fc_count reference count in the f_device_t before returning.
3353  *
3354  * This function is called by: fctl_create_remote_port_t().
3355  *
3356  * OLD COMMENT:
3357  * Note: The calling thread needs to make sure it isn't holding any device
3358  * mutex (more so the fc_remote_node_t that could potentially have this wwn).
3359  */
3360 fc_remote_node_t *
3361 fctl_get_remote_node_by_nwwn(la_wwn_t *node_wwn)
3362 {
3363         int                     index;
3364         fctl_nwwn_elem_t        *elem;
3365         fc_remote_node_t        *next;
3366         fc_remote_node_t        *rnodep = NULL;
3367 
3368         index = HASH_FUNC(WWN_HASH_KEY(node_wwn->raw_wwn),
3369             fctl_nwwn_table_size);
3370         ASSERT(index >= 0 && index < fctl_nwwn_table_size);
3371 
3372         mutex_enter(&fctl_nwwn_hash_mutex);
3373         elem = fctl_nwwn_hash_table[index].fnl_headp;
3374         while (elem != NULL) {
3375                 next = elem->fne_nodep;
3376                 if (next != NULL) {
3377                         mutex_enter(&next->fd_mutex);
3378                         if (fctl_wwn_cmp(node_wwn, &next->fd_node_name) == 0) {
3379                                 rnodep = next;
3380                                 mutex_exit(&next->fd_mutex);
3381                                 break;
3382                         }
3383                         mutex_exit(&next->fd_mutex);
3384                 }
3385                 elem = elem->fne_nextp;
3386         }
3387         mutex_exit(&fctl_nwwn_hash_mutex);
3388 
3389         return (rnodep);
3390 }
3391 
3392 
3393 /*
3394  * Returns a reference to an fc_remote_node_t struct for the given node_wwn.
3395  * Looks in the global fctl_nwwn_hash_table[]. Increments the fd_numports
3396  * reference count in the f_device_t before returning.
3397  *
3398  * This function is only called by fctl_create_remote_port_t().
3399  */
3400 fc_remote_node_t *
3401 fctl_lock_remote_node_by_nwwn(la_wwn_t *node_wwn)
3402 {
3403         int                     index;
3404         fctl_nwwn_elem_t        *elem;
3405         fc_remote_node_t        *next;
3406         fc_remote_node_t        *rnodep = NULL;
3407 
3408         index = HASH_FUNC(WWN_HASH_KEY(node_wwn->raw_wwn),
3409             fctl_nwwn_table_size);
3410         ASSERT(index >= 0 && index < fctl_nwwn_table_size);
3411 
3412         mutex_enter(&fctl_nwwn_hash_mutex);
3413         elem = fctl_nwwn_hash_table[index].fnl_headp;
3414         while (elem != NULL) {
3415                 next = elem->fne_nodep;
3416                 if (next != NULL) {
3417                         mutex_enter(&next->fd_mutex);
3418                         if (fctl_wwn_cmp(node_wwn, &next->fd_node_name) == 0) {
3419                                 rnodep = next;
3420                                 rnodep->fd_numports++;
3421                                 mutex_exit(&next->fd_mutex);
3422                                 break;
3423                         }
3424                         mutex_exit(&next->fd_mutex);
3425                 }
3426                 elem = elem->fne_nextp;
3427         }
3428         mutex_exit(&fctl_nwwn_hash_mutex);
3429 
3430         return (rnodep);
3431 }
3432 
3433 
3434 /*
3435  * Allocate and initialize an fc_remote_port_t struct & returns a pointer to
3436  * the newly allocated struct.  Only fails if the kmem_zalloc() fails.
3437  */
3438 fc_remote_port_t *
3439 fctl_alloc_remote_port(fc_local_port_t *port, la_wwn_t *port_wwn,
3440     uint32_t d_id, uchar_t recepient, int sleep)
3441 {
3442         fc_remote_port_t *pd;
3443 
3444         ASSERT(MUTEX_HELD(&port->fp_mutex));
3445         ASSERT(FC_IS_REAL_DEVICE(d_id));
3446 
3447         if ((pd = kmem_zalloc(sizeof (*pd), sleep)) == NULL) {
3448                 return (NULL);
3449         }
3450         fctl_tc_constructor(&pd->pd_logo_tc, FC_LOGO_TOLERANCE_LIMIT,
3451             FC_LOGO_TOLERANCE_TIME_LIMIT);
3452 
3453         mutex_init(&pd->pd_mutex, NULL, MUTEX_DRIVER, NULL);
3454 
3455         pd->pd_port_id.port_id = d_id;
3456         pd->pd_port_name = *port_wwn;
3457         pd->pd_port = port;
3458         pd->pd_state = PORT_DEVICE_VALID;
3459         pd->pd_type = PORT_DEVICE_NEW;
3460         pd->pd_recepient = recepient;
3461 
3462         return (pd);
3463 }
3464 
3465 
3466 /*
3467  * Deconstruct and free the given fc_remote_port_t struct (unconditionally).
3468  */
3469 void
3470 fctl_dealloc_remote_port(fc_remote_port_t *pd)
3471 {
3472         ASSERT(!MUTEX_HELD(&pd->pd_mutex));
3473 
3474         fctl_tc_destructor(&pd->pd_logo_tc);
3475         mutex_destroy(&pd->pd_mutex);
3476         kmem_free(pd, sizeof (*pd));
3477 }
3478 
3479 /*
3480  * Add the given fc_remote_port_t onto the linked list of remote port
3481  * devices associated with the given fc_remote_node_t. Does NOT add the
3482  * fc_remote_port_t to the list if already exists on the list.
3483  */
3484 void
3485 fctl_link_remote_port_to_remote_node(fc_remote_node_t *rnodep,
3486     fc_remote_port_t *pd)
3487 {
3488         fc_remote_port_t *last;
3489         fc_remote_port_t *ports;
3490 
3491         mutex_enter(&rnodep->fd_mutex);
3492 
3493         last = NULL;
3494         for (ports = rnodep->fd_portlistp; ports != NULL;
3495             ports = ports->pd_port_next) {
3496                 if (ports == pd) {
3497                         /*
3498                          * The given fc_remote_port_t is already on the linked
3499                          * list chain for the given remote node, so bail now.
3500                          */
3501                         mutex_exit(&rnodep->fd_mutex);
3502                         return;
3503                 }
3504                 last = ports;
3505         }
3506 
3507         /* Add the fc_remote_port_t to the tail of the linked list */
3508         if (last != NULL) {
3509                 last->pd_port_next = pd;
3510         } else {
3511                 rnodep->fd_portlistp = pd;
3512         }
3513         pd->pd_port_next = NULL;
3514 
3515         /*
3516          * Link the fc_remote_port_t back to the associated fc_remote_node_t.
3517          */
3518         mutex_enter(&pd->pd_mutex);
3519         pd->pd_remote_nodep = rnodep;
3520         mutex_exit(&pd->pd_mutex);
3521 
3522         mutex_exit(&rnodep->fd_mutex);
3523 }
3524 
3525 
3526 /*
3527  * Remove the specified fc_remote_port_t from the linked list of remote ports
3528  * for the given fc_remote_node_t.
3529  *
3530  * Returns a count of the _remaining_ fc_remote_port_t structs on the linked
3531  * list of the fc_remote_node_t.
3532  *
3533  * The fd_numports on the given fc_remote_node_t is decremented, and if
3534  * it hits zero then this function also removes the fc_remote_node_t from the
3535  * global fctl_nwwn_hash_table[]. This appears to be the ONLY WAY that entries
3536  * are removed from the fctl_nwwn_hash_table[].
3537  */
3538 int
3539 fctl_unlink_remote_port_from_remote_node(fc_remote_node_t *rnodep,
3540     fc_remote_port_t *pd)
3541 {
3542         int                     rcount = 0;
3543         fc_remote_port_t        *last;
3544         fc_remote_port_t        *ports;
3545 
3546         ASSERT(!MUTEX_HELD(&rnodep->fd_mutex));
3547         ASSERT(!MUTEX_HELD(&pd->pd_mutex));
3548 
3549         last = NULL;
3550 
3551         mutex_enter(&fctl_nwwn_hash_mutex);
3552 
3553         mutex_enter(&rnodep->fd_mutex);
3554 
3555         /*
3556          * Go thru the linked list of fc_remote_port_t structs for the given
3557          * fc_remote_node_t; try to find the specified fc_remote_port_t (pd).
3558          */
3559         ports = rnodep->fd_portlistp;
3560         while (ports != NULL) {
3561                 if (ports == pd) {
3562                         break;  /* Found the requested fc_remote_port_t */
3563                 }
3564                 last = ports;
3565                 ports = ports->pd_port_next;
3566         }
3567 
3568         if (ports) {
3569                 rcount = --rnodep->fd_numports;
3570                 if (rcount == 0) {
3571                         /* Note: this is only ever called from here */
3572                         fctl_delist_nwwn_table(rnodep);
3573                 }
3574                 if (last) {
3575                         last->pd_port_next = pd->pd_port_next;
3576                 } else {
3577                         rnodep->fd_portlistp = pd->pd_port_next;
3578                 }
3579                 mutex_enter(&pd->pd_mutex);
3580                 pd->pd_remote_nodep = NULL;
3581                 mutex_exit(&pd->pd_mutex);
3582         }
3583 
3584         pd->pd_port_next = NULL;
3585 
3586         mutex_exit(&rnodep->fd_mutex);
3587         mutex_exit(&fctl_nwwn_hash_mutex);
3588 
3589         return (rcount);
3590 }
3591 
3592 
3593 /*
3594  * Add the given fc_remote_port_t struct to the d_id table in the given
3595  * fc_local_port_t struct.  Hashes based upon the pd->pd_port_id.port_id in the
3596  * fc_remote_port_t.
3597  *
3598  * No memory allocs are required, so this never fails, but it does use the
3599  * (pd->pd_aux_flags & PD_IN_DID_QUEUE) to keep duplicates off the list.
3600  * (There does not seem to be a way to tell the caller that a duplicate
3601  * exists.)
3602  */
3603 void
3604 fctl_enlist_did_table(fc_local_port_t *port, fc_remote_port_t *pd)
3605 {
3606         struct d_id_hash *head;
3607 
3608         ASSERT(MUTEX_HELD(&port->fp_mutex));
3609         ASSERT(MUTEX_HELD(&pd->pd_mutex));
3610 
3611         if (pd->pd_aux_flags & PD_IN_DID_QUEUE) {
3612                 return;
3613         }
3614 
3615         head = &port->fp_did_table[D_ID_HASH_FUNC(pd->pd_port_id.port_id,
3616             did_table_size)];
3617 
3618 #ifdef  DEBUG
3619         {
3620                 int                     index;
3621                 fc_remote_port_t        *tmp_pd;
3622                 struct d_id_hash        *tmp_head;
3623 
3624                 /*
3625                  * Search down in each bucket for a duplicate pd
3626                  * Also search for duplicate D_IDs
3627                  * This DEBUG code will force an ASSERT if a duplicate
3628                  * is ever found.
3629                  */
3630                 for (index = 0; index < did_table_size; index++) {
3631                         tmp_head = &port->fp_did_table[index];
3632 
3633                         tmp_pd = tmp_head->d_id_head;
3634                         while (tmp_pd != NULL) {
3635                                 ASSERT(tmp_pd != pd);
3636 
3637                                 if (tmp_pd->pd_state != PORT_DEVICE_INVALID &&
3638                                     tmp_pd->pd_type != PORT_DEVICE_OLD) {
3639                                         ASSERT(tmp_pd->pd_port_id.port_id !=
3640                                             pd->pd_port_id.port_id);
3641                                 }
3642 
3643                                 tmp_pd = tmp_pd->pd_did_hnext;
3644                         }
3645                 }
3646         }
3647 
3648         bzero(pd->pd_d_stack, sizeof (pd->pd_d_stack));
3649         pd->pd_d_depth = getpcstack(pd->pd_d_stack, FC_STACK_DEPTH);
3650 #endif
3651 
3652         pd->pd_did_hnext = head->d_id_head;
3653         head->d_id_head = pd;
3654 
3655         pd->pd_aux_flags |= PD_IN_DID_QUEUE;
3656         head->d_id_count++;
3657 }
3658 
3659 
3660 /*
3661  * Remove the given fc_remote_port_t struct from the d_id table in the given
3662  * fc_local_port_t struct.  Hashes based upon the pd->pd_port_id.port_id in the
3663  * fc_remote_port_t.
3664  *
3665  * Does nothing if the requested fc_remote_port_t was not found.
3666  */
3667 void
3668 fctl_delist_did_table(fc_local_port_t *port, fc_remote_port_t *pd)
3669 {
3670         uint32_t                d_id;
3671         struct d_id_hash        *head;
3672         fc_remote_port_t        *pd_next;
3673         fc_remote_port_t        *last;
3674 
3675         ASSERT(MUTEX_HELD(&port->fp_mutex));
3676         ASSERT(MUTEX_HELD(&pd->pd_mutex));
3677 
3678         d_id = pd->pd_port_id.port_id;
3679         head = &port->fp_did_table[D_ID_HASH_FUNC(d_id, did_table_size)];
3680 
3681         pd_next = head->d_id_head;
3682         last = NULL;
3683         while (pd_next != NULL) {
3684                 if (pd == pd_next) {
3685                         break;  /* Found the given fc_remote_port_t */
3686                 }
3687                 last = pd_next;
3688                 pd_next = pd_next->pd_did_hnext;
3689         }
3690 
3691         if (pd_next) {
3692                 /*
3693                  * Found the given fc_remote_port_t; now remove it from the
3694                  * d_id list.
3695                  */
3696                 head->d_id_count--;
3697                 if (last == NULL) {
3698                         head->d_id_head = pd->pd_did_hnext;
3699                 } else {
3700                         last->pd_did_hnext = pd->pd_did_hnext;
3701                 }
3702                 pd->pd_aux_flags &= ~PD_IN_DID_QUEUE;
3703                 pd->pd_did_hnext = NULL;
3704         }
3705 }
3706 
3707 
3708 /*
3709  * Add the given fc_remote_port_t struct to the pwwn table in the given
3710  * fc_local_port_t struct.  Hashes based upon the pd->pd_port_name.raw_wwn
3711  * in the fc_remote_port_t.
3712  *
3713  * No memory allocs are required, so this never fails.
3714  */
3715 void
3716 fctl_enlist_pwwn_table(fc_local_port_t *port, fc_remote_port_t *pd)
3717 {
3718         int index;
3719         struct pwwn_hash *head;
3720 
3721         ASSERT(MUTEX_HELD(&port->fp_mutex));
3722         ASSERT(MUTEX_HELD(&pd->pd_mutex));
3723 
3724         ASSERT(fctl_is_wwn_zero(&pd->pd_port_name) == FC_FAILURE);
3725 
3726         index = HASH_FUNC(WWN_HASH_KEY(pd->pd_port_name.raw_wwn),
3727             pwwn_table_size);
3728 
3729         head = &port->fp_pwwn_table[index];
3730 
3731 #ifdef  DEBUG
3732         {
3733                 int                     index;
3734                 fc_remote_port_t        *tmp_pd;
3735                 struct pwwn_hash        *tmp_head;
3736 
3737                 /*
3738                  * Search down in each bucket for a duplicate pd
3739                  * Search also for a duplicate WWN
3740                  * Throw an ASSERT if any duplicate is found.
3741                  */
3742                 for (index = 0; index < pwwn_table_size; index++) {
3743                         tmp_head = &port->fp_pwwn_table[index];
3744 
3745                         tmp_pd = tmp_head->pwwn_head;
3746                         while (tmp_pd != NULL) {
3747                                 ASSERT(tmp_pd != pd);
3748 
3749                                 if (tmp_pd->pd_state != PORT_DEVICE_INVALID &&
3750                                     tmp_pd->pd_type != PORT_DEVICE_OLD) {
3751                                         ASSERT(fctl_wwn_cmp(
3752                                             &tmp_pd->pd_port_name,
3753                                             &pd->pd_port_name) != 0);
3754                                 }
3755 
3756                                 tmp_pd = tmp_pd->pd_wwn_hnext;
3757                         }
3758                 }
3759         }
3760 
3761         bzero(pd->pd_w_stack, sizeof (pd->pd_w_stack));
3762         pd->pd_w_depth = getpcstack(pd->pd_w_stack, FC_STACK_DEPTH);
3763 #endif /* DEBUG */
3764 
3765         pd->pd_wwn_hnext = head->pwwn_head;
3766         head->pwwn_head = pd;
3767 
3768         head->pwwn_count++;
3769         /*
3770          * Make sure we tie fp_dev_count to the size of the
3771          * pwwn_table
3772          */
3773         port->fp_dev_count++;
3774 }
3775 
3776 
3777 /*
3778  * Remove the given fc_remote_port_t struct from the pwwn table in the given
3779  * fc_local_port_t struct.  Hashes based upon the pd->pd_port_name.raw_wwn
3780  * in the fc_remote_port_t.
3781  *
3782  * Does nothing if the requested fc_remote_port_t was not found.
3783  */
3784 void
3785 fctl_delist_pwwn_table(fc_local_port_t *port, fc_remote_port_t *pd)
3786 {
3787         int                     index;
3788         la_wwn_t                pwwn;
3789         struct pwwn_hash        *head;
3790         fc_remote_port_t        *pd_next;
3791         fc_remote_port_t        *last;
3792 
3793         ASSERT(MUTEX_HELD(&port->fp_mutex));
3794         ASSERT(MUTEX_HELD(&pd->pd_mutex));
3795 
3796         pwwn = pd->pd_port_name;
3797         index = HASH_FUNC(WWN_HASH_KEY(pwwn.raw_wwn), pwwn_table_size);
3798 
3799         head = &port->fp_pwwn_table[index];
3800 
3801         last = NULL;
3802         pd_next = head->pwwn_head;
3803         while (pd_next != NULL) {
3804                 if (pd_next == pd) {
3805                         break;  /* Found the given fc_remote_port_t */
3806                 }
3807                 last = pd_next;
3808                 pd_next = pd_next->pd_wwn_hnext;
3809         }
3810 
3811         if (pd_next) {
3812                 /*
3813                  * Found the given fc_remote_port_t; now remove it from the
3814                  * pwwn list.
3815                  */
3816                 head->pwwn_count--;
3817                 /*
3818                  * Make sure we tie fp_dev_count to the size of the
3819                  * pwwn_table
3820                  */
3821                 port->fp_dev_count--;
3822                 if (last == NULL) {
3823                         head->pwwn_head = pd->pd_wwn_hnext;
3824                 } else {
3825                         last->pd_wwn_hnext = pd->pd_wwn_hnext;
3826                 }
3827                 pd->pd_wwn_hnext = NULL;
3828         }
3829 }
3830 
3831 
3832 /*
3833  * Looks in the d_id table of the specified fc_local_port_t for the
3834  * fc_remote_port_t that matches the given d_id.  Hashes based upon
3835  * the given d_id.
3836  * Returns a pointer to the fc_remote_port_t struct, but does not update any
3837  * reference counts or otherwise indicate that the fc_remote_port_t is in
3838  * use.
3839  */
3840 fc_remote_port_t *
3841 fctl_get_remote_port_by_did(fc_local_port_t *port, uint32_t d_id)
3842 {
3843         struct d_id_hash        *head;
3844         fc_remote_port_t        *pd;
3845 
3846         ASSERT(!MUTEX_HELD(&port->fp_mutex));
3847 
3848         mutex_enter(&port->fp_mutex);
3849 
3850         head = &port->fp_did_table[D_ID_HASH_FUNC(d_id, did_table_size)];
3851 
3852         pd = head->d_id_head;
3853         while (pd != NULL) {
3854                 mutex_enter(&pd->pd_mutex);
3855                 if (pd->pd_port_id.port_id == d_id) {
3856                         /* Match found -- break out of the loop */
3857                         mutex_exit(&pd->pd_mutex);
3858                         break;
3859                 }
3860                 mutex_exit(&pd->pd_mutex);
3861                 pd = pd->pd_did_hnext;
3862         }
3863 
3864         mutex_exit(&port->fp_mutex);
3865 
3866         return (pd);
3867 }
3868 
3869 
3870 void
3871 fc_ulp_hold_remote_port(opaque_t port_handle)
3872 {
3873         fc_remote_port_t *pd = port_handle;
3874 
3875         mutex_enter(&pd->pd_mutex);
3876         pd->pd_ref_count++;
3877         mutex_exit(&pd->pd_mutex);
3878 }
3879 
3880 /*
3881  * Looks in the d_id table of the specified fc_local_port_t for the
3882  * fc_remote_port_t that matches the given d_id.  Hashes based upon
3883  * the given d_id. Returns a pointer to the fc_remote_port_t struct.
3884  *
3885  * Increments pd_ref_count in the fc_remote_port_t if the
3886  * fc_remote_port_t is found at the given d_id.
3887  *
3888  * The fc_remote_port_t is ignored (treated as non-existent) if either
3889  * its pd_state == PORT_DEVICE_INVALID _OR_ its pd_type == PORT_DEVICE_OLD.
3890  */
3891 fc_remote_port_t *
3892 fctl_hold_remote_port_by_did(fc_local_port_t *port, uint32_t d_id)
3893 {
3894         struct d_id_hash        *head;
3895         fc_remote_port_t        *pd;
3896 
3897         ASSERT(!MUTEX_HELD(&port->fp_mutex));
3898 
3899         mutex_enter(&port->fp_mutex);
3900 
3901         head = &port->fp_did_table[D_ID_HASH_FUNC(d_id, did_table_size)];
3902 
3903         pd = head->d_id_head;
3904         while (pd != NULL) {
3905                 mutex_enter(&pd->pd_mutex);
3906                 if (pd->pd_port_id.port_id == d_id && pd->pd_state !=
3907                     PORT_DEVICE_INVALID && pd->pd_type != PORT_DEVICE_OLD) {
3908                         ASSERT(pd->pd_ref_count >= 0);
3909                         pd->pd_ref_count++;
3910                         mutex_exit(&pd->pd_mutex);
3911                         break;
3912                 }
3913                 mutex_exit(&pd->pd_mutex);
3914                 pd = pd->pd_did_hnext;
3915         }
3916 
3917         mutex_exit(&port->fp_mutex);
3918 
3919         return (pd);
3920 }
3921 
3922 /*
3923  * Looks in the pwwn table of the specified fc_local_port_t for the
3924  * fc_remote_port_t that matches the given pwwn.  Hashes based upon the
3925  * given pwwn->raw_wwn. Returns a pointer to the fc_remote_port_t struct,
3926  * but does not update any reference counts or otherwise indicate that
3927  * the fc_remote_port_t is in use.
3928  */
3929 fc_remote_port_t *
3930 fctl_get_remote_port_by_pwwn(fc_local_port_t *port, la_wwn_t *pwwn)
3931 {
3932         int                     index;
3933         struct pwwn_hash        *head;
3934         fc_remote_port_t        *pd;
3935 
3936         ASSERT(!MUTEX_HELD(&port->fp_mutex));
3937 
3938         mutex_enter(&port->fp_mutex);
3939 
3940         index = HASH_FUNC(WWN_HASH_KEY(pwwn->raw_wwn), pwwn_table_size);
3941         head = &port->fp_pwwn_table[index];
3942 
3943         pd = head->pwwn_head;
3944         while (pd != NULL) {
3945                 mutex_enter(&pd->pd_mutex);
3946                 if (fctl_wwn_cmp(&pd->pd_port_name, pwwn) == 0) {
3947                         mutex_exit(&pd->pd_mutex);
3948                         break;
3949                 }
3950                 mutex_exit(&pd->pd_mutex);
3951                 pd = pd->pd_wwn_hnext;
3952         }
3953 
3954         mutex_exit(&port->fp_mutex);
3955 
3956         return (pd);
3957 }
3958 
3959 
3960 /*
3961  * Basically the same as fctl_get_remote_port_by_pwwn(), but requires that
3962  * the caller already hold the fp_mutex in the fc_local_port_t struct.
3963  */
3964 fc_remote_port_t *
3965 fctl_get_remote_port_by_pwwn_mutex_held(fc_local_port_t *port, la_wwn_t *pwwn)
3966 {
3967         int                     index;
3968         struct pwwn_hash        *head;
3969         fc_remote_port_t        *pd;
3970 
3971         ASSERT(MUTEX_HELD(&port->fp_mutex));
3972 
3973         index = HASH_FUNC(WWN_HASH_KEY(pwwn->raw_wwn), pwwn_table_size);
3974         head = &port->fp_pwwn_table[index];
3975 
3976         pd = head->pwwn_head;
3977         while (pd != NULL) {
3978                 mutex_enter(&pd->pd_mutex);
3979                 if (fctl_wwn_cmp(&pd->pd_port_name, pwwn) == 0) {
3980                         mutex_exit(&pd->pd_mutex);
3981                         break;
3982                 }
3983                 mutex_exit(&pd->pd_mutex);
3984                 pd = pd->pd_wwn_hnext;
3985         }
3986 
3987         return (pd);
3988 }
3989 
3990 
3991 /*
3992  * Looks in the pwwn table of the specified fc_local_port_t for the
3993  * fc_remote_port_t that matches the given d_id.  Hashes based upon the
3994  * given pwwn->raw_wwn. Returns a pointer to the fc_remote_port_t struct.
3995  *
3996  * Increments pd_ref_count in the fc_remote_port_t if the
3997  * fc_remote_port_t is found at the given pwwn.
3998  *
3999  * The fc_remote_port_t is ignored (treated as non-existent) if either
4000  * its pd_state == PORT_DEVICE_INVALID _OR_ its pd_type == PORT_DEVICE_OLD.
4001  */
4002 fc_remote_port_t *
4003 fctl_hold_remote_port_by_pwwn(fc_local_port_t *port, la_wwn_t *pwwn)
4004 {
4005         int                     index;
4006         struct pwwn_hash        *head;
4007         fc_remote_port_t        *pd;
4008 
4009         ASSERT(!MUTEX_HELD(&port->fp_mutex));
4010 
4011         mutex_enter(&port->fp_mutex);
4012 
4013         index = HASH_FUNC(WWN_HASH_KEY(pwwn->raw_wwn), pwwn_table_size);
4014         head = &port->fp_pwwn_table[index];
4015 
4016         pd = head->pwwn_head;
4017         while (pd != NULL) {
4018                 mutex_enter(&pd->pd_mutex);
4019                 if (fctl_wwn_cmp(&pd->pd_port_name, pwwn) == 0 &&
4020                     pd->pd_state != PORT_DEVICE_INVALID &&
4021                     pd->pd_type != PORT_DEVICE_OLD) {
4022                         ASSERT(pd->pd_ref_count >= 0);
4023                         pd->pd_ref_count++;
4024                         mutex_exit(&pd->pd_mutex);
4025                         break;
4026                 }
4027                 mutex_exit(&pd->pd_mutex);
4028                 pd = pd->pd_wwn_hnext;
4029         }
4030 
4031         mutex_exit(&port->fp_mutex);
4032 
4033         return (pd);
4034 }
4035 
4036 
4037 /*
4038  * Unconditionally decrement pd_ref_count in the given fc_remote_port_t
4039  * struct.
4040  *
4041  * If pd_ref_count reaches zero, then this function will see if the
4042  * fc_remote_port_t has been marked for deallocation. If so (and also if there
4043  * are no other potential operations in progress, as indicated by the
4044  * PD_ELS_IN_PROGRESS & PD_ELS_MARK settings in the pd_flags), then
4045  * fctl_destroy_remote_port_t() is called to deconstruct/free the given
4046  * fc_remote_port_t (which will also remove it from the d_id and pwwn tables
4047  * on the associated fc_local_port_t).  If the associated fc_remote_node_t is no
4048  * longer in use, then it too is deconstructed/freed.
4049  */
4050 void
4051 fctl_release_remote_port(fc_remote_port_t *pd)
4052 {
4053         int                     remove = 0;
4054         fc_remote_node_t        *node;
4055         fc_local_port_t         *port;
4056 
4057         mutex_enter(&pd->pd_mutex);
4058         port = pd->pd_port;
4059 
4060         ASSERT(pd->pd_ref_count > 0);
4061         pd->pd_ref_count--;
4062         if (pd->pd_ref_count == 0 &&
4063             (pd->pd_aux_flags & PD_NEEDS_REMOVAL) &&
4064             (pd->pd_flags != PD_ELS_IN_PROGRESS) &&
4065             (pd->pd_flags != PD_ELS_MARK)) {
4066                 remove = 1;
4067                 pd->pd_aux_flags &= ~PD_NEEDS_REMOVAL;
4068         }
4069         node = pd->pd_remote_nodep;
4070         ASSERT(node != NULL);
4071 
4072         mutex_exit(&pd->pd_mutex);
4073 
4074         if (remove) {
4075                 /*
4076                  * The fc_remote_port_t struct has to go away now, so call the
4077                  * cleanup function to get it off the various lists and remove
4078                  * references to it in any other associated structs.
4079                  */
4080                 if (fctl_destroy_remote_port(port, pd) == 0) {
4081                         /*
4082                          * No more fc_remote_port_t references found in the
4083                          * associated fc_remote_node_t, so deallocate the
4084                          * fc_remote_node_t (if it even exists).
4085                          */
4086                         if (node) {
4087                                 fctl_destroy_remote_node(node);
4088                         }
4089                 }
4090         }
4091 }
4092 
4093 
4094 void
4095 fctl_fillout_map(fc_local_port_t *port, fc_portmap_t **map, uint32_t *len,
4096     int whole_map, int justcopy, int orphan)
4097 {
4098         int                     index;
4099         int                     listlen;
4100         int                     full_list;
4101         int                     initiator;
4102         uint32_t                topology;
4103         struct pwwn_hash        *head;
4104         fc_remote_port_t        *pd;
4105         fc_remote_port_t        *old_pd;
4106         fc_remote_port_t        *last_pd;
4107         fc_portmap_t            *listptr;
4108 
4109         ASSERT(!MUTEX_HELD(&port->fp_mutex));
4110 
4111         mutex_enter(&port->fp_mutex);
4112 
4113         topology = port->fp_topology;
4114 
4115         if (orphan) {
4116                 ASSERT(!FC_IS_TOP_SWITCH(topology));
4117         }
4118 
4119         for (full_list = listlen = index = 0;
4120             index < pwwn_table_size; index++) {
4121                 head = &port->fp_pwwn_table[index];
4122                 pd = head->pwwn_head;
4123                 while (pd != NULL) {
4124                         full_list++;
4125                         mutex_enter(&pd->pd_mutex);
4126                         if (pd->pd_type != PORT_DEVICE_NOCHANGE) {
4127                                 listlen++;
4128                         }
4129                         mutex_exit(&pd->pd_mutex);
4130                         pd = pd->pd_wwn_hnext;
4131                 }
4132         }
4133 
4134         if (whole_map == 0) {
4135                 if (listlen == 0 && *len == 0) {
4136                         *map = NULL;
4137                         *len = listlen;
4138                         mutex_exit(&port->fp_mutex);
4139                         return;
4140                 }
4141         } else {
4142                 if (full_list == 0 && *len == 0) {
4143                         *map = NULL;
4144                         *len = full_list;
4145                         mutex_exit(&port->fp_mutex);
4146                         return;
4147                 }
4148         }
4149 
4150         if (*len == 0) {
4151                 ASSERT(*map == NULL);
4152                 if (whole_map == 0) {
4153                         listptr = *map = kmem_zalloc(
4154                             sizeof (*listptr) * listlen, KM_SLEEP);
4155                         *len = listlen;
4156                 } else {
4157                         listptr = *map = kmem_zalloc(
4158                             sizeof (*listptr) * full_list, KM_SLEEP);
4159                         *len = full_list;
4160                 }
4161         } else {
4162                 /*
4163                  * By design this routine mandates the callers to
4164                  * ask for a whole map when they specify the length
4165                  * and the listptr.
4166                  */
4167                 ASSERT(whole_map == 1);
4168                 if (*len < full_list) {
4169                         *len = full_list;
4170                         mutex_exit(&port->fp_mutex);
4171                         return;
4172                 }
4173                 listptr = *map;
4174                 *len = full_list;
4175         }
4176 
4177         for (index = 0; index < pwwn_table_size; index++) {
4178                 head = &port->fp_pwwn_table[index];
4179                 last_pd = NULL;
4180                 pd = head->pwwn_head;
4181                 while (pd != NULL) {
4182                         mutex_enter(&pd->pd_mutex);
4183                         if ((whole_map == 0 &&
4184                             pd->pd_type == PORT_DEVICE_NOCHANGE) ||
4185                             pd->pd_state == PORT_DEVICE_INVALID) {
4186                                 mutex_exit(&pd->pd_mutex);
4187                                 last_pd = pd;
4188                                 pd = pd->pd_wwn_hnext;
4189                                 continue;
4190                         }
4191                         mutex_exit(&pd->pd_mutex);
4192 
4193                         fctl_copy_portmap(listptr, pd);
4194 
4195                         if (justcopy) {
4196                                 last_pd = pd;
4197                                 pd = pd->pd_wwn_hnext;
4198                                 listptr++;
4199                                 continue;
4200                         }
4201 
4202                         mutex_enter(&pd->pd_mutex);
4203                         ASSERT(pd->pd_state != PORT_DEVICE_INVALID);
4204                         if (pd->pd_type == PORT_DEVICE_OLD) {
4205                                 listptr->map_pd = pd;
4206                                 listptr->map_state = pd->pd_state =
4207                                     PORT_DEVICE_INVALID;
4208                                 /*
4209                                  * Remove this from the PWWN hash table.
4210                                  */
4211                                 old_pd = pd;
4212                                 pd = old_pd->pd_wwn_hnext;
4213 
4214                                 if (last_pd == NULL) {
4215                                         ASSERT(old_pd == head->pwwn_head);
4216 
4217                                         head->pwwn_head = pd;
4218                                 } else {
4219                                         last_pd->pd_wwn_hnext = pd;
4220                                 }
4221                                 head->pwwn_count--;
4222                                 /*
4223                                  * Make sure we tie fp_dev_count to the size
4224                                  * of the pwwn_table
4225                                  */
4226                                 port->fp_dev_count--;
4227                                 old_pd->pd_wwn_hnext = NULL;
4228 
4229                                 if (port->fp_topology == FC_TOP_PRIVATE_LOOP &&
4230                                     port->fp_statec_busy && !orphan) {
4231                                         fctl_check_alpa_list(port, old_pd);
4232                                 }
4233 
4234                                 /*
4235                                  * Remove if the port device has stealthily
4236                                  * present in the D_ID hash table
4237                                  */
4238                                 fctl_delist_did_table(port, old_pd);
4239 
4240                                 ASSERT(old_pd->pd_remote_nodep != NULL);
4241 
4242                                 initiator = (old_pd->pd_recepient ==
4243                                     PD_PLOGI_INITIATOR) ? 1 : 0;
4244 
4245                                 mutex_exit(&old_pd->pd_mutex);
4246                                 mutex_exit(&port->fp_mutex);
4247 
4248                                 if (orphan) {
4249                                         fctl_print_if_not_orphan(port, old_pd);
4250 
4251                                         (void) fctl_add_orphan(port, old_pd,
4252                                             KM_NOSLEEP);
4253                                 }
4254 
4255                                 if (FC_IS_TOP_SWITCH(topology) && initiator) {
4256                                         (void) fctl_add_orphan(port, old_pd,
4257                                             KM_NOSLEEP);
4258                                 }
4259                                 mutex_enter(&port->fp_mutex);
4260                         } else {
4261                                 listptr->map_pd = pd;
4262                                 pd->pd_type = PORT_DEVICE_NOCHANGE;
4263                                 mutex_exit(&pd->pd_mutex);
4264                                 last_pd = pd;
4265                                 pd = pd->pd_wwn_hnext;
4266                         }
4267                         listptr++;
4268                 }
4269         }
4270         mutex_exit(&port->fp_mutex);
4271 }
4272 
4273 
4274 job_request_t *
4275 fctl_alloc_job(int job_code, int job_flags, void (*comp) (opaque_t, uchar_t),
4276     opaque_t arg, int sleep)
4277 {
4278         job_request_t *job;
4279 
4280         job = (job_request_t *)kmem_cache_alloc(fctl_job_cache, sleep);
4281         if (job != NULL) {
4282                 job->job_result = FC_SUCCESS;
4283                 job->job_code = job_code;
4284                 job->job_flags = job_flags;
4285                 job->job_cb_arg = arg;
4286                 job->job_comp = comp;
4287                 job->job_private = NULL;
4288                 job->job_ulp_pkts = NULL;
4289                 job->job_ulp_listlen = 0;
4290                 job->job_counter = 0;
4291                 job->job_next = NULL;
4292         }
4293 
4294         return (job);
4295 }
4296 
4297 
4298 void
4299 fctl_dealloc_job(job_request_t *job)
4300 {
4301         kmem_cache_free(fctl_job_cache, (void *)job);
4302 }
4303 
4304 
4305 void
4306 fctl_enque_job(fc_local_port_t *port, job_request_t *job)
4307 {
4308         ASSERT(!MUTEX_HELD(&port->fp_mutex));
4309 
4310         mutex_enter(&port->fp_mutex);
4311 
4312         if (port->fp_job_tail == NULL) {
4313                 ASSERT(port->fp_job_head == NULL);
4314                 port->fp_job_head = port->fp_job_tail = job;
4315         } else {
4316                 port->fp_job_tail->job_next = job;
4317                 port->fp_job_tail = job;
4318         }
4319         job->job_next = NULL;
4320 
4321         cv_signal(&port->fp_cv);
4322         mutex_exit(&port->fp_mutex);
4323 }
4324 
4325 
4326 job_request_t *
4327 fctl_deque_job(fc_local_port_t *port)
4328 {
4329         job_request_t *job;
4330 
4331         ASSERT(MUTEX_HELD(&port->fp_mutex));
4332 
4333         if (port->fp_job_head == NULL) {
4334                 ASSERT(port->fp_job_tail == NULL);
4335                 job = NULL;
4336         } else {
4337                 job = port->fp_job_head;
4338                 if (job->job_next == NULL) {
4339                         ASSERT(job == port->fp_job_tail);
4340                         port->fp_job_tail = NULL;
4341                 }
4342                 port->fp_job_head = job->job_next;
4343         }
4344 
4345         return (job);
4346 }
4347 
4348 
4349 void
4350 fctl_priority_enque_job(fc_local_port_t *port, job_request_t *job)
4351 {
4352         ASSERT(!MUTEX_HELD(&port->fp_mutex));
4353 
4354         mutex_enter(&port->fp_mutex);
4355         if (port->fp_job_tail == NULL) {
4356                 ASSERT(port->fp_job_head == NULL);
4357                 port->fp_job_head = port->fp_job_tail = job;
4358                 job->job_next = NULL;
4359         } else {
4360                 job->job_next = port->fp_job_head;
4361                 port->fp_job_head = job;
4362         }
4363         cv_signal(&port->fp_cv);
4364         mutex_exit(&port->fp_mutex);
4365 }
4366 
4367 
4368 void
4369 fctl_jobwait(job_request_t *job)
4370 {
4371         ASSERT(!(job->job_flags & JOB_TYPE_FCTL_ASYNC));
4372         sema_p(&job->job_fctl_sema);
4373         ASSERT(!MUTEX_HELD(&job->job_mutex));
4374 }
4375 
4376 
4377 void
4378 fctl_jobdone(job_request_t *job)
4379 {
4380         if (job->job_flags & JOB_TYPE_FCTL_ASYNC) {
4381                 if (job->job_comp) {
4382                         job->job_comp(job->job_cb_arg, job->job_result);
4383                 }
4384                 fctl_dealloc_job(job);
4385         } else {
4386                 sema_v(&job->job_fctl_sema);
4387         }
4388 }
4389 
4390 
4391 /*
4392  * Compare two WWNs.
4393  * The NAA can't be omitted for comparison.
4394  *
4395  * Return Values:
4396  *   if src == dst return  0
4397  *   if src > dst  return  1
4398  *   if src < dst  return -1
4399  */
4400 int
4401 fctl_wwn_cmp(la_wwn_t *src, la_wwn_t *dst)
4402 {
4403         uint8_t *l, *r;
4404         int i;
4405         uint64_t wl, wr;
4406 
4407         l = (uint8_t *)src;
4408         r = (uint8_t *)dst;
4409 
4410         for (i = 0, wl = 0; i < 8; i++) {
4411                 wl <<= 8;
4412                 wl |= l[i];
4413         }
4414         for (i = 0, wr = 0; i < 8; i++) {
4415                 wr <<= 8;
4416                 wr |= r[i];
4417         }
4418 
4419         if (wl > wr) {
4420                 return (1);
4421         } else if (wl == wr) {
4422                 return (0);
4423         } else {
4424                 return (-1);
4425         }
4426 }
4427 
4428 
4429 /*
4430  * ASCII to Integer goodie with support for base 16, 10, 2 and 8
4431  */
4432 int
4433 fctl_atoi(char *s, int base)
4434 {
4435         int val;
4436         int ch;
4437 
4438         for (val = 0; *s != '\0'; s++) {
4439                 switch (base) {
4440                 case 16:
4441                         if (*s >= '0' && *s <= '9') {
4442                                 ch = *s - '0';
4443                         } else if (*s >= 'a' && *s <= 'f') {
4444                                 ch = *s - 'a' + 10;
4445                         } else if (*s >= 'A' && *s <= 'F') {
4446                                 ch = *s - 'A' + 10;
4447                         } else {
4448                                 return (-1);
4449                         }
4450                         break;
4451 
4452                 case 10:
4453                         if (*s < '0' || *s > '9') {
4454                                 return (-1);
4455                         }
4456                         ch = *s - '0';
4457                         break;
4458 
4459                 case 2:
4460                         if (*s < '0' || *s > '1') {
4461                                 return (-1);
4462                         }
4463                         ch = *s - '0';
4464                         break;
4465 
4466                 case 8:
4467                         if (*s < '0' || *s > '7') {
4468                                 return (-1);
4469                         }
4470                         ch = *s - '0';
4471                         break;
4472 
4473                 default:
4474                         return (-1);
4475                 }
4476                 val = (val * base) + ch;
4477         }
4478         return (val);
4479 }
4480 
4481 
4482 /*
4483  * Create the fc_remote_port_t struct for the given port_wwn and d_id.
4484  *
4485  * If the struct already exists (and is "valid"), then use it. Before using
4486  * it, the code below also checks: (a) if the d_id has changed, and (b) if
4487  * the device is maked as PORT_DEVICE_OLD.
4488  *
4489  * If no fc_remote_node_t struct exists for the given node_wwn, then that
4490  * struct is also created (and linked with the fc_remote_port_t).
4491  *
4492  * The given fc_local_port_t struct is updated with the info on the new
4493  * struct(s). The d_id and pwwn hash tables in the port_wwn are updated.
4494  * The global node_hash_table[] is updated (if necessary).
4495  */
4496 fc_remote_port_t *
4497 fctl_create_remote_port(fc_local_port_t *port, la_wwn_t *node_wwn,
4498     la_wwn_t *port_wwn, uint32_t d_id, uchar_t recepient, int sleep)
4499 {
4500         int                     invalid = 0;
4501         fc_remote_node_t        *rnodep;
4502         fc_remote_port_t        *pd;
4503 
4504         rnodep = fctl_get_remote_node_by_nwwn(node_wwn);
4505         if (rnodep) {
4506                 /*
4507                  * We found an fc_remote_node_t for the remote node -- see if
4508                  * anyone has marked it as going away or gone.
4509                  */
4510                 mutex_enter(&rnodep->fd_mutex);
4511                 invalid = (rnodep->fd_flags == FC_REMOTE_NODE_INVALID) ? 1 : 0;
4512                 mutex_exit(&rnodep->fd_mutex);
4513         }
4514         if (rnodep == NULL || invalid) {
4515                 /*
4516                  * No valid remote node struct found -- create it.
4517                  * Note: this is the only place that this func is called.
4518                  */
4519                 rnodep = fctl_create_remote_node(node_wwn, sleep);
4520                 if (rnodep == NULL) {
4521                         return (NULL);
4522                 }
4523         }
4524 
4525         mutex_enter(&port->fp_mutex);
4526 
4527         /*
4528          * See if there already is an fc_remote_port_t struct in existence
4529          * on the specified fc_local_port_t for the given pwwn.  If so, then
4530          * grab a reference to it. The 'held' here just means that fp_mutex
4531          * is held by the caller -- no reference counts are updated.
4532          */
4533         pd = fctl_get_remote_port_by_pwwn_mutex_held(port, port_wwn);
4534         if (pd) {
4535                 /*
4536                  * An fc_remote_port_t struct was found -- see if anyone has
4537                  * marked it as "invalid", which means that it is in the
4538                  * process of going away & we don't want to use it.
4539                  */
4540                 mutex_enter(&pd->pd_mutex);
4541                 invalid = (pd->pd_state == PORT_DEVICE_INVALID) ? 1 : 0;
4542                 mutex_exit(&pd->pd_mutex);
4543         }
4544 
4545         if (pd == NULL || invalid) {
4546                 /*
4547                  * No fc_remote_port_t was found (or the existing one is
4548                  * marked as "invalid".) Allocate a new one and use that.
4549                  * This call will also update the d_id and pwwn hash tables
4550                  * in the given fc_local_port_t struct with the newly allocated
4551                  * fc_remote_port_t.
4552                  */
4553                 if ((pd = fctl_alloc_remote_port(port, port_wwn, d_id,
4554                     recepient, sleep)) == NULL) {
4555                         /* Just give up if the allocation fails. */
4556                         mutex_exit(&port->fp_mutex);
4557                         fctl_destroy_remote_node(rnodep);
4558                         return (pd);
4559                 }
4560 
4561                 /*
4562                  * Add the new fc_remote_port_t struct to the d_id and pwwn
4563                  * hash tables on the associated fc_local_port_t struct.
4564                  */
4565                 mutex_enter(&pd->pd_mutex);
4566                 pd->pd_remote_nodep = rnodep;
4567                 fctl_enlist_did_table(port, pd);
4568                 fctl_enlist_pwwn_table(port, pd);
4569                 mutex_exit(&pd->pd_mutex);
4570                 mutex_exit(&port->fp_mutex);
4571 
4572                 /*
4573                  * Retrieve a pointer to the fc_remote_node_t (i.e., remote
4574                  * node) specified by the given node_wwn.  This looks in the
4575                  * global fctl_nwwn_hash_table[]. The fd_numports reference
4576                  * count in the fc_remote_node_t struct is incremented.
4577                  */
4578                 rnodep = fctl_lock_remote_node_by_nwwn(node_wwn);
4579 
4580         } else {
4581                 /*
4582                  * An existing and valid fc_remote_port_t struct already
4583                  * exists on the fc_local_port_t for the given pwwn.
4584                  */
4585 
4586                 mutex_enter(&pd->pd_mutex);
4587                 ASSERT(pd->pd_remote_nodep != NULL);
4588 
4589                 if (pd->pd_port_id.port_id != d_id) {
4590                         /*
4591                          * A very unlikely occurance in a well
4592                          * behaved environment.
4593                          */
4594 
4595                         /*
4596                          * The existing fc_remote_port_t has a different
4597                          * d_id than what we were given. This code will
4598                          * update the existing one with the one that was
4599                          * just given.
4600                          */
4601                         char string[(FCTL_WWN_SIZE(port_wwn) << 1) + 1];
4602                         uint32_t old_id;
4603 
4604                         fc_wwn_to_str(port_wwn, string);
4605 
4606                         old_id = pd->pd_port_id.port_id;
4607 
4608                         fctl_delist_did_table(port, pd);
4609 
4610                         cmn_err(CE_NOTE, "!fctl(%d): D_ID of a device"
4611                             " with PWWN %s changed. New D_ID = %x,"
4612                             " OLD D_ID = %x", port->fp_instance, string,
4613                             d_id, old_id);
4614 
4615                         pd->pd_port_id.port_id = d_id;
4616 
4617                         /*
4618                          * Looks like we have to presume here that the
4619                          * remote port could be something entirely different
4620                          * from what was previously existing & valid at this
4621                          * pwwn.
4622                          */
4623                         pd->pd_type = PORT_DEVICE_CHANGED;
4624 
4625                         /* Record (update) the new d_id for the remote port */
4626                         fctl_enlist_did_table(port, pd);
4627 
4628                 } else if (pd->pd_type == PORT_DEVICE_OLD) {
4629                         /*
4630                          * OK at least the old & new d_id's match. So for
4631                          * PORT_DEVICE_OLD, this assumes that the remote
4632                          * port had disappeared but now has come back.
4633                          * Update the pd_type and pd_state to put the
4634                          * remote port back into service.
4635                          */
4636                         pd->pd_type = PORT_DEVICE_NOCHANGE;
4637                         pd->pd_state = PORT_DEVICE_VALID;
4638 
4639                         fctl_enlist_did_table(port, pd);
4640 
4641                 } else {
4642                         /*
4643                          * OK the old & new d_id's match, and the remote
4644                          * port struct is not marked as PORT_DEVICE_OLD, so
4645                          * presume that it's still the same device and is
4646                          * still in good shape.  Also this presumes that we
4647                          * do not need to update d_id or pwwn hash tables.
4648                          */
4649                         /* sanitize device values */
4650                         pd->pd_type = PORT_DEVICE_NOCHANGE;
4651                         pd->pd_state = PORT_DEVICE_VALID;
4652                 }
4653 
4654                 mutex_exit(&pd->pd_mutex);
4655                 mutex_exit(&port->fp_mutex);
4656 
4657                 if (rnodep != pd->pd_remote_nodep) {
4658                         if ((rnodep != NULL) &&
4659                             (fctl_wwn_cmp(&pd->pd_remote_nodep->fd_node_name,
4660                             node_wwn) != 0)) {
4661                                 /*
4662                                  * Rut-roh, there is an fc_remote_node_t remote
4663                                  * node struct for the given node_wwn, but the
4664                                  * fc_remote_port_t remote port struct doesn't
4665                                  * know about it.  This just prints a warning
4666                                  * message & fails the fc_remote_port_t
4667                                  * allocation (possible leak here?).
4668                                  */
4669                                 char    ww1_name[17];
4670                                 char    ww2_name[17];
4671 
4672                                 fc_wwn_to_str(
4673                                     &pd->pd_remote_nodep->fd_node_name,
4674                                     ww1_name);
4675                                 fc_wwn_to_str(node_wwn, ww2_name);
4676 
4677                                 cmn_err(CE_WARN, "fctl(%d) NWWN Mismatch: "
4678                                     "Expected %s Got %s", port->fp_instance,
4679                                     ww1_name, ww2_name);
4680                         }
4681 
4682                         return (NULL);
4683                 }
4684         }
4685 
4686         /*
4687          * Add  the fc_remote_port_t onto the linked list of remote port
4688          * devices associated with the given fc_remote_node_t (remote node).
4689          */
4690         fctl_link_remote_port_to_remote_node(rnodep, pd);
4691 
4692         return (pd);
4693 }
4694 
4695 
4696 /*
4697  * Disassociate the given fc_local_port_t and fc_remote_port_t structs. Removes
4698  * the fc_remote_port_t from the associated fc_remote_node_t. Also removes any
4699  * references to the fc_remote_port_t from the d_id and pwwn tables in the
4700  * given fc_local_port_t.  Deallocates the given fc_remote_port_t.
4701  *
4702  * Returns a count of the number of remaining fc_remote_port_t structs
4703  * associated with the fc_remote_node_t struct.
4704  *
4705  * If pd_ref_count in the given fc_remote_port_t is nonzero, then this
4706  * function just sets the pd->pd_aux_flags |= PD_NEEDS_REMOVAL and the
4707  * pd->pd_type = PORT_DEVICE_OLD and lets some other function(s) worry about
4708  * the cleanup.  The function then also returns '1'
4709  * instead of the actual number of remaining fc_remote_port_t structs
4710  *
4711  * If there are no more remote ports on the remote node, return 0.
4712  * Otherwise, return non-zero.
4713  */
4714 int
4715 fctl_destroy_remote_port(fc_local_port_t *port, fc_remote_port_t *pd)
4716 {
4717         fc_remote_node_t        *rnodep;
4718         int                     rcount = 0;
4719 
4720         mutex_enter(&pd->pd_mutex);
4721 
4722         /*
4723          * If pd_ref_count > 0, we can't pull the rug out from any
4724          * current users of this fc_remote_port_t.  We'll mark it as old
4725          * and in need of removal.  The same goes for any fc_remote_port_t
4726          * that has a reference handle(s) in a ULP(s) but for which the ULP(s)
4727          * have not yet been notified that the handle is no longer valid
4728          * (i.e., PD_GIVEN_TO_ULPS is set).
4729          */
4730         if ((pd->pd_ref_count > 0) ||
4731             (pd->pd_aux_flags & PD_GIVEN_TO_ULPS)) {
4732                 pd->pd_aux_flags |= PD_NEEDS_REMOVAL;
4733                 pd->pd_type = PORT_DEVICE_OLD;
4734                 mutex_exit(&pd->pd_mutex);
4735                 return (1);
4736         }
4737 
4738         pd->pd_type = PORT_DEVICE_OLD;
4739 
4740         rnodep = pd->pd_remote_nodep;
4741 
4742         mutex_exit(&pd->pd_mutex);
4743 
4744         if (rnodep != NULL) {
4745                 /*
4746                  * Remove the fc_remote_port_t from the linked list of remote
4747                  * ports for the given fc_remote_node_t. This is only called
4748                  * here and in fctl_destroy_all_remote_ports().
4749                  */
4750                 rcount = fctl_unlink_remote_port_from_remote_node(rnodep, pd);
4751         }
4752 
4753         mutex_enter(&port->fp_mutex);
4754         mutex_enter(&pd->pd_mutex);
4755 
4756         fctl_delist_did_table(port, pd);
4757         fctl_delist_pwwn_table(port, pd);
4758 
4759         mutex_exit(&pd->pd_mutex);
4760 
4761         /*
4762          * Deconstruct & free the fc_remote_port_t. This is only called
4763          * here and in fctl_destroy_all_remote_ports().
4764          */
4765         fctl_dealloc_remote_port(pd);
4766 
4767         mutex_exit(&port->fp_mutex);
4768 
4769         return (rcount);
4770 }
4771 
4772 
4773 /*
4774  * This goes thru the d_id table on the given fc_local_port_t.
4775  * For each fc_remote_port_t found, this will:
4776  *
4777  *  - Remove the fc_remote_port_t from the linked list of remote ports for
4778  *    the associated fc_remote_node_t.  If the linked list goes empty, then this
4779  *    tries to deconstruct & free the fc_remote_node_t (that also removes the
4780  *    fc_remote_node_t from the global fctl_nwwn_hash_table[]).
4781  *
4782  *  - Remove the fc_remote_port_t from the pwwn list on the given
4783  *    fc_local_port_t.
4784  *
4785  *  - Deconstruct and free the fc_remote_port_t.
4786  *
4787  *  - Removes the link to the fc_remote_port_t in the d_id table. Note, this
4788  *    does not appear to correctle decrement the d_id_count tho.
4789  */
4790 void
4791 fctl_destroy_all_remote_ports(fc_local_port_t *port)
4792 {
4793         int                     index;
4794         fc_remote_port_t        *pd;
4795         fc_remote_node_t        *rnodep;
4796         struct d_id_hash        *head;
4797 
4798         mutex_enter(&port->fp_mutex);
4799 
4800         for (index = 0; index < did_table_size; index++) {
4801 
4802                 head = &port->fp_did_table[index];
4803 
4804                 while (head->d_id_head != NULL) {
4805                         pd = head->d_id_head;
4806 
4807                         /*
4808                          * See if this remote port (fc_remote_port_t) has a
4809                          * reference to a remote node (fc_remote_node_t) in its
4810                          * pd->pd_remote_nodep pointer.
4811                          */
4812                         mutex_enter(&pd->pd_mutex);
4813                         rnodep = pd->pd_remote_nodep;
4814                         mutex_exit(&pd->pd_mutex);
4815 
4816                         if (rnodep != NULL) {
4817                                 /*
4818                                  * An fc_remote_node_t reference exists. Remove
4819                                  * the fc_remote_port_t from the linked list of
4820                                  * remote ports for fc_remote_node_t.
4821                                  */
4822                                 if (fctl_unlink_remote_port_from_remote_node(
4823                                     rnodep, pd) == 0) {
4824                                         /*
4825                                          * The fd_numports reference count
4826                                          * in the fc_remote_node_t has come
4827                                          * back as zero, so we can free the
4828                                          * fc_remote_node_t. This also means
4829                                          * that the fc_remote_node_t was
4830                                          * removed from the
4831                                          * fctl_nwwn_hash_table[].
4832                                          *
4833                                          * This will silently skip the
4834                                          * kmem_free() if either the
4835                                          * fd_numports is nonzero or
4836                                          * the fd_port is not NULL in
4837                                          * the fc_remote_node_t.
4838                                          */
4839                                         fctl_destroy_remote_node(rnodep);
4840                                 }
4841                         }
4842 
4843                         /*
4844                          * Clean up the entry in the fc_local_port_t's pwwn
4845                          * table for the given fc_remote_port_t (i.e., the pd).
4846                          */
4847                         mutex_enter(&pd->pd_mutex);
4848                         fctl_delist_pwwn_table(port, pd);
4849                         pd->pd_aux_flags &= ~PD_IN_DID_QUEUE;
4850                         mutex_exit(&pd->pd_mutex);
4851 
4852                         /*
4853                          * Remove the current entry from the d_id list.
4854                          */
4855                         head->d_id_head = pd->pd_did_hnext;
4856 
4857                         /*
4858                          * Deconstruct & free the fc_remote_port_t (pd)
4859                          * Note: this is only called here and in
4860                          * fctl_destroy_remote_port_t().
4861                          */
4862                         fctl_dealloc_remote_port(pd);
4863                 }
4864         }
4865 
4866         mutex_exit(&port->fp_mutex);
4867 }
4868 
4869 
4870 int
4871 fctl_is_wwn_zero(la_wwn_t *wwn)
4872 {
4873         int count;
4874 
4875         for (count = 0; count < sizeof (la_wwn_t); count++) {
4876                 if (wwn->raw_wwn[count] != 0) {
4877                         return (FC_FAILURE);
4878                 }
4879         }
4880 
4881         return (FC_SUCCESS);
4882 }
4883 
4884 
4885 void
4886 fctl_ulp_unsol_cb(fc_local_port_t *port, fc_unsol_buf_t *buf, uchar_t type)
4887 {
4888         int                     data_cb;
4889         int                     check_type;
4890         int                     rval;
4891         uint32_t                claimed;
4892         fc_ulp_module_t         *mod;
4893         fc_ulp_ports_t          *ulp_port;
4894 
4895         claimed = 0;
4896         check_type = 1;
4897 
4898         switch ((buf->ub_frame.r_ctl) & R_CTL_ROUTING) {
4899         case R_CTL_DEVICE_DATA:
4900                 data_cb = 1;
4901                 break;
4902 
4903         case R_CTL_EXTENDED_SVC:
4904                 check_type = 0;
4905                 /* FALLTHROUGH */
4906 
4907         case R_CTL_FC4_SVC:
4908                 data_cb = 0;
4909                 break;
4910 
4911         default:
4912                 mutex_enter(&port->fp_mutex);
4913                 ASSERT(port->fp_active_ubs > 0);
4914                 if (--(port->fp_active_ubs) == 0) {
4915                         port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
4916                 }
4917                 mutex_exit(&port->fp_mutex);
4918                 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
4919                     1, &buf->ub_token);
4920                 return;
4921         }
4922 
4923         rw_enter(&fctl_ulp_lock, RW_READER);
4924         for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
4925                 if (check_type && mod->mod_info->ulp_type != type) {
4926                         continue;
4927                 }
4928 
4929                 rw_enter(&fctl_mod_ports_lock, RW_READER);
4930                 ulp_port = fctl_get_ulp_port(mod, port);
4931                 rw_exit(&fctl_mod_ports_lock);
4932 
4933                 if (ulp_port == NULL) {
4934                         continue;
4935                 }
4936 
4937                 mutex_enter(&ulp_port->port_mutex);
4938                 if (FCTL_DISALLOW_CALLBACKS(ulp_port->port_dstate)) {
4939                         mutex_exit(&ulp_port->port_mutex);
4940                         continue;
4941                 }
4942                 mutex_exit(&ulp_port->port_mutex);
4943 
4944                 if (data_cb == 1) {
4945                         rval = mod->mod_info->ulp_data_callback(
4946                             mod->mod_info->ulp_handle,
4947                             (opaque_t)port, buf, claimed);
4948                 } else {
4949                         rval = mod->mod_info->ulp_els_callback(
4950                             mod->mod_info->ulp_handle,
4951                             (opaque_t)port, buf, claimed);
4952                 }
4953 
4954                 if (rval == FC_SUCCESS && claimed == 0) {
4955                         claimed = 1;
4956                 }
4957         }
4958         rw_exit(&fctl_ulp_lock);
4959 
4960         if (claimed == 0) {
4961                 /*
4962                  * We should actually RJT since nobody claimed it.
4963                  */
4964                 mutex_enter(&port->fp_mutex);
4965                 ASSERT(port->fp_active_ubs > 0);
4966                 if (--(port->fp_active_ubs) == 0) {
4967                         port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
4968                 }
4969                 mutex_exit(&port->fp_mutex);
4970                 port->fp_fca_tran->fca_ub_release(port->fp_fca_handle,
4971                     1, &buf->ub_token);
4972 
4973         } else {
4974                 mutex_enter(&port->fp_mutex);
4975                 if (--port->fp_active_ubs == 0) {
4976                         port->fp_soft_state &= ~FP_SOFT_IN_UNSOL_CB;
4977                 }
4978                 mutex_exit(&port->fp_mutex);
4979         }
4980 }
4981 
4982 
4983 /*
4984  * Both fd_mutex and pd_mutex are held (in that order) coming in to this func
4985  *
4986  * With all these mutexes held, we should make sure this function does not eat
4987  * up much time.
4988  */
4989 void
4990 fctl_copy_portmap_held(fc_portmap_t *map, fc_remote_port_t *pd)
4991 {
4992         fc_remote_node_t *node;
4993 
4994         ASSERT(MUTEX_HELD(&pd->pd_mutex));
4995 
4996         map->map_pwwn = pd->pd_port_name;
4997         map->map_did = pd->pd_port_id;
4998         map->map_hard_addr = pd->pd_hard_addr;
4999         map->map_state = pd->pd_state;
5000         map->map_type = pd->pd_type;
5001         map->map_flags = 0;
5002 
5003         ASSERT(map->map_type <= PORT_DEVICE_DELETE);
5004 
5005         bcopy(pd->pd_fc4types, map->map_fc4_types, sizeof (pd->pd_fc4types));
5006 
5007         node = pd->pd_remote_nodep;
5008 
5009         ASSERT(MUTEX_HELD(&node->fd_mutex));
5010 
5011         if (node) {
5012                 map->map_nwwn = node->fd_node_name;
5013         }
5014         map->map_pd = pd;
5015 }
5016 
5017 void
5018 fctl_copy_portmap(fc_portmap_t *map, fc_remote_port_t *pd)
5019 {
5020         fc_remote_node_t *node;
5021 
5022         ASSERT(!MUTEX_HELD(&pd->pd_mutex));
5023 
5024         mutex_enter(&pd->pd_mutex);
5025         map->map_pwwn = pd->pd_port_name;
5026         map->map_did = pd->pd_port_id;
5027         map->map_hard_addr = pd->pd_hard_addr;
5028         map->map_state = pd->pd_state;
5029         map->map_type = pd->pd_type;
5030         map->map_flags = 0;
5031 
5032         ASSERT(map->map_type <= PORT_DEVICE_DELETE);
5033 
5034         bcopy(pd->pd_fc4types, map->map_fc4_types, sizeof (pd->pd_fc4types));
5035 
5036         node = pd->pd_remote_nodep;
5037         mutex_exit(&pd->pd_mutex);
5038 
5039         if (node) {
5040                 mutex_enter(&node->fd_mutex);
5041                 map->map_nwwn = node->fd_node_name;
5042                 mutex_exit(&node->fd_mutex);
5043         }
5044         map->map_pd = pd;
5045 }
5046 
5047 
5048 static int
5049 fctl_update_host_ns_values(fc_local_port_t *port, fc_ns_cmd_t *ns_req)
5050 {
5051         int     rval = FC_SUCCESS;
5052 
5053         switch (ns_req->ns_cmd) {
5054         case NS_RFT_ID: {
5055                 int             count;
5056                 uint32_t        *src;
5057                 uint32_t        *dst;
5058                 ns_rfc_type_t   *rfc;
5059 
5060                 rfc = (ns_rfc_type_t *)ns_req->ns_req_payload;
5061 
5062                 mutex_enter(&port->fp_mutex);
5063                 src = (uint32_t *)port->fp_fc4_types;
5064                 dst = (uint32_t *)rfc->rfc_types;
5065 
5066                 for (count = 0; count < 8; count++) {
5067                         *src++ |= *dst++;
5068                 }
5069                 mutex_exit(&port->fp_mutex);
5070 
5071                 break;
5072         }
5073 
5074         case NS_RSPN_ID: {
5075                 ns_spn_t *spn;
5076 
5077                 spn = (ns_spn_t *)ns_req->ns_req_payload;
5078 
5079                 mutex_enter(&port->fp_mutex);
5080                 port->fp_sym_port_namelen = spn->spn_len;
5081                 if (spn->spn_len) {
5082                         bcopy((caddr_t)spn + sizeof (ns_spn_t),
5083                             port->fp_sym_port_name, spn->spn_len);
5084                 }
5085                 mutex_exit(&port->fp_mutex);
5086 
5087                 break;
5088         }
5089 
5090         case NS_RSNN_NN: {
5091                 ns_snn_t *snn;
5092 
5093                 snn = (ns_snn_t *)ns_req->ns_req_payload;
5094 
5095                 mutex_enter(&port->fp_mutex);
5096                 port->fp_sym_node_namelen = snn->snn_len;
5097                 if (snn->snn_len) {
5098                         bcopy((caddr_t)snn + sizeof (ns_snn_t),
5099                             port->fp_sym_node_name, snn->snn_len);
5100                 }
5101                 mutex_exit(&port->fp_mutex);
5102 
5103                 break;
5104         }
5105 
5106         case NS_RIP_NN: {
5107                 ns_rip_t *rip;
5108 
5109                 rip = (ns_rip_t *)ns_req->ns_req_payload;
5110 
5111                 mutex_enter(&port->fp_mutex);
5112                 bcopy(rip->rip_ip_addr, port->fp_ip_addr,
5113                     sizeof (rip->rip_ip_addr));
5114                 mutex_exit(&port->fp_mutex);
5115 
5116                 break;
5117         }
5118 
5119         case NS_RIPA_NN: {
5120                 ns_ipa_t *ipa;
5121 
5122                 ipa = (ns_ipa_t *)ns_req->ns_req_payload;
5123 
5124                 mutex_enter(&port->fp_mutex);
5125                 bcopy(ipa->ipa_value, port->fp_ipa, sizeof (ipa->ipa_value));
5126                 mutex_exit(&port->fp_mutex);
5127 
5128                 break;
5129         }
5130 
5131         default:
5132                 rval = FC_BADOBJECT;
5133                 break;
5134         }
5135 
5136         return (rval);
5137 }
5138 
5139 
5140 static int
5141 fctl_retrieve_host_ns_values(fc_local_port_t *port, fc_ns_cmd_t *ns_req)
5142 {
5143         int     rval = FC_SUCCESS;
5144 
5145         switch (ns_req->ns_cmd) {
5146         case NS_GFT_ID: {
5147                 ns_rfc_type_t *rfc;
5148 
5149                 rfc = (ns_rfc_type_t *)ns_req->ns_resp_payload;
5150 
5151                 mutex_enter(&port->fp_mutex);
5152                 bcopy(port->fp_fc4_types, rfc->rfc_types,
5153                     sizeof (rfc->rfc_types));
5154                 mutex_exit(&port->fp_mutex);
5155                 break;
5156         }
5157 
5158         case NS_GSPN_ID: {
5159                 ns_spn_t *spn;
5160 
5161                 spn = (ns_spn_t *)ns_req->ns_resp_payload;
5162 
5163                 mutex_enter(&port->fp_mutex);
5164                 spn->spn_len = port->fp_sym_port_namelen;
5165                 if (spn->spn_len) {
5166                         bcopy(port->fp_sym_port_name, (caddr_t)spn +
5167                             sizeof (ns_spn_t), spn->spn_len);
5168                 }
5169                 mutex_exit(&port->fp_mutex);
5170 
5171                 break;
5172         }
5173 
5174         case NS_GSNN_NN: {
5175                 ns_snn_t *snn;
5176 
5177                 snn = (ns_snn_t *)ns_req->ns_resp_payload;
5178 
5179                 mutex_enter(&port->fp_mutex);
5180                 snn->snn_len = port->fp_sym_node_namelen;
5181                 if (snn->snn_len) {
5182                         bcopy(port->fp_sym_node_name, (caddr_t)snn +
5183                             sizeof (ns_snn_t), snn->snn_len);
5184                 }
5185                 mutex_exit(&port->fp_mutex);
5186 
5187                 break;
5188         }
5189 
5190         case NS_GIP_NN: {
5191                 ns_rip_t *rip;
5192 
5193                 rip = (ns_rip_t *)ns_req->ns_resp_payload;
5194 
5195                 mutex_enter(&port->fp_mutex);
5196                 bcopy(port->fp_ip_addr, rip->rip_ip_addr,
5197                     sizeof (rip->rip_ip_addr));
5198                 mutex_exit(&port->fp_mutex);
5199 
5200                 break;
5201         }
5202 
5203         case NS_GIPA_NN: {
5204                 ns_ipa_t *ipa;
5205 
5206                 ipa = (ns_ipa_t *)ns_req->ns_resp_payload;
5207 
5208                 mutex_enter(&port->fp_mutex);
5209                 bcopy(port->fp_ipa, ipa->ipa_value, sizeof (ipa->ipa_value));
5210                 mutex_exit(&port->fp_mutex);
5211 
5212                 break;
5213         }
5214 
5215         default:
5216                 rval = FC_BADOBJECT;
5217                 break;
5218         }
5219 
5220         return (rval);
5221 }
5222 
5223 
5224 fctl_ns_req_t *
5225 fctl_alloc_ns_cmd(uint32_t cmd_len, uint32_t resp_len, uint32_t data_len,
5226     uint32_t ns_flags, int sleep)
5227 {
5228         fctl_ns_req_t *ns_cmd;
5229 
5230         ns_cmd = kmem_zalloc(sizeof (*ns_cmd), sleep);
5231         if (ns_cmd == NULL) {
5232                 return (NULL);
5233         }
5234 
5235         if (cmd_len) {
5236                 ns_cmd->ns_cmd_buf = kmem_zalloc(cmd_len, sleep);
5237                 if (ns_cmd->ns_cmd_buf == NULL) {
5238                         kmem_free(ns_cmd, sizeof (*ns_cmd));
5239                         return (NULL);
5240                 }
5241                 ns_cmd->ns_cmd_size = cmd_len;
5242         }
5243 
5244         ns_cmd->ns_resp_size = resp_len;
5245 
5246         if (data_len) {
5247                 ns_cmd->ns_data_buf = kmem_zalloc(data_len, sleep);
5248                 if (ns_cmd->ns_data_buf == NULL) {
5249                         if (ns_cmd->ns_cmd_buf && cmd_len) {
5250                                 kmem_free(ns_cmd->ns_cmd_buf, cmd_len);
5251                         }
5252                         kmem_free(ns_cmd, sizeof (*ns_cmd));
5253                         return (NULL);
5254                 }
5255                 ns_cmd->ns_data_len = data_len;
5256         }
5257         ns_cmd->ns_flags = ns_flags;
5258 
5259         return (ns_cmd);
5260 }
5261 
5262 
5263 void
5264 fctl_free_ns_cmd(fctl_ns_req_t *ns_cmd)
5265 {
5266         if (ns_cmd->ns_cmd_size && ns_cmd->ns_cmd_buf) {
5267                 kmem_free(ns_cmd->ns_cmd_buf, ns_cmd->ns_cmd_size);
5268         }
5269         if (ns_cmd->ns_data_len && ns_cmd->ns_data_buf) {
5270                 kmem_free(ns_cmd->ns_data_buf, ns_cmd->ns_data_len);
5271         }
5272         kmem_free(ns_cmd, sizeof (*ns_cmd));
5273 }
5274 
5275 
5276 int
5277 fctl_ulp_port_ioctl(fc_local_port_t *port, dev_t dev, int cmd,
5278     intptr_t data, int mode, cred_t *credp, int *rval)
5279 {
5280         int                     ret;
5281         int                     save;
5282         uint32_t                claimed;
5283         fc_ulp_module_t         *mod;
5284         fc_ulp_ports_t          *ulp_port;
5285 
5286         save = *rval;
5287         *rval = ENOTTY;
5288 
5289         rw_enter(&fctl_ulp_lock, RW_READER);
5290         for (claimed = 0, mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
5291                 rw_enter(&fctl_mod_ports_lock, RW_READER);
5292                 ulp_port = fctl_get_ulp_port(mod, port);
5293                 rw_exit(&fctl_mod_ports_lock);
5294 
5295                 if (ulp_port == NULL) {
5296                         continue;
5297                 }
5298 
5299                 mutex_enter(&ulp_port->port_mutex);
5300                 if (FCTL_DISALLOW_CALLBACKS(ulp_port->port_dstate) ||
5301                     mod->mod_info->ulp_port_ioctl == NULL) {
5302                         mutex_exit(&ulp_port->port_mutex);
5303                         continue;
5304                 }
5305                 mutex_exit(&ulp_port->port_mutex);
5306 
5307                 ret = mod->mod_info->ulp_port_ioctl(
5308                     mod->mod_info->ulp_handle, (opaque_t)port,
5309                     dev, cmd, data, mode, credp, rval, claimed);
5310 
5311                 if (ret == FC_SUCCESS && claimed == 0) {
5312                         claimed = 1;
5313                 }
5314         }
5315         rw_exit(&fctl_ulp_lock);
5316 
5317         ret = *rval;
5318         *rval = save;
5319 
5320         return (ret);
5321 }
5322 
5323 /*
5324  * raise power if necessary, and set the port busy
5325  *
5326  * this may cause power to be raised, so no power related locks should
5327  * be held
5328  */
5329 int
5330 fc_ulp_busy_port(opaque_t port_handle)
5331 {
5332         fc_local_port_t *port = port_handle;
5333 
5334         return (fctl_busy_port(port));
5335 }
5336 
5337 void
5338 fc_ulp_idle_port(opaque_t port_handle)
5339 {
5340         fc_local_port_t *port = port_handle;
5341         fctl_idle_port(port);
5342 }
5343 
5344 void
5345 fc_ulp_copy_portmap(fc_portmap_t *map, opaque_t pd)
5346 {
5347         fctl_copy_portmap(map, (fc_remote_port_t *)pd);
5348 }
5349 
5350 
5351 int
5352 fc_ulp_get_npiv_port_num(opaque_t port_handle)
5353 {
5354         int portsnum = 0;
5355         fc_local_port_t *port = port_handle;
5356         fc_local_port_t *tmpport;
5357 
5358         mutex_enter(&port->fp_mutex);
5359         tmpport = port->fp_port_next;
5360         if (!tmpport) {
5361                 mutex_exit(&port->fp_mutex);
5362                 return (portsnum);
5363         }
5364         while (tmpport != port) {
5365                 portsnum ++;
5366                 tmpport = tmpport->fp_port_next;
5367         }
5368         mutex_exit(&port->fp_mutex);
5369         return (portsnum);
5370 }
5371 
5372 fc_local_port_t *
5373 fc_get_npiv_port(fc_local_port_t *phyport, la_wwn_t *pwwn)
5374 {
5375         fc_fca_port_t   *fca_port;
5376         fc_local_port_t *tmpPort = phyport;
5377 
5378         mutex_enter(&fctl_port_lock);
5379 
5380         for (fca_port = fctl_fca_portlist; fca_port != NULL;
5381             fca_port = fca_port->port_next) {
5382                 tmpPort = fca_port->port_handle;
5383                 if (tmpPort == NULL) {
5384                         continue;
5385                 }
5386                 mutex_enter(&tmpPort->fp_mutex);
5387                 if (bcmp(tmpPort->fp_service_params.nport_ww_name.raw_wwn,
5388                     pwwn->raw_wwn, sizeof (la_wwn_t)) == 0) {
5389                         mutex_exit(&tmpPort->fp_mutex);
5390                         mutex_exit(&fctl_port_lock);
5391                         return (tmpPort);
5392                 }
5393                 mutex_exit(&tmpPort->fp_mutex);
5394         }
5395 
5396         mutex_exit(&fctl_port_lock);
5397 
5398         return (NULL);
5399 }
5400 
5401 int
5402 fc_ulp_get_npiv_port_list(opaque_t port_handle, char *pathList)
5403 {
5404         int portsnum = 0;
5405         fc_local_port_t *port = port_handle;
5406         fc_local_port_t *tmpport;
5407 
5408         mutex_enter(&port->fp_mutex);
5409         tmpport = port->fp_port_next;
5410         if (!tmpport || (port->fp_npiv_type == FC_NPIV_PORT)) {
5411                 mutex_exit(&port->fp_mutex);
5412                 return (portsnum);
5413         }
5414 
5415         while (tmpport != port) {
5416                 (void) ddi_pathname(tmpport->fp_port_dip,
5417                     &pathList[MAXPATHLEN * portsnum]);
5418                 portsnum ++;
5419                 tmpport = tmpport->fp_port_next;
5420         }
5421         mutex_exit(&port->fp_mutex);
5422 
5423         return (portsnum);
5424 }
5425 
5426 
5427 fc_local_port_t *
5428 fc_delete_npiv_port(fc_local_port_t *port, la_wwn_t *pwwn)
5429 {
5430         fc_local_port_t *tmpport;
5431 
5432         mutex_enter(&port->fp_mutex);
5433         tmpport = port->fp_port_next;
5434         if (!tmpport || (port->fp_npiv_type == FC_NPIV_PORT)) {
5435                 mutex_exit(&port->fp_mutex);
5436                 return (NULL);
5437         }
5438 
5439         while (tmpport != port) {
5440                 if ((bcmp(tmpport->fp_service_params.nport_ww_name.raw_wwn,
5441                     pwwn->raw_wwn, sizeof (la_wwn_t)) == 0) &&
5442                     (tmpport->fp_npiv_state == 0)) {
5443                         tmpport->fp_npiv_state = FC_NPIV_DELETING;
5444                         mutex_exit(&port->fp_mutex);
5445                         return (tmpport);
5446                 }
5447                 tmpport = tmpport->fp_port_next;
5448         }
5449 
5450         mutex_exit(&port->fp_mutex);
5451         return (NULL);
5452 }
5453 
5454 /*
5455  * Get the list of Adapters.  On multi-ported adapters,
5456  * only ONE port on the adapter will be returned.
5457  * pathList should be (count * MAXPATHLEN) long.
5458  * The return value will be set to the number of
5459  * HBAs that were found on the system.  If the value
5460  * is greater than count, the routine should be retried
5461  * with a larger buffer.
5462  */
5463 int
5464 fc_ulp_get_adapter_paths(char *pathList, int count)
5465 {
5466         fc_fca_port_t   *fca_port;
5467         int             in = 0, out = 0, check, skip, maxPorts = 0;
5468         fc_local_port_t         **portList;
5469         fc_local_port_t         *new_port, *stored_port;
5470         fca_hba_fru_details_t   *new_fru, *stored_fru;
5471 
5472         ASSERT(pathList != NULL);
5473 
5474         /* First figure out how many ports we have */
5475         mutex_enter(&fctl_port_lock);
5476 
5477         for (fca_port = fctl_fca_portlist; fca_port != NULL;
5478             fca_port = fca_port->port_next) {
5479                 maxPorts ++;
5480         }
5481 
5482         /* Now allocate a buffer to store all the pointers for comparisons */
5483         portList = kmem_zalloc(sizeof (fc_local_port_t *) * maxPorts, KM_SLEEP);
5484 
5485         for (fca_port = fctl_fca_portlist; fca_port != NULL;
5486             fca_port = fca_port->port_next) {
5487                 skip = 0;
5488 
5489                 /* Lock the new port for subsequent comparisons */
5490                 new_port = fca_port->port_handle;
5491                 mutex_enter(&new_port->fp_mutex);
5492                 new_fru = &new_port->fp_hba_port_attrs.hba_fru_details;
5493 
5494                 /* Filter out secondary ports from the list */
5495                 for (check = 0; check < out; check++) {
5496                         if (portList[check] == NULL) {
5497                                 continue;
5498                         }
5499                         /* Guard against duplicates (should never happen) */
5500                         if (portList[check] == fca_port->port_handle) {
5501                                 /* Same port */
5502                                 skip = 1;
5503                                 break;
5504                         }
5505 
5506                         /* Lock the already stored port for comparison */
5507                         stored_port = portList[check];
5508                         mutex_enter(&stored_port->fp_mutex);
5509                         stored_fru =
5510                             &stored_port->fp_hba_port_attrs.hba_fru_details;
5511 
5512                         /* Are these ports on the same HBA? */
5513                         if (new_fru->high == stored_fru->high &&
5514                             new_fru->low == stored_fru->low) {
5515                                 /* Now double check driver */
5516                                 if (strncmp(
5517                                     new_port->fp_hba_port_attrs.driver_name,
5518                                     stored_port->fp_hba_port_attrs.driver_name,
5519                                     FCHBA_DRIVER_NAME_LEN) == 0) {
5520                                         /* we don't need to grow the list */
5521                                         skip = 1;
5522                                         /* looking at a lower port index? */
5523                                         if (new_fru->port_index <
5524                                             stored_fru->port_index) {
5525                                                 /* Replace the port in list */
5526                                                 mutex_exit(
5527                                                     &stored_port->fp_mutex);
5528                                                 if (new_port->fp_npiv_type ==
5529                                                     FC_NPIV_PORT) {
5530                                                         break;
5531                                                 }
5532                                                 portList[check] = new_port;
5533                                                 break;
5534                                         } /* Else, just skip this port */
5535                                 }
5536                         }
5537 
5538                         mutex_exit(&stored_port->fp_mutex);
5539                 }
5540                 mutex_exit(&new_port->fp_mutex);
5541 
5542                 if (!skip) {
5543                         /*
5544                          * Either this is the first port for this HBA, or
5545                          * it's a secondary port and we haven't stored the
5546                          * primary/first port for that HBA.  In the latter case,
5547                          * will just filter it out as we proceed to loop.
5548                          */
5549                         if (fca_port->port_handle->fp_npiv_type ==
5550                             FC_NPIV_PORT) {
5551                                 continue;
5552                         } else {
5553                                 portList[out++] = fca_port->port_handle;
5554                         }
5555                 }
5556         }
5557 
5558         if (out <= count) {
5559                 for (in = 0; in < out; in++) {
5560                         (void) ddi_pathname(portList[in]->fp_port_dip,
5561                             &pathList[MAXPATHLEN * in]);
5562                 }
5563         }
5564         mutex_exit(&fctl_port_lock);
5565         kmem_free(portList, sizeof (*portList) * maxPorts);
5566         return (out);
5567 }
5568 
5569 uint32_t
5570 fc_ulp_get_rscn_count(opaque_t port_handle)
5571 {
5572         uint32_t        count;
5573         fc_local_port_t *port;
5574 
5575         port = (fc_local_port_t *)port_handle;
5576         mutex_enter(&port->fp_mutex);
5577         count = port->fp_rscn_count;
5578         mutex_exit(&port->fp_mutex);
5579 
5580         return (count);
5581 }
5582 
5583 
5584 /*
5585  * This function is a very similar to fctl_add_orphan except that it expects
5586  * that the fp_mutex and pd_mutex of the pd passed in are held coming in.
5587  *
5588  * Note that there is a lock hierarchy here (fp_mutex should be held first) but
5589  * since this function could be called with a different pd's pd_mutex held, we
5590  * should take care not to release fp_mutex in this function.
5591  */
5592 int
5593 fctl_add_orphan_held(fc_local_port_t *port, fc_remote_port_t *pd)
5594 {
5595         int             rval = FC_FAILURE;
5596         la_wwn_t        pwwn;
5597         fc_orphan_t     *orp;
5598         fc_orphan_t     *orphan;
5599 
5600         ASSERT(MUTEX_HELD(&port->fp_mutex));
5601         ASSERT(MUTEX_HELD(&pd->pd_mutex));
5602 
5603         pwwn = pd->pd_port_name;
5604 
5605         for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) {
5606                 if (fctl_wwn_cmp(&orp->orp_pwwn, &pwwn) == 0) {
5607                         return (FC_SUCCESS);
5608                 }
5609         }
5610 
5611         orphan = kmem_zalloc(sizeof (*orphan), KM_NOSLEEP);
5612         if (orphan) {
5613                 orphan->orp_pwwn = pwwn;
5614                 orphan->orp_tstamp = ddi_get_lbolt();
5615 
5616                 if (port->fp_orphan_list) {
5617                         ASSERT(port->fp_orphan_count > 0);
5618                         orphan->orp_next = port->fp_orphan_list;
5619                 }
5620                 port->fp_orphan_list = orphan;
5621                 port->fp_orphan_count++;
5622 
5623                 rval = FC_SUCCESS;
5624         }
5625 
5626         return (rval);
5627 }
5628 
5629 int
5630 fctl_add_orphan(fc_local_port_t *port, fc_remote_port_t *pd, int sleep)
5631 {
5632         int             rval = FC_FAILURE;
5633         la_wwn_t        pwwn;
5634         fc_orphan_t     *orp;
5635         fc_orphan_t     *orphan;
5636 
5637         mutex_enter(&port->fp_mutex);
5638 
5639         mutex_enter(&pd->pd_mutex);
5640         pwwn = pd->pd_port_name;
5641         mutex_exit(&pd->pd_mutex);
5642 
5643         for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) {
5644                 if (fctl_wwn_cmp(&orp->orp_pwwn, &pwwn) == 0) {
5645                         mutex_exit(&port->fp_mutex);
5646                         return (FC_SUCCESS);
5647                 }
5648         }
5649         mutex_exit(&port->fp_mutex);
5650 
5651         orphan = kmem_zalloc(sizeof (*orphan), sleep);
5652         if (orphan != NULL) {
5653                 mutex_enter(&port->fp_mutex);
5654 
5655                 orphan->orp_pwwn = pwwn;
5656                 orphan->orp_tstamp = ddi_get_lbolt();
5657 
5658                 if (port->fp_orphan_list) {
5659                         ASSERT(port->fp_orphan_count > 0);
5660                         orphan->orp_next = port->fp_orphan_list;
5661                 }
5662                 port->fp_orphan_list = orphan;
5663                 port->fp_orphan_count++;
5664                 mutex_exit(&port->fp_mutex);
5665 
5666                 rval = FC_SUCCESS;
5667         }
5668 
5669         return (rval);
5670 }
5671 
5672 
5673 int
5674 fctl_remove_if_orphan(fc_local_port_t *port, la_wwn_t *pwwn)
5675 {
5676         int             rval = FC_FAILURE;
5677         fc_orphan_t     *prev = NULL;
5678         fc_orphan_t     *orp;
5679 
5680         mutex_enter(&port->fp_mutex);
5681         for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) {
5682                 if (fctl_wwn_cmp(&orp->orp_pwwn, pwwn) == 0) {
5683                         if (prev) {
5684                                 prev->orp_next = orp->orp_next;
5685                         } else {
5686                                 ASSERT(port->fp_orphan_list == orp);
5687                                 port->fp_orphan_list = orp->orp_next;
5688                         }
5689                         port->fp_orphan_count--;
5690                         rval = FC_SUCCESS;
5691                         break;
5692                 }
5693                 prev = orp;
5694         }
5695         mutex_exit(&port->fp_mutex);
5696 
5697         if (rval == FC_SUCCESS) {
5698                 kmem_free(orp, sizeof (*orp));
5699         }
5700 
5701         return (rval);
5702 }
5703 
5704 
5705 static void
5706 fctl_print_if_not_orphan(fc_local_port_t *port, fc_remote_port_t *pd)
5707 {
5708         char            ww_name[17];
5709         la_wwn_t        pwwn;
5710         fc_orphan_t     *orp;
5711 
5712         mutex_enter(&port->fp_mutex);
5713 
5714         mutex_enter(&pd->pd_mutex);
5715         pwwn = pd->pd_port_name;
5716         mutex_exit(&pd->pd_mutex);
5717 
5718         for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) {
5719                 if (fctl_wwn_cmp(&orp->orp_pwwn, &pwwn) == 0) {
5720                         mutex_exit(&port->fp_mutex);
5721                         return;
5722                 }
5723         }
5724         mutex_exit(&port->fp_mutex);
5725 
5726         fc_wwn_to_str(&pwwn, ww_name);
5727 
5728         cmn_err(CE_WARN, "!fctl(%d): N_x Port with D_ID=%x, PWWN=%s"
5729             " disappeared from fabric", port->fp_instance,
5730             pd->pd_port_id.port_id, ww_name);
5731 }
5732 
5733 
5734 /* ARGSUSED */
5735 static void
5736 fctl_link_reset_done(opaque_t port_handle, uchar_t result)
5737 {
5738         fc_local_port_t *port = port_handle;
5739 
5740         mutex_enter(&port->fp_mutex);
5741         port->fp_soft_state &= ~FP_SOFT_IN_LINK_RESET;
5742         mutex_exit(&port->fp_mutex);
5743 
5744         fctl_idle_port(port);
5745 }
5746 
5747 
5748 static int
5749 fctl_error(int fc_errno, char **errmsg)
5750 {
5751         int count;
5752 
5753         for (count = 0; count < sizeof (fc_errlist) /
5754             sizeof (fc_errlist[0]); count++) {
5755                 if (fc_errlist[count].fc_errno == fc_errno) {
5756                         *errmsg = fc_errlist[count].fc_errname;
5757                         return (FC_SUCCESS);
5758                 }
5759         }
5760         *errmsg = fctl_undefined;
5761 
5762         return (FC_FAILURE);
5763 }
5764 
5765 
5766 /*
5767  * Return number of successful translations.
5768  *      Anybody with some userland programming experience would have
5769  *      figured it by now that the return value exactly resembles that
5770  *      of scanf(3c). This function returns a count of successful
5771  *      translations. It could range from 0 (no match for state, reason,
5772  *      action, expln) to 4 (successful matches for all state, reason,
5773  *      action, expln) and where translation isn't successful into a
5774  *      friendlier message the relevent field is set to "Undefined"
5775  */
5776 static int
5777 fctl_pkt_error(fc_packet_t *pkt, char **state, char **reason,
5778     char **action, char **expln)
5779 {
5780         int             ret;
5781         int             len;
5782         int             index;
5783         fc_pkt_error_t  *error;
5784         fc_pkt_reason_t *reason_b;      /* Base pointer */
5785         fc_pkt_action_t *action_b;      /* Base pointer */
5786         fc_pkt_expln_t  *expln_b;       /* Base pointer */
5787 
5788         ret = 0;
5789         *state = *reason = *action = *expln = fctl_undefined;
5790 
5791         len = sizeof (fc_pkt_errlist) / sizeof fc_pkt_errlist[0];
5792         for (index = 0; index < len; index++) {
5793                 error = fc_pkt_errlist + index;
5794                 if (pkt->pkt_state == error->pkt_state) {
5795                         *state = error->pkt_msg;
5796                         ret++;
5797 
5798                         reason_b = error->pkt_reason;
5799                         action_b = error->pkt_action;
5800                         expln_b = error->pkt_expln;
5801 
5802                         while (reason_b != NULL &&
5803                             reason_b->reason_val != FC_REASON_INVALID) {
5804                                 if (reason_b->reason_val == pkt->pkt_reason) {
5805                                         *reason = reason_b->reason_msg;
5806                                         ret++;
5807                                         break;
5808                                 }
5809                                 reason_b++;
5810                         }
5811 
5812                         while (action_b != NULL &&
5813                             action_b->action_val != FC_ACTION_INVALID) {
5814                                 if (action_b->action_val == pkt->pkt_action) {
5815                                         *action = action_b->action_msg;
5816                                         ret++;
5817                                         break;
5818                                 }
5819                                 action_b++;
5820                         }
5821 
5822                         while (expln_b != NULL &&
5823                             expln_b->expln_val != FC_EXPLN_INVALID) {
5824                                 if (expln_b->expln_val == pkt->pkt_expln) {
5825                                         *expln = expln_b->expln_msg;
5826                                         ret++;
5827                                         break;
5828                                 }
5829                                 expln_b++;
5830                         }
5831                         break;
5832                 }
5833         }
5834 
5835         return (ret);
5836 }
5837 
5838 
5839 /*
5840  * Remove all port devices that are marked OLD, remove
5841  * corresponding node devices (fc_remote_node_t)
5842  */
5843 void
5844 fctl_remove_oldies(fc_local_port_t *port)
5845 {
5846         int                     index;
5847         int                     initiator;
5848         fc_remote_node_t        *node;
5849         struct pwwn_hash        *head;
5850         fc_remote_port_t        *pd;
5851         fc_remote_port_t        *old_pd;
5852         fc_remote_port_t        *last_pd;
5853 
5854         /*
5855          * Nuke all OLD devices
5856          */
5857         mutex_enter(&port->fp_mutex);
5858 
5859         for (index = 0; index < pwwn_table_size; index++) {
5860                 head = &port->fp_pwwn_table[index];
5861                 last_pd = NULL;
5862                 pd = head->pwwn_head;
5863 
5864                 while (pd != NULL) {
5865                         mutex_enter(&pd->pd_mutex);
5866                         if (pd->pd_type != PORT_DEVICE_OLD) {
5867                                 mutex_exit(&pd->pd_mutex);
5868                                 last_pd = pd;
5869                                 pd = pd->pd_wwn_hnext;
5870                                 continue;
5871                         }
5872 
5873                         /*
5874                          * Remove this from the PWWN hash table
5875                          */
5876                         old_pd = pd;
5877                         pd = old_pd->pd_wwn_hnext;
5878 
5879                         if (last_pd == NULL) {
5880                                 ASSERT(old_pd == head->pwwn_head);
5881                                 head->pwwn_head = pd;
5882                         } else {
5883                                 last_pd->pd_wwn_hnext = pd;
5884                         }
5885                         head->pwwn_count--;
5886                         /*
5887                          * Make sure we tie fp_dev_count to the size of the
5888                          * pwwn_table
5889                          */
5890                         port->fp_dev_count--;
5891                         old_pd->pd_wwn_hnext = NULL;
5892 
5893                         fctl_delist_did_table(port, old_pd);
5894                         node = old_pd->pd_remote_nodep;
5895                         ASSERT(node != NULL);
5896 
5897                         initiator = (old_pd->pd_recepient ==
5898                             PD_PLOGI_INITIATOR) ? 1 : 0;
5899 
5900                         mutex_exit(&old_pd->pd_mutex);
5901 
5902                         if (FC_IS_TOP_SWITCH(port->fp_topology) && initiator) {
5903                                 mutex_exit(&port->fp_mutex);
5904 
5905                                 (void) fctl_add_orphan(port, old_pd,
5906                                     KM_NOSLEEP);
5907                         } else {
5908                                 mutex_exit(&port->fp_mutex);
5909                         }
5910 
5911                         if (fctl_destroy_remote_port(port, old_pd) == 0) {
5912                                 if (node) {
5913                                         fctl_destroy_remote_node(node);
5914                                 }
5915                         }
5916 
5917                         mutex_enter(&port->fp_mutex);
5918                 }
5919         }
5920 
5921         mutex_exit(&port->fp_mutex);
5922 }
5923 
5924 
5925 static void
5926 fctl_check_alpa_list(fc_local_port_t *port, fc_remote_port_t *pd)
5927 {
5928         ASSERT(MUTEX_HELD(&port->fp_mutex));
5929         ASSERT(port->fp_topology == FC_TOP_PRIVATE_LOOP);
5930 
5931         if (fctl_is_alpa_present(port, pd->pd_port_id.port_id) == FC_SUCCESS) {
5932                 return;
5933         }
5934 
5935         cmn_err(CE_WARN, "!fctl(%d): AL_PA=0x%x doesn't exist in LILP map",
5936             port->fp_instance, pd->pd_port_id.port_id);
5937 }
5938 
5939 
5940 static int
5941 fctl_is_alpa_present(fc_local_port_t *port, uchar_t alpa)
5942 {
5943         int index;
5944 
5945         ASSERT(MUTEX_HELD(&port->fp_mutex));
5946         ASSERT(port->fp_topology == FC_TOP_PRIVATE_LOOP);
5947 
5948         for (index = 0; index < port->fp_lilp_map.lilp_length; index++) {
5949                 if (port->fp_lilp_map.lilp_alpalist[index] == alpa) {
5950                         return (FC_SUCCESS);
5951                 }
5952         }
5953 
5954         return (FC_FAILURE);
5955 }
5956 
5957 
5958 fc_remote_port_t *
5959 fctl_lookup_pd_by_did(fc_local_port_t *port, uint32_t d_id)
5960 {
5961         int                     index;
5962         struct pwwn_hash        *head;
5963         fc_remote_port_t        *pd;
5964 
5965         ASSERT(MUTEX_HELD(&port->fp_mutex));
5966 
5967         for (index = 0; index < pwwn_table_size; index++) {
5968                 head = &port->fp_pwwn_table[index];
5969                 pd = head->pwwn_head;
5970 
5971                 while (pd != NULL) {
5972                         mutex_enter(&pd->pd_mutex);
5973                         if (pd->pd_port_id.port_id == d_id) {
5974                                 mutex_exit(&pd->pd_mutex);
5975                                 return (pd);
5976                         }
5977                         mutex_exit(&pd->pd_mutex);
5978                         pd = pd->pd_wwn_hnext;
5979                 }
5980         }
5981 
5982         return (pd);
5983 }
5984 
5985 
5986 /*
5987  * trace debugging
5988  */
5989 void
5990 fc_trace_debug(fc_trace_logq_t *logq, caddr_t name, int dflag, int dlevel,
5991     int errno, const char *fmt, ...)
5992 {
5993         char    buf[FC_MAX_TRACE_BUF_LEN + 3]; /* 3 is for "\n" */
5994         char    *bufptr = buf;
5995         va_list ap;
5996         int     cnt = 0;
5997 
5998         if ((dlevel & dflag) == 0) {
5999                 return;
6000         }
6001 
6002         if (name) {
6003                 cnt = snprintf(buf, FC_MAX_TRACE_BUF_LEN + 1, "%d=>%s::",
6004                     logq->il_id++, name);
6005         } else {
6006                 cnt = snprintf(buf, FC_MAX_TRACE_BUF_LEN + 1, "%d=>trace::",
6007                     logq->il_id++);
6008         }
6009 
6010         if (cnt < FC_MAX_TRACE_BUF_LEN) {
6011                 va_start(ap, fmt);
6012                 cnt += vsnprintf(buf + cnt, FC_MAX_TRACE_BUF_LEN + 1 - cnt,
6013                     fmt, ap);
6014                 va_end(ap);
6015         }
6016 
6017         if (cnt > FC_MAX_TRACE_BUF_LEN) {
6018                 cnt = FC_MAX_TRACE_BUF_LEN;
6019         }
6020         if (errno && (cnt < FC_MAX_TRACE_BUF_LEN)) {
6021                 cnt += snprintf(buf + cnt, FC_MAX_TRACE_BUF_LEN + 1 - cnt,
6022                     "error=0x%x\n", errno);
6023         }
6024         (void) snprintf(buf + cnt, FC_MAX_TRACE_BUF_LEN + 3 - cnt, "\n");
6025 
6026         if (logq && (dlevel & FC_TRACE_LOG_BUF) != 0) {
6027                 fc_trace_logmsg(logq, buf, dlevel);
6028         }
6029 
6030         /*
6031          * We do not want to print the log numbers that appear as
6032          * random numbers at the console and messages files, to
6033          * the user.
6034          */
6035         if ((bufptr = strchr(buf, '>')) == NULL) {
6036                 /*
6037                  * We would have added the a string with "=>" above and so,
6038                  * ideally, we should not get here at all. But, if we do,
6039                  * we'll just use the full buf.
6040                  */
6041                 bufptr = buf;
6042         } else {
6043                 bufptr++;
6044         }
6045 
6046         switch (dlevel & FC_TRACE_LOG_MASK) {
6047         case FC_TRACE_LOG_CONSOLE:
6048                 cmn_err(CE_WARN, "%s", bufptr);
6049                 break;
6050 
6051         case FC_TRACE_LOG_CONSOLE_MSG:
6052                 cmn_err(CE_WARN, "%s", bufptr);
6053                 break;
6054 
6055         case FC_TRACE_LOG_MSG:
6056                 cmn_err(CE_WARN, "!%s", bufptr);
6057                 break;
6058 
6059         default:
6060                 break;
6061         }
6062 }
6063 
6064 
6065 /*
6066  * This function can block
6067  */
6068 fc_trace_logq_t *
6069 fc_trace_alloc_logq(int maxsize)
6070 {
6071         fc_trace_logq_t *logq;
6072 
6073         logq = kmem_zalloc(sizeof (*logq), KM_SLEEP);
6074 
6075         mutex_init(&logq->il_lock, NULL, MUTEX_DRIVER, NULL);
6076         logq->il_hiwat = maxsize;
6077         logq->il_flags |= FC_TRACE_LOGQ_V2;
6078 
6079         return (logq);
6080 }
6081 
6082 
6083 void
6084 fc_trace_free_logq(fc_trace_logq_t *logq)
6085 {
6086         mutex_enter(&logq->il_lock);
6087         while (logq->il_msgh) {
6088                 fc_trace_freemsg(logq);
6089         }
6090         mutex_exit(&logq->il_lock);
6091 
6092         mutex_destroy(&logq->il_lock);
6093         kmem_free(logq, sizeof (*logq));
6094 }
6095 
6096 
6097 /* ARGSUSED */
6098 void
6099 fc_trace_logmsg(fc_trace_logq_t *logq, caddr_t buf, int level)
6100 {
6101         int             qfull = 0;
6102         fc_trace_dmsg_t *dmsg;
6103 
6104         dmsg = kmem_alloc(sizeof (*dmsg), KM_NOSLEEP);
6105         if (dmsg == NULL) {
6106                 mutex_enter(&logq->il_lock);
6107                 logq->il_afail++;
6108                 mutex_exit(&logq->il_lock);
6109 
6110                 return;
6111         }
6112 
6113         gethrestime(&dmsg->id_time);
6114 
6115         dmsg->id_size = strlen(buf) + 1;
6116         dmsg->id_buf = kmem_alloc(dmsg->id_size, KM_NOSLEEP);
6117         if (dmsg->id_buf == NULL) {
6118                 kmem_free(dmsg, sizeof (*dmsg));
6119 
6120                 mutex_enter(&logq->il_lock);
6121                 logq->il_afail++;
6122                 mutex_exit(&logq->il_lock);
6123 
6124                 return;
6125         }
6126         bcopy(buf, dmsg->id_buf, strlen(buf));
6127         dmsg->id_buf[strlen(buf)] = '\0';
6128 
6129         mutex_enter(&logq->il_lock);
6130 
6131         logq->il_size += dmsg->id_size;
6132         if (logq->il_size >= logq->il_hiwat) {
6133                 qfull = 1;
6134         }
6135 
6136         if (qfull) {
6137                 fc_trace_freemsg(logq);
6138         }
6139 
6140         dmsg->id_next = NULL;
6141         if (logq->il_msgt) {
6142                 logq->il_msgt->id_next = dmsg;
6143         } else {
6144                 ASSERT(logq->il_msgh == NULL);
6145                 logq->il_msgh = dmsg;
6146         }
6147         logq->il_msgt = dmsg;
6148 
6149         mutex_exit(&logq->il_lock);
6150 }
6151 
6152 
6153 static void
6154 fc_trace_freemsg(fc_trace_logq_t *logq)
6155 {
6156         fc_trace_dmsg_t *dmsg;
6157 
6158         ASSERT(MUTEX_HELD(&logq->il_lock));
6159 
6160         if ((dmsg = logq->il_msgh) != NULL) {
6161                 logq->il_msgh = dmsg->id_next;
6162                 if (logq->il_msgh == NULL) {
6163                         logq->il_msgt = NULL;
6164                 }
6165 
6166                 logq->il_size -= dmsg->id_size;
6167                 kmem_free(dmsg->id_buf, dmsg->id_size);
6168                 kmem_free(dmsg, sizeof (*dmsg));
6169         } else {
6170                 ASSERT(logq->il_msgt == NULL);
6171         }
6172 }
6173 
6174 /*
6175  * Used by T11 FC-HBA to fetch discovered ports by index.
6176  * Returns NULL if the index isn't valid.
6177  */
6178 fc_remote_port_t *
6179 fctl_lookup_pd_by_index(fc_local_port_t *port, uint32_t index)
6180 {
6181         int                     outer;
6182         int                     match = 0;
6183         struct pwwn_hash        *head;
6184         fc_remote_port_t        *pd;
6185 
6186         ASSERT(MUTEX_HELD(&port->fp_mutex));
6187 
6188         for (outer = 0;
6189             outer < pwwn_table_size && match <= index;
6190             outer++) {
6191                 head = &port->fp_pwwn_table[outer];
6192                 pd = head->pwwn_head;
6193                 if (pd != NULL) match ++;
6194 
6195                 while (pd != NULL && match <= index) {
6196                         pd = pd->pd_wwn_hnext;
6197                         if (pd != NULL) match ++;
6198                 }
6199         }
6200 
6201         return (pd);
6202 }
6203 
6204 /*
6205  * Search for a matching Node or Port WWN in the discovered port list
6206  */
6207 fc_remote_port_t *
6208 fctl_lookup_pd_by_wwn(fc_local_port_t *port, la_wwn_t wwn)
6209 {
6210         int                     index;
6211         struct pwwn_hash        *head;
6212         fc_remote_port_t        *pd;
6213 
6214         ASSERT(MUTEX_HELD(&port->fp_mutex));
6215 
6216         for (index = 0; index < pwwn_table_size; index++) {
6217                 head = &port->fp_pwwn_table[index];
6218                 pd = head->pwwn_head;
6219 
6220                 while (pd != NULL) {
6221                         mutex_enter(&pd->pd_mutex);
6222                         if (bcmp(pd->pd_port_name.raw_wwn, wwn.raw_wwn,
6223                             sizeof (la_wwn_t)) == 0) {
6224                                 mutex_exit(&pd->pd_mutex);
6225                                 return (pd);
6226                         }
6227                         if (bcmp(pd->pd_remote_nodep->fd_node_name.raw_wwn,
6228                             wwn.raw_wwn, sizeof (la_wwn_t)) == 0) {
6229                                 mutex_exit(&pd->pd_mutex);
6230                                 return (pd);
6231                         }
6232                         mutex_exit(&pd->pd_mutex);
6233                         pd = pd->pd_wwn_hnext;
6234                 }
6235         }
6236         /* No match */
6237         return (NULL);
6238 }
6239 
6240 
6241 /*
6242  * Count the number of ports on this adapter.
6243  * This routine will walk the port list and count up the number of adapters
6244  * with matching fp_hba_port_attrs.hba_fru_details.high and
6245  * fp_hba_port_attrs.hba_fru_details.low.
6246  *
6247  * port->fp_mutex must not be held.
6248  */
6249 int
6250 fctl_count_fru_ports(fc_local_port_t *port, int npivflag)
6251 {
6252         fca_hba_fru_details_t   *fru;
6253         fc_fca_port_t   *fca_port;
6254         fc_local_port_t *tmpPort = NULL;
6255         uint32_t        count = 1;
6256 
6257         mutex_enter(&fctl_port_lock);
6258 
6259         mutex_enter(&port->fp_mutex);
6260         fru = &port->fp_hba_port_attrs.hba_fru_details;
6261 
6262         /* Detect FCA drivers that don't support linking HBA ports */
6263         if (fru->high == 0 && fru->low == 0 && fru->port_index == 0) {
6264                 mutex_exit(&port->fp_mutex);
6265                 mutex_exit(&fctl_port_lock);
6266                 return (1);
6267         }
6268 
6269         for (fca_port = fctl_fca_portlist; fca_port != NULL;
6270             fca_port = fca_port->port_next) {
6271                 tmpPort = fca_port->port_handle;
6272                 if (tmpPort == port) {
6273                         continue;
6274                 }
6275                 mutex_enter(&tmpPort->fp_mutex);
6276 
6277                 /*
6278                  * If an FCA driver returns unique fru->high and fru->low for
6279                  * ports on the same card, there is no way for the transport
6280                  * layer to determine that the two ports on the same FRU. So,
6281                  * the discovery of the ports on a same FRU  is limited to what
6282                  * the FCA driver can report back.
6283                  */
6284                 if (tmpPort->fp_hba_port_attrs.hba_fru_details.high ==
6285                     fru->high &&
6286                     tmpPort->fp_hba_port_attrs.hba_fru_details.low ==
6287                     fru->low) {
6288                         /* Now double check driver */
6289                         if (strncmp(port->fp_hba_port_attrs.driver_name,
6290                             tmpPort->fp_hba_port_attrs.driver_name,
6291                             FCHBA_DRIVER_NAME_LEN) == 0) {
6292                                 if (!npivflag ||
6293                                     (tmpPort->fp_npiv_type != FC_NPIV_PORT)) {
6294                                         count++;
6295                                 }
6296                         } /* Else, different FCA driver */
6297                 } /* Else not the same HBA FRU */
6298                 mutex_exit(&tmpPort->fp_mutex);
6299         }
6300 
6301         mutex_exit(&port->fp_mutex);
6302         mutex_exit(&fctl_port_lock);
6303 
6304         return (count);
6305 }
6306 
6307 fc_fca_port_t *
6308 fctl_local_port_list_add(fc_fca_port_t *list, fc_local_port_t *port)
6309 {
6310         fc_fca_port_t *tmp = list, *newentry = NULL;
6311 
6312         newentry = kmem_zalloc(sizeof (fc_fca_port_t), KM_NOSLEEP);
6313         if (newentry == NULL) {
6314                 return (list);
6315         }
6316         newentry->port_handle = port;
6317 
6318         if (tmp == NULL) {
6319                 return (newentry);
6320         }
6321         while (tmp->port_next != NULL)       tmp = tmp->port_next;
6322         tmp->port_next = newentry;
6323 
6324         return (list);
6325 }
6326 
6327 void
6328 fctl_local_port_list_free(fc_fca_port_t *list)
6329 {
6330         fc_fca_port_t *tmp = list, *nextentry;
6331 
6332         if (tmp == NULL) {
6333                 return;
6334         }
6335 
6336         while (tmp != NULL) {
6337                 nextentry = tmp->port_next;
6338                 kmem_free(tmp, sizeof (*tmp));
6339                 tmp = nextentry;
6340         }
6341 }
6342 
6343 /*
6344  * Fetch another port on the HBA FRU based on index.
6345  * Returns NULL if index not found.
6346  *
6347  * port->fp_mutex must not be held.
6348  */
6349 fc_local_port_t *
6350 fctl_get_adapter_port_by_index(fc_local_port_t *port, uint32_t port_index)
6351 {
6352         fca_hba_fru_details_t   *fru;
6353         fc_fca_port_t   *fca_port;
6354         fc_local_port_t *tmpPort = NULL;
6355         fc_fca_port_t   *list = NULL, *tmpEntry;
6356         fc_local_port_t         *phyPort, *virPort = NULL;
6357         int     index, phyPortNum = 0;
6358 
6359         mutex_enter(&fctl_port_lock);
6360 
6361         mutex_enter(&port->fp_mutex);
6362         fru = &port->fp_hba_port_attrs.hba_fru_details;
6363 
6364         /* Are we looking for this port? */
6365         if (fru->port_index == port_index) {
6366                 mutex_exit(&port->fp_mutex);
6367                 mutex_exit(&fctl_port_lock);
6368                 return (port);
6369         }
6370 
6371         /* Detect FCA drivers that don't support linking HBA ports */
6372         if (fru->high == 0 && fru->low == 0 && fru->port_index == 0) {
6373                 mutex_exit(&port->fp_mutex);
6374                 mutex_exit(&fctl_port_lock);
6375                 return (NULL);
6376         }
6377 
6378         list = fctl_local_port_list_add(list, port);
6379         phyPortNum++;
6380         /* Loop through all known ports */
6381         for (fca_port = fctl_fca_portlist; fca_port != NULL;
6382             fca_port = fca_port->port_next) {
6383                 tmpPort = fca_port->port_handle;
6384                 if (tmpPort == port) {
6385                         /* Skip the port that was passed in as the argument */
6386                         continue;
6387                 }
6388                 mutex_enter(&tmpPort->fp_mutex);
6389 
6390                 /* See if this port is on the same HBA FRU (fast check) */
6391                 if (tmpPort->fp_hba_port_attrs.hba_fru_details.high ==
6392                     fru->high &&
6393                     tmpPort->fp_hba_port_attrs.hba_fru_details.low ==
6394                     fru->low) {
6395                         /* Now double check driver (slower check) */
6396                         if (strncmp(port->fp_hba_port_attrs.driver_name,
6397                             tmpPort->fp_hba_port_attrs.driver_name,
6398                             FCHBA_DRIVER_NAME_LEN) == 0) {
6399 
6400                                 fru =
6401                                     &tmpPort->fp_hba_port_attrs.hba_fru_details;
6402                                 /* Check for the matching port_index */
6403                                 if ((tmpPort->fp_npiv_type != FC_NPIV_PORT) &&
6404                                     (fru->port_index == port_index)) {
6405                                         /* Found it! */
6406                                         mutex_exit(&tmpPort->fp_mutex);
6407                                         mutex_exit(&port->fp_mutex);
6408                                         mutex_exit(&fctl_port_lock);
6409                                         fctl_local_port_list_free(list);
6410                                         return (tmpPort);
6411                                 }
6412                                 if (tmpPort->fp_npiv_type != FC_NPIV_PORT) {
6413                                         (void) fctl_local_port_list_add(list,
6414                                             tmpPort);
6415                                         phyPortNum++;
6416                                 }
6417                         } /* Else, different FCA driver */
6418                 } /* Else not the same HBA FRU */
6419                 mutex_exit(&tmpPort->fp_mutex);
6420 
6421         }
6422 
6423         /* scan all physical port on same chip to find virtual port */
6424         tmpEntry = list;
6425         index = phyPortNum - 1;
6426         virPort = NULL;
6427         while (index < port_index) {
6428                 if (tmpEntry == NULL) {
6429                         break;
6430                 }
6431                 if (virPort == NULL) {
6432                         phyPort = tmpEntry->port_handle;
6433                         virPort = phyPort->fp_port_next;
6434                         if (virPort == NULL) {
6435                                 tmpEntry = tmpEntry->port_next;
6436                                 continue;
6437                         }
6438                 } else {
6439                         virPort = virPort->fp_port_next;
6440                 }
6441                 if (virPort == phyPort) {
6442                         tmpEntry = tmpEntry->port_next;
6443                         virPort = NULL;
6444                 } else {
6445                         index++;
6446                 }
6447         }
6448         mutex_exit(&port->fp_mutex);
6449         mutex_exit(&fctl_port_lock);
6450 
6451         fctl_local_port_list_free(list);
6452         if (virPort) {
6453                 return (virPort);
6454         }
6455         return (NULL);
6456 }
6457 
6458 int
6459 fctl_busy_port(fc_local_port_t *port)
6460 {
6461         ASSERT(!MUTEX_HELD(&port->fp_mutex));
6462 
6463         mutex_enter(&port->fp_mutex);
6464         if (port->fp_soft_state & FP_SOFT_NO_PMCOMP) {
6465                 /*
6466                  * If fctl_busy_port() is called before we've registered our
6467                  * PM components, we return success. We need to be aware of
6468                  * this because the caller will eventually call fctl_idle_port.
6469                  * This wouldn't be a problem except that if we have
6470                  * registered our PM components in the meantime, we will
6471                  * then be idling a component that was never busied.  PM
6472                  * will be very unhappy if we do this.  Thus, we keep
6473                  * track of this with port->fp_pm_busy_nocomp.
6474                  */
6475                 port->fp_pm_busy_nocomp++;
6476                 mutex_exit(&port->fp_mutex);
6477                 return (0);
6478         }
6479         port->fp_pm_busy++;
6480         mutex_exit(&port->fp_mutex);
6481 
6482         if (pm_busy_component(port->fp_port_dip,
6483             FP_PM_COMPONENT) != DDI_SUCCESS) {
6484                 mutex_enter(&port->fp_mutex);
6485                 port->fp_pm_busy--;
6486                 mutex_exit(&port->fp_mutex);
6487                 return (ENXIO);
6488         }
6489 
6490         mutex_enter(&port->fp_mutex);
6491         if (port->fp_pm_level == FP_PM_PORT_DOWN) {
6492                 mutex_exit(&port->fp_mutex);
6493                 if (pm_raise_power(port->fp_port_dip, FP_PM_COMPONENT,
6494                     FP_PM_PORT_UP) != DDI_SUCCESS) {
6495 
6496                         mutex_enter(&port->fp_mutex);
6497                         port->fp_pm_busy--;
6498                         mutex_exit(&port->fp_mutex);
6499 
6500                         (void) pm_idle_component(port->fp_port_dip,
6501                             FP_PM_COMPONENT);
6502                         return (EIO);
6503                 }
6504                 return (0);
6505         }
6506         mutex_exit(&port->fp_mutex);
6507         return (0);
6508 }
6509 
6510 void
6511 fctl_idle_port(fc_local_port_t *port)
6512 {
6513         ASSERT(!MUTEX_HELD(&port->fp_mutex));
6514 
6515         mutex_enter(&port->fp_mutex);
6516 
6517         /*
6518          * If port->fp_pm_busy_nocomp is > 0, that means somebody had
6519          * called fctl_busy_port prior to us registering our PM components.
6520          * In that case, we just decrement fp_pm_busy_nocomp and return.
6521          */
6522 
6523         if (port->fp_pm_busy_nocomp > 0) {
6524                 port->fp_pm_busy_nocomp--;
6525                 mutex_exit(&port->fp_mutex);
6526                 return;
6527         }
6528 
6529         port->fp_pm_busy--;
6530         mutex_exit(&port->fp_mutex);
6531 
6532         (void) pm_idle_component(port->fp_port_dip, FP_PM_COMPONENT);
6533 }
6534 
6535 /*
6536  *     Function: fctl_tc_timer
6537  *
6538  *  Description: Resets the value of the timed counter.
6539  *
6540  *    Arguments: *tc            Timed counter
6541  *
6542  * Return Value: Nothing
6543  *
6544  *      Context: Kernel context.
6545  */
6546 static void
6547 fctl_tc_timer(void *arg)
6548 {
6549         timed_counter_t *tc = (timed_counter_t *)arg;
6550 
6551         ASSERT(tc != NULL);
6552         ASSERT(tc->sig == tc);
6553 
6554         mutex_enter(&tc->mutex);
6555         if (tc->active) {
6556                 tc->active = B_FALSE;
6557                 tc->counter = 0;
6558         }
6559         mutex_exit(&tc->mutex);
6560 }
6561 
6562 /*
6563  *     Function: fctl_tc_constructor
6564  *
6565  *  Description: Constructs a timed counter.
6566  *
6567  *    Arguments: *tc            Address where the timed counter will reside.
6568  *               max_value      Maximum value the counter is allowed to take.
6569  *               timer          Number of microseconds after which the counter
6570  *                              will be reset. The timer is started when the
6571  *                              value of the counter goes from 0 to 1.
6572  *
6573  * Return Value: Nothing
6574  *
6575  *      Context: Kernel context.
6576  */
6577 void
6578 fctl_tc_constructor(timed_counter_t *tc, uint32_t max_value, clock_t timer)
6579 {
6580         ASSERT(tc != NULL);
6581         ASSERT(tc->sig != tc);
6582 
6583         bzero(tc, sizeof (*tc));
6584         mutex_init(&tc->mutex, NULL, MUTEX_DRIVER, NULL);
6585         tc->timer = drv_usectohz(timer);
6586         tc->active = B_FALSE;
6587         tc->maxed_out = B_FALSE;
6588         tc->max_value = max_value;
6589         tc->sig = tc;
6590 }
6591 
6592 /*
6593  *     Function: fctl_tc_destructor
6594  *
6595  *  Description: Destroyes a timed counter.
6596  *
6597  *    Arguments: *tc            Timed counter to destroy.
6598  *
6599  * Return Value: Nothing
6600  *
6601  *      Context: Kernel context.
6602  */
6603 void
6604 fctl_tc_destructor(timed_counter_t *tc)
6605 {
6606         ASSERT(tc != NULL);
6607         ASSERT(tc->sig == tc);
6608         ASSERT(!mutex_owned(&tc->mutex));
6609 
6610         mutex_enter(&tc->mutex);
6611         if (tc->active) {
6612                 tc->active = B_FALSE;
6613                 mutex_exit(&tc->mutex);
6614                 (void) untimeout(tc->tid);
6615                 mutex_enter(&tc->mutex);
6616                 tc->sig = NULL;
6617         }
6618         mutex_exit(&tc->mutex);
6619         mutex_destroy(&tc->mutex);
6620 }
6621 
6622 /*
6623  *     Function: fctl_tc_increment
6624  *
6625  *  Description: Increments a timed counter
6626  *
6627  *    Arguments: *tc            Timed counter to increment.
6628  *
6629  * Return Value: B_TRUE         Counter reached the max value.
6630  *               B_FALSE        Counter hasn't reached the max value.
6631  *
6632  *      Context: Kernel or interrupt context.
6633  */
6634 boolean_t
6635 fctl_tc_increment(timed_counter_t *tc)
6636 {
6637         ASSERT(tc != NULL);
6638         ASSERT(tc->sig == tc);
6639 
6640         mutex_enter(&tc->mutex);
6641         if (!tc->maxed_out) {
6642                 /* Hasn't maxed out yet. */
6643                 ++tc->counter;
6644                 if (tc->counter >= tc->max_value) {
6645                         /* Just maxed out. */
6646                         tc->maxed_out = B_TRUE;
6647                 }
6648                 if (!tc->active) {
6649                         tc->tid = timeout(fctl_tc_timer, tc, tc->timer);
6650                         tc->active = B_TRUE;
6651                 }
6652         }
6653         mutex_exit(&tc->mutex);
6654 
6655         return (tc->maxed_out);
6656 }
6657 
6658 /*
6659  *     Function: fctl_tc_reset
6660  *
6661  *  Description: Resets a timed counter.  The caller of this function has to
6662  *               to make sure that while in fctl_tc_reset() fctl_tc_increment()
6663  *               is not called.
6664  *
6665  *    Arguments: *tc            Timed counter to reset.
6666  *
6667  * Return Value: 0              Counter reached the max value.
6668  *               Not 0          Counter hasn't reached the max value.
6669  *
6670  *      Context: Kernel or interrupt context.
6671  */
6672 void
6673 fctl_tc_reset(timed_counter_t *tc)
6674 {
6675         ASSERT(tc != NULL);
6676         ASSERT(tc->sig == tc);
6677 
6678         mutex_enter(&tc->mutex);
6679         tc->counter = 0;
6680         tc->maxed_out = B_FALSE;
6681         if (tc->active) {
6682                 tc->active = B_FALSE;
6683                 (void) untimeout(tc->tid);
6684         }
6685         mutex_exit(&tc->mutex);
6686 }
6687 
6688 void
6689 fc_ulp_log_device_event(opaque_t port_handle, int type)
6690 {
6691         fc_local_port_t *port = port_handle;
6692         nvlist_t *attr_list;
6693 
6694         if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
6695             KM_SLEEP) != DDI_SUCCESS) {
6696                 return;
6697         }
6698 
6699         if (nvlist_add_uint32(attr_list, "instance",
6700             port->fp_instance) != DDI_SUCCESS) {
6701                 goto error;
6702         }
6703 
6704         if (nvlist_add_byte_array(attr_list, "port-wwn",
6705             port->fp_service_params.nport_ww_name.raw_wwn,
6706             sizeof (la_wwn_t)) != DDI_SUCCESS) {
6707                 goto error;
6708         }
6709 
6710         (void) ddi_log_sysevent(port->fp_port_dip, DDI_VENDOR_SUNW, EC_SUNFC,
6711             (type == FC_ULP_DEVICE_ONLINE) ?
6712             ESC_SUNFC_DEVICE_ONLINE : ESC_SUNFC_DEVICE_OFFLINE,
6713             attr_list, NULL, DDI_SLEEP);
6714         nvlist_free(attr_list);
6715         return;
6716 
6717 error:
6718         nvlist_free(attr_list);
6719 }