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