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