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