Print this page
    
NEX-7540 cstyle can't handle ellipsis on continuation line
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-6832 fcsm module's debug level default should be 0
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Steve Peng <steve.peng@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/io/fibre-channel/ulp/fcsm.c
          +++ new/usr/src/uts/common/io/fibre-channel/ulp/fcsm.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
  
    | 
      ↓ open down ↓ | 
    13 lines elided | 
    
      ↑ open up ↑ | 
  
  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 2009 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
       24 + * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
  24   25   */
  25   26  
  26   27  /*
  27   28   * fcsm - ULP Module for Fibre Channel SAN Management
  28   29   */
  29   30  
  30   31  #include <sys/types.h>
  31   32  #include <sys/file.h>
  32   33  #include <sys/kmem.h>
  33   34  #include <sys/scsi/scsi.h>
  34   35  #include <sys/var.h>
  35   36  #include <sys/byteorder.h>
  36   37  #include <sys/fibre-channel/fc.h>
  37   38  #include <sys/fibre-channel/impl/fc_ulpif.h>
  38   39  #include <sys/fibre-channel/ulp/fcsm.h>
  39   40  
  40   41  /* Definitions */
  41   42  #define FCSM_VERSION            "20090729-1.28"
  42   43  #define FCSM_NAME_VERSION       "SunFC FCSM v" FCSM_VERSION
  43   44  
  44   45  /* Global Variables */
  45   46  static char             fcsm_name[] = "FCSM";
  46   47  static void             *fcsm_state = NULL;
  47   48  static kmutex_t         fcsm_global_mutex;
  48   49  static uint32_t         fcsm_flag = FCSM_IDLE;
  49   50  static dev_info_t       *fcsm_dip = NULL;
  50   51  static fcsm_t           *fcsm_port_head = NULL;
  51   52  static kmem_cache_t     *fcsm_job_cache = NULL;
  52   53  static int              fcsm_num_attaching = 0;
  53   54  static int              fcsm_num_detaching = 0;
  54   55  static int              fcsm_detached = 0;
  55   56  
  56   57  static int              fcsm_max_cmd_retries = FCSM_MAX_CMD_RETRIES;
  57   58  static int              fcsm_retry_interval = FCSM_RETRY_INTERVAL;
  58   59  static int              fcsm_retry_ticker = FCSM_RETRY_TICKER;
  59   60  static int              fcsm_offline_ticker = FCSM_OFFLINE_TICKER;
  60   61  static int              fcsm_max_job_retries = FCSM_MAX_JOB_RETRIES;
  61   62  static clock_t          fcsm_retry_ticks;
  62   63  static clock_t          fcsm_offline_ticks;
  63   64  
  64   65  
  65   66  
  66   67  #ifdef DEBUG
  67   68  uint32_t                fcsm_debug = 0;
  68   69  #endif
  69   70  
  70   71  
  71   72  /* Character/Block entry points */
  72   73  struct cb_ops   fcsm_cb_ops = {
  73   74          fcsm_open,      /* open */
  74   75          fcsm_close,     /* close */
  75   76          nodev,          /* strategy */
  76   77          nodev,          /* print */
  77   78          nodev,          /* dump */
  78   79          nodev,          /* read */
  79   80          nodev,          /* write */
  80   81          fcsm_ioctl,     /* ioctl */
  81   82          nodev,          /* devmap */
  82   83          nodev,          /* mmap */
  83   84          nodev,          /* segmap */
  84   85          nochpoll,       /* poll */
  85   86          ddi_prop_op,
  86   87          NULL,           /* streams info */
  87   88          D_NEW | D_MP,
  88   89          CB_REV,
  89   90          nodev,          /* aread */
  90   91          nodev           /* awrite */
  91   92  };
  92   93  
  93   94  struct dev_ops fcsm_ops = {
  94   95          DEVO_REV,
  95   96          0,              /* refcnt */
  96   97          fcsm_getinfo,   /* get info */
  97   98          nulldev,        /* identify (obsolete) */
  98   99          nulldev,        /* probe (not required for self-identifying devices) */
  99  100          fcsm_attach,    /* attach */
 100  101          fcsm_detach,    /* detach */
 101  102          nodev,          /* reset */
 102  103          &fcsm_cb_ops,   /* char/block entry points structure for leaf drivers */
 103  104          NULL,           /* bus operations for nexus driver */
 104  105          NULL            /* power management */
 105  106  };
 106  107  
 107  108  
 108  109  struct modldrv modldrv = {
 109  110          &mod_driverops,
 110  111          FCSM_NAME_VERSION,
 111  112          &fcsm_ops
 112  113  };
 113  114  
 114  115  struct modlinkage modlinkage = {
 115  116          MODREV_1,
 116  117          &modldrv,
 117  118          NULL
 118  119  };
 119  120  
 120  121  static fc_ulp_modinfo_t fcsm_modinfo = {
 121  122          &fcsm_modinfo,          /* ulp_handle */
 122  123          FCTL_ULP_MODREV_4,      /* ulp_rev */
 123  124          FC_TYPE_FC_SERVICES,    /* ulp_type */
 124  125          fcsm_name,              /* ulp_name */
 125  126          0,                      /* ulp_statec_mask: get all statec callbacks */
 126  127          fcsm_port_attach,       /* ulp_port_attach */
 127  128          fcsm_port_detach,       /* ulp_port_detach */
 128  129          fcsm_port_ioctl,        /* ulp_port_ioctl */
 129  130          fcsm_els_cb,            /* ulp_els_callback */
 130  131          fcsm_data_cb,           /* ulp_data_callback */
 131  132          fcsm_statec_cb          /* ulp_statec_callback */
 132  133  };
 133  134  
 134  135  struct fcsm_xlat_pkt_state {
 135  136          uchar_t xlat_state;
 136  137          int     xlat_rval;
 137  138  } fcsm_xlat_pkt_state [] = {
 138  139          { FC_PKT_SUCCESS,               FC_SUCCESS },
 139  140          { FC_PKT_REMOTE_STOP,           FC_FAILURE },
 140  141          { FC_PKT_LOCAL_RJT,             FC_TRANSPORT_ERROR },
 141  142          { FC_PKT_NPORT_RJT,             FC_PREJECT },
 142  143          { FC_PKT_FABRIC_RJT,            FC_FREJECT },
 143  144          { FC_PKT_LOCAL_BSY,             FC_TRAN_BUSY },
 144  145          { FC_PKT_TRAN_BSY,              FC_TRAN_BUSY },
 145  146          { FC_PKT_NPORT_BSY,             FC_PBUSY },
 146  147          { FC_PKT_FABRIC_BSY,            FC_FBUSY },
 147  148          { FC_PKT_LS_RJT,                FC_PREJECT },
 148  149          { FC_PKT_BA_RJT,                FC_PREJECT },
 149  150          { FC_PKT_TIMEOUT,               FC_FAILURE },
 150  151          { FC_PKT_FS_RJT,                FC_FAILURE },
 151  152          { FC_PKT_TRAN_ERROR,            FC_TRANSPORT_ERROR },
 152  153          { FC_PKT_FAILURE,               FC_FAILURE },
 153  154          { FC_PKT_PORT_OFFLINE,          FC_OFFLINE },
 154  155          { FC_PKT_ELS_IN_PROGRESS,       FC_FAILURE }
 155  156  };
 156  157  
 157  158  struct fcsm_xlat_port_state {
 158  159          uint32_t        xlat_pstate;
 159  160          caddr_t         xlat_state_str;
 160  161  } fcsm_xlat_port_state [] = {
 161  162          { FC_STATE_OFFLINE,             "OFFLINE" },
 162  163          { FC_STATE_ONLINE,              "ONLINE" },
 163  164          { FC_STATE_LOOP,                "LOOP" },
 164  165          { FC_STATE_NAMESERVICE,         "NAMESERVICE" },
 165  166          { FC_STATE_RESET,               "RESET" },
 166  167          { FC_STATE_RESET_REQUESTED,     "RESET_REQUESTED" },
 167  168          { FC_STATE_LIP,                 "LIP" },
 168  169          { FC_STATE_LIP_LBIT_SET,        "LIP_LBIT_SET" },
 169  170          { FC_STATE_DEVICE_CHANGE,       "DEVICE_CHANGE" },
 170  171          { FC_STATE_TARGET_PORT_RESET,   "TARGET_PORT_RESET" }
 171  172  };
 172  173  
 173  174  struct fcsm_xlat_topology {
 174  175          uint32_t        xlat_top;
 175  176          caddr_t         xlat_top_str;
 176  177  } fcsm_xlat_topology [] = {
 177  178          { FC_TOP_UNKNOWN,       "UNKNOWN" },
 178  179          { FC_TOP_PRIVATE_LOOP,  "Private Loop" },
 179  180          { FC_TOP_PUBLIC_LOOP,   "Public Loop" },
 180  181          { FC_TOP_FABRIC,        "Fabric" },
 181  182          { FC_TOP_PT_PT,         "Point-to-Point" },
 182  183          { FC_TOP_NO_NS,         "NO_NS" }
 183  184  };
 184  185  
 185  186  struct fcsm_xlat_dev_type {
 186  187          uint32_t        xlat_type;
 187  188          caddr_t         xlat_str;
 188  189  } fcsm_xlat_dev_type [] = {
 189  190          { PORT_DEVICE_NOCHANGE,         "No Change" },
 190  191          { PORT_DEVICE_NEW,              "New" },
 191  192          { PORT_DEVICE_OLD,              "Old" },
 192  193          { PORT_DEVICE_CHANGED,          "Changed" },
 193  194          { PORT_DEVICE_DELETE,           "Delete" },
 194  195          { PORT_DEVICE_USER_LOGIN,       "User Login" },
 195  196          { PORT_DEVICE_USER_LOGOUT,      "User Logout" },
 196  197          { PORT_DEVICE_USER_CREATE,      "User Create" },
 197  198          { PORT_DEVICE_USER_DELETE,      "User Delete" }
 198  199  };
 199  200  
 200  201  int
 201  202  _init(void)
 202  203  {
 203  204          int             rval;
 204  205  
 205  206          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "_init"));
 206  207  
 207  208          fcsm_retry_ticks = drv_usectohz(fcsm_retry_ticker * 1000 * 1000);
 208  209          fcsm_offline_ticks = drv_usectohz(fcsm_offline_ticker * 1000 * 1000);
 209  210  
 210  211          if (rval = ddi_soft_state_init(&fcsm_state, sizeof (fcsm_t),
 211  212              FCSM_INIT_INSTANCES)) {
 212  213                  fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
 213  214                      "_init: ddi_soft_state_init failed");
 214  215                  return (ENOMEM);
 215  216          }
 216  217  
 217  218          mutex_init(&fcsm_global_mutex, NULL, MUTEX_DRIVER, NULL);
 218  219  
 219  220          fcsm_job_cache = kmem_cache_create("fcsm_job_cache",
 220  221              sizeof (fcsm_job_t), 8, fcsm_job_cache_constructor,
 221  222              fcsm_job_cache_destructor, NULL, NULL, NULL, 0);
 222  223  
 223  224          if (fcsm_job_cache == NULL) {
 224  225                  mutex_destroy(&fcsm_global_mutex);
 225  226                  ddi_soft_state_fini(&fcsm_state);
 226  227                  return (ENOMEM);
 227  228          }
 228  229  
 229  230          /*
 230  231           * Now call fc_ulp_add to add this ULP in the transport layer
 231  232           * database. This will cause 'ulp_port_attach' callback function
 232  233           * to be called.
 233  234           */
 234  235          rval = fc_ulp_add(&fcsm_modinfo);
 235  236          if (rval != 0) {
 236  237                  switch (rval) {
 237  238                  case FC_ULP_SAMEMODULE:
 238  239                          fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
 239  240                              "_init: FC SAN Management module is already "
 240  241                              "registered with transport layer");
 241  242                          rval = EEXIST;
 242  243                          break;
 243  244  
 244  245                  case FC_ULP_SAMETYPE:
 245  246                          fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
 246  247                              "_init: Another module with same type 0x%x is "
 247  248                              "already registered with transport layer",
 248  249                              fcsm_modinfo.ulp_type);
 249  250                          rval = EEXIST;
 250  251                          break;
 251  252  
 252  253                  case FC_BADULP:
 253  254                          fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
 254  255                              "_init: Please upgrade this module. Current "
 255  256                              "version 0x%x is not the most recent version",
 256  257                              fcsm_modinfo.ulp_rev);
 257  258                          rval = EIO;
 258  259                          break;
 259  260                  default:
 260  261                          fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
 261  262                              "_init: fc_ulp_add failed with status 0x%x", rval);
 262  263                          rval = EIO;
 263  264                          break;
 264  265                  }
 265  266                  kmem_cache_destroy(fcsm_job_cache);
 266  267                  mutex_destroy(&fcsm_global_mutex);
 267  268                  ddi_soft_state_fini(&fcsm_state);
 268  269                  return (rval);
 269  270          }
 270  271  
 271  272          if ((rval = mod_install(&modlinkage)) != 0) {
 272  273                  FCSM_DEBUG(SMDL_ERR, (CE_WARN, SM_LOG, NULL, NULL,
 273  274                      "_init: mod_install failed with status 0x%x", rval));
 274  275                  (void) fc_ulp_remove(&fcsm_modinfo);
 275  276                  kmem_cache_destroy(fcsm_job_cache);
 276  277                  mutex_destroy(&fcsm_global_mutex);
 277  278                  ddi_soft_state_fini(&fcsm_state);
 278  279                  return (rval);
 279  280          }
 280  281  
 281  282          return (rval);
 282  283  }
 283  284  
 284  285  int
 285  286  _fini(void)
 286  287  {
 287  288          int     rval;
 288  289  #ifdef  DEBUG
 289  290          int     status;
 290  291  #endif /* DEBUG */
 291  292  
 292  293          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "_fini"));
 293  294  
 294  295          /*
 295  296           * don't start cleaning up until we know that the module remove
 296  297           * has worked  -- if this works, then we know that each instance
 297  298           * has successfully been DDI_DETACHed
 298  299           */
 299  300          if ((rval = mod_remove(&modlinkage)) != 0) {
 300  301                  return (rval);
 301  302          }
 302  303  
 303  304  #ifdef DEBUG
 304  305          status = fc_ulp_remove(&fcsm_modinfo);
 305  306          if (status != 0) {
 306  307                  FCSM_DEBUG(SMDL_ERR, (CE_WARN, SM_LOG, NULL, NULL,
 307  308                      "_fini: fc_ulp_remove failed with status 0x%x", status));
 308  309          }
 309  310  #else
 310  311          (void) fc_ulp_remove(&fcsm_modinfo);
 311  312  #endif /* DEBUG */
 312  313  
 313  314          fcsm_detached = 0;
 314  315  
 315  316          /*
 316  317           * It is possible to modunload fcsm manually, which will cause
 317  318           * a bypass of all the port_detach functionality.  We may need
 318  319           * to force that code path to be executed to properly clean up
 319  320           * in that case.
 320  321           */
 321  322          fcsm_force_port_detach_all();
 322  323  
 323  324          kmem_cache_destroy(fcsm_job_cache);
 324  325          mutex_destroy(&fcsm_global_mutex);
 325  326          ddi_soft_state_fini(&fcsm_state);
 326  327  
 327  328          return (rval);
 328  329  }
 329  330  
 330  331  
 331  332  int
 332  333  _info(struct modinfo *modinfop)
 333  334  {
 334  335          return (mod_info(&modlinkage, modinfop));
 335  336  }
 336  337  
 337  338  /* ARGSUSED */
 338  339  static int
 339  340  fcsm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 340  341  {
 341  342          int rval = DDI_FAILURE;
 342  343  
 343  344          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
 344  345              "attach: cmd 0x%x", cmd));
 345  346  
 346  347          switch (cmd) {
 347  348          case DDI_ATTACH:
 348  349                  mutex_enter(&fcsm_global_mutex);
 349  350                  if (fcsm_dip != NULL) {
 350  351                          mutex_exit(&fcsm_global_mutex);
 351  352                          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
 352  353                              "attach: duplicate attach of fcsm!!"));
 353  354                          break;
 354  355                  }
 355  356  
 356  357                  fcsm_dip = dip;
 357  358  
 358  359                  /*
 359  360                   * The detach routine cleans up all the port instances
 360  361                   * i.e. it detaches all ports.
 361  362                   * If _fini never got called after detach, then
 362  363                   * perform an fc_ulp_remove() followed by fc_ulp_add()
 363  364                   * to ensure that port_attach callbacks are called
 364  365                   * again.
 365  366                   */
 366  367                  if (fcsm_detached) {
 367  368                          int status;
 368  369  
 369  370                          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
 370  371                              "attach: rebinding to transport driver"));
 371  372  
 372  373                          mutex_exit(&fcsm_global_mutex);
 373  374  
 374  375                          (void) fc_ulp_remove(&fcsm_modinfo);
 375  376  
 376  377                          /*
 377  378                           * Reset the detached flag, so that ports can attach
 378  379                           */
 379  380                          mutex_enter(&fcsm_global_mutex);
 380  381                          fcsm_detached = 0;
 381  382                          mutex_exit(&fcsm_global_mutex);
 382  383  
 383  384                          status = fc_ulp_add(&fcsm_modinfo);
 384  385  
 385  386                          if (status != 0) {
 386  387                                  /*
 387  388                                   * ULP add failed. So set the
 388  389                                   * detached flag again
 389  390                                   */
 390  391                                  mutex_enter(&fcsm_global_mutex);
 391  392                                  fcsm_detached = 1;
 392  393                                  mutex_exit(&fcsm_global_mutex);
 393  394  
 394  395                                  switch (status) {
 395  396                                  case FC_ULP_SAMEMODULE:
 396  397                                          fcsm_display(CE_WARN, SM_LOG, NULL,
 397  398                                              NULL, "attach: FC SAN Management "
 398  399                                              "module is already "
 399  400                                              "registered with transport layer");
 400  401                                          break;
 401  402  
 402  403                                  case FC_ULP_SAMETYPE:
 403  404                                          fcsm_display(CE_WARN, SM_LOG, NULL,
 404  405                                              NULL, "attach: Another module with "
 405  406                                              "same type 0x%x is already "
 406  407                                              "registered with transport layer",
 407  408                                              fcsm_modinfo.ulp_type);
 408  409                                          break;
 409  410  
 410  411                                  case FC_BADULP:
 411  412                                          fcsm_display(CE_WARN, SM_LOG, NULL,
 412  413                                              NULL, "attach: Please upgrade this "
 413  414                                              "module. Current version 0x%x is "
 414  415                                              "not the most recent version",
 415  416                                              fcsm_modinfo.ulp_rev);
 416  417                                          break;
 417  418                                  default:
 418  419                                          fcsm_display(CE_WARN, SM_LOG, NULL,
 419  420                                              NULL, "attach: fc_ulp_add failed "
 420  421                                              "with status 0x%x", status);
 421  422                                          break;
 422  423                                  }
 423  424  
 424  425                                  /* Return failure */
 425  426                                  break;
 426  427                          }
 427  428  
 428  429                          mutex_enter(&fcsm_global_mutex);
 429  430                  }
 430  431  
 431  432                  /* Create a minor node */
 432  433                  if (ddi_create_minor_node(fcsm_dip, "fcsm", S_IFCHR,
 433  434                      NULL, DDI_PSEUDO, 0) == DDI_SUCCESS) {
 434  435                          /* Announce presence of the device */
 435  436                          mutex_exit(&fcsm_global_mutex);
 436  437                          ddi_report_dev(dip);
 437  438                          rval = DDI_SUCCESS;
 438  439                  } else {
 439  440                          fcsm_dip = NULL;
 440  441                          mutex_exit(&fcsm_global_mutex);
 441  442                          fcsm_display(CE_WARN, SM_LOG_AND_CONSOLE,
 442  443                              NULL, NULL, "attach: create minor node failed");
 443  444                  }
 444  445                  break;
 445  446  
 446  447          case DDI_RESUME:
 447  448                  rval = DDI_SUCCESS;
 448  449                  break;
 449  450  
 450  451          default:
 451  452                  FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, NULL, NULL,
 452  453                      "attach: unknown cmd 0x%x dip 0x%p", cmd, dip));
 453  454                  break;
 454  455          }
 455  456  
 456  457          return (rval);
 457  458  }
 458  459  
 459  460  /* ARGSUSED */
 460  461  static int
 461  462  fcsm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
 462  463  {
 463  464          int     instance;
 464  465          int     rval = DDI_SUCCESS;
 465  466  
 466  467          instance = getminor((dev_t)arg);
 467  468  
 468  469          switch (cmd) {
 469  470          case DDI_INFO_DEVT2INSTANCE:
 470  471                  *result = (void *)(long)instance; /* minor number is instance */
 471  472                  break;
 472  473  
 473  474          case DDI_INFO_DEVT2DEVINFO:
 474  475                  mutex_enter(&fcsm_global_mutex);
 475  476                  *result = (void *)fcsm_dip;
 476  477                  mutex_exit(&fcsm_global_mutex);
 477  478                  break;
 478  479  
 479  480          default:
 480  481                  rval = DDI_FAILURE;
 481  482                  break;
 482  483          }
 483  484  
 484  485          return (rval);
 485  486  }
 486  487  
 487  488  
 488  489  /* ARGSUSED */
 489  490  static int
 490  491  fcsm_port_attach(opaque_t ulph, fc_ulp_port_info_t *pinfo,
 491  492      fc_attach_cmd_t cmd, uint32_t s_id)
 492  493  {
 493  494          int     instance;
 494  495          int     rval = FC_FAILURE;
 495  496  
 496  497          instance = ddi_get_instance(pinfo->port_dip);
 497  498  
 498  499          /*
 499  500           * Set the attaching flag, so that fcsm_detach will fail, if
 500  501           * port attach is in progress.
 501  502           */
 502  503          mutex_enter(&fcsm_global_mutex);
 503  504          if (fcsm_detached) {
 504  505                  mutex_exit(&fcsm_global_mutex);
 505  506  
 506  507                  FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
 507  508                      "port_attach: end. detach in progress. failing attach "
 508  509                      "instance 0x%x", instance));
 509  510                  return (((cmd == FC_CMD_POWER_UP) || (cmd == FC_CMD_RESUME)) ?
 510  511                      FC_FAILURE_SILENT : FC_FAILURE);
 511  512          }
 512  513  
 513  514          fcsm_num_attaching++;
 514  515          mutex_exit(&fcsm_global_mutex);
 515  516  
 516  517          switch (cmd) {
 517  518          case FC_CMD_ATTACH:
 518  519                  if (fcsm_handle_port_attach(pinfo, s_id, instance)
 519  520                      != DDI_SUCCESS) {
 520  521                          ASSERT(ddi_get_soft_state(fcsm_state,
 521  522                              instance) == NULL);
 522  523                          break;
 523  524                  }
 524  525                  rval = FC_SUCCESS;
 525  526                  break;
 526  527  
 527  528          case FC_CMD_RESUME:
 528  529          case FC_CMD_POWER_UP: {
 529  530                  fcsm_t  *fcsm;
 530  531                  char fcsm_pathname[MAXPATHLEN];
 531  532  
 532  533                  FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
 533  534                      "port_attach: cmd 0x%x instance 0x%x", cmd, instance));
 534  535  
 535  536                  /* Get the soft state structure */
 536  537                  if ((fcsm = ddi_get_soft_state(fcsm_state, instance)) == NULL) {
 537  538                          FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL,
 538  539                              "port_attach: instance 0x%x, cmd 0x%x "
 539  540                              "get softstate failed", instance, cmd));
 540  541                          break;
 541  542                  }
 542  543  
 543  544                  ASSERT(fcsm->sm_instance == instance);
 544  545  
 545  546                  /* If this instance is not attached, then return failure */
 546  547                  mutex_enter(&fcsm->sm_mutex);
 547  548                  if ((fcsm->sm_flags & FCSM_ATTACHED) == 0) {
 548  549                          mutex_exit(&fcsm->sm_mutex);
 549  550                          fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
 550  551                              "port_detach: port is not attached");
 551  552                          break;
 552  553                  }
 553  554                  mutex_exit(&fcsm->sm_mutex);
 554  555  
 555  556                  if (fcsm_handle_port_resume(ulph, pinfo, cmd, s_id, fcsm) !=
 556  557                      DDI_SUCCESS) {
 557  558                          break;
 558  559                  }
 559  560  
 560  561                  (void) ddi_pathname(fcsm->sm_port_info.port_dip, fcsm_pathname);
 561  562                  fcsm_display(CE_NOTE, SM_LOG, fcsm, NULL,
 562  563                      "attached to path %s", fcsm_pathname);
 563  564                  rval = FC_SUCCESS;
 564  565                  break;
 565  566          }
 566  567  
 567  568          default:
 568  569                  FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, NULL, NULL,
 569  570                      "port_attach: unknown cmd 0x%x for port 0x%x",
 570  571                      cmd, instance));
 571  572                  break;
 572  573          }
 573  574  
 574  575          mutex_enter(&fcsm_global_mutex);
 575  576          fcsm_num_attaching--;
 576  577          mutex_exit(&fcsm_global_mutex);
 577  578          return (rval);
 578  579  }
 579  580  
 580  581  
 581  582  static int
 582  583  fcsm_handle_port_attach(fc_ulp_port_info_t *pinfo, uint32_t s_id, int instance)
 583  584  {
 584  585          fcsm_t          *fcsm;
 585  586          kthread_t       *thread;
 586  587          char            name[32];
 587  588          char fcsm_pathname[MAXPATHLEN];
 588  589  
 589  590          /* Allocate a soft state structure for the port */
 590  591          if (ddi_soft_state_zalloc(fcsm_state, instance) != DDI_SUCCESS) {
 591  592                  fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
 592  593                      "port_attach: instance 0x%x, soft state alloc failed",
 593  594                      instance);
 594  595                  return (DDI_FAILURE);
 595  596          }
 596  597  
 597  598          if ((fcsm = ddi_get_soft_state(fcsm_state, instance)) == NULL) {
 598  599                  fcsm_display(CE_WARN, SM_LOG, NULL, NULL,
 599  600                      "port_attach: instance 0x%x, get soft state failed",
 600  601                      instance);
 601  602                  ddi_soft_state_free(fcsm_state, instance);
 602  603                  return (DDI_FAILURE);
 603  604          }
 604  605  
 605  606  
 606  607          /* Initialize the mutex */
 607  608          mutex_init(&fcsm->sm_mutex, NULL, MUTEX_DRIVER, NULL);
 608  609          cv_init(&fcsm->sm_job_cv, NULL, CV_DRIVER, NULL);
 609  610  
 610  611          mutex_enter(&fcsm->sm_mutex);
 611  612          fcsm->sm_flags          |= FCSM_ATTACHING;
 612  613          fcsm->sm_sid            = s_id;
 613  614          fcsm->sm_instance       = instance;
 614  615          fcsm->sm_port_state     = pinfo->port_state;
 615  616  
 616  617          /*
 617  618           * Make a copy of the port_information structure, since fctl
 618  619           * uses a temporary structure.
 619  620           */
 620  621          fcsm->sm_port_info      = *pinfo;       /* Structure copy !!! */
 621  622          mutex_exit(&fcsm->sm_mutex);
 622  623  
 623  624  
 624  625          (void) sprintf(name, "fcsm%d_cmd_cache", fcsm->sm_instance);
 625  626          fcsm->sm_cmd_cache = kmem_cache_create(name,
 626  627              sizeof (fcsm_cmd_t) + pinfo->port_fca_pkt_size, 8,
 627  628              fcsm_cmd_cache_constructor, fcsm_cmd_cache_destructor,
 628  629              NULL, (void *)fcsm, NULL, 0);
 629  630          if (fcsm->sm_cmd_cache == NULL) {
 630  631                  fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
 631  632                      "port_attach: pkt cache create failed");
 632  633                  cv_destroy(&fcsm->sm_job_cv);
 633  634                  mutex_destroy(&fcsm->sm_mutex);
 634  635                  ddi_soft_state_free(fcsm_state, instance);
 635  636                  return (DDI_FAILURE);
 636  637          }
 637  638  
 638  639          thread = thread_create((caddr_t)NULL, 0, fcsm_job_thread,
 639  640              (caddr_t)fcsm, 0, &p0, TS_RUN, v.v_maxsyspri-2);
 640  641          if (thread == NULL) {
 641  642                  fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
 642  643                      "port_attach: job thread create failed");
 643  644                  kmem_cache_destroy(fcsm->sm_cmd_cache);
 644  645                  cv_destroy(&fcsm->sm_job_cv);
 645  646                  mutex_destroy(&fcsm->sm_mutex);
 646  647                  ddi_soft_state_free(fcsm_state, instance);
 647  648                  return (DDI_FAILURE);
 648  649          }
 649  650  
 650  651          fcsm->sm_thread = thread;
 651  652  
 652  653          /* Add this structure to fcsm global linked list */
 653  654          mutex_enter(&fcsm_global_mutex);
 654  655          if (fcsm_port_head == NULL) {
 655  656                  fcsm_port_head = fcsm;
 656  657          } else {
 657  658                  fcsm->sm_next = fcsm_port_head;
 658  659                  fcsm_port_head = fcsm;
 659  660          }
 660  661          mutex_exit(&fcsm_global_mutex);
 661  662  
 662  663          mutex_enter(&fcsm->sm_mutex);
 663  664          fcsm->sm_flags &= ~FCSM_ATTACHING;
 664  665          fcsm->sm_flags |= FCSM_ATTACHED;
 665  666          fcsm->sm_port_top = pinfo->port_flags;
 666  667          fcsm->sm_port_state = pinfo->port_state;
 667  668          if (pinfo->port_acc_attr == NULL) {
 668  669                  /*
 669  670                   * The corresponding FCA doesn't support DMA at all
 670  671                   */
 671  672                  fcsm->sm_flags |= FCSM_USING_NODMA_FCA;
 672  673          }
 673  674          mutex_exit(&fcsm->sm_mutex);
 674  675  
 675  676          (void) ddi_pathname(fcsm->sm_port_info.port_dip, fcsm_pathname);
 676  677          fcsm_display(CE_NOTE, SM_LOG, fcsm, NULL,
 677  678              "attached to path %s", fcsm_pathname);
 678  679  
 679  680          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
 680  681              "port_attach: state <%s>(0x%x) topology <%s>(0x%x)",
 681  682              fcsm_port_state_to_str(FC_PORT_STATE_MASK(pinfo->port_state)),
 682  683              pinfo->port_state,
 683  684              fcsm_topology_to_str(pinfo->port_flags), pinfo->port_flags));
 684  685  
 685  686          return (DDI_SUCCESS);
 686  687  }
 687  688  
 688  689  static int
 689  690  fcsm_handle_port_resume(opaque_t ulph, fc_ulp_port_info_t *pinfo,
 690  691      fc_attach_cmd_t cmd, uint32_t s_id, fcsm_t *fcsm)
 691  692  {
 692  693          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
 693  694              "port_resume: cmd 0x%x", cmd));
 694  695  
 695  696          mutex_enter(&fcsm->sm_mutex);
 696  697  
 697  698          switch (cmd) {
 698  699          case FC_CMD_RESUME:
 699  700                  ASSERT(!(fcsm->sm_flags & FCSM_POWER_DOWN));
 700  701                  fcsm->sm_flags &= ~FCSM_SUSPENDED;
 701  702                  break;
 702  703  
 703  704          case FC_CMD_POWER_UP:
 704  705                  /* If port is suspended, then no need to resume */
 705  706                  fcsm->sm_flags &= ~FCSM_POWER_DOWN;
 706  707                  if (fcsm->sm_flags & FCSM_SUSPENDED) {
 707  708                          mutex_exit(&fcsm->sm_mutex);
 708  709                          return (DDI_SUCCESS);
 709  710                  }
 710  711                  break;
 711  712          default:
 712  713                  mutex_exit(&fcsm->sm_mutex);
 713  714                  return (DDI_FAILURE);
 714  715          }
 715  716  
 716  717          fcsm->sm_sid = s_id;
 717  718  
 718  719          /*
 719  720           * Make a copy of the new port_information structure
 720  721           */
 721  722          fcsm->sm_port_info      = *pinfo;       /* Structure copy !!! */
 722  723          mutex_exit(&fcsm->sm_mutex);
 723  724  
 724  725          fcsm_resume_port(fcsm);
 725  726  
 726  727          /*
 727  728           * Invoke state change processing.
 728  729           * This will ensure that
 729  730           *    - offline timer is started if new port state changed to offline.
 730  731           *    - MGMT_SERVER_LOGIN flag is reset.
 731  732           *    - Port topology is updated.
 732  733           */
 733  734          fcsm_statec_cb(ulph, (opaque_t)pinfo->port_handle, pinfo->port_state,
 734  735              pinfo->port_flags, NULL, 0, s_id);
 735  736  
 736  737          return (DDI_SUCCESS);
 737  738  }
 738  739  
 739  740  
 740  741  /* ARGSUSED */
 741  742  static int
 742  743  fcsm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 743  744  {
 744  745          int     rval = DDI_SUCCESS;
 745  746  
 746  747          switch (cmd) {
 747  748          case DDI_DETACH: {
 748  749                  fcsm_t  *fcsm;
 749  750  
 750  751                  FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
 751  752                      "detach: start. cmd <DETACH>", cmd));
 752  753  
 753  754                  mutex_enter(&fcsm_global_mutex);
 754  755  
 755  756                  /*
 756  757                   * If port attach/detach in progress, then wait for 5 seconds
 757  758                   * for them to complete.
 758  759                   */
 759  760                  if (fcsm_num_attaching || fcsm_num_detaching) {
 760  761                          int count;
 761  762  
 762  763                          FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL,
 763  764                              "detach: wait for port attach/detach to complete"));
 764  765  
 765  766                          count = 0;
 766  767                          while ((count++ <= 30) &&
 767  768                              (fcsm_num_attaching || fcsm_num_detaching)) {
 768  769                                  mutex_exit(&fcsm_global_mutex);
 769  770                                  delay(drv_usectohz(1000000));
 770  771                                  mutex_enter(&fcsm_global_mutex);
 771  772                          }
 772  773  
 773  774                          /* Port attach/detach still in prog, so fail detach */
 774  775                          if (fcsm_num_attaching || fcsm_num_detaching) {
 775  776                                  mutex_exit(&fcsm_global_mutex);
 776  777                                  FCSM_DEBUG(SMDL_ERR, (CE_WARN, SM_LOG, NULL,
 777  778                                      NULL, "detach: Failing detach. port "
 778  779                                      "attach/detach in progress"));
 779  780                                  rval = DDI_FAILURE;
 780  781                                  break;
 781  782                          }
 782  783                  }
 783  784  
 784  785                  if (fcsm_port_head == NULL) {
 785  786                          /* Not much do, Succeed to detach. */
 786  787                          ddi_remove_minor_node(fcsm_dip, NULL);
 787  788                          fcsm_dip = NULL;
 788  789                          fcsm_detached = 0;
 789  790                          mutex_exit(&fcsm_global_mutex);
 790  791                          break;
 791  792                  }
 792  793  
 793  794                  /*
 794  795                   * Check to see, if any ports are active.
 795  796                   * If not, then set the DETACHING flag to indicate
 796  797                   * that they are being detached.
 797  798                   */
 798  799                  fcsm = fcsm_port_head;
 799  800                  while (fcsm != NULL) {
 800  801  
 801  802                          mutex_enter(&fcsm->sm_mutex);
 802  803                          if (!(fcsm->sm_flags & FCSM_ATTACHED) ||
 803  804                              fcsm->sm_ncmds || fcsm->sm_cb_count) {
 804  805                                  /* port is busy. We can't detach */
 805  806                                  mutex_exit(&fcsm->sm_mutex);
 806  807                                  break;
 807  808                          }
 808  809  
 809  810                          fcsm->sm_flags |= FCSM_DETACHING;
 810  811                          mutex_exit(&fcsm->sm_mutex);
 811  812  
 812  813                          fcsm = fcsm->sm_next;
 813  814                  }
 814  815  
 815  816                  /*
 816  817                   * If all ports could not be marked for detaching,
 817  818                   * then clear the flags and fail the detach.
 818  819                   * Also if a port attach is currently in progress
 819  820                   * then fail the detach.
 820  821                   */
 821  822                  if (fcsm != NULL || fcsm_num_attaching || fcsm_num_detaching) {
 822  823                          /*
 823  824                           * Some ports were busy, so can't detach.
 824  825                           * Clear the DETACHING flag and return failure
 825  826                           */
 826  827                          fcsm = fcsm_port_head;
 827  828                          while (fcsm != NULL) {
 828  829                                  mutex_enter(&fcsm->sm_mutex);
 829  830                                  if (fcsm->sm_flags & FCSM_DETACHING) {
 830  831                                          fcsm->sm_flags &= ~FCSM_DETACHING;
 831  832                                  }
 832  833                                  mutex_exit(&fcsm->sm_mutex);
 833  834  
 834  835                                  fcsm = fcsm->sm_next;
 835  836                          }
 836  837                          mutex_exit(&fcsm_global_mutex);
 837  838                          return (DDI_FAILURE);
 838  839                  } else {
 839  840                          fcsm_detached = 1;
 840  841                          /*
 841  842                           * Mark all the detaching ports as detached, as we
 842  843                           * will be detaching them
 843  844                           */
 844  845                          fcsm = fcsm_port_head;
 845  846                          while (fcsm != NULL) {
 846  847                                  mutex_enter(&fcsm->sm_mutex);
 847  848                                  fcsm->sm_flags &= ~FCSM_DETACHING;
 848  849                                  fcsm->sm_flags |= FCSM_DETACHED;
 849  850                                  mutex_exit(&fcsm->sm_mutex);
 850  851  
 851  852                                  fcsm = fcsm->sm_next;
 852  853                          }
 853  854                  }
 854  855                  mutex_exit(&fcsm_global_mutex);
 855  856  
 856  857  
 857  858                  /*
 858  859                   * Go ahead and detach the ports
 859  860                   */
 860  861                  mutex_enter(&fcsm_global_mutex);
 861  862                  while (fcsm_port_head != NULL) {
 862  863                          fcsm = fcsm_port_head;
 863  864                          mutex_exit(&fcsm_global_mutex);
 864  865  
 865  866                          /*
 866  867                           * Call fcsm_cleanup_port(). This cleansup and
 867  868                           * removes the fcsm structure from global linked list
 868  869                           */
 869  870                          fcsm_cleanup_port(fcsm);
 870  871  
 871  872                          /*
 872  873                           * Soft state cleanup done.
 873  874                           * Remember that fcsm struct doesn't exist anymore.
 874  875                           */
 875  876  
 876  877                          mutex_enter(&fcsm_global_mutex);
 877  878                  }
 878  879  
 879  880                  ddi_remove_minor_node(fcsm_dip, NULL);
 880  881                  fcsm_dip = NULL;
 881  882                  mutex_exit(&fcsm_global_mutex);
 882  883                  break;
 883  884          }
 884  885  
 885  886          case DDI_SUSPEND:
 886  887                  rval = DDI_SUCCESS;
 887  888                  break;
 888  889  
 889  890          default:
 890  891                  FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, NULL, NULL,
 891  892                      "detach: unknown cmd 0x%x", cmd));
 892  893                  rval = DDI_FAILURE;
 893  894                  break;
 894  895          }
 895  896  
 896  897          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
 897  898              "detach: end. cmd 0x%x, rval 0x%x", cmd, rval));
 898  899  
 899  900          return (rval);
 900  901  }
 901  902  
 902  903  
 903  904  /* ARGSUSED */
 904  905  static void
 905  906  fcsm_force_port_detach_all(void)
 906  907  {
 907  908          fcsm_t  *fcsm;
 908  909  
 909  910          fcsm = fcsm_port_head;
 910  911  
 911  912          while (fcsm) {
 912  913                  fcsm_cleanup_port(fcsm);
 913  914                  /*
 914  915                   * fcsm_cleanup_port will remove the current fcsm structure
 915  916                   * from the list, which will cause fcsm_port_head to point
 916  917                   * to what would have been the next structure on the list.
 917  918                   */
 918  919                  fcsm = fcsm_port_head;
 919  920          }
 920  921  }
 921  922  
 922  923  
 923  924  /* ARGSUSED */
 924  925  static int
 925  926  fcsm_port_detach(opaque_t ulph, fc_ulp_port_info_t *pinfo, fc_detach_cmd_t cmd)
 926  927  {
 927  928          int     instance;
 928  929          int     rval = FC_FAILURE;
 929  930          fcsm_t  *fcsm;
 930  931  
 931  932          instance = ddi_get_instance(pinfo->port_dip);
 932  933  
 933  934          mutex_enter(&fcsm_global_mutex);
 934  935          if (fcsm_detached) {
 935  936                  mutex_exit(&fcsm_global_mutex);
 936  937  
 937  938                  FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL,
 938  939                      "port_detach: end. instance 0x%x, fcsm is detached",
 939  940                      instance));
 940  941                  return (FC_SUCCESS);
 941  942          }
 942  943          fcsm_num_detaching++;   /* Set the flag */
 943  944          mutex_exit(&fcsm_global_mutex);
 944  945  
 945  946          /* Get the soft state structure */
 946  947          if ((fcsm = ddi_get_soft_state(fcsm_state, instance)) == NULL) {
 947  948                  FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL,
 948  949                      "port_detach: instance 0x%x, cmd 0x%x get softstate failed",
 949  950                      instance, cmd));
 950  951                  mutex_enter(&fcsm_global_mutex);
 951  952                  fcsm_num_detaching--;
 952  953                  mutex_exit(&fcsm_global_mutex);
 953  954                  return (rval);
 954  955          }
 955  956  
 956  957          ASSERT(fcsm->sm_instance == instance);
 957  958  
 958  959          /* If this instance is not attached, then fail the detach */
 959  960          mutex_enter(&fcsm->sm_mutex);
 960  961          if ((fcsm->sm_flags & FCSM_ATTACHED) == 0) {
 961  962                  mutex_exit(&fcsm->sm_mutex);
 962  963                  fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
 963  964                      "port_detach: port is not attached");
 964  965                  mutex_enter(&fcsm_global_mutex);
 965  966                  fcsm_num_detaching--;
 966  967                  mutex_exit(&fcsm_global_mutex);
 967  968                  return (rval);
 968  969          }
 969  970          mutex_exit(&fcsm->sm_mutex);
 970  971  
 971  972          /*
 972  973           * If fcsm has been detached, then all instance has already been
 973  974           * detached or are being detached. So succeed this detach.
 974  975           */
 975  976  
 976  977          switch (cmd) {
 977  978          case FC_CMD_DETACH:
 978  979          case FC_CMD_SUSPEND:
 979  980          case FC_CMD_POWER_DOWN:
 980  981                  break;
 981  982  
 982  983          default:
 983  984                  FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
 984  985                      "port_detach: port unknown cmd 0x%x", cmd));
 985  986                  mutex_enter(&fcsm_global_mutex);
 986  987                  fcsm_num_detaching--;
 987  988                  mutex_exit(&fcsm_global_mutex);
 988  989                  return (rval);
 989  990          };
 990  991  
 991  992          if (fcsm_handle_port_detach(pinfo, fcsm, cmd) == DDI_SUCCESS) {
 992  993                  rval = FC_SUCCESS;
 993  994          }
 994  995  
 995  996          mutex_enter(&fcsm_global_mutex);
 996  997          fcsm_num_detaching--;
 997  998          mutex_exit(&fcsm_global_mutex);
 998  999  
 999 1000          /* If it was a detach, then fcsm state structure no longer exists */
1000 1001          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
1001 1002              "port_detach: end. cmd 0x%x rval 0x%x", cmd, rval));
1002 1003          return (rval);
1003 1004  }
1004 1005  
1005 1006  
1006 1007  static int
1007 1008  fcsm_handle_port_detach(fc_ulp_port_info_t *pinfo, fcsm_t *fcsm,
1008 1009      fc_detach_cmd_t cmd)
1009 1010  {
1010 1011          uint32_t        flag;
1011 1012          int             count;
1012 1013  #ifdef DEBUG
1013 1014          char            pathname[MAXPATHLEN];
1014 1015  #endif /* DEBUG */
1015 1016  
1016 1017          /*
1017 1018           * If port is already powered down OR suspended and there is nothing
1018 1019           * else to do then just return.
1019 1020           * Otherwise, set the flag, so that no more new activity will be
1020 1021           * initiated on this port.
1021 1022           */
1022 1023          mutex_enter(&fcsm->sm_mutex);
1023 1024  
1024 1025          switch (cmd) {
1025 1026          case FC_CMD_DETACH:
1026 1027                  flag = FCSM_DETACHING;
1027 1028                  break;
1028 1029  
1029 1030          case FC_CMD_SUSPEND:
1030 1031          case FC_CMD_POWER_DOWN:
1031 1032                  ((cmd == FC_CMD_SUSPEND) ? (flag = FCSM_SUSPENDED) :
1032 1033                      (flag = FCSM_POWER_DOWN));
1033 1034                  if (fcsm->sm_flags &
1034 1035                      (FCSM_POWER_DOWN | FCSM_SUSPENDED)) {
1035 1036                          fcsm->sm_flags |= flag;
1036 1037                          mutex_exit(&fcsm->sm_mutex);
1037 1038                          return (DDI_SUCCESS);
1038 1039                  }
1039 1040                  break;
1040 1041  
1041 1042          default:
1042 1043                  mutex_exit(&fcsm->sm_mutex);
1043 1044                  return (DDI_FAILURE);
1044 1045          };
1045 1046  
1046 1047          fcsm->sm_flags |= flag;
1047 1048  
1048 1049          /*
1049 1050           * If some commands are pending OR callback in progress, then
1050 1051           * wait for some finite amount of time for their completion.
1051 1052           * TODO: add more checks here to check for cmd timeout, offline
1052 1053           * timeout and other (??) threads.
1053 1054           */
1054 1055          count = 0;
1055 1056          while ((count++ <= 30) && (fcsm->sm_ncmds || fcsm->sm_cb_count)) {
1056 1057                  mutex_exit(&fcsm->sm_mutex);
1057 1058                  delay(drv_usectohz(1000000));
1058 1059                  mutex_enter(&fcsm->sm_mutex);
1059 1060          }
1060 1061          if (fcsm->sm_ncmds || fcsm->sm_cb_count) {
1061 1062                  fcsm->sm_flags &= ~flag;
1062 1063                  mutex_exit(&fcsm->sm_mutex);
1063 1064                  fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
1064 1065                      "port_detach: Failing suspend, port is busy");
1065 1066                  return (DDI_FAILURE);
1066 1067          }
1067 1068          if (flag == FCSM_DETACHING) {
1068 1069                  fcsm->sm_flags &= ~FCSM_DETACHING;
1069 1070                  fcsm->sm_flags |= FCSM_DETACHED;
1070 1071          }
1071 1072  
1072 1073          mutex_exit(&fcsm->sm_mutex);
1073 1074  
1074 1075          FCSM_DEBUG(SMDL_INFO, (CE_CONT, SM_LOG, fcsm, NULL,
1075 1076              "port_detach: cmd 0x%x pathname <%s>",
1076 1077              cmd, ddi_pathname(pinfo->port_dip, pathname)));
1077 1078  
1078 1079          if (cmd == FC_CMD_DETACH) {
1079 1080                  fcsm_cleanup_port(fcsm);
1080 1081                  /*
1081 1082                   * Soft state cleanup done.
1082 1083                   * Always remember that fcsm struct doesn't exist anymore.
1083 1084                   */
1084 1085          } else {
1085 1086                  fcsm_suspend_port(fcsm);
1086 1087          }
1087 1088  
1088 1089          return (DDI_SUCCESS);
1089 1090  }
1090 1091  
1091 1092  static void
1092 1093  fcsm_suspend_port(fcsm_t *fcsm)
1093 1094  {
1094 1095          mutex_enter(&fcsm->sm_mutex);
1095 1096  
1096 1097          if (fcsm->sm_offline_tid != NULL) {
1097 1098                  timeout_id_t    tid;
1098 1099  
1099 1100                  tid = fcsm->sm_offline_tid;
1100 1101                  fcsm->sm_offline_tid = (timeout_id_t)NULL;
1101 1102                  mutex_exit(&fcsm->sm_mutex);
1102 1103                  (void) untimeout(tid);
1103 1104                  mutex_enter(&fcsm->sm_mutex);
1104 1105                  fcsm->sm_flags |= FCSM_RESTORE_OFFLINE_TIMEOUT;
1105 1106          }
1106 1107  
1107 1108          if (fcsm->sm_retry_tid != NULL) {
1108 1109                  timeout_id_t    tid;
1109 1110  
1110 1111                  tid = fcsm->sm_retry_tid;
1111 1112                  fcsm->sm_retry_tid = (timeout_id_t)NULL;
1112 1113                  mutex_exit(&fcsm->sm_mutex);
1113 1114                  (void) untimeout(tid);
1114 1115                  mutex_enter(&fcsm->sm_mutex);
1115 1116                  fcsm->sm_flags |= FCSM_RESTORE_RETRY_TIMEOUT;
1116 1117          }
1117 1118  
1118 1119          mutex_exit(&fcsm->sm_mutex);
1119 1120  }
1120 1121  
1121 1122  static void
1122 1123  fcsm_resume_port(fcsm_t *fcsm)
1123 1124  {
1124 1125          mutex_enter(&fcsm->sm_mutex);
1125 1126  
1126 1127          if (fcsm->sm_flags & FCSM_RESTORE_OFFLINE_TIMEOUT) {
1127 1128                  fcsm->sm_flags &= ~FCSM_RESTORE_OFFLINE_TIMEOUT;
1128 1129  
1129 1130                  /*
1130 1131                   * If port if offline, link is not marked down and offline
1131 1132                   * timer is not already running, then restart offline timer.
1132 1133                   */
1133 1134                  if (!(fcsm->sm_flags & FCSM_LINK_DOWN) &&
1134 1135                      fcsm->sm_offline_tid == NULL &&
1135 1136                      (fcsm->sm_flags & FCSM_PORT_OFFLINE)) {
1136 1137                          fcsm->sm_offline_tid = timeout(fcsm_offline_timeout,
1137 1138                              (caddr_t)fcsm, fcsm_offline_ticks);
1138 1139                  }
1139 1140          }
1140 1141  
1141 1142          if (fcsm->sm_flags & FCSM_RESTORE_RETRY_TIMEOUT) {
1142 1143                  fcsm->sm_flags &= ~FCSM_RESTORE_RETRY_TIMEOUT;
1143 1144  
1144 1145                  /*
1145 1146                   * If retry queue is not suspended and some cmds are waiting
1146 1147                   * to be retried, then restart the retry timer
1147 1148                   */
1148 1149                  if (fcsm->sm_retry_head && fcsm->sm_retry_tid == NULL) {
1149 1150                          fcsm->sm_retry_tid = timeout(fcsm_retry_timeout,
1150 1151                              (caddr_t)fcsm, fcsm_retry_ticks);
1151 1152                  }
1152 1153          }
1153 1154          mutex_exit(&fcsm->sm_mutex);
1154 1155  }
1155 1156  
1156 1157  static void
1157 1158  fcsm_cleanup_port(fcsm_t *fcsm)
1158 1159  {
1159 1160          fcsm_t          *curr, *prev;
1160 1161          int             status;
1161 1162          fcsm_job_t      *job;
1162 1163  
1163 1164          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
1164 1165              "fcsm_cleanup_port: entered"));
1165 1166  
1166 1167          /*
1167 1168           * Kill the job thread
1168 1169           */
1169 1170          job = fcsm_alloc_job(KM_SLEEP);
1170 1171          ASSERT(job != NULL);
1171 1172          fcsm_init_job(job, fcsm->sm_instance, FCSM_JOB_THREAD_SHUTDOWN,
1172 1173              FCSM_JOBFLAG_SYNC, NULL, NULL, NULL, NULL);
1173 1174  
1174 1175          status = fcsm_process_job(job, 0);
1175 1176          ASSERT(status == FC_SUCCESS);
1176 1177  
1177 1178          ASSERT(job->job_result == FC_SUCCESS);
1178 1179          fcsm_dealloc_job(job);
1179 1180  
1180 1181          /*
1181 1182           * We got here after ensuring the no commands are pending or active.
1182 1183           * Therefore retry timeout thread should NOT be running.
1183 1184           * Kill the offline timeout thread if currently running.
1184 1185           */
1185 1186          mutex_enter(&fcsm->sm_mutex);
1186 1187  
1187 1188          ASSERT(fcsm->sm_retry_tid == NULL);
1188 1189  
1189 1190          if (fcsm->sm_offline_tid != NULL) {
1190 1191                  timeout_id_t    tid;
1191 1192  
1192 1193                  tid = fcsm->sm_offline_tid;
1193 1194                  fcsm->sm_offline_tid = (timeout_id_t)NULL;
1194 1195                  mutex_exit(&fcsm->sm_mutex);
1195 1196                  (void) untimeout(tid);
1196 1197          } else {
1197 1198                  mutex_exit(&fcsm->sm_mutex);
1198 1199          }
1199 1200  
1200 1201          /* Remove from the fcsm state structure from global linked list */
1201 1202          mutex_enter(&fcsm_global_mutex);
1202 1203          curr = fcsm_port_head;
1203 1204          prev = NULL;
1204 1205          while (curr != fcsm && curr != NULL) {
1205 1206                  prev = curr;
1206 1207                  curr = curr->sm_next;
1207 1208          }
1208 1209          ASSERT(curr != NULL);
1209 1210  
1210 1211          if (prev == NULL) {
1211 1212                  fcsm_port_head = curr->sm_next;
1212 1213          } else {
1213 1214                  prev->sm_next = curr->sm_next;
1214 1215          }
1215 1216          mutex_exit(&fcsm_global_mutex);
1216 1217  
1217 1218          if (fcsm->sm_cmd_cache != NULL) {
1218 1219                  kmem_cache_destroy(fcsm->sm_cmd_cache);
1219 1220          }
1220 1221          cv_destroy(&fcsm->sm_job_cv);
1221 1222          mutex_destroy(&fcsm->sm_mutex);
1222 1223  
1223 1224          /* Free the fcsm state structure */
1224 1225          ddi_soft_state_free(fcsm_state, fcsm->sm_instance);
1225 1226  }
1226 1227  
1227 1228  
1228 1229  /* ARGSUSED */
1229 1230  static void
1230 1231  fcsm_statec_cb(opaque_t ulph, opaque_t port_handle, uint32_t port_state,
1231 1232      uint32_t port_top, fc_portmap_t *devlist, uint32_t dev_cnt,
1232 1233      uint32_t port_sid)
1233 1234  {
1234 1235          fcsm_t          *fcsm;
1235 1236          timeout_id_t    offline_tid, retry_tid;
1236 1237  
1237 1238          mutex_enter(&fcsm_global_mutex);
1238 1239          if (fcsm_detached) {
1239 1240                  mutex_exit(&fcsm_global_mutex);
1240 1241                  return;
1241 1242          }
1242 1243  
1243 1244          fcsm = ddi_get_soft_state(fcsm_state,
1244 1245              fc_ulp_get_port_instance(port_handle));
1245 1246          if (fcsm == NULL) {
1246 1247                  mutex_exit(&fcsm_global_mutex);
1247 1248                  FCSM_DEBUG(SMDL_TRACE, (CE_NOTE, SM_LOG, NULL, NULL,
1248 1249                      "statec_cb: instance 0x%x not found",
1249 1250                      fc_ulp_get_port_instance(port_handle)));
1250 1251                  return;
1251 1252          }
1252 1253          mutex_enter(&fcsm->sm_mutex);
1253 1254          ASSERT(fcsm->sm_instance == fc_ulp_get_port_instance(port_handle));
1254 1255          if ((fcsm->sm_flags & FCSM_ATTACHED) == 0) {
1255 1256                  mutex_exit(&fcsm->sm_mutex);
1256 1257                  mutex_exit(&fcsm_global_mutex);
1257 1258                  FCSM_DEBUG(SMDL_TRACE, (CE_NOTE, SM_LOG, fcsm, NULL,
1258 1259                      "statec_cb: port not attached"));
1259 1260                  return;
1260 1261          }
1261 1262  
1262 1263          ASSERT(fcsm->sm_cb_count >= 0);
1263 1264  
1264 1265          fcsm->sm_cb_count++;
1265 1266          mutex_exit(&fcsm->sm_mutex);
1266 1267          mutex_exit(&fcsm_global_mutex);
1267 1268  
1268 1269          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
1269 1270              "statec_cb: state <%s>(0x%x) topology <%s>(0x%x) dev_cnt %d",
1270 1271              fcsm_port_state_to_str(FC_PORT_STATE_MASK(port_state)), port_state,
1271 1272              fcsm_topology_to_str(port_top), port_top, dev_cnt));
1272 1273  
1273 1274          fcsm_disp_devlist(fcsm, devlist, dev_cnt);
1274 1275  
1275 1276          mutex_enter(&fcsm->sm_mutex);
1276 1277  
1277 1278          /*
1278 1279           * Reset the Mgmt server Login flag, so that login is performed again.
1279 1280           */
1280 1281          fcsm->sm_flags &= ~FCSM_MGMT_SERVER_LOGGED_IN;
1281 1282  
1282 1283          fcsm->sm_sid = port_sid;
1283 1284          fcsm->sm_port_top = port_top;
1284 1285          fcsm->sm_port_state = port_state;
1285 1286  
1286 1287          switch (port_state) {
1287 1288          case FC_STATE_OFFLINE:
1288 1289          case FC_STATE_RESET:
1289 1290          case FC_STATE_RESET_REQUESTED:
1290 1291                  fcsm->sm_flags |= FCSM_PORT_OFFLINE;
1291 1292                  break;
1292 1293  
1293 1294          case FC_STATE_ONLINE:
1294 1295          case FC_STATE_LOOP:
1295 1296          case FC_STATE_LIP:
1296 1297          case FC_STATE_LIP_LBIT_SET:
1297 1298                  fcsm->sm_flags &= ~FCSM_PORT_OFFLINE;
1298 1299                  fcsm->sm_flags &= ~FCSM_LINK_DOWN;
1299 1300                  break;
1300 1301  
1301 1302          case FC_STATE_NAMESERVICE:
1302 1303          case FC_STATE_DEVICE_CHANGE:
1303 1304          case FC_STATE_TARGET_PORT_RESET:
1304 1305          default:
1305 1306                  /* Do nothing */
1306 1307                  break;
1307 1308          }
1308 1309  
1309 1310          offline_tid = retry_tid = NULL;
1310 1311          if (fcsm->sm_flags & FCSM_PORT_OFFLINE) {
1311 1312                  /*
1312 1313                   * Port is offline.
1313 1314                   * Suspend cmd processing and start offline timeout thread.
1314 1315                   */
1315 1316                  if (fcsm->sm_offline_tid == NULL) {
1316 1317                          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
1317 1318                              "statec_cb: schedule offline timeout thread"));
1318 1319                          fcsm->sm_flags |= FCSM_CMD_RETRY_Q_SUSPENDED;
1319 1320                          /* Stop the cmd retry thread */
1320 1321                          retry_tid = fcsm->sm_retry_tid;
1321 1322                          fcsm->sm_retry_tid = (timeout_id_t)NULL;
1322 1323  
1323 1324                          fcsm->sm_offline_tid = timeout(fcsm_offline_timeout,
1324 1325                              (caddr_t)fcsm, fcsm_offline_ticks);
1325 1326                  }
1326 1327  
1327 1328          } else {
1328 1329                  /*
1329 1330                   * Port is online.
1330 1331                   * Cancel offline timeout thread and resume command processing.
1331 1332                   */
1332 1333                  if (fcsm->sm_offline_tid) {
1333 1334                          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
1334 1335                              "statec_cb: cancel offline timeout thread"));
1335 1336                          offline_tid = fcsm->sm_offline_tid;
1336 1337                          fcsm->sm_offline_tid = (timeout_id_t)NULL;
1337 1338                  }
1338 1339  
1339 1340                  fcsm->sm_flags &= ~FCSM_CMD_RETRY_Q_SUSPENDED;
1340 1341                  /* Start retry thread if needed */
1341 1342                  if (fcsm->sm_retry_head && fcsm->sm_retry_tid == NULL) {
1342 1343                          fcsm->sm_retry_tid = timeout(fcsm_retry_timeout,
1343 1344                              (caddr_t)fcsm, fcsm_retry_ticks);
1344 1345                  }
1345 1346          }
1346 1347  
1347 1348          mutex_exit(&fcsm->sm_mutex);
1348 1349  
1349 1350          if (offline_tid != NULL) {
1350 1351                  (void) untimeout(offline_tid);
1351 1352          }
1352 1353  
1353 1354          if (retry_tid != NULL) {
1354 1355                  (void) untimeout(retry_tid);
1355 1356          }
1356 1357  
1357 1358          mutex_enter(&fcsm->sm_mutex);
1358 1359          fcsm->sm_cb_count--;
1359 1360          ASSERT(fcsm->sm_cb_count >= 0);
1360 1361          mutex_exit(&fcsm->sm_mutex);
1361 1362  }
1362 1363  
1363 1364  
1364 1365  static void
1365 1366  fcsm_offline_timeout(void *handle)
1366 1367  {
1367 1368          fcsm_t  *fcsm = (fcsm_t *)handle;
1368 1369  
1369 1370          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
1370 1371              "offline_timeout"));
1371 1372  
1372 1373          mutex_enter(&fcsm->sm_mutex);
1373 1374          if (fcsm->sm_flags & FCSM_PORT_OFFLINE) {
1374 1375                  fcsm->sm_flags |= FCSM_LINK_DOWN;
1375 1376          }
1376 1377          fcsm->sm_offline_tid = (timeout_id_t)NULL;
1377 1378          fcsm->sm_flags &= ~FCSM_CMD_RETRY_Q_SUSPENDED;
1378 1379  
1379 1380          /* Start the retry thread if needed */
1380 1381          if (fcsm->sm_retry_head && fcsm->sm_retry_tid == NULL) {
1381 1382                  FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
1382 1383                      "offline_timeout: reschedule cmd retry thread"));
1383 1384                  ASSERT(fcsm->sm_retry_tid == NULL);
1384 1385                  fcsm->sm_retry_tid = timeout(fcsm_retry_timeout,
1385 1386                      (caddr_t)fcsm, fcsm_retry_ticks);
1386 1387          }
1387 1388          mutex_exit(&fcsm->sm_mutex);
1388 1389  }
1389 1390  
1390 1391  /* ARGSUSED */
1391 1392  static int
1392 1393  fcsm_els_cb(opaque_t ulph, opaque_t port_handle, fc_unsol_buf_t *buf,
1393 1394      uint32_t claimed)
1394 1395  {
1395 1396          return (FC_UNCLAIMED);
1396 1397  }
1397 1398  
1398 1399  
1399 1400  /* ARGSUSED */
1400 1401  static int
1401 1402  fcsm_data_cb(opaque_t ulph, opaque_t port_handle, fc_unsol_buf_t *buf,
1402 1403      uint32_t claimed)
1403 1404  {
1404 1405          return (FC_UNCLAIMED);
1405 1406  }
1406 1407  
1407 1408  
1408 1409  /* ARGSUSED */
1409 1410  static int
1410 1411  fcsm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1411 1412      int *rval_p)
1412 1413  {
1413 1414          int retval = 0;
1414 1415  
1415 1416          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "ioctl: start"));
1416 1417  
1417 1418          mutex_enter(&fcsm_global_mutex);
1418 1419          if (!(fcsm_flag & FCSM_OPEN)) {
1419 1420                  mutex_exit(&fcsm_global_mutex);
1420 1421                  return (ENXIO);
1421 1422          }
1422 1423          mutex_exit(&fcsm_global_mutex);
1423 1424  
1424 1425          /* Allow only root to talk */
1425 1426          if (drv_priv(credp)) {
1426 1427                  FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
1427 1428                      "ioctl: end (disallowing underprivileged user)"));
1428 1429                  return (EPERM);
1429 1430          }
1430 1431  
1431 1432          switch (cmd) {
1432 1433  
1433 1434          case FCSMIO_CMD: {
1434 1435                  fcio_t  fcio;
1435 1436                  int     status;
1436 1437  #ifdef  _MULTI_DATAMODEL
1437 1438                  switch (ddi_model_convert_from(mode & FMODELS)) {
1438 1439                  case DDI_MODEL_ILP32: {
1439 1440                          struct fcio32 fcio32;
1440 1441  
1441 1442                          if (status = ddi_copyin((void *)arg, (void *)&fcio32,
1442 1443                              sizeof (struct fcio32), mode)) {
1443 1444                                  retval = EFAULT;
1444 1445                                  break;
1445 1446                          }
1446 1447                          fcio.fcio_xfer = fcio32.fcio_xfer;
1447 1448                          fcio.fcio_cmd = fcio32.fcio_cmd;
1448 1449                          fcio.fcio_flags = fcio32.fcio_flags;
1449 1450                          fcio.fcio_cmd_flags = fcio32.fcio_cmd_flags;
1450 1451                          fcio.fcio_ilen = (size_t)fcio32.fcio_ilen;
1451 1452                          fcio.fcio_ibuf = (caddr_t)(long)fcio32.fcio_ibuf;
1452 1453                          fcio.fcio_olen = (size_t)fcio32.fcio_olen;
1453 1454                          fcio.fcio_obuf = (caddr_t)(long)fcio32.fcio_obuf;
1454 1455                          fcio.fcio_alen = (size_t)fcio32.fcio_alen;
1455 1456                          fcio.fcio_abuf = (caddr_t)(long)fcio32.fcio_abuf;
1456 1457                          fcio.fcio_errno = fcio32.fcio_errno;
1457 1458                          break;
1458 1459                  }
1459 1460  
1460 1461                  case DDI_MODEL_NONE:
1461 1462                          if (status = ddi_copyin((void *)arg, (void *)&fcio,
1462 1463                              sizeof (fcio_t), mode)) {
1463 1464                                  retval = EFAULT;
1464 1465                          }
1465 1466                          break;
1466 1467                  }
1467 1468  #else   /* _MULTI_DATAMODEL */
1468 1469                  if (status = ddi_copyin((void *)arg, (void *)&fcio,
1469 1470                      sizeof (fcio_t), mode)) {
1470 1471                          retval = EFAULT;
1471 1472                          break;
1472 1473                  }
1473 1474  #endif  /* _MULTI_DATAMODEL */
1474 1475                  if (!status) {
1475 1476                          retval = fcsm_fciocmd(arg, mode, credp, &fcio);
1476 1477                  }
1477 1478                  break;
1478 1479          }
1479 1480  
1480 1481          default:
1481 1482                  retval = ENOTTY;
1482 1483                  break;
1483 1484          }
1484 1485  
1485 1486          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "ioctl: end"));
1486 1487          return (retval);
1487 1488  }
1488 1489  
1489 1490  /* ARGSUSED */
1490 1491  static int
1491 1492  fcsm_port_ioctl(opaque_t ulph, opaque_t port_handle, dev_t dev, int cmd,
1492 1493      intptr_t arg, int mode, cred_t *credp, int *rval, uint32_t claimed)
1493 1494  {
1494 1495          return (FC_UNCLAIMED);
1495 1496  }
1496 1497  
1497 1498  
1498 1499  /* ARGSUSED */
1499 1500  static int
1500 1501  fcsm_fciocmd(intptr_t arg, int mode, cred_t *credp, fcio_t *fcio)
1501 1502  {
1502 1503          int  retval = 0;
1503 1504  
1504 1505          switch (fcio->fcio_cmd) {
1505 1506          case  FCSMIO_CT_CMD: {
1506 1507                  fcsm_t          *fcsm;
1507 1508                  caddr_t         user_ibuf, user_obuf;
1508 1509                  caddr_t         req_iu, rsp_iu, abuf;
1509 1510                  int             status, instance, count;
1510 1511  
1511 1512                  if ((fcio->fcio_xfer != FCIO_XFER_RW) ||
1512 1513                      (fcio->fcio_ilen == 0) || (fcio->fcio_ibuf == 0) ||
1513 1514                      (fcio->fcio_olen == 0) || (fcio->fcio_obuf == 0) ||
1514 1515                      (fcio->fcio_alen == 0) || (fcio->fcio_abuf == 0) ||
1515 1516                      (fcio->fcio_flags != 0) || (fcio->fcio_cmd_flags != 0) ||
1516 1517                      (fcio->fcio_ilen > FCSM_MAX_CT_SIZE) ||
1517 1518                      (fcio->fcio_olen > FCSM_MAX_CT_SIZE) ||
1518 1519                      (fcio->fcio_alen > MAXPATHLEN)) {
1519 1520                          retval = EINVAL;
1520 1521                          break;
1521 1522                  }
1522 1523  
1523 1524                  /*
1524 1525                   * Get the destination port for which this ioctl
1525 1526                   * is targeted. The abuf will have the fp_minor
1526 1527                   * number.
1527 1528                   */
1528 1529                  abuf = kmem_zalloc(fcio->fcio_alen, KM_SLEEP);
1529 1530                  ASSERT(abuf != NULL);
1530 1531                  if (ddi_copyin(fcio->fcio_abuf, abuf, fcio->fcio_alen, mode)) {
1531 1532                          retval = EFAULT;
1532 1533                          kmem_free(abuf, fcio->fcio_alen);
1533 1534                          break;
1534 1535                  }
1535 1536  
1536 1537                  instance = *((int *)abuf);
1537 1538                  kmem_free(abuf, fcio->fcio_alen);
1538 1539  
1539 1540                  if (instance < 0) {
1540 1541                          FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL,
1541 1542                              "fciocmd: instance 0x%x, invalid instance",
1542 1543                              instance));
1543 1544                          retval = ENXIO;
1544 1545                          break;
1545 1546                  }
1546 1547  
1547 1548                  /*
1548 1549                   * We confirmed that path corresponds to our port driver
1549 1550                   * and a valid instance.
1550 1551                   * If this port instance is not yet attached, then wait
1551 1552                   * for a finite time for attach to complete
1552 1553                   */
1553 1554                  fcsm = ddi_get_soft_state(fcsm_state, instance);
1554 1555                  count = 0;
1555 1556                  while (count++ <= 30) {
1556 1557                          if (fcsm != NULL) {
1557 1558                                  mutex_enter(&fcsm->sm_mutex);
1558 1559                                  if (fcsm->sm_flags & FCSM_ATTACHED) {
1559 1560                                          mutex_exit(&fcsm->sm_mutex);
1560 1561                                          break;
1561 1562                                  }
1562 1563                                  mutex_exit(&fcsm->sm_mutex);
1563 1564                          }
1564 1565                          if (count == 1) {
1565 1566                                  FCSM_DEBUG(SMDL_TRACE,
1566 1567                                      (CE_WARN, SM_LOG, NULL, NULL,
1567 1568                                      "fciocmd: instance 0x%x, "
1568 1569                                      "wait for port attach", instance));
1569 1570                          }
1570 1571                          delay(drv_usectohz(1000000));
1571 1572                          fcsm = ddi_get_soft_state(fcsm_state, instance);
1572 1573                  }
1573 1574                  if (count > 30) {
1574 1575                          FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL,
1575 1576                              "fciocmd: instance 0x%x, port not attached",
1576 1577                              instance));
1577 1578                          retval = ENXIO;
1578 1579                          break;
1579 1580                  }
1580 1581  
1581 1582                  req_iu = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP);
1582 1583                  rsp_iu = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
1583 1584                  ASSERT((req_iu != NULL) && (rsp_iu != NULL));
1584 1585  
1585 1586                  if (ddi_copyin(fcio->fcio_ibuf, req_iu,
1586 1587                      fcio->fcio_ilen, mode)) {
1587 1588                          retval = EFAULT;
1588 1589                          kmem_free(req_iu, fcio->fcio_ilen);
1589 1590                          kmem_free(rsp_iu, fcio->fcio_olen);
1590 1591                          break;
1591 1592                  }
1592 1593  
1593 1594                  user_ibuf = fcio->fcio_ibuf;
1594 1595                  user_obuf = fcio->fcio_obuf;
1595 1596                  fcio->fcio_ibuf = req_iu;
1596 1597                  fcio->fcio_obuf = rsp_iu;
1597 1598  
1598 1599                  status = fcsm_ct_passthru(fcsm->sm_instance, fcio, KM_SLEEP,
1599 1600                      FCSM_JOBFLAG_SYNC, NULL);
1600 1601                  if (status != FC_SUCCESS) {
1601 1602                          retval = EIO;
1602 1603                  }
1603 1604  
1604 1605                  FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
1605 1606                      "fciocmd: cmd 0x%x completion status 0x%x",
1606 1607                      fcio->fcio_cmd, status));
1607 1608                  fcio->fcio_errno = status;
1608 1609                  fcio->fcio_ibuf = user_ibuf;
1609 1610                  fcio->fcio_obuf = user_obuf;
1610 1611  
1611 1612                  if (ddi_copyout(rsp_iu, fcio->fcio_obuf,
1612 1613                      fcio->fcio_olen, mode)) {
1613 1614                          retval = EFAULT;
1614 1615                          kmem_free(req_iu, fcio->fcio_ilen);
1615 1616                          kmem_free(rsp_iu, fcio->fcio_olen);
1616 1617                          break;
1617 1618                  }
1618 1619  
1619 1620                  kmem_free(req_iu, fcio->fcio_ilen);
1620 1621                  kmem_free(rsp_iu, fcio->fcio_olen);
1621 1622  
1622 1623                  if (fcsm_fcio_copyout(fcio, arg, mode)) {
1623 1624                          retval = EFAULT;
1624 1625                  }
1625 1626                  break;
1626 1627          }
1627 1628  
1628 1629          case  FCSMIO_ADAPTER_LIST: {
1629 1630                  fc_hba_list_t   *list;
1630 1631                  int                     count;
1631 1632  
1632 1633                  if ((fcio->fcio_xfer != FCIO_XFER_RW) ||
1633 1634                      (fcio->fcio_olen == 0) || (fcio->fcio_obuf == 0)) {
1634 1635                          retval = EINVAL;
1635 1636                          break;
1636 1637                  }
1637 1638  
1638 1639                  list = kmem_zalloc(fcio->fcio_olen, KM_SLEEP);
1639 1640  
1640 1641                  if (ddi_copyin(fcio->fcio_obuf, list, fcio->fcio_olen, mode)) {
1641 1642                          retval = EFAULT;
1642 1643                          break;
1643 1644                  }
1644 1645                  list->version = FC_HBA_LIST_VERSION;
1645 1646  
1646 1647                  if (fcio->fcio_olen < MAXPATHLEN * list->numAdapters) {
1647 1648                          retval = EFAULT;
1648 1649                          break;
1649 1650                  }
1650 1651  
1651 1652                  count = fc_ulp_get_adapter_paths((char *)list->hbaPaths,
1652 1653                      list->numAdapters);
1653 1654                  if (count < 0) {
1654 1655                          /* Did something go wrong? */
1655 1656                          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
1656 1657                              "Error fetching adapter list."));
1657 1658                          retval = ENXIO;
1658 1659                          kmem_free(list, fcio->fcio_olen);
1659 1660                          break;
1660 1661                  }
1661 1662                  /* Sucess (or short buffer) */
1662 1663                  list->numAdapters = count;
1663 1664                  if (ddi_copyout(list, fcio->fcio_obuf,
1664 1665                      fcio->fcio_olen, mode)) {
1665 1666                          retval = EFAULT;
1666 1667                  }
1667 1668                  kmem_free(list, fcio->fcio_olen);
1668 1669                  break;
1669 1670          }
1670 1671  
1671 1672          default:
1672 1673                  FCSM_DEBUG(SMDL_TRACE, (CE_NOTE, SM_LOG, NULL, NULL,
1673 1674                      "fciocmd: unknown cmd <0x%x>", fcio->fcio_cmd));
1674 1675                  retval = ENOTTY;
1675 1676                  break;
1676 1677          }
1677 1678  
1678 1679          return (retval);
1679 1680  }
1680 1681  
1681 1682  static int
1682 1683  fcsm_fcio_copyout(fcio_t *fcio, intptr_t arg, int mode)
1683 1684  {
1684 1685          int status;
1685 1686  
1686 1687  #ifdef  _MULTI_DATAMODEL
1687 1688          switch (ddi_model_convert_from(mode & FMODELS)) {
1688 1689          case DDI_MODEL_ILP32: {
1689 1690                  struct fcio32 fcio32;
1690 1691  
1691 1692                  fcio32.fcio_xfer = fcio->fcio_xfer;
1692 1693                  fcio32.fcio_cmd = fcio->fcio_cmd;
1693 1694                  fcio32.fcio_flags = fcio->fcio_flags;
1694 1695                  fcio32.fcio_cmd_flags = fcio->fcio_cmd_flags;
1695 1696                  fcio32.fcio_ilen = fcio->fcio_ilen;
1696 1697                  fcio32.fcio_ibuf = (caddr32_t)(long)fcio->fcio_ibuf;
1697 1698                  fcio32.fcio_olen = fcio->fcio_olen;
1698 1699                  fcio32.fcio_obuf = (caddr32_t)(long)fcio->fcio_obuf;
1699 1700                  fcio32.fcio_alen = fcio->fcio_alen;
1700 1701                  fcio32.fcio_abuf = (caddr32_t)(long)fcio->fcio_abuf;
1701 1702                  fcio32.fcio_errno = fcio->fcio_errno;
1702 1703  
1703 1704                  status = ddi_copyout((void *)&fcio32, (void *)arg,
1704 1705                      sizeof (struct fcio32), mode);
1705 1706                  break;
1706 1707          }
1707 1708          case DDI_MODEL_NONE:
1708 1709                  status = ddi_copyout((void *)fcio, (void *)arg,
1709 1710                      sizeof (fcio_t), mode);
1710 1711                  break;
1711 1712          }
1712 1713  #else   /* _MULTI_DATAMODEL */
1713 1714          status = ddi_copyout((void *)fcio, (void *)arg, sizeof (fcio_t), mode);
1714 1715  #endif  /* _MULTI_DATAMODEL */
1715 1716  
1716 1717          return (status);
1717 1718  }
1718 1719  
1719 1720  
1720 1721  /* ARGSUSED */
1721 1722  static int
1722 1723  fcsm_open(dev_t *devp, int flags, int otyp, cred_t *credp)
1723 1724  {
1724 1725          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "open"));
1725 1726  
1726 1727          if (otyp != OTYP_CHR) {
1727 1728                  FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
1728 1729                      "fcsm_open: failed. open type 0x%x for minor 0x%x is not "
1729 1730                      "OTYP_CHR", otyp, getminor(*devp)));
1730 1731                  return (EINVAL);
1731 1732          }
1732 1733  
1733 1734          /*
1734 1735           * Allow anybody to open (both root and non-root users).
1735 1736           * Previlege level checks are made on the per ioctl basis.
1736 1737           */
1737 1738          mutex_enter(&fcsm_global_mutex);
1738 1739          if (flags & FEXCL) {
1739 1740                  if (fcsm_flag & FCSM_OPEN) {
1740 1741                          mutex_exit(&fcsm_global_mutex);
1741 1742                          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
1742 1743                              "fcsm_open: exclusive open of 0x%x failed",
1743 1744                              getminor(*devp)));
1744 1745                          return (EBUSY);
1745 1746                  } else {
1746 1747                          ASSERT(fcsm_flag == FCSM_IDLE);
1747 1748                          fcsm_flag |= FCSM_EXCL;
1748 1749                  }
1749 1750          } else {
1750 1751                  if (fcsm_flag & FCSM_EXCL) {
1751 1752                          mutex_exit(&fcsm_global_mutex);
1752 1753                          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
1753 1754                              "fcsm_open: failed. Device minor 0x%x is in "
1754 1755                              "exclusive open mode", getminor(*devp)));
1755 1756                          return (EBUSY);
1756 1757                  }
1757 1758  
1758 1759          }
1759 1760          fcsm_flag |= FCSM_OPEN;
1760 1761          mutex_exit(&fcsm_global_mutex);
1761 1762          return (0);
1762 1763  }
1763 1764  
1764 1765  
1765 1766  /* ARGSUSED */
1766 1767  static int
1767 1768  fcsm_close(dev_t dev, int flag, int otyp, cred_t *credp)
1768 1769  {
1769 1770          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "close"));
1770 1771  
1771 1772          if (otyp != OTYP_CHR) {
1772 1773                  FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
1773 1774                      "fcsm_close: failed. close type 0x%x for minor 0x%x is not "
1774 1775                      "OTYP_CHR", otyp, getminor(dev)));
1775 1776                  return (EINVAL);
1776 1777          }
1777 1778  
1778 1779          mutex_enter(&fcsm_global_mutex);
1779 1780          if ((fcsm_flag & FCSM_OPEN) == 0) {
1780 1781                  mutex_exit(&fcsm_global_mutex);
1781 1782                  FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
1782 1783                      "fcsm_close: failed. minor 0x%x is already closed",
1783 1784                      getminor(dev)));
1784 1785                  return (ENODEV);
1785 1786          }
1786 1787          fcsm_flag = FCSM_IDLE;
1787 1788          mutex_exit(&fcsm_global_mutex);
1788 1789          return (0);
1789 1790  }
1790 1791  
1791 1792  
1792 1793  /* ARGSUSED */
1793 1794  static void
1794 1795  fcsm_disp_devlist(fcsm_t *fcsm, fc_portmap_t *devlist, uint32_t dev_cnt)
1795 1796  {
1796 1797          fc_portmap_t    *map;
1797 1798          uint32_t        i;
1798 1799  
1799 1800          if (dev_cnt == 0) {
1800 1801                  return;
1801 1802          }
1802 1803  
1803 1804          ASSERT(devlist != NULL);
1804 1805          for (i = 0; i < dev_cnt; i++) {
1805 1806                  map = &devlist[i];
1806 1807                  FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
1807 1808                      "list[%d]: ID 0x%x WWN %x:%x:%x:%x:%x:%x:%x:%x "
1808 1809                      "state (0x%x) "
1809 1810                      "type <%s>(0x%x) "
1810 1811                      "flags (0x%x)",
1811 1812                      i, map->map_did.port_id,
1812 1813                      map->map_pwwn.raw_wwn[0], map->map_pwwn.raw_wwn[1],
1813 1814                      map->map_pwwn.raw_wwn[2], map->map_pwwn.raw_wwn[3],
1814 1815                      map->map_pwwn.raw_wwn[4], map->map_pwwn.raw_wwn[5],
1815 1816                      map->map_pwwn.raw_wwn[6], map->map_pwwn.raw_wwn[7],
1816 1817                      map->map_state,
1817 1818                      fcsm_dev_type_to_str(map->map_type), map->map_type,
1818 1819                      map->map_flags));
1819 1820          }
1820 1821  }
1821 1822  
1822 1823  /* ARGSUSED */
1823 1824  static void
1824 1825  fcsm_display(int level, int flags, fcsm_t *fcsm, fc_packet_t *pkt,
1825 1826      const char *fmt, ...)
1826 1827  {
1827 1828          caddr_t buf;
1828 1829          va_list ap;
1829 1830  
1830 1831          buf = kmem_zalloc(256, KM_NOSLEEP);
1831 1832          if (buf == NULL) {
1832 1833                  return;
1833 1834          }
1834 1835  
1835 1836          if (fcsm) {
1836 1837                  (void) sprintf(buf + strlen(buf), "fcsm(%d): ",
1837 1838                      ddi_get_instance(fcsm->sm_port_info.port_dip));
1838 1839          } else {
1839 1840                  (void) sprintf(buf, "fcsm: ");
1840 1841          }
1841 1842  
1842 1843          va_start(ap, fmt);
1843 1844          (void) vsprintf(buf + strlen(buf), fmt, ap);
1844 1845          va_end(ap);
1845 1846  
1846 1847          if (pkt) {
1847 1848                  caddr_t state, reason, action, expln;
1848 1849  
1849 1850                  (void) fc_ulp_pkt_error(pkt, &state, &reason, &action, &expln);
1850 1851  
1851 1852                  (void) sprintf(buf + strlen(buf),
1852 1853                      " state: %s(0x%x); reason: %s(0x%x)",
1853 1854                      state, pkt->pkt_state, reason, pkt->pkt_reason);
1854 1855          }
1855 1856  
1856 1857          switch (flags) {
1857 1858          case SM_LOG:
1858 1859                  cmn_err(level, "!%s", buf);
1859 1860                  break;
1860 1861  
1861 1862          case SM_CONSOLE:
1862 1863                  cmn_err(level, "^%s", buf);
1863 1864                  break;
1864 1865  
1865 1866          default:
1866 1867                  cmn_err(level, "%s", buf);
1867 1868                  break;
1868 1869          }
1869 1870  
1870 1871          kmem_free(buf, 256);
1871 1872  }
1872 1873  
1873 1874  
1874 1875  /*
1875 1876   * Convert FC packet state to FC errno
1876 1877   */
1877 1878  int
1878 1879  fcsm_pkt_state_to_rval(uchar_t state, uint32_t reason)
1879 1880  {
1880 1881          int count;
1881 1882  
1882 1883          if (state == FC_PKT_LOCAL_RJT && (reason == FC_REASON_NO_CONNECTION ||
1883 1884              reason == FC_REASON_LOGIN_REQUIRED)) {
1884 1885                  return (FC_LOGINREQ);
1885 1886          } else if (state == FC_PKT_PORT_OFFLINE &&
1886 1887              reason == FC_REASON_LOGIN_REQUIRED) {
1887 1888                  return (FC_LOGINREQ);
1888 1889          }
1889 1890  
1890 1891          for (count = 0; count < sizeof (fcsm_xlat_pkt_state) /
1891 1892              sizeof (fcsm_xlat_pkt_state[0]); count++) {
1892 1893                  if (fcsm_xlat_pkt_state[count].xlat_state == state) {
1893 1894                          return (fcsm_xlat_pkt_state[count].xlat_rval);
1894 1895                  }
1895 1896          }
1896 1897  
1897 1898          return (FC_FAILURE);
1898 1899  }
1899 1900  
1900 1901  
1901 1902  /*
1902 1903   * Convert port state state to descriptive string
1903 1904   */
1904 1905  caddr_t
1905 1906  fcsm_port_state_to_str(uint32_t port_state)
1906 1907  {
1907 1908          int count;
1908 1909  
1909 1910          for (count = 0; count < sizeof (fcsm_xlat_port_state) /
1910 1911              sizeof (fcsm_xlat_port_state[0]); count++) {
1911 1912                  if (fcsm_xlat_port_state[count].xlat_pstate == port_state) {
1912 1913                          return (fcsm_xlat_port_state[count].xlat_state_str);
1913 1914                  }
1914 1915          }
1915 1916  
1916 1917          return (NULL);
1917 1918  }
1918 1919  
1919 1920  
1920 1921  /*
1921 1922   * Convert port topology state to descriptive string
1922 1923   */
1923 1924  caddr_t
1924 1925  fcsm_topology_to_str(uint32_t topology)
1925 1926  {
1926 1927          int count;
1927 1928  
1928 1929          for (count = 0; count < sizeof (fcsm_xlat_topology) /
1929 1930              sizeof (fcsm_xlat_topology[0]); count++) {
1930 1931                  if (fcsm_xlat_topology[count].xlat_top == topology) {
1931 1932                          return (fcsm_xlat_topology[count].xlat_top_str);
1932 1933                  }
1933 1934          }
1934 1935  
1935 1936          return (NULL);
1936 1937  }
1937 1938  
1938 1939  
1939 1940  /*
1940 1941   * Convert port topology state to descriptive string
1941 1942   */
1942 1943  static caddr_t
1943 1944  fcsm_dev_type_to_str(uint32_t type)
1944 1945  {
1945 1946          int count;
1946 1947  
1947 1948          for (count = 0; count < sizeof (fcsm_xlat_dev_type) /
1948 1949              sizeof (fcsm_xlat_dev_type[0]); count++) {
1949 1950                  if (fcsm_xlat_dev_type[count].xlat_type == type) {
1950 1951                          return (fcsm_xlat_dev_type[count].xlat_str);
1951 1952                  }
1952 1953          }
1953 1954  
1954 1955          return (NULL);
1955 1956  }
1956 1957  
1957 1958  static int
1958 1959  fcsm_cmd_cache_constructor(void *buf, void *cdarg, int kmflags)
1959 1960  {
1960 1961          fcsm_cmd_t              *cmd = (fcsm_cmd_t *)buf;
1961 1962          fcsm_t                  *fcsm = (fcsm_t *)cdarg;
1962 1963          int                     (*callback)(caddr_t);
1963 1964          fc_packet_t             *pkt;
1964 1965          fc_ulp_port_info_t      *pinfo;
1965 1966  
1966 1967          ASSERT(fcsm != NULL && buf != NULL);
1967 1968          callback = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP: DDI_DMA_DONTWAIT;
1968 1969  
1969 1970          cmd->cmd_fp_pkt         = &cmd->cmd_fc_packet;
1970 1971          cmd->cmd_job            = NULL;
1971 1972          cmd->cmd_fcsm           = fcsm;
1972 1973          cmd->cmd_dma_flags      = 0;
1973 1974  
1974 1975          pkt = &cmd->cmd_fc_packet;
1975 1976  
1976 1977          pkt->pkt_ulp_rscn_infop = NULL;
1977 1978          pkt->pkt_fca_private = (opaque_t)((caddr_t)cmd + sizeof (fcsm_cmd_t));
1978 1979          pkt->pkt_ulp_private = (opaque_t)cmd;
1979 1980  
1980 1981          if (!(fcsm->sm_flags & FCSM_USING_NODMA_FCA)) {
1981 1982                  pinfo = &fcsm->sm_port_info;
1982 1983                  if (ddi_dma_alloc_handle(pinfo->port_dip,
1983 1984                      pinfo->port_cmd_dma_attr,
1984 1985                      callback, NULL, &pkt->pkt_cmd_dma) != DDI_SUCCESS) {
1985 1986                          return (1);
1986 1987                  }
1987 1988  
1988 1989                  if (ddi_dma_alloc_handle(pinfo->port_dip,
1989 1990                      pinfo->port_resp_dma_attr,
1990 1991                      callback, NULL, &pkt->pkt_resp_dma) != DDI_SUCCESS) {
1991 1992                          ddi_dma_free_handle(&pkt->pkt_cmd_dma);
1992 1993                          return (1);
1993 1994                  }
1994 1995          } else {
1995 1996                  pkt->pkt_cmd_dma  = NULL;
1996 1997                  pkt->pkt_cmd      = NULL;
1997 1998                  pkt->pkt_resp_dma = NULL;
1998 1999                  pkt->pkt_resp     = NULL;
1999 2000          }
2000 2001  
2001 2002          pkt->pkt_cmd_acc = pkt->pkt_resp_acc = NULL;
2002 2003          pkt->pkt_cmd_cookie_cnt = pkt->pkt_resp_cookie_cnt =
2003 2004              pkt->pkt_data_cookie_cnt = 0;
2004 2005          pkt->pkt_cmd_cookie = pkt->pkt_resp_cookie =
2005 2006              pkt->pkt_data_cookie = NULL;
2006 2007  
2007 2008          return (0);
2008 2009  }
2009 2010  
2010 2011  
2011 2012  /* ARGSUSED */
2012 2013  static void
2013 2014  fcsm_cmd_cache_destructor(void *buf, void *cdarg)
2014 2015  {
2015 2016          fcsm_cmd_t      *cmd = (fcsm_cmd_t *)buf;
2016 2017          fcsm_t          *fcsm = (fcsm_t *)cdarg;
2017 2018          fc_packet_t     *pkt;
2018 2019  
2019 2020          ASSERT(fcsm == cmd->cmd_fcsm);
2020 2021  
2021 2022          pkt = cmd->cmd_fp_pkt;
2022 2023  
2023 2024          if (pkt->pkt_cmd_dma != NULL) {
2024 2025                  ddi_dma_free_handle(&pkt->pkt_cmd_dma);
2025 2026          }
2026 2027  
2027 2028          if (pkt->pkt_resp_dma != NULL) {
2028 2029                  ddi_dma_free_handle(&pkt->pkt_resp_dma);
2029 2030          }
2030 2031  }
2031 2032  
2032 2033  
2033 2034  static fcsm_cmd_t *
2034 2035  fcsm_alloc_cmd(fcsm_t *fcsm, uint32_t cmd_len, uint32_t resp_len, int sleep)
2035 2036  {
2036 2037          fcsm_cmd_t      *cmd;
2037 2038          fc_packet_t     *pkt;
2038 2039          int             rval;
2039 2040          ulong_t         real_len;
2040 2041          int             (*callback)(caddr_t);
2041 2042          ddi_dma_cookie_t        pkt_cookie;
2042 2043          ddi_dma_cookie_t        *cp;
2043 2044          uint32_t                cnt;
2044 2045          fc_ulp_port_info_t      *pinfo;
2045 2046  
2046 2047          ASSERT(fcsm != NULL);
2047 2048          pinfo = &fcsm->sm_port_info;
2048 2049  
2049 2050          callback = (sleep == KM_SLEEP) ? DDI_DMA_SLEEP: DDI_DMA_DONTWAIT;
2050 2051  
2051 2052          cmd = (fcsm_cmd_t *)kmem_cache_alloc(fcsm->sm_cmd_cache, sleep);
2052 2053          if (cmd == NULL) {
2053 2054                  FCSM_DEBUG(SMDL_ERR, (CE_WARN, SM_LOG, fcsm, NULL,
2054 2055                      "alloc_cmd: kmem_cache_alloc failed"));
2055 2056                  return (NULL);
2056 2057          }
2057 2058  
2058 2059          cmd->cmd_retry_count    = 0;
2059 2060          cmd->cmd_max_retries    = 0;
2060 2061          cmd->cmd_retry_interval = 0;
2061 2062          cmd->cmd_transport      = NULL;
2062 2063  
2063 2064          ASSERT(cmd->cmd_dma_flags == 0);
2064 2065          ASSERT(cmd->cmd_fp_pkt == &cmd->cmd_fc_packet);
2065 2066          pkt = cmd->cmd_fp_pkt;
2066 2067  
2067 2068          /* Zero out the important fc_packet fields */
2068 2069          pkt->pkt_pd             = NULL;
2069 2070          pkt->pkt_datalen        = 0;
2070 2071          pkt->pkt_data           = NULL;
2071 2072          pkt->pkt_state          = 0;
2072 2073          pkt->pkt_action         = 0;
2073 2074          pkt->pkt_reason         = 0;
2074 2075          pkt->pkt_expln          = 0;
2075 2076  
2076 2077          /*
2077 2078           * Now that pkt_pd is initialized, we can call fc_ulp_init_packet
2078 2079           */
2079 2080  
2080 2081          if (fc_ulp_init_packet((opaque_t)pinfo->port_handle, pkt, sleep)
2081 2082              != FC_SUCCESS) {
2082 2083                  kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2083 2084                  return (NULL);
2084 2085          }
2085 2086  
2086 2087          if ((cmd_len) && !(fcsm->sm_flags & FCSM_USING_NODMA_FCA)) {
2087 2088                  ASSERT(pkt->pkt_cmd_dma != NULL);
2088 2089  
2089 2090                  rval = ddi_dma_mem_alloc(pkt->pkt_cmd_dma, cmd_len,
2090 2091                      fcsm->sm_port_info.port_acc_attr, DDI_DMA_CONSISTENT,
2091 2092                      callback, NULL, (caddr_t *)&pkt->pkt_cmd, &real_len,
2092 2093                      &pkt->pkt_cmd_acc);
2093 2094  
2094 2095                  if (rval != DDI_SUCCESS) {
2095 2096                          (void) fc_ulp_uninit_packet(
2096 2097                              (opaque_t)pinfo->port_handle, pkt);
2097 2098                          kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2098 2099                          fcsm_free_cmd_dma(cmd);
2099 2100                          return (NULL);
2100 2101                  }
2101 2102  
2102 2103                  cmd->cmd_dma_flags |= FCSM_CF_CMD_VALID_DMA_MEM;
2103 2104  
2104 2105                  if (real_len < cmd_len) {
2105 2106                          (void) fc_ulp_uninit_packet(
2106 2107                              (opaque_t)pinfo->port_handle, pkt);
2107 2108                          kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2108 2109                          fcsm_free_cmd_dma(cmd);
2109 2110                          return (NULL);
2110 2111                  }
2111 2112  
2112 2113                  rval = ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL,
2113 2114                      pkt->pkt_cmd, real_len, DDI_DMA_WRITE | DDI_DMA_CONSISTENT,
2114 2115                      callback, NULL, &pkt_cookie, &pkt->pkt_cmd_cookie_cnt);
2115 2116  
2116 2117                  if (rval != DDI_DMA_MAPPED) {
2117 2118                          (void) fc_ulp_uninit_packet(
2118 2119                              (opaque_t)pinfo->port_handle, pkt);
2119 2120                          kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2120 2121                          fcsm_free_cmd_dma(cmd);
2121 2122                          return (NULL);
2122 2123                  }
2123 2124  
2124 2125                  cmd->cmd_dma_flags |= FCSM_CF_CMD_VALID_DMA_BIND;
2125 2126  
2126 2127                  if (pkt->pkt_cmd_cookie_cnt >
2127 2128                      pinfo->port_cmd_dma_attr->dma_attr_sgllen) {
2128 2129                          (void) fc_ulp_uninit_packet(
2129 2130                              (opaque_t)pinfo->port_handle, pkt);
2130 2131                          kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2131 2132                          fcsm_free_cmd_dma(cmd);
2132 2133                          return (NULL);
2133 2134                  }
2134 2135  
2135 2136                  ASSERT(pkt->pkt_cmd_cookie_cnt != 0);
2136 2137  
2137 2138                  cp = pkt->pkt_cmd_cookie = (ddi_dma_cookie_t *)kmem_alloc(
2138 2139                      pkt->pkt_cmd_cookie_cnt * sizeof (pkt_cookie),
2139 2140                      KM_NOSLEEP);
2140 2141  
2141 2142                  if (cp == NULL) {
2142 2143                          (void) fc_ulp_uninit_packet(
2143 2144                              (opaque_t)pinfo->port_handle, pkt);
2144 2145                          kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2145 2146                          fcsm_free_cmd_dma(cmd);
2146 2147                          return (NULL);
2147 2148                  }
2148 2149  
2149 2150                  *cp = pkt_cookie;
2150 2151                  cp++;
2151 2152                  for (cnt = 1; cnt < pkt->pkt_cmd_cookie_cnt; cnt++, cp++) {
2152 2153                          ddi_dma_nextcookie(pkt->pkt_cmd_dma, &pkt_cookie);
2153 2154                          *cp = pkt_cookie;
2154 2155                  }
2155 2156          } else if (cmd_len != 0) {
2156 2157                  pkt->pkt_cmd = kmem_zalloc(cmd_len, KM_SLEEP);
2157 2158          }
2158 2159  
2159 2160          if ((resp_len) && !(fcsm->sm_flags & FCSM_USING_NODMA_FCA)) {
2160 2161                  ASSERT(pkt->pkt_resp_dma != NULL);
2161 2162  
2162 2163                  rval = ddi_dma_mem_alloc(pkt->pkt_resp_dma, resp_len,
2163 2164                      fcsm->sm_port_info.port_acc_attr, DDI_DMA_CONSISTENT,
2164 2165                      callback, NULL, (caddr_t *)&pkt->pkt_resp, &real_len,
2165 2166                      &pkt->pkt_resp_acc);
2166 2167  
2167 2168                  if (rval != DDI_SUCCESS) {
2168 2169                          (void) fc_ulp_uninit_packet(
2169 2170                              (opaque_t)pinfo->port_handle, pkt);
2170 2171                          kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2171 2172                          fcsm_free_cmd_dma(cmd);
2172 2173                          return (NULL);
2173 2174                  }
2174 2175  
2175 2176                  cmd->cmd_dma_flags |= FCSM_CF_RESP_VALID_DMA_MEM;
2176 2177  
2177 2178                  if (real_len < resp_len) {
2178 2179                          (void) fc_ulp_uninit_packet(
2179 2180                              (opaque_t)pinfo->port_handle, pkt);
2180 2181                          kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2181 2182                          fcsm_free_cmd_dma(cmd);
2182 2183                          return (NULL);
2183 2184                  }
2184 2185  
2185 2186                  rval = ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL,
2186 2187                      pkt->pkt_resp, real_len, DDI_DMA_READ | DDI_DMA_CONSISTENT,
2187 2188                      callback, NULL, &pkt_cookie, &pkt->pkt_resp_cookie_cnt);
2188 2189  
2189 2190                  if (rval != DDI_DMA_MAPPED) {
2190 2191                          (void) fc_ulp_uninit_packet(
2191 2192                              (opaque_t)pinfo->port_handle, pkt);
2192 2193                          kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2193 2194                          fcsm_free_cmd_dma(cmd);
2194 2195                          return (NULL);
2195 2196                  }
2196 2197  
2197 2198                  cmd->cmd_dma_flags |= FCSM_CF_RESP_VALID_DMA_BIND;
2198 2199  
2199 2200                  if (pkt->pkt_resp_cookie_cnt >
2200 2201                      pinfo->port_resp_dma_attr->dma_attr_sgllen) {
2201 2202                          (void) fc_ulp_uninit_packet(
2202 2203                              (opaque_t)pinfo->port_handle, pkt);
2203 2204                          kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2204 2205                          fcsm_free_cmd_dma(cmd);
2205 2206                          return (NULL);
2206 2207                  }
2207 2208  
2208 2209                  ASSERT(pkt->pkt_resp_cookie_cnt != 0);
2209 2210  
2210 2211                  cp = pkt->pkt_resp_cookie = (ddi_dma_cookie_t *)kmem_alloc(
2211 2212                      pkt->pkt_resp_cookie_cnt * sizeof (pkt_cookie),
2212 2213                      KM_NOSLEEP);
2213 2214  
2214 2215                  if (cp == NULL) {
2215 2216                          (void) fc_ulp_uninit_packet(
2216 2217                              (opaque_t)pinfo->port_handle, pkt);
2217 2218                          kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2218 2219                          fcsm_free_cmd_dma(cmd);
2219 2220                          return (NULL);
2220 2221                  }
2221 2222  
2222 2223                  *cp = pkt_cookie;
2223 2224                  cp++;
2224 2225                  for (cnt = 1; cnt < pkt->pkt_resp_cookie_cnt; cnt++, cp++) {
2225 2226                          ddi_dma_nextcookie(pkt->pkt_resp_dma, &pkt_cookie);
2226 2227                          *cp = pkt_cookie;
2227 2228                  }
2228 2229          } else if (resp_len != 0) {
2229 2230                  pkt->pkt_resp = kmem_zalloc(resp_len, KM_SLEEP);
2230 2231          }
2231 2232  
2232 2233          pkt->pkt_cmdlen = cmd_len;
2233 2234          pkt->pkt_rsplen = resp_len;
2234 2235  
2235 2236          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
2236 2237              "alloc_cmd: cmd 0x%p", (void *)cmd));
2237 2238          return (cmd);
2238 2239  }
2239 2240  
2240 2241  static void
2241 2242  fcsm_free_cmd(fcsm_cmd_t *cmd)
2242 2243  {
2243 2244          fcsm_t          *fcsm;
2244 2245  
2245 2246          fcsm = cmd->cmd_fcsm;
2246 2247          ASSERT(fcsm != NULL);
2247 2248  
2248 2249          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
2249 2250              "free_cmd: cmd 0x%p", (void *)cmd));
2250 2251  
2251 2252          fcsm_free_cmd_dma(cmd);
2252 2253  
2253 2254          (void) fc_ulp_uninit_packet((opaque_t)fcsm->sm_port_info.port_handle,
2254 2255              cmd->cmd_fp_pkt);
2255 2256          kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd);
2256 2257  }
2257 2258  
2258 2259  static void
2259 2260  fcsm_free_cmd_dma(fcsm_cmd_t *cmd)
2260 2261  {
2261 2262          fc_packet_t     *pkt;
2262 2263  
2263 2264          pkt = cmd->cmd_fp_pkt;
2264 2265          ASSERT(pkt != NULL);
2265 2266  
2266 2267          if (cmd->cmd_fcsm->sm_flags & FCSM_USING_NODMA_FCA) {
2267 2268                  if (pkt->pkt_cmd) {
2268 2269                          kmem_free(pkt->pkt_cmd, pkt->pkt_cmdlen);
2269 2270                          pkt->pkt_cmd = NULL;
2270 2271                  }
2271 2272  
2272 2273                  if (pkt->pkt_resp) {
2273 2274                          kmem_free(pkt->pkt_resp, pkt->pkt_rsplen);
2274 2275                          pkt->pkt_resp = NULL;
2275 2276                  }
2276 2277          }
2277 2278  
2278 2279          pkt->pkt_cmdlen = 0;
2279 2280          pkt->pkt_rsplen = 0;
2280 2281          pkt->pkt_tran_type = 0;
2281 2282          pkt->pkt_tran_flags = 0;
2282 2283  
2283 2284          if (pkt->pkt_cmd_cookie != NULL) {
2284 2285                  kmem_free(pkt->pkt_cmd_cookie, pkt->pkt_cmd_cookie_cnt *
2285 2286                      sizeof (ddi_dma_cookie_t));
2286 2287                  pkt->pkt_cmd_cookie = NULL;
2287 2288          }
2288 2289  
2289 2290          if (pkt->pkt_resp_cookie != NULL) {
2290 2291                  kmem_free(pkt->pkt_resp_cookie, pkt->pkt_resp_cookie_cnt *
2291 2292                      sizeof (ddi_dma_cookie_t));
2292 2293                  pkt->pkt_resp_cookie = NULL;
2293 2294          }
2294 2295  
2295 2296          if (cmd->cmd_dma_flags & FCSM_CF_CMD_VALID_DMA_BIND) {
2296 2297                  (void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma);
2297 2298          }
2298 2299  
2299 2300          if (cmd->cmd_dma_flags & FCSM_CF_CMD_VALID_DMA_MEM) {
2300 2301                  if (pkt->pkt_cmd_acc) {
2301 2302                          ddi_dma_mem_free(&pkt->pkt_cmd_acc);
2302 2303                  }
2303 2304          }
2304 2305  
2305 2306          if (cmd->cmd_dma_flags & FCSM_CF_RESP_VALID_DMA_BIND) {
2306 2307                  (void) ddi_dma_unbind_handle(pkt->pkt_resp_dma);
2307 2308          }
2308 2309  
2309 2310          if (cmd->cmd_dma_flags & FCSM_CF_RESP_VALID_DMA_MEM) {
2310 2311                  if (pkt->pkt_resp_acc) {
2311 2312                          ddi_dma_mem_free(&pkt->pkt_resp_acc);
2312 2313                  }
2313 2314          }
2314 2315  
2315 2316          cmd->cmd_dma_flags = 0;
2316 2317  }
2317 2318  
2318 2319  /* ARGSUSED */
2319 2320  static int
2320 2321  fcsm_job_cache_constructor(void *buf, void *cdarg, int kmflag)
2321 2322  {
2322 2323          fcsm_job_t *job = (fcsm_job_t *)buf;
2323 2324  
2324 2325          mutex_init(&job->job_mutex, NULL, MUTEX_DRIVER, NULL);
2325 2326          sema_init(&job->job_sema, 0, NULL, SEMA_DEFAULT, NULL);
2326 2327  
2327 2328          return (0);
2328 2329  }
2329 2330  
2330 2331  /* ARGSUSED */
2331 2332  static void
2332 2333  fcsm_job_cache_destructor(void *buf, void *cdarg)
2333 2334  {
2334 2335          fcsm_job_t *job = (fcsm_job_t *)buf;
2335 2336  
2336 2337          sema_destroy(&job->job_sema);
2337 2338          mutex_destroy(&job->job_mutex);
2338 2339  }
2339 2340  
2340 2341  
2341 2342  static fcsm_job_t *
2342 2343  fcsm_alloc_job(int sleep)
2343 2344  {
2344 2345          fcsm_job_t      *job;
2345 2346  
2346 2347          job = (fcsm_job_t *)kmem_cache_alloc(fcsm_job_cache, sleep);
2347 2348          if (job != NULL) {
2348 2349                  job->job_code           = FCSM_JOB_NONE;
2349 2350                  job->job_flags          = 0;
2350 2351                  job->job_port_instance  = -1;
2351 2352                  job->job_result         = -1;
2352 2353                  job->job_arg            = (opaque_t)0;
2353 2354                  job->job_caller_priv    = (opaque_t)0;
2354 2355                  job->job_comp           = NULL;
2355 2356                  job->job_comp_arg       = (opaque_t)0;
2356 2357                  job->job_priv           = (void *)0;
2357 2358                  job->job_priv_flags     = 0;
2358 2359                  job->job_next           = 0;
2359 2360          }
2360 2361  
2361 2362          return (job);
2362 2363  }
2363 2364  
2364 2365  static void
2365 2366  fcsm_dealloc_job(fcsm_job_t *job)
2366 2367  {
2367 2368          kmem_cache_free(fcsm_job_cache, (void *)job);
2368 2369  }
2369 2370  
2370 2371  
2371 2372  static void
2372 2373  fcsm_init_job(fcsm_job_t *job, int instance, uint32_t command, uint32_t flags,
2373 2374      opaque_t arg, opaque_t caller_priv,
2374 2375      void (*comp)(opaque_t, fcsm_job_t *, int), opaque_t comp_arg)
2375 2376  {
2376 2377          ASSERT(job != NULL);
2377 2378          job->job_port_instance  = instance;
2378 2379          job->job_code           = command;
2379 2380          job->job_flags          = flags;
2380 2381          job->job_arg            = arg;
2381 2382          job->job_caller_priv    = caller_priv;
2382 2383          job->job_comp           = comp;
2383 2384          job->job_comp_arg       = comp_arg;
2384 2385          job->job_retry_count    = 0;
2385 2386  }
2386 2387  
2387 2388  static int
2388 2389  fcsm_process_job(fcsm_job_t *job, int priority_flag)
2389 2390  {
2390 2391          fcsm_t  *fcsm;
2391 2392          int     sync;
2392 2393  
2393 2394          ASSERT(job != NULL);
2394 2395          ASSERT(!MUTEX_HELD(&job->job_mutex));
2395 2396  
2396 2397          fcsm = ddi_get_soft_state(fcsm_state, job->job_port_instance);
2397 2398  
2398 2399          if (fcsm == NULL) {
2399 2400                  FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, NULL, NULL,
2400 2401                      "process_job: port instance 0x%x not found",
2401 2402                      job->job_port_instance));
2402 2403                  return (FC_BADDEV);
2403 2404          }
2404 2405  
2405 2406          mutex_enter(&job->job_mutex);
2406 2407          /* Both SYNC and ASYNC flags should not be set */
2407 2408          ASSERT(((job->job_flags & (FCSM_JOBFLAG_SYNC | FCSM_JOBFLAG_ASYNC)) ==
2408 2409              FCSM_JOBFLAG_SYNC) || ((job->job_flags &
2409 2410              (FCSM_JOBFLAG_SYNC | FCSM_JOBFLAG_ASYNC)) == FCSM_JOBFLAG_ASYNC));
2410 2411          /*
2411 2412           * Check if job is a synchronous job. We might not be able to
2412 2413           * check it reliably after enque_job(), if job is an ASYNC job.
2413 2414           */
2414 2415          sync = job->job_flags & FCSM_JOBFLAG_SYNC;
2415 2416          mutex_exit(&job->job_mutex);
2416 2417  
2417 2418          /* Queue the job for processing by job thread */
2418 2419          fcsm_enque_job(fcsm, job, priority_flag);
2419 2420  
2420 2421          /* Wait for job completion, if it is a synchronous job */
2421 2422          if (sync) {
2422 2423                  /*
2423 2424                   * This is a Synchronous Job. So job structure is available.
2424 2425                   * Caller is responsible for freeing it.
2425 2426                   */
2426 2427                  FCSM_DEBUG(SMDL_ERR, (CE_CONT, SM_LOG, fcsm, NULL,
2427 2428                      "process_job: Waiting for sync job <%p> completion",
2428 2429                      (void *)job));
2429 2430                  sema_p(&job->job_sema);
2430 2431          }
2431 2432  
2432 2433          return (FC_SUCCESS);
2433 2434  }
2434 2435  
2435 2436  static void
2436 2437  fcsm_enque_job(fcsm_t *fcsm, fcsm_job_t *job, int priority_flag)
2437 2438  {
2438 2439          ASSERT(!MUTEX_HELD(&fcsm->sm_mutex));
2439 2440  
2440 2441          mutex_enter(&fcsm->sm_mutex);
2441 2442          /* Queue the job at the head or tail depending on the job priority */
2442 2443          if (priority_flag) {
2443 2444                  FCSM_DEBUG(SMDL_INFO, (CE_CONT, SM_LOG, fcsm, NULL,
2444 2445                      "enque_job: job 0x%p is high priority", job));
2445 2446                  /* Queue at the head */
2446 2447                  if (fcsm->sm_job_tail == NULL) {
2447 2448                          ASSERT(fcsm->sm_job_head == NULL);
2448 2449                          fcsm->sm_job_head = fcsm->sm_job_tail = job;
2449 2450                  } else {
2450 2451                          ASSERT(fcsm->sm_job_head != NULL);
2451 2452                          job->job_next = fcsm->sm_job_head;
2452 2453                          fcsm->sm_job_head = job;
2453 2454                  }
2454 2455          } else {
2455 2456                  FCSM_DEBUG(SMDL_INFO, (CE_CONT, SM_LOG, fcsm, NULL,
2456 2457                      "enque_job: job 0x%p is normal", job));
2457 2458                  /* Queue at the tail */
2458 2459                  if (fcsm->sm_job_tail == NULL) {
2459 2460                          ASSERT(fcsm->sm_job_head == NULL);
2460 2461                          fcsm->sm_job_head = fcsm->sm_job_tail = job;
2461 2462                  } else {
2462 2463                          ASSERT(fcsm->sm_job_head != NULL);
2463 2464                          fcsm->sm_job_tail->job_next = job;
2464 2465                          fcsm->sm_job_tail = job;
2465 2466                  }
2466 2467                  job->job_next = NULL;
2467 2468          }
2468 2469  
2469 2470          /* Signal the job thread to process the job */
2470 2471          cv_signal(&fcsm->sm_job_cv);
2471 2472          mutex_exit(&fcsm->sm_mutex);
2472 2473  }
2473 2474  
2474 2475  static int
2475 2476  fcsm_retry_job(fcsm_t *fcsm, fcsm_job_t *job)
2476 2477  {
2477 2478          /*
2478 2479           * If it is a CT passthru job and status is login required, then
2479 2480           * retry the job so that login can be performed again.
2480 2481           * Ensure that this retry is performed a finite number of times,
2481 2482           * so that a faulty fabric does not cause us to retry forever.
2482 2483           */
2483 2484  
2484 2485          switch (job->job_code) {
2485 2486          case FCSM_JOB_CT_PASSTHRU: {
2486 2487                  uint32_t        jobflag;
2487 2488                  fc_ct_header_t  *ct_header;
2488 2489  
2489 2490                  if (job->job_result != FC_LOGINREQ) {
2490 2491                          break;
2491 2492                  }
2492 2493  
2493 2494                  /*
2494 2495                   * If it is a management server command
2495 2496                   * then Reset the Management server login flag, so that login
2496 2497                   * gets re-established.
2497 2498                   * If it is a Name server command,
2498 2499                   * then it is 'fp' responsibility to perform the login.
2499 2500                   */
2500 2501                  ASSERT(job->job_arg != NULL);
2501 2502                  ct_header =
2502 2503                      (fc_ct_header_t *)((fcio_t *)job->job_arg)->fcio_ibuf;
2503 2504                  if (ct_header->ct_fcstype == FCSTYPE_MGMTSERVICE) {
2504 2505                          mutex_enter(&fcsm->sm_mutex);
2505 2506                          fcsm->sm_flags &= ~FCSM_MGMT_SERVER_LOGGED_IN;
2506 2507                          mutex_exit(&fcsm->sm_mutex);
2507 2508                  }
2508 2509  
2509 2510                  if (job->job_retry_count >= fcsm_max_job_retries) {
2510 2511                          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
2511 2512                              "retry_job: job 0x%p max retries (%d) reached",
2512 2513                              (void *)job, job->job_retry_count));
2513 2514                          break;
2514 2515                  }
2515 2516  
2516 2517                  /*
2517 2518                   * Login is required again. Retry the command, so that
2518 2519                   * login will get performed again.
2519 2520                   */
2520 2521                  mutex_enter(&job->job_mutex);
2521 2522                  job->job_retry_count++;
2522 2523                  jobflag = job->job_flags;
2523 2524                  mutex_exit(&job->job_mutex);
2524 2525  
2525 2526                  FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
2526 2527                      "retry_job: retry(%d) job 0x%p",
2527 2528                      job->job_retry_count, (void *)job));
2528 2529                  /*
2529 2530                   * This job should get picked up before the
2530 2531                   * other jobs sitting in the queue.
2531 2532                   * Requeue the command at the head and then
2532 2533                   * reset the SERIALIZE flag.
2533 2534                   */
2534 2535                  fcsm_enque_job(fcsm, job, 1);
2535 2536                  if (jobflag & FCSM_JOBFLAG_SERIALIZE) {
2536 2537                          mutex_enter(&fcsm->sm_mutex);
2537 2538                          ASSERT(fcsm->sm_flags & FCSM_SERIALIZE_JOBTHREAD);
2538 2539                          fcsm->sm_flags &= ~FCSM_SERIALIZE_JOBTHREAD;
2539 2540  
2540 2541                          /* Signal the job thread to process the job */
2541 2542                          cv_signal(&fcsm->sm_job_cv);
2542 2543                          mutex_exit(&fcsm->sm_mutex);
2543 2544                  }
2544 2545  
2545 2546                  /* Command is queued for retrying */
2546 2547                  return (0);
2547 2548          }
2548 2549  
2549 2550          default:
2550 2551                  break;
2551 2552          }
2552 2553          return (1);
2553 2554  }
2554 2555  
2555 2556  static void
2556 2557  fcsm_jobdone(fcsm_job_t *job)
2557 2558  {
2558 2559          fcsm_t  *fcsm;
2559 2560  
2560 2561          fcsm = ddi_get_soft_state(fcsm_state, job->job_port_instance);
2561 2562          ASSERT(fcsm != NULL);
2562 2563  
2563 2564          if (job->job_result != FC_SUCCESS) {
2564 2565                  if (fcsm_retry_job(fcsm, job) == 0) {
2565 2566                          /* Job retried. so just return from here */
2566 2567                          return;
2567 2568                  }
2568 2569          }
2569 2570  
2570 2571          if (job->job_comp) {
2571 2572                  job->job_comp(job->job_comp_arg, job, job->job_result);
2572 2573          }
2573 2574  
2574 2575          mutex_enter(&job->job_mutex);
2575 2576          if (job->job_flags & FCSM_JOBFLAG_SERIALIZE) {
2576 2577                  mutex_exit(&job->job_mutex);
2577 2578                  mutex_enter(&fcsm->sm_mutex);
2578 2579                  ASSERT(fcsm->sm_flags & FCSM_SERIALIZE_JOBTHREAD);
2579 2580                  fcsm->sm_flags &= ~FCSM_SERIALIZE_JOBTHREAD;
2580 2581  
2581 2582                  /* Signal the job thread to process the job */
2582 2583                  cv_signal(&fcsm->sm_job_cv);
2583 2584                  mutex_exit(&fcsm->sm_mutex);
2584 2585                  mutex_enter(&job->job_mutex);
2585 2586          }
2586 2587  
2587 2588          if (job->job_flags & FCSM_JOBFLAG_SYNC) {
2588 2589                  mutex_exit(&job->job_mutex);
2589 2590                  sema_v(&job->job_sema);
2590 2591          } else {
2591 2592                  mutex_exit(&job->job_mutex);
2592 2593                  /* Async job, free the job structure */
2593 2594                  fcsm_dealloc_job(job);
2594 2595          }
2595 2596  }
2596 2597  
2597 2598  fcsm_job_t *
2598 2599  fcsm_deque_job(fcsm_t *fcsm)
2599 2600  {
2600 2601          fcsm_job_t      *job;
2601 2602  
2602 2603          ASSERT(MUTEX_HELD(&fcsm->sm_mutex));
2603 2604  
2604 2605          if (fcsm->sm_job_head == NULL) {
2605 2606                  ASSERT(fcsm->sm_job_tail == NULL);
2606 2607                  job = NULL;
2607 2608          } else {
2608 2609                  ASSERT(fcsm->sm_job_tail != NULL);
2609 2610                  job = fcsm->sm_job_head;
2610 2611                  if (job->job_next == NULL) {
2611 2612                          ASSERT(fcsm->sm_job_tail == job);
2612 2613                          fcsm->sm_job_tail = NULL;
2613 2614                  }
2614 2615                  fcsm->sm_job_head = job->job_next;
2615 2616                  job->job_next = NULL;
2616 2617          }
2617 2618  
2618 2619          return (job);
2619 2620  }
2620 2621  
2621 2622  
2622 2623  /* Dedicated per port thread to process various commands */
2623 2624  static void
2624 2625  fcsm_job_thread(fcsm_t *fcsm)
2625 2626  {
2626 2627          fcsm_job_t      *job;
2627 2628  
2628 2629          ASSERT(fcsm != NULL);
2629 2630  #ifndef __lock_lint
2630 2631          CALLB_CPR_INIT(&fcsm->sm_cpr_info, &fcsm->sm_mutex,
2631 2632              callb_generic_cpr, "fcsm_job_thread");
2632 2633  #endif /* __lock_lint */
2633 2634  
2634 2635          for (;;) {
2635 2636                  mutex_enter(&fcsm->sm_mutex);
2636 2637  
2637 2638                  while (fcsm->sm_job_head == NULL ||
2638 2639                      fcsm->sm_flags & FCSM_SERIALIZE_JOBTHREAD) {
2639 2640                          CALLB_CPR_SAFE_BEGIN(&fcsm->sm_cpr_info);
2640 2641                          cv_wait(&fcsm->sm_job_cv, &fcsm->sm_mutex);
2641 2642                          CALLB_CPR_SAFE_END(&fcsm->sm_cpr_info, &fcsm->sm_mutex);
2642 2643                  }
2643 2644  
2644 2645                  job = fcsm_deque_job(fcsm);
2645 2646  
2646 2647                  mutex_exit(&fcsm->sm_mutex);
2647 2648  
2648 2649                  mutex_enter(&job->job_mutex);
2649 2650                  if (job->job_flags & FCSM_JOBFLAG_SERIALIZE) {
2650 2651                          mutex_exit(&job->job_mutex);
2651 2652  
2652 2653                          mutex_enter(&fcsm->sm_mutex);
2653 2654                          ASSERT(!(fcsm->sm_flags & FCSM_SERIALIZE_JOBTHREAD));
2654 2655                          fcsm->sm_flags |= FCSM_SERIALIZE_JOBTHREAD;
2655 2656                          mutex_exit(&fcsm->sm_mutex);
2656 2657                  } else {
2657 2658                          mutex_exit(&job->job_mutex);
2658 2659                  }
2659 2660  
2660 2661                  ASSERT(fcsm->sm_instance == job->job_port_instance);
2661 2662  
2662 2663                  switch (job->job_code) {
2663 2664                  case FCSM_JOB_NONE:
2664 2665                          fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
2665 2666                              "job_thread: uninitialized job code");
2666 2667                          job->job_result = FC_FAILURE;
2667 2668                          fcsm_jobdone(job);
2668 2669                          break;
2669 2670  
2670 2671                  case FCSM_JOB_THREAD_SHUTDOWN:
2671 2672                          FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
2672 2673                              "job_thread: job code <JOB PORT SHUTDOWN>"));
2673 2674  
2674 2675                          /*
2675 2676                           * There should not be any pending jobs, when this
2676 2677                           * is being called.
2677 2678                           */
2678 2679                          mutex_enter(&fcsm->sm_mutex);
2679 2680                          ASSERT(fcsm->sm_job_head == NULL);
2680 2681                          ASSERT(fcsm->sm_job_tail == NULL);
2681 2682                          ASSERT(fcsm->sm_retry_head == NULL);
2682 2683                          ASSERT(fcsm->sm_retry_tail == NULL);
2683 2684                          job->job_result = FC_SUCCESS;
2684 2685  #ifndef __lock_lint
2685 2686                          CALLB_CPR_EXIT(&fcsm->sm_cpr_info);
2686 2687  #endif
2687 2688                          /* CPR_EXIT has also dropped the fcsm->sm_mutex */
2688 2689  
2689 2690                          fcsm_jobdone(job);
2690 2691                          thread_exit();
2691 2692                          /* NOTREACHED */
2692 2693                          break;
2693 2694  
2694 2695                  case FCSM_JOB_LOGIN_NAME_SERVER:
2695 2696                          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
2696 2697                              "job_thread: job code <LOGIN_NAME_SERVER>"));
2697 2698                          job->job_result = FC_SUCCESS;
2698 2699                          fcsm_jobdone(job);
2699 2700                          break;
2700 2701  
2701 2702                  case FCSM_JOB_LOGIN_MGMT_SERVER:
2702 2703                          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
2703 2704                              "job_thread: job code <LOGIN_MGMT_SERVER>"));
2704 2705                          fcsm_job_login_mgmt_server(job);
2705 2706                          break;
2706 2707  
2707 2708                  case FCSM_JOB_CT_PASSTHRU:
2708 2709                          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
2709 2710                              "job_thread: job code <CT_PASSTHRU>"));
2710 2711                          fcsm_job_ct_passthru(job);
2711 2712                          break;
2712 2713  
2713 2714                  default:
2714 2715                          FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
2715 2716                              "job_thread: job code <UNKNOWN>"));
2716 2717                          job->job_result = FC_FAILURE;
2717 2718                          fcsm_jobdone(job);
2718 2719                          break;
2719 2720                  }
2720 2721          }
2721 2722  
2722 2723          /* NOTREACHED */
2723 2724  }
2724 2725  
2725 2726  
2726 2727  static void
2727 2728  fcsm_ct_init(fcsm_t *fcsm, fcsm_cmd_t *cmd, fc_ct_aiu_t *req_iu, size_t req_len,
2728 2729      void (*comp_func)())
2729 2730  {
2730 2731          fc_packet_t     *pkt;
2731 2732  
2732 2733          pkt = cmd->cmd_fp_pkt;
2733 2734          ASSERT(pkt != NULL);
2734 2735  
2735 2736          ASSERT(req_iu->aiu_header.ct_fcstype == FCSTYPE_MGMTSERVICE ||
2736 2737              (req_iu->aiu_header.ct_fcstype == FCSTYPE_DIRECTORY &&
2737 2738              req_iu->aiu_header.ct_fcssubtype == FCSSUB_DS_NAME_SERVER));
2738 2739  
2739 2740  
2740 2741          /* Set the pkt d_id properly */
2741 2742          if (req_iu->aiu_header.ct_fcstype == FCSTYPE_MGMTSERVICE) {
2742 2743                  pkt->pkt_cmd_fhdr.d_id  = FS_MANAGEMENT_SERVER;
2743 2744          } else {
2744 2745                  pkt->pkt_cmd_fhdr.d_id  = FS_NAME_SERVER;
2745 2746          }
2746 2747  
2747 2748          pkt->pkt_cmd_fhdr.r_ctl = R_CTL_UNSOL_CONTROL;
2748 2749          pkt->pkt_cmd_fhdr.rsvd  = 0;
2749 2750          pkt->pkt_cmd_fhdr.s_id  = fcsm->sm_sid;
2750 2751          pkt->pkt_cmd_fhdr.type  = FC_TYPE_FC_SERVICES;
2751 2752          pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE |
2752 2753              F_CTL_FIRST_SEQ | F_CTL_END_SEQ;
2753 2754          pkt->pkt_cmd_fhdr.seq_id = 0;
2754 2755          pkt->pkt_cmd_fhdr.df_ctl = 0;
2755 2756          pkt->pkt_cmd_fhdr.seq_cnt = 0;
2756 2757          pkt->pkt_cmd_fhdr.ox_id = 0xffff;
2757 2758          pkt->pkt_cmd_fhdr.rx_id = 0xffff;
2758 2759          pkt->pkt_cmd_fhdr.ro    = 0;
2759 2760  
2760 2761          pkt->pkt_timeout        = FCSM_MS_TIMEOUT;
2761 2762          pkt->pkt_comp           = comp_func;
2762 2763  
2763 2764          FCSM_REP_WR(pkt->pkt_cmd_acc, req_iu, pkt->pkt_cmd, req_len);
2764 2765  
2765 2766          cmd->cmd_transport = fc_ulp_transport;
2766 2767  }
2767 2768  
2768 2769  static void
2769 2770  fcsm_ct_intr(fcsm_cmd_t *cmd)
2770 2771  {
2771 2772          fc_packet_t     *pkt;
2772 2773          fcsm_job_t      *job;
2773 2774          fcio_t          *fcio;
2774 2775          fcsm_t          *fcsm;
2775 2776  
2776 2777          pkt = cmd->cmd_fp_pkt;
2777 2778          job = cmd->cmd_job;
2778 2779          ASSERT(job != NULL);
2779 2780  
2780 2781          fcio = job->job_arg;
2781 2782          ASSERT(fcio != NULL);
2782 2783  
2783 2784          if (pkt->pkt_state != FC_PKT_SUCCESS) {
2784 2785                  FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, cmd->cmd_fcsm, pkt,
2785 2786                      "ct_intr: CT command <0x%x> to did 0x%x failed",
2786 2787                      ((fc_ct_aiu_t *)fcio->fcio_ibuf)->aiu_header.ct_cmdrsp,
2787 2788                      pkt->pkt_cmd_fhdr.d_id));
2788 2789          } else {
2789 2790                  /* Get the CT response payload */
2790 2791                  fcsm = cmd->cmd_fcsm;
2791 2792                  FCSM_REP_RD(pkt->pkt_resp_acc, fcio->fcio_obuf,
2792 2793                      pkt->pkt_resp, fcio->fcio_olen);
2793 2794          }
2794 2795  
2795 2796          job->job_result =
2796 2797              fcsm_pkt_state_to_rval(pkt->pkt_state, pkt->pkt_reason);
2797 2798  
2798 2799          fcsm_free_cmd(cmd);
2799 2800  
2800 2801          fcsm_jobdone(job);
2801 2802  }
2802 2803  
2803 2804  
2804 2805  static void
2805 2806  fcsm_job_ct_passthru(fcsm_job_t *job)
2806 2807  {
2807 2808          fcsm_t          *fcsm;
2808 2809          fcio_t          *fcio;
2809 2810          fcsm_cmd_t      *cmd;
2810 2811          int             status;
2811 2812          fc_ct_header_t  *ct_header;
2812 2813  
2813 2814          ASSERT(job != NULL);
2814 2815          ASSERT(job->job_port_instance != -1);
2815 2816  
2816 2817          job->job_result = FC_FAILURE;
2817 2818          fcsm = ddi_get_soft_state(fcsm_state, job->job_port_instance);
2818 2819          if (fcsm == NULL) {
2819 2820                  fcsm_jobdone(job);
2820 2821                  return;
2821 2822          }
2822 2823  
2823 2824          /*
2824 2825           * Process the CT Passthru job only if port is attached
2825 2826           * to a FABRIC.
2826 2827           */
2827 2828          if (!FC_TOP_EXTERNAL(fcsm->sm_port_top)) {
2828 2829                  FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
2829 2830                      "job_ct_passthru: end (non-fabric port)"));
2830 2831                  job->job_result = FC_BADDEV;
2831 2832                  fcsm_jobdone(job);
2832 2833                  return;
2833 2834          }
2834 2835  
2835 2836          fcio = job->job_arg;
2836 2837          ASSERT(fcio != NULL);
2837 2838  
2838 2839          /*
2839 2840           * If it is NOT a Management Seriver (MS) or Name Server (NS) command
2840 2841           * then complete the command with failure.
2841 2842           */
2842 2843          ct_header = (fc_ct_header_t *)fcio->fcio_ibuf;
2843 2844  
2844 2845          /*
2845 2846           * According to libHBAAPI spec, CT header from libHBAAPI would always
2846 2847           * be big endian, so we must swap CT header before continue in little
2847 2848           * endian platforms.
2848 2849           */
2849 2850          mutex_enter(&job->job_mutex);
2850 2851          if (!(job->job_flags & FCSM_JOBFLAG_CTHEADER_BE)) {
2851 2852                  job->job_flags |= FCSM_JOBFLAG_CTHEADER_BE;
2852 2853                  *((uint32_t *)((uint32_t *)ct_header + 0)) =
2853 2854                      BE_32(*((uint32_t *)((uint32_t *)ct_header + 0)));
2854 2855                  *((uint32_t *)((uint32_t *)ct_header + 1)) =
2855 2856                      BE_32(*((uint32_t *)((uint32_t *)ct_header + 1)));
2856 2857                  *((uint32_t *)((uint32_t *)ct_header + 2)) =
2857 2858                      BE_32(*((uint32_t *)((uint32_t *)ct_header + 2)));
2858 2859                  *((uint32_t *)((uint32_t *)ct_header + 3)) =
2859 2860                      BE_32(*((uint32_t *)((uint32_t *)ct_header + 3)));
2860 2861          }
2861 2862          mutex_exit(&job->job_mutex);
2862 2863  
2863 2864          if (ct_header->ct_fcstype == FCSTYPE_MGMTSERVICE) {
2864 2865                  FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
2865 2866                      "job_ct_passthru: Management Server Cmd"));
2866 2867          } else if (ct_header->ct_fcstype == FCSTYPE_DIRECTORY) {
2867 2868                  FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
2868 2869                      "job_ct_passthru: Name Server Cmd"));
2869 2870          } else {
2870 2871                  FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
2871 2872                      "job_ct_passthru: Unsupported Destination "
2872 2873                      "gs_type <0x%x> gs_subtype <0x%x>",
2873 2874                      ct_header->ct_fcstype, ct_header->ct_fcssubtype));
2874 2875          }
2875 2876  
2876 2877          if (ct_header->ct_fcstype != FCSTYPE_MGMTSERVICE &&
2877 2878              (ct_header->ct_fcstype != FCSTYPE_DIRECTORY ||
2878 2879              ct_header->ct_fcssubtype != FCSSUB_DS_NAME_SERVER)) {
2879 2880                  FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
2880 2881                      "job_ct_passthru: end (Not a Name Server OR "
2881 2882                      "Mgmt Server Cmd)"));
2882 2883                  job->job_result = FC_BADCMD;
2883 2884                  fcsm_jobdone(job);
2884 2885                  return;
2885 2886          }
2886 2887  
2887 2888          /*
2888 2889           * If it is an MS command and we are not logged in to the management
2889 2890           * server, then start the login and requeue the command.
2890 2891           * If login to management server is in progress, then reque the
2891 2892           * command to wait for login to complete.
2892 2893           */
2893 2894          mutex_enter(&fcsm->sm_mutex);
2894 2895          if ((ct_header->ct_fcstype == FCSTYPE_MGMTSERVICE) &&
2895 2896              !(fcsm->sm_flags & FCSM_MGMT_SERVER_LOGGED_IN)) {
2896 2897                  mutex_exit(&fcsm->sm_mutex);
2897 2898                  if (fcsm_login_and_process_job(fcsm, job) != FC_SUCCESS) {
2898 2899                          FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
2899 2900                              "job_ct_passthru: perform login failed"));
2900 2901                          job->job_result = FC_FAILURE;
2901 2902                          fcsm_jobdone(job);
2902 2903                  }
2903 2904                  return;
2904 2905          }
2905 2906          mutex_exit(&fcsm->sm_mutex);
2906 2907  
2907 2908          /*
2908 2909           * We are already logged in to the management server.
2909 2910           * Issue the CT Passthru command
2910 2911           */
2911 2912          cmd = fcsm_alloc_cmd(fcsm, fcio->fcio_ilen, fcio->fcio_olen, KM_SLEEP);
2912 2913          if (cmd == NULL) {
2913 2914                  job->job_result = FC_NOMEM;
2914 2915                  fcsm_jobdone(job);
2915 2916                  return;
2916 2917          }
2917 2918  
2918 2919          FCSM_INIT_CMD(cmd, job, FC_TRAN_INTR | FC_TRAN_CLASS3, FC_PKT_EXCHANGE,
2919 2920              fcsm_max_cmd_retries, fcsm_ct_intr);
2920 2921  
2921 2922          fcsm_ct_init(fcsm, cmd, (fc_ct_aiu_t *)fcio->fcio_ibuf, fcio->fcio_ilen,
2922 2923              fcsm_pkt_common_intr);
2923 2924  
2924 2925          if ((status = fcsm_issue_cmd(cmd)) != FC_SUCCESS) {
2925 2926                  FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, cmd->cmd_fcsm, NULL,
2926 2927                      "job_ct_passthru: issue CT Passthru failed, status 0x%x",
2927 2928                      status));
2928 2929                  job->job_result = status;
2929 2930                  fcsm_free_cmd(cmd);
2930 2931                  fcsm_jobdone(job);
2931 2932                  return;
2932 2933          }
2933 2934  }
2934 2935  
2935 2936  static int
2936 2937  fcsm_login_and_process_job(fcsm_t *fcsm, fcsm_job_t *orig_job)
2937 2938  {
2938 2939          fcsm_job_t      *login_job;
2939 2940  #ifdef DEBUG
2940 2941          int             status;
2941 2942  #endif /* DEBUG */
2942 2943  
2943 2944          if (orig_job->job_code != FCSM_JOB_CT_PASSTHRU) {
2944 2945                  return (FC_FAILURE);
2945 2946          }
2946 2947  
2947 2948          FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
2948 2949              "login_and_process_job: start login."));
2949 2950  
2950 2951          mutex_enter(&fcsm->sm_mutex);
2951 2952          if (fcsm->sm_flags & FCSM_MGMT_SERVER_LOGGED_IN) {
2952 2953                  /*
2953 2954                   * Directory server login completed just now, while the
2954 2955                   * mutex was dropped. Just queue the command again for
2955 2956                   * processing.
2956 2957                   */
2957 2958                  mutex_exit(&fcsm->sm_mutex);
2958 2959                  FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
2959 2960                      "login_and_process_job: got job 0x%p. login just "
2960 2961                      "completed", (void *)orig_job));
2961 2962                  fcsm_enque_job(fcsm, orig_job, 0);
2962 2963                  return (FC_SUCCESS);
2963 2964          }
2964 2965  
2965 2966          if (fcsm->sm_flags & FCSM_MGMT_SERVER_LOGIN_IN_PROG) {
2966 2967                  /*
2967 2968                   * Ideally we shouldn't have come here, since login
2968 2969                   * job has the serialize flag set.
2969 2970                   * Anyway, put the command back on the queue.
2970 2971                   */
2971 2972                  mutex_exit(&fcsm->sm_mutex);
2972 2973                  FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
2973 2974                      "login_and_process_job: got job 0x%p while login to "
2974 2975                      "management server in progress", (void *)orig_job));
2975 2976                  fcsm_enque_job(fcsm, orig_job, 0);
2976 2977                  return (FC_SUCCESS);
2977 2978          }
2978 2979  
2979 2980          fcsm->sm_flags |= FCSM_MGMT_SERVER_LOGIN_IN_PROG;
2980 2981          mutex_exit(&fcsm->sm_mutex);
2981 2982  
2982 2983          login_job = fcsm_alloc_job(KM_SLEEP);
2983 2984          ASSERT(login_job != NULL);
2984 2985  
2985 2986          /*
2986 2987           * Mark the login job as SERIALIZE, so that all other jobs will
2987 2988           * be processed after completing the login.
2988 2989           * Save the original job (CT Passthru job) in the caller private
2989 2990           * field in the job structure, so that CT command can be issued
2990 2991           * after login has completed.
2991 2992           */
2992 2993          fcsm_init_job(login_job, fcsm->sm_instance, FCSM_JOB_LOGIN_MGMT_SERVER,
2993 2994              FCSM_JOBFLAG_ASYNC | FCSM_JOBFLAG_SERIALIZE,
2994 2995              (opaque_t)NULL, (opaque_t)orig_job, fcsm_login_ms_comp, NULL);
2995 2996          orig_job->job_priv = (void *)login_job;
2996 2997  
2997 2998  #ifdef DEBUG
2998 2999          status = fcsm_process_job(login_job, 1);
2999 3000          ASSERT(status == FC_SUCCESS);
3000 3001  #else /* DEBUG */
3001 3002          (void) fcsm_process_job(login_job, 1);
3002 3003  #endif /* DEBUG */
3003 3004          return (FC_SUCCESS);
3004 3005  }
3005 3006  
3006 3007  
3007 3008  /* ARGSUSED */
3008 3009  static void
3009 3010  fcsm_login_ms_comp(opaque_t comp_arg, fcsm_job_t *login_job, int result)
3010 3011  {
3011 3012          fcsm_t          *fcsm;
3012 3013          fcsm_job_t      *orig_job;
3013 3014  
3014 3015          ASSERT(login_job != NULL);
3015 3016  
3016 3017          orig_job = (fcsm_job_t *)login_job->job_caller_priv;
3017 3018  
3018 3019          ASSERT(orig_job != NULL);
3019 3020          ASSERT(orig_job->job_priv == (void *)login_job);
3020 3021          orig_job->job_priv = NULL;
3021 3022  
3022 3023          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
3023 3024              "login_ms_comp: result 0x%x", login_job->job_result));
3024 3025  
3025 3026          /* Set the login flag in the per port fcsm structure */
3026 3027          ASSERT(login_job->job_port_instance == orig_job->job_port_instance);
3027 3028          fcsm = ddi_get_soft_state(fcsm_state, login_job->job_port_instance);
3028 3029          ASSERT(fcsm != NULL);
3029 3030  
3030 3031          mutex_enter(&fcsm->sm_mutex);
3031 3032          ASSERT((fcsm->sm_flags & FCSM_MGMT_SERVER_LOGGED_IN) == 0);
3032 3033          ASSERT(fcsm->sm_flags & FCSM_MGMT_SERVER_LOGIN_IN_PROG);
3033 3034          fcsm->sm_flags &= ~FCSM_MGMT_SERVER_LOGIN_IN_PROG;
3034 3035          if (login_job->job_result != FC_SUCCESS) {
3035 3036                  caddr_t msg;
3036 3037  
3037 3038                  /*
3038 3039                   * Login failed. Complete the original job with FC_LOGINREQ
3039 3040                   * status. Retry of that job will cause login to be
3040 3041                   * retried.
3041 3042                   */
3042 3043                  mutex_exit(&fcsm->sm_mutex);
3043 3044                  orig_job->job_result = FC_LOGINREQ;
3044 3045                  fcsm_jobdone(orig_job);
3045 3046  
3046 3047                  (void) fc_ulp_error(login_job->job_result, &msg);
3047 3048                  fcsm_display(CE_WARN, SM_LOG, fcsm, NULL,
3048 3049                      "login_ms_comp: Management server login failed: <%s>", msg);
3049 3050                  return;
3050 3051          }
3051 3052          fcsm->sm_flags |= FCSM_MGMT_SERVER_LOGGED_IN;
3052 3053          mutex_exit(&fcsm->sm_mutex);
3053 3054  
3054 3055          /*
3055 3056           * Queue the original job at the head of the queue for processing.
3056 3057           */
3057 3058          fcsm_enque_job(fcsm, orig_job, 1);
3058 3059  }
3059 3060  
3060 3061  
3061 3062  static void
3062 3063  fcsm_els_init(fcsm_cmd_t *cmd, uint32_t d_id)
3063 3064  {
3064 3065          fc_packet_t     *pkt;
3065 3066          fcsm_t          *fcsm;
3066 3067  
3067 3068          fcsm = cmd->cmd_fcsm;
3068 3069          pkt = cmd->cmd_fp_pkt;
3069 3070          ASSERT(fcsm != NULL && pkt != NULL);
3070 3071  
3071 3072          pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ;
3072 3073          pkt->pkt_cmd_fhdr.d_id  = d_id;
3073 3074          pkt->pkt_cmd_fhdr.rsvd  = 0;
3074 3075          pkt->pkt_cmd_fhdr.s_id  = fcsm->sm_sid;
3075 3076          pkt->pkt_cmd_fhdr.type  = FC_TYPE_EXTENDED_LS;
3076 3077          pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ;
3077 3078          pkt->pkt_cmd_fhdr.seq_id = 0;
3078 3079          pkt->pkt_cmd_fhdr.df_ctl = 0;
3079 3080          pkt->pkt_cmd_fhdr.seq_cnt = 0;
3080 3081          pkt->pkt_cmd_fhdr.ox_id = 0xffff;
3081 3082          pkt->pkt_cmd_fhdr.rx_id = 0xffff;
3082 3083          pkt->pkt_cmd_fhdr.ro    = 0;
3083 3084  
3084 3085          pkt->pkt_timeout        = FCSM_ELS_TIMEOUT;
3085 3086  }
3086 3087  
3087 3088  
3088 3089  static int
3089 3090  fcsm_xlogi_init(fcsm_t *fcsm, fcsm_cmd_t *cmd, uint32_t d_id,
3090 3091      void (*comp_func)(), uchar_t ls_code)
3091 3092  {
3092 3093          ls_code_t       payload;
3093 3094          fc_packet_t     *pkt;
3094 3095          la_els_logi_t   *login_params;
3095 3096          int             status;
3096 3097  
3097 3098          login_params = (la_els_logi_t *)
3098 3099              kmem_zalloc(sizeof (la_els_logi_t), KM_SLEEP);
3099 3100          if (login_params == NULL) {
3100 3101                  return (FC_NOMEM);
3101 3102          }
3102 3103  
3103 3104          status = fc_ulp_get_port_login_params(fcsm->sm_port_info.port_handle,
3104 3105              login_params);
3105 3106          if (status != FC_SUCCESS) {
3106 3107                  kmem_free(login_params, sizeof (la_els_logi_t));
3107 3108                  return (status);
3108 3109          }
3109 3110  
3110 3111          pkt = cmd->cmd_fp_pkt;
3111 3112  
3112 3113          fcsm_els_init(cmd, d_id);
3113 3114          pkt->pkt_comp = comp_func;
3114 3115  
3115 3116          payload.ls_code = ls_code;
3116 3117          payload.mbz = 0;
3117 3118  
3118 3119          FCSM_REP_WR(pkt->pkt_cmd_acc, login_params,
3119 3120              pkt->pkt_cmd, sizeof (la_els_logi_t));
3120 3121          FCSM_REP_WR(pkt->pkt_cmd_acc, &payload,
3121 3122              pkt->pkt_cmd, sizeof (payload));
3122 3123  
3123 3124          cmd->cmd_transport = fc_ulp_issue_els;
3124 3125  
3125 3126          kmem_free(login_params, sizeof (la_els_logi_t));
3126 3127  
3127 3128          return (FC_SUCCESS);
3128 3129  }
3129 3130  
3130 3131  static void
3131 3132  fcsm_xlogi_intr(fcsm_cmd_t *cmd)
3132 3133  {
3133 3134          fc_packet_t     *pkt;
3134 3135          fcsm_job_t      *job;
3135 3136          fcsm_t          *fcsm;
3136 3137  
3137 3138          pkt = cmd->cmd_fp_pkt;
3138 3139          job = cmd->cmd_job;
3139 3140          ASSERT(job != NULL);
3140 3141  
3141 3142          fcsm = cmd->cmd_fcsm;
3142 3143          ASSERT(fcsm != NULL);
3143 3144  
3144 3145          if (pkt->pkt_state != FC_PKT_SUCCESS) {
3145 3146                  fcsm_display(CE_WARN, SM_LOG, fcsm, pkt,
3146 3147                      "xlogi_intr: login to DID 0x%x failed",
3147 3148                      pkt->pkt_cmd_fhdr.d_id);
3148 3149          } else {
3149 3150                  /* Get the Login parameters of the Management Server */
3150 3151                  FCSM_REP_RD(pkt->pkt_resp_acc, &fcsm->sm_ms_service_params,
3151 3152                      pkt->pkt_resp, sizeof (la_els_logi_t));
3152 3153          }
3153 3154  
3154 3155          job->job_result =
3155 3156              fcsm_pkt_state_to_rval(pkt->pkt_state, pkt->pkt_reason);
3156 3157  
3157 3158          fcsm_free_cmd(cmd);
3158 3159  
3159 3160          fcsm_jobdone(job);
3160 3161  }
3161 3162  
3162 3163  static void
3163 3164  fcsm_job_login_mgmt_server(fcsm_job_t *job)
3164 3165  {
3165 3166          fcsm_t          *fcsm;
3166 3167          fcsm_cmd_t      *cmd;
3167 3168          int             status;
3168 3169  
3169 3170          ASSERT(job != NULL);
3170 3171          ASSERT(job->job_port_instance != -1);
3171 3172  
3172 3173          fcsm = ddi_get_soft_state(fcsm_state, job->job_port_instance);
3173 3174          if (fcsm == NULL) {
3174 3175                  job->job_result = FC_NOMEM;
3175 3176                  fcsm_jobdone(job);
3176 3177                  return;
3177 3178          }
3178 3179  
3179 3180          /*
3180 3181           * Issue the  Login command to the management server.
3181 3182           */
3182 3183          cmd = fcsm_alloc_cmd(fcsm, sizeof (la_els_logi_t),
3183 3184              sizeof (la_els_logi_t), KM_SLEEP);
3184 3185          if (cmd == NULL) {
3185 3186                  job->job_result = FC_NOMEM;
3186 3187                  fcsm_jobdone(job);
3187 3188                  return;
3188 3189          }
3189 3190  
3190 3191          FCSM_INIT_CMD(cmd, job, FC_TRAN_INTR | FC_TRAN_CLASS3, FC_PKT_EXCHANGE,
3191 3192              fcsm_max_cmd_retries, fcsm_xlogi_intr);
3192 3193  
3193 3194          status = fcsm_xlogi_init(fcsm, cmd, FS_MANAGEMENT_SERVER,
3194 3195              fcsm_pkt_common_intr, LA_ELS_PLOGI);
3195 3196  
3196 3197          if (status != FC_SUCCESS) {
3197 3198                  FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
3198 3199                      "job_login_mgmt_server: plogi init failed. status 0x%x",
3199 3200                      status));
3200 3201                  job->job_result = status;
3201 3202                  fcsm_free_cmd(cmd);
3202 3203                  fcsm_jobdone(job);
3203 3204                  return;
3204 3205          }
3205 3206  
3206 3207          if ((status = fcsm_issue_cmd(cmd)) != FC_SUCCESS) {
3207 3208                  FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, cmd->cmd_fcsm, NULL,
3208 3209                      "job_ct_passthru: issue login cmd failed, status 0x%x",
3209 3210                      status));
3210 3211                  job->job_result = status;
3211 3212                  fcsm_free_cmd(cmd);
3212 3213                  fcsm_jobdone(job);
3213 3214                  return;
3214 3215          }
3215 3216  }
3216 3217  
3217 3218  
3218 3219  int
3219 3220  fcsm_ct_passthru(int instance, fcio_t *fcio, int sleep, int job_flags,
3220 3221      void (*func)(fcio_t *))
3221 3222  {
3222 3223          fcsm_job_t      *job;
3223 3224          int             status;
3224 3225  
3225 3226          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
3226 3227              "ct_passthru: instance 0x%x fcio 0x%p", instance, fcio));
3227 3228          job = fcsm_alloc_job(sleep);
3228 3229          ASSERT(sleep == KM_NOSLEEP || job != NULL);
3229 3230  
3230 3231          fcsm_init_job(job, instance, FCSM_JOB_CT_PASSTHRU, job_flags,
3231 3232              (opaque_t)fcio, (opaque_t)func, fcsm_ct_passthru_comp, NULL);
3232 3233          status = fcsm_process_job(job, 0);
3233 3234          if (status != FC_SUCCESS) {
3234 3235                  /* Job could not be issued. So free the job and return */
3235 3236                  fcsm_dealloc_job(job);
3236 3237                  return (status);
3237 3238          }
3238 3239  
3239 3240          if (job_flags & FCSM_JOBFLAG_SYNC) {
3240 3241                  status = job->job_result;
3241 3242                  fcsm_dealloc_job(job);
3242 3243          }
3243 3244  
3244 3245          return (status);
3245 3246  }
3246 3247  
3247 3248  
3248 3249  /* ARGSUSED */
3249 3250  static void
3250 3251  fcsm_ct_passthru_comp(opaque_t comp_arg, fcsm_job_t *job, int result)
3251 3252  {
3252 3253          ASSERT(job != NULL);
3253 3254          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
3254 3255              "ct_passthru_comp: result 0x%x port 0x%x",
3255 3256              job->job_result, job->job_port_instance));
3256 3257  }
3257 3258  
3258 3259  
3259 3260  static void
3260 3261  fcsm_pkt_common_intr(fc_packet_t *pkt)
3261 3262  {
3262 3263          fcsm_cmd_t      *cmd;
3263 3264          int             jobstatus;
3264 3265          fcsm_t          *fcsm;
3265 3266  
3266 3267          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
3267 3268              "pkt_common_intr"));
3268 3269  
3269 3270          cmd = (fcsm_cmd_t *)pkt->pkt_ulp_private;
3270 3271          ASSERT(cmd != NULL);
3271 3272  
3272 3273          if (pkt->pkt_state == FC_PKT_SUCCESS) {
3273 3274                  /* Command completed successfully. Just complete the command */
3274 3275                  cmd->cmd_comp(cmd);
3275 3276                  return;
3276 3277          }
3277 3278  
3278 3279          fcsm = cmd->cmd_fcsm;
3279 3280          ASSERT(fcsm != NULL);
3280 3281  
3281 3282          FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, cmd->cmd_fcsm, pkt,
3282 3283              "fc packet to DID 0x%x failed for pkt 0x%p",
3283 3284              pkt->pkt_cmd_fhdr.d_id, pkt));
3284 3285  
3285 3286          mutex_enter(&fcsm->sm_mutex);
3286 3287          if (fcsm->sm_flags & FCSM_LINK_DOWN) {
3287 3288                  /*
3288 3289                   * No need to retry the command. The link previously
3289 3290                   * suffered an offline  timeout.
3290 3291                   */
3291 3292                  mutex_exit(&fcsm->sm_mutex);
3292 3293                  FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, cmd->cmd_fcsm, NULL,
3293 3294                      "pkt_common_intr: end. Link is down"));
3294 3295                  cmd->cmd_comp(cmd);
3295 3296                  return;
3296 3297          }
3297 3298          mutex_exit(&fcsm->sm_mutex);
3298 3299  
3299 3300          jobstatus = fcsm_pkt_state_to_rval(pkt->pkt_state, pkt->pkt_reason);
3300 3301          if (jobstatus == FC_LOGINREQ) {
3301 3302                  /*
3302 3303                   * Login to the destination is required. No need to
3303 3304                   * retry this cmd again.
3304 3305                   */
3305 3306                  FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, cmd->cmd_fcsm, NULL,
3306 3307                      "pkt_common_intr: end. LOGIN required"));
3307 3308                  cmd->cmd_comp(cmd);
3308 3309                  return;
3309 3310          }
3310 3311  
3311 3312          switch (pkt->pkt_state) {
3312 3313          case FC_PKT_PORT_OFFLINE:
3313 3314          case FC_PKT_LOCAL_RJT:
3314 3315          case FC_PKT_TIMEOUT: {
3315 3316                  uchar_t         pkt_state;
3316 3317  
3317 3318                  pkt_state = pkt->pkt_state;
3318 3319                  cmd->cmd_retry_interval = fcsm_retry_interval;
3319 3320                  if (fcsm_retry_cmd(cmd) != 0) {
3320 3321                          FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG,
3321 3322                              cmd->cmd_fcsm, NULL,
3322 3323                              "common_intr: max retries(%d) reached, status 0x%x",
3323 3324                              cmd->cmd_retry_count));
3324 3325  
3325 3326                          /*
3326 3327                           * Restore the pkt_state to the actual failure status
3327 3328                           * received at the time of pkt completion.
3328 3329                           */
3329 3330                          pkt->pkt_state = pkt_state;
3330 3331                          pkt->pkt_reason = 0;
3331 3332                          cmd->cmd_comp(cmd);
3332 3333                  } else {
3333 3334                          FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG,
3334 3335                              cmd->cmd_fcsm, NULL,
3335 3336                              "pkt_common_intr: retry(%d) on pkt state (0x%x)",
3336 3337                              cmd->cmd_retry_count, pkt_state));
3337 3338                  }
3338 3339                  break;
3339 3340          }
3340 3341          default:
3341 3342                  cmd->cmd_comp(cmd);
3342 3343                  break;
3343 3344          }
3344 3345  }
3345 3346  
3346 3347  static int
3347 3348  fcsm_issue_cmd(fcsm_cmd_t *cmd)
3348 3349  {
3349 3350          fc_packet_t     *pkt;
3350 3351          fcsm_t          *fcsm;
3351 3352          int             status;
3352 3353  
3353 3354          pkt = cmd->cmd_fp_pkt;
3354 3355          fcsm = cmd->cmd_fcsm;
3355 3356  
3356 3357          /* Explicitly invalidate this field till fcsm decides to use it */
3357 3358          pkt->pkt_ulp_rscn_infop = NULL;
3358 3359  
3359 3360          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
3360 3361              "issue_cmd: entry"));
3361 3362  
3362 3363          ASSERT(!MUTEX_HELD(&fcsm->sm_mutex));
3363 3364          mutex_enter(&fcsm->sm_mutex);
3364 3365          if (fcsm->sm_flags & FCSM_LINK_DOWN) {
3365 3366                  /*
3366 3367                   * Update the pkt_state/pkt_reason appropriately.
3367 3368                   * Caller of this function can decide whether to call
3368 3369                   * 'pkt->pkt_comp' or use the 'status' returned by this func.
3369 3370                   */
3370 3371                  mutex_exit(&fcsm->sm_mutex);
3371 3372                  pkt->pkt_state = FC_PKT_PORT_OFFLINE;
3372 3373                  pkt->pkt_reason = FC_REASON_OFFLINE;
3373 3374                  return (FC_OFFLINE);
3374 3375          }
3375 3376          mutex_exit(&fcsm->sm_mutex);
3376 3377  
3377 3378          ASSERT(cmd->cmd_transport != NULL);
3378 3379          status = cmd->cmd_transport(fcsm->sm_port_info.port_handle, pkt);
3379 3380          if (status != FC_SUCCESS) {
3380 3381                  switch (status) {
3381 3382                  case FC_LOGINREQ:
3382 3383                          /*
3383 3384                           * No need to retry. Return the cause of failure.
3384 3385                           * Also update the pkt_state/pkt_reason. Caller of
3385 3386                           * this function can decide, whether to call
3386 3387                           * 'pkt->pkt_comp' or use the 'status' code returned
3387 3388                           * by this function.
3388 3389                           */
3389 3390                          pkt->pkt_state = FC_PKT_LOCAL_RJT;
3390 3391                          pkt->pkt_reason = FC_REASON_LOGIN_REQUIRED;
3391 3392                          break;
3392 3393  
3393 3394                  case FC_DEVICE_BUSY_NEW_RSCN:
3394 3395                          /*
3395 3396                           * There was a newer RSCN than what fcsm knows about.
3396 3397                           * So, just retry again
3397 3398                           */
3398 3399                          cmd->cmd_retry_count = 0;
3399 3400                          /*FALLTHROUGH*/
3400 3401                  case FC_OFFLINE:
3401 3402                  case FC_STATEC_BUSY:
3402 3403                          /*
3403 3404                           * TODO: set flag, so that command is retried after
3404 3405                           * port is back online.
3405 3406                           * FALL Through for now.
3406 3407                           */
3407 3408  
3408 3409                  case FC_TRAN_BUSY:
3409 3410                  case FC_NOMEM:
3410 3411                  case FC_DEVICE_BUSY:
3411 3412                          cmd->cmd_retry_interval = fcsm_retry_interval;
3412 3413                          if (fcsm_retry_cmd(cmd) != 0) {
3413 3414                                  FCSM_DEBUG(SMDL_TRACE,
3414 3415                                      (CE_WARN, SM_LOG, fcsm, NULL,
3415 3416                                      "issue_cmd: max retries (%d) reached",
3416 3417                                      cmd->cmd_retry_count));
3417 3418  
3418 3419                                  /*
3419 3420                                   * status variable is not changed here.
3420 3421                                   * Return the cause of the original
3421 3422                                   * cmd_transport failure.
3422 3423                                   * Update the pkt_state/pkt_reason. Caller
3423 3424                                   * of this function can decide whether to
3424 3425                                   * call 'pkt->pkt_comp' or use the 'status'
3425 3426                                   * code returned by this function.
3426 3427                                   */
3427 3428                                  pkt->pkt_state = FC_PKT_TRAN_BSY;
3428 3429                                  pkt->pkt_reason = 0;
3429 3430                          } else {
3430 3431                                  FCSM_DEBUG(SMDL_TRACE,
3431 3432                                      (CE_WARN, SM_LOG, fcsm, NULL,
3432 3433                                      "issue_cmd: retry (%d) on fc status (0x%x)",
3433 3434                                      cmd->cmd_retry_count, status));
3434 3435  
3435 3436                                  status = FC_SUCCESS;
3436 3437                          }
3437 3438                          break;
3438 3439  
3439 3440                  default:
3440 3441                          FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL,
3441 3442                              "issue_cmd: failure status 0x%x", status));
3442 3443  
3443 3444                          pkt->pkt_state = FC_PKT_TRAN_ERROR;
3444 3445                          pkt->pkt_reason = 0;
3445 3446                          break;
3446 3447  
3447 3448  
3448 3449                  }
3449 3450          }
3450 3451  
3451 3452          return (status);
3452 3453  }
3453 3454  
3454 3455  
3455 3456  static int
3456 3457  fcsm_retry_cmd(fcsm_cmd_t *cmd)
3457 3458  {
3458 3459          if (cmd->cmd_retry_count < cmd->cmd_max_retries) {
3459 3460                  cmd->cmd_retry_count++;
3460 3461                  fcsm_enque_cmd(cmd->cmd_fcsm, cmd);
3461 3462                  return (0);
3462 3463          }
3463 3464  
3464 3465          return (1);
3465 3466  }
3466 3467  
3467 3468  static void
3468 3469  fcsm_enque_cmd(fcsm_t *fcsm, fcsm_cmd_t *cmd)
3469 3470  {
3470 3471          ASSERT(!MUTEX_HELD(&fcsm->sm_mutex));
3471 3472  
3472 3473          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, "enque_cmd"));
3473 3474  
3474 3475          cmd->cmd_next = NULL;
3475 3476          mutex_enter(&fcsm->sm_mutex);
3476 3477          if (fcsm->sm_retry_tail) {
3477 3478                  ASSERT(fcsm->sm_retry_head != NULL);
3478 3479                  fcsm->sm_retry_tail->cmd_next = cmd;
3479 3480                  fcsm->sm_retry_tail = cmd;
3480 3481          } else {
3481 3482                  ASSERT(fcsm->sm_retry_tail == NULL);
3482 3483                  fcsm->sm_retry_head = fcsm->sm_retry_tail = cmd;
3483 3484  
3484 3485                  /* Schedule retry thread, if not already running */
3485 3486                  if (fcsm->sm_retry_tid == NULL) {
3486 3487                          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
3487 3488                              "enque_cmd: schedule retry thread"));
3488 3489                          fcsm->sm_retry_tid = timeout(fcsm_retry_timeout,
3489 3490                              (caddr_t)fcsm, fcsm_retry_ticks);
3490 3491                  }
3491 3492          }
3492 3493          mutex_exit(&fcsm->sm_mutex);
3493 3494  }
3494 3495  
3495 3496  
3496 3497  static fcsm_cmd_t *
3497 3498  fcsm_deque_cmd(fcsm_t *fcsm)
3498 3499  {
3499 3500          fcsm_cmd_t      *cmd;
3500 3501  
3501 3502          ASSERT(!MUTEX_HELD(&fcsm->sm_mutex));
3502 3503  
3503 3504          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, "deque_cmd"));
3504 3505  
3505 3506          mutex_enter(&fcsm->sm_mutex);
3506 3507          if (fcsm->sm_retry_head == NULL) {
3507 3508                  ASSERT(fcsm->sm_retry_tail == NULL);
3508 3509                  cmd = NULL;
3509 3510          } else {
3510 3511                  cmd = fcsm->sm_retry_head;
3511 3512                  fcsm->sm_retry_head = cmd->cmd_next;
3512 3513                  if (fcsm->sm_retry_head == NULL) {
3513 3514                          fcsm->sm_retry_tail = NULL;
3514 3515                  }
3515 3516                  cmd->cmd_next = NULL;
3516 3517          }
3517 3518          mutex_exit(&fcsm->sm_mutex);
3518 3519  
3519 3520          return (cmd);
3520 3521  }
3521 3522  
3522 3523  static void
3523 3524  fcsm_retry_timeout(void *handle)
3524 3525  {
3525 3526          fcsm_t          *fcsm;
3526 3527          fcsm_cmd_t      *curr_tail;
3527 3528          fcsm_cmd_t      *cmd;
3528 3529          int             done = 0;
3529 3530          int             linkdown;
3530 3531  
3531 3532          fcsm = (fcsm_t *)handle;
3532 3533  
3533 3534          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, "retry_timeout"));
3534 3535  
3535 3536          /*
3536 3537           * If retry cmd queue is suspended, then go away.
3537 3538           * This retry thread will be restarted, when cmd queue resumes.
3538 3539           */
3539 3540          mutex_enter(&fcsm->sm_mutex);
3540 3541          if (fcsm->sm_flags & FCSM_CMD_RETRY_Q_SUSPENDED) {
3541 3542                  /*
3542 3543                   * Clear the retry_tid, to indicate that this routine is not
3543 3544                   * currently being rescheduled.
3544 3545                   */
3545 3546                  fcsm->sm_retry_tid = (timeout_id_t)NULL;
3546 3547                  mutex_exit(&fcsm->sm_mutex);
3547 3548                  FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
3548 3549                      "retry_timeout: end. No processing. "
3549 3550                      "Queue is currently suspended for this instance"));
3550 3551                  return;
3551 3552          }
3552 3553  
3553 3554          linkdown = (fcsm->sm_flags & FCSM_LINK_DOWN) ? 1 : 0;
3554 3555  
3555 3556          /*
3556 3557           * Save the curr_tail, so that we only process the commands
3557 3558           * which are in the queue at this time.
3558 3559           */
3559 3560          curr_tail = fcsm->sm_retry_tail;
3560 3561          mutex_exit(&fcsm->sm_mutex);
3561 3562  
3562 3563          /*
3563 3564           * Check for done flag before dequeing the command.
3564 3565           * Dequeing before checking the done flag will cause a command
3565 3566           * to be lost.
3566 3567           */
3567 3568          while ((!done) && ((cmd = fcsm_deque_cmd(fcsm)) != NULL)) {
3568 3569  
3569 3570                  if (cmd == curr_tail) {
3570 3571                          done = 1;
3571 3572                  }
3572 3573  
3573 3574                  cmd->cmd_retry_interval -= fcsm_retry_ticker;
3574 3575  
3575 3576                  if (linkdown) {
3576 3577                          fc_packet_t *pkt;
3577 3578  
3578 3579                          /*
3579 3580                           * No need to retry the command. The link has
3580 3581                           * suffered an offline  timeout.
3581 3582                           */
3582 3583                          pkt = cmd->cmd_fp_pkt;
3583 3584                          pkt->pkt_state = FC_PKT_PORT_OFFLINE;
3584 3585                          pkt->pkt_reason = FC_REASON_OFFLINE;
3585 3586                          pkt->pkt_comp(pkt);
3586 3587                          continue;
3587 3588                  }
3588 3589  
3589 3590                  if (cmd->cmd_retry_interval <= 0) {
3590 3591                          /* Retry the command */
3591 3592                          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
3592 3593                              "retry_timeout: issue cmd 0x%p", (void *)cmd));
3593 3594                          if (fcsm_issue_cmd(cmd) != FC_SUCCESS) {
3594 3595                                  cmd->cmd_fp_pkt->pkt_comp(cmd->cmd_fp_pkt);
3595 3596                          }
3596 3597                  } else {
3597 3598                          /*
3598 3599                           * Put the command back on the queue. Retry time
3599 3600                           * has not yet reached.
3600 3601                           */
3601 3602                          FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
3602 3603                              "retry_timeout: queue cmd 0x%p", (void *)cmd));
3603 3604                          fcsm_enque_cmd(fcsm, cmd);
3604 3605                  }
3605 3606          }
3606 3607  
3607 3608          mutex_enter(&fcsm->sm_mutex);
3608 3609          if (fcsm->sm_retry_head) {
3609 3610                  /* Activate timer */
3610 3611                  fcsm->sm_retry_tid = timeout(fcsm_retry_timeout,
3611 3612                      (caddr_t)fcsm, fcsm_retry_ticks);
3612 3613                  FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
3613 3614                      "retry_timeout: retry thread rescheduled"));
3614 3615          } else {
3615 3616                  /*
3616 3617                   * Reset the tid variable. The first thread which queues the
3617 3618                   * command, will restart the timer.
3618 3619                   */
3619 3620                  fcsm->sm_retry_tid = (timeout_id_t)NULL;
3620 3621          }
3621 3622          mutex_exit(&fcsm->sm_mutex);
3622 3623  }
  
    | 
      ↓ open down ↓ | 
    3589 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX