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