Print this page
    
*** NO COMMENTS ***
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/io/comstar/port/pppt/pppt.c
          +++ new/usr/src/uts/common/io/comstar/port/pppt/pppt.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  23   23   */
  24   24  
  25   25  #include <sys/cpuvar.h>
  26   26  #include <sys/types.h>
  27   27  #include <sys/conf.h>
  28   28  #include <sys/stat.h>
  29   29  #include <sys/file.h>
  30   30  #include <sys/ddi.h>
  31   31  #include <sys/sunddi.h>
  32   32  #include <sys/modctl.h>
  33   33  #include <sys/sysmacros.h>
  34   34  #include <sys/nvpair.h>
  35   35  #include <sys/door.h>
  36   36  #include <sys/sdt.h>
  37   37  
  38   38  #include <sys/stmf.h>
  39   39  #include <sys/stmf_ioctl.h>
  40   40  #include <sys/pppt_ioctl.h>
  41   41  #include <sys/portif.h>
  42   42  
  43   43  #include "pppt.h"
  44   44  
  45   45  #define PPPT_VERSION            BUILD_DATE "-1.18dev"
  46   46  #define PPPT_NAME_VERSION       "COMSTAR PPPT v" PPPT_VERSION
  47   47  
  48   48  /*
  49   49   * DDI entry points.
  50   50   */
  51   51  static int pppt_drv_attach(dev_info_t *, ddi_attach_cmd_t);
  52   52  static int pppt_drv_detach(dev_info_t *, ddi_detach_cmd_t);
  53   53  static int pppt_drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
  54   54  static int pppt_drv_open(dev_t *, int, int, cred_t *);
  55   55  static int pppt_drv_close(dev_t, int, int, cred_t *);
  56   56  static boolean_t pppt_drv_busy(void);
  57   57  static int pppt_drv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
  58   58  
  59   59  extern pppt_status_t pppt_ic_so_enable(boolean_t);
  60   60  extern void pppt_ic_so_disable();
  61   61  extern void stmf_ic_rx_msg(char *, size_t);
  62   62  
  63   63  extern struct mod_ops mod_miscops;
  64   64  
  65   65  static struct cb_ops pppt_cb_ops = {
  66   66          pppt_drv_open,  /* cb_open */
  67   67          pppt_drv_close, /* cb_close */
  68   68          nodev,                  /* cb_strategy */
  69   69          nodev,                  /* cb_print */
  70   70          nodev,                  /* cb_dump */
  71   71          nodev,                  /* cb_read */
  72   72          nodev,                  /* cb_write */
  73   73          pppt_drv_ioctl,         /* cb_ioctl */
  74   74          nodev,                  /* cb_devmap */
  75   75          nodev,                  /* cb_mmap */
  76   76          nodev,                  /* cb_segmap */
  77   77          nochpoll,               /* cb_chpoll */
  78   78          ddi_prop_op,            /* cb_prop_op */
  79   79          NULL,                   /* cb_streamtab */
  80   80          D_MP,                   /* cb_flag */
  81   81          CB_REV,                 /* cb_rev */
  82   82          nodev,                  /* cb_aread */
  83   83          nodev,                  /* cb_awrite */
  84   84  };
  85   85  
  86   86  static struct dev_ops pppt_dev_ops = {
  87   87          DEVO_REV,               /* devo_rev */
  88   88          0,                      /* devo_refcnt */
  89   89          pppt_drv_getinfo,       /* devo_getinfo */
  90   90          nulldev,                /* devo_identify */
  91   91          nulldev,                /* devo_probe */
  92   92          pppt_drv_attach,        /* devo_attach */
  93   93          pppt_drv_detach,        /* devo_detach */
  94   94          nodev,                  /* devo_reset */
  95   95          &pppt_cb_ops,           /* devo_cb_ops */
  96   96          NULL,                   /* devo_bus_ops */
  97   97          NULL,                   /* devo_power */
  98   98          ddi_quiesce_not_needed, /* quiesce */
  99   99  };
 100  100  
 101  101  static struct modldrv modldrv = {
 102  102          &mod_driverops,
 103  103          "Proxy Port Provider",
 104  104          &pppt_dev_ops,
 105  105  };
 106  106  
 107  107  static struct modlinkage modlinkage = {
 108  108          MODREV_1,
 109  109          &modldrv,
 110  110          NULL,
 111  111  };
 112  112  
 113  113  pppt_global_t pppt_global;
 114  114  
 115  115  int pppt_logging = 0;
 116  116  
 117  117  static int pppt_enable_svc(void);
 118  118  
 119  119  static void pppt_disable_svc(void);
 120  120  
 121  121  static int pppt_task_avl_compare(const void *tgt1, const void *tgt2);
 122  122  
 123  123  static stmf_data_buf_t *pppt_dbuf_alloc(scsi_task_t *task,
  
    | 
      ↓ open down ↓ | 
    123 lines elided | 
    
      ↑ open up ↑ | 
  
 124  124      uint32_t size, uint32_t *pminsize, uint32_t flags);
 125  125  
 126  126  static void pppt_dbuf_free(stmf_dbuf_store_t *ds, stmf_data_buf_t *dbuf);
 127  127  
 128  128  static void pppt_sess_destroy_task(void *ps_void);
 129  129  
 130  130  static void pppt_task_sent_status(pppt_task_t *ptask);
 131  131  
 132  132  static pppt_status_t pppt_task_try_abort(pppt_task_t *ptask);
 133  133  
 134      -static pppt_status_t pppt_task_hold(pppt_task_t *ptask);
 135      -
 136  134  static void pppt_task_rele(pppt_task_t *ptask);
 137  135  
 138  136  static void pppt_task_update_state(pppt_task_t *ptask,
 139  137      pppt_task_state_t new_state);
 140  138  
 141  139  /*
 142  140   * Lock order:  global --> target --> session --> task
 143  141   */
 144  142  
 145  143  int
 146  144  _init(void)
 147  145  {
 148  146          int rc;
 149  147  
 150  148          mutex_init(&pppt_global.global_lock, NULL, MUTEX_DEFAULT, NULL);
 151  149          mutex_init(&pppt_global.global_door_lock, NULL, MUTEX_DEFAULT, NULL);
 152  150          pppt_global.global_svc_state = PSS_DETACHED;
 153  151  
 154  152          if ((rc = mod_install(&modlinkage)) != 0) {
 155  153                  mutex_destroy(&pppt_global.global_door_lock);
 156  154                  mutex_destroy(&pppt_global.global_lock);
 157  155                  return (rc);
 158  156          }
 159  157  
 160  158          return (rc);
 161  159  }
 162  160  
 163  161  int
 164  162  _info(struct modinfo *modinfop)
 165  163  {
 166  164          return (mod_info(&modlinkage, modinfop));
 167  165  }
 168  166  
 169  167  int
 170  168  _fini(void)
 171  169  {
 172  170          int rc;
 173  171  
 174  172          rc = mod_remove(&modlinkage);
 175  173  
 176  174          if (rc == 0) {
 177  175                  mutex_destroy(&pppt_global.global_lock);
 178  176                  mutex_destroy(&pppt_global.global_door_lock);
 179  177          }
 180  178  
 181  179          return (rc);
 182  180  }
 183  181  
 184  182  /*
 185  183   * DDI entry points.
 186  184   */
 187  185  
 188  186  /* ARGSUSED */
 189  187  static int
 190  188  pppt_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
 191  189      void **result)
 192  190  {
 193  191          ulong_t instance = getminor((dev_t)arg);
 194  192  
 195  193          switch (cmd) {
 196  194          case DDI_INFO_DEVT2DEVINFO:
 197  195                  *result = pppt_global.global_dip;
 198  196                  return (DDI_SUCCESS);
 199  197  
 200  198          case DDI_INFO_DEVT2INSTANCE:
 201  199                  *result = (void *)instance;
 202  200                  return (DDI_SUCCESS);
 203  201  
 204  202          default:
 205  203                  break;
 206  204          }
 207  205  
 208  206          return (DDI_FAILURE);
 209  207  }
 210  208  
 211  209  static int
 212  210  pppt_drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 213  211  {
 214  212          if (cmd != DDI_ATTACH) {
 215  213                  return (DDI_FAILURE);
 216  214          }
 217  215  
 218  216          if (ddi_get_instance(dip) != 0) {
 219  217                  /* we only allow instance 0 to attach */
 220  218                  return (DDI_FAILURE);
 221  219          }
 222  220  
 223  221          /* create the minor node */
 224  222          if (ddi_create_minor_node(dip, PPPT_MODNAME, S_IFCHR, 0,
 225  223              DDI_PSEUDO, 0) != DDI_SUCCESS) {
 226  224                  cmn_err(CE_WARN, "pppt_drv_attach: "
 227  225                      "failed creating minor node");
 228  226                  return (DDI_FAILURE);
 229  227          }
 230  228  
 231  229          pppt_global.global_svc_state = PSS_DISABLED;
 232  230          pppt_global.global_dip = dip;
 233  231  
 234  232          return (DDI_SUCCESS);
 235  233  }
 236  234  
 237  235  /*ARGSUSED*/
 238  236  static int
 239  237  pppt_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 240  238  {
 241  239          if (cmd != DDI_DETACH)
 242  240                  return (DDI_FAILURE);
 243  241  
 244  242          PPPT_GLOBAL_LOCK();
 245  243          if (pppt_drv_busy()) {
 246  244                  PPPT_GLOBAL_UNLOCK();
 247  245                  return (EBUSY);
 248  246          }
 249  247  
 250  248          ddi_remove_minor_node(dip, NULL);
 251  249          ddi_prop_remove_all(dip);
 252  250  
 253  251          pppt_global.global_svc_state = PSS_DETACHED;
 254  252  
 255  253          PPPT_GLOBAL_UNLOCK();
 256  254  
 257  255          return (DDI_SUCCESS);
 258  256  }
 259  257  
 260  258  /*ARGSUSED*/
 261  259  static int
 262  260  pppt_drv_open(dev_t *devp, int flag, int otyp, cred_t *credp)
 263  261  {
 264  262          int     rc = 0;
 265  263  
 266  264          PPPT_GLOBAL_LOCK();
 267  265  
 268  266          switch (pppt_global.global_svc_state) {
 269  267          case PSS_DISABLED:
 270  268                  pppt_global.global_svc_state = PSS_ENABLING;
 271  269                  PPPT_GLOBAL_UNLOCK();
 272  270                  rc = pppt_enable_svc();
 273  271                  PPPT_GLOBAL_LOCK();
 274  272                  if (rc == 0) {
 275  273                          pppt_global.global_svc_state = PSS_ENABLED;
 276  274                  } else {
 277  275                          pppt_global.global_svc_state = PSS_DISABLED;
 278  276                  }
 279  277                  break;
 280  278          case PSS_DISABLING:
 281  279          case PSS_ENABLING:
 282  280          case PSS_ENABLED:
 283  281                  rc = EBUSY;
 284  282                  break;
 285  283          default:
 286  284                  rc = EFAULT;
 287  285                  break;
 288  286          }
 289  287  
 290  288          PPPT_GLOBAL_UNLOCK();
 291  289  
 292  290          return (rc);
 293  291  }
 294  292  
 295  293  /* ARGSUSED */
 296  294  static int
 297  295  pppt_drv_close(dev_t dev, int flag, int otyp, cred_t *credp)
 298  296  {
 299  297          int rc = 0;
 300  298  
 301  299          PPPT_GLOBAL_LOCK();
 302  300  
 303  301          switch (pppt_global.global_svc_state) {
 304  302          case PSS_ENABLED:
 305  303                  pppt_global.global_svc_state = PSS_DISABLING;
 306  304                  PPPT_GLOBAL_UNLOCK();
 307  305                  pppt_disable_svc();
 308  306                  PPPT_GLOBAL_LOCK();
 309  307                  pppt_global.global_svc_state = PSS_DISABLED;
 310  308                  /*
 311  309                   * release the door to the daemon
 312  310                   */
 313  311                  mutex_enter(&pppt_global.global_door_lock);
 314  312                  if (pppt_global.global_door != NULL) {
 315  313                          door_ki_rele(pppt_global.global_door);
 316  314                          pppt_global.global_door = NULL;
 317  315                  }
 318  316                  mutex_exit(&pppt_global.global_door_lock);
 319  317                  break;
 320  318          default:
 321  319                  rc = EFAULT;
 322  320                  break;
 323  321          }
 324  322  
 325  323          PPPT_GLOBAL_UNLOCK();
 326  324  
 327  325          return (rc);
 328  326  }
 329  327  
 330  328  static boolean_t
 331  329  pppt_drv_busy(void)
 332  330  {
 333  331          switch (pppt_global.global_svc_state) {
 334  332          case PSS_DISABLED:
 335  333          case PSS_DETACHED:
 336  334                  return (B_FALSE);
 337  335          default:
 338  336                  return (B_TRUE);
 339  337          }
 340  338          /* NOTREACHED */
 341  339  }
 342  340  
 343  341  /* ARGSUSED */
 344  342  static int
 345  343  pppt_drv_ioctl(dev_t drv, int cmd, intptr_t argp, int flag, cred_t *cred,
 346  344      int *retval)
 347  345  {
 348  346          int                             rc;
 349  347          void                            *buf;
 350  348          size_t                          buf_size;
 351  349          pppt_iocdata_t                  iocd;
 352  350          door_handle_t                   new_handle;
 353  351  
 354  352          if (drv_priv(cred) != 0) {
 355  353                  return (EPERM);
 356  354          }
 357  355  
 358  356          rc = ddi_copyin((void *)argp, &iocd, sizeof (iocd), flag);
 359  357          if (rc)
 360  358                  return (EFAULT);
 361  359  
 362  360          if (iocd.pppt_version != PPPT_VERSION_1)
 363  361                  return (EINVAL);
 364  362  
 365  363          switch (cmd) {
 366  364          case PPPT_MESSAGE:
 367  365  
 368  366                  /* XXX limit buf_size ? */
 369  367                  buf_size = (size_t)iocd.pppt_buf_size;
 370  368                  buf = kmem_alloc(buf_size, KM_SLEEP);
 371  369                  if (buf == NULL)
 372  370                          return (ENOMEM);
 373  371  
 374  372                  rc = ddi_copyin((void *)(unsigned long)iocd.pppt_buf,
 375  373                      buf, buf_size, flag);
 376  374                  if (rc) {
 377  375                          kmem_free(buf, buf_size);
 378  376                          return (EFAULT);
 379  377                  }
 380  378  
 381  379                  stmf_ic_rx_msg(buf, buf_size);
 382  380  
 383  381                  kmem_free(buf, buf_size);
 384  382                  break;
 385  383          case PPPT_INSTALL_DOOR:
 386  384  
 387  385                  new_handle = door_ki_lookup((int)iocd.pppt_door_fd);
 388  386                  if (new_handle == NULL)
 389  387                          return (EINVAL);
 390  388  
 391  389                  mutex_enter(&pppt_global.global_door_lock);
 392  390                  ASSERT(pppt_global.global_svc_state == PSS_ENABLED);
 393  391                  if (pppt_global.global_door != NULL) {
 394  392                          /*
 395  393                           * There can only be one door installed
 396  394                           */
 397  395                          mutex_exit(&pppt_global.global_door_lock);
 398  396                          door_ki_rele(new_handle);
 399  397                          return (EBUSY);
 400  398                  }
 401  399                  pppt_global.global_door = new_handle;
 402  400                  mutex_exit(&pppt_global.global_door_lock);
 403  401                  break;
 404  402          }
 405  403  
 406  404          return (rc);
 407  405  }
 408  406  
 409  407  /*
 410  408   * pppt_enable_svc
 411  409   *
 412  410   * registers all the configured targets and target portals with STMF
 413  411   */
 414  412  static int
 415  413  pppt_enable_svc(void)
 416  414  {
 417  415          stmf_port_provider_t    *pp;
 418  416          stmf_dbuf_store_t       *dbuf_store;
 419  417          int                     rc = 0;
 420  418  
 421  419          ASSERT(pppt_global.global_svc_state == PSS_ENABLING);
 422  420  
 423  421          /*
 424  422           * Make sure that can tell if we have partially allocated
 425  423           * in case we need to exit and tear down anything allocated.
 426  424           */
 427  425          pppt_global.global_dbuf_store = NULL;
 428  426          pp = NULL;
 429  427          pppt_global.global_pp = NULL;
 430  428          pppt_global.global_dispatch_taskq = NULL;
 431  429          pppt_global.global_sess_taskq = NULL;
 432  430  
 433  431          avl_create(&pppt_global.global_target_list,
 434  432              pppt_tgt_avl_compare, sizeof (pppt_tgt_t),
 435  433              offsetof(pppt_tgt_t, target_global_ln));
 436  434  
 437  435          avl_create(&pppt_global.global_sess_list,
 438  436              pppt_sess_avl_compare_by_id, sizeof (pppt_sess_t),
 439  437              offsetof(pppt_sess_t, ps_global_ln));
 440  438  
 441  439          /*
 442  440           * Setup STMF dbuf store.  Tf buffers are associated with a particular
 443  441           * lport (FC, SRP) then the dbuf_store should stored in the lport
 444  442           * context, otherwise (iSCSI) the dbuf_store should be global.
 445  443           */
 446  444          dbuf_store = stmf_alloc(STMF_STRUCT_DBUF_STORE, 0, 0);
 447  445          if (dbuf_store == NULL) {
 448  446                  rc = ENOMEM;
 449  447                  goto tear_down_and_return;
 450  448          }
 451  449          dbuf_store->ds_alloc_data_buf = pppt_dbuf_alloc;
 452  450          dbuf_store->ds_free_data_buf = pppt_dbuf_free;
 453  451          dbuf_store->ds_port_private = NULL;
 454  452          pppt_global.global_dbuf_store = dbuf_store;
 455  453  
 456  454          /* Register port provider */
 457  455          pp = stmf_alloc(STMF_STRUCT_PORT_PROVIDER, 0, 0);
 458  456          if (pp == NULL) {
 459  457                  rc = ENOMEM;
 460  458                  goto tear_down_and_return;
 461  459          }
 462  460  
 463  461          pp->pp_portif_rev = PORTIF_REV_1;
 464  462          pp->pp_instance = 0;
 465  463          pp->pp_name = PPPT_MODNAME;
 466  464          pp->pp_cb = NULL;
 467  465  
 468  466          pppt_global.global_pp = pp;
 469  467  
 470  468          if (stmf_register_port_provider(pp) != STMF_SUCCESS) {
 471  469                  rc = EIO;
 472  470                  goto tear_down_and_return;
 473  471          }
 474  472  
 475  473          pppt_global.global_dispatch_taskq = taskq_create("pppt_dispatch",
 476  474              1, minclsyspri, 1, INT_MAX, TASKQ_PREPOPULATE);
 477  475  
 478  476          pppt_global.global_sess_taskq = taskq_create("pppt_session",
 479  477              1, minclsyspri, 1, INT_MAX, TASKQ_PREPOPULATE);
 480  478  
 481  479          return (0);
 482  480  
 483  481  tear_down_and_return:
 484  482  
 485  483          if (pppt_global.global_sess_taskq) {
 486  484                  taskq_destroy(pppt_global.global_sess_taskq);
 487  485                  pppt_global.global_sess_taskq = NULL;
 488  486          }
 489  487  
 490  488          if (pppt_global.global_dispatch_taskq) {
 491  489                  taskq_destroy(pppt_global.global_dispatch_taskq);
 492  490                  pppt_global.global_dispatch_taskq = NULL;
 493  491          }
 494  492  
 495  493          if (pppt_global.global_pp)
 496  494                  pppt_global.global_pp = NULL;
 497  495  
 498  496          if (pp)
 499  497                  stmf_free(pp);
 500  498  
 501  499          if (pppt_global.global_dbuf_store) {
 502  500                  stmf_free(pppt_global.global_dbuf_store);
 503  501                  pppt_global.global_dbuf_store = NULL;
 504  502          }
 505  503  
 506  504          avl_destroy(&pppt_global.global_sess_list);
 507  505          avl_destroy(&pppt_global.global_target_list);
 508  506  
 509  507          return (rc);
 510  508  }
 511  509  
 512  510  /*
 513  511   * pppt_disable_svc
 514  512   *
 515  513   * clean up all existing sessions and deregister targets from STMF
 516  514   */
 517  515  static void
 518  516  pppt_disable_svc(void)
 519  517  {
 520  518          pppt_tgt_t      *tgt, *next_tgt;
 521  519          avl_tree_t      delete_target_list;
 522  520  
 523  521          ASSERT(pppt_global.global_svc_state == PSS_DISABLING);
 524  522  
 525  523          avl_create(&delete_target_list,
 526  524              pppt_tgt_avl_compare, sizeof (pppt_tgt_t),
 527  525              offsetof(pppt_tgt_t, target_global_ln));
 528  526  
 529  527          PPPT_GLOBAL_LOCK();
 530  528          for (tgt = avl_first(&pppt_global.global_target_list);
 531  529              tgt != NULL;
 532  530              tgt = next_tgt) {
 533  531                  next_tgt = AVL_NEXT(&pppt_global.global_target_list, tgt);
 534  532                  avl_remove(&pppt_global.global_target_list, tgt);
 535  533                  avl_add(&delete_target_list, tgt);
 536  534                  pppt_tgt_async_delete(tgt);
 537  535          }
 538  536          PPPT_GLOBAL_UNLOCK();
 539  537  
 540  538          for (tgt = avl_first(&delete_target_list);
 541  539              tgt != NULL;
 542  540              tgt = next_tgt) {
 543  541                  next_tgt = AVL_NEXT(&delete_target_list, tgt);
 544  542                  mutex_enter(&tgt->target_mutex);
 545  543                  while ((tgt->target_refcount > 0) ||
 546  544                      (tgt->target_state != TS_DELETING)) {
 547  545                          cv_wait(&tgt->target_cv, &tgt->target_mutex);
 548  546                  }
 549  547                  mutex_exit(&tgt->target_mutex);
 550  548  
 551  549                  avl_remove(&delete_target_list, tgt);
 552  550                  pppt_tgt_destroy(tgt);
 553  551          }
 554  552  
 555  553          taskq_destroy(pppt_global.global_sess_taskq);
 556  554  
 557  555          taskq_destroy(pppt_global.global_dispatch_taskq);
 558  556  
 559  557          avl_destroy(&pppt_global.global_sess_list);
 560  558          avl_destroy(&pppt_global.global_target_list);
 561  559  
 562  560          (void) stmf_deregister_port_provider(pppt_global.global_pp);
 563  561  
 564  562          stmf_free(pppt_global.global_dbuf_store);
 565  563          pppt_global.global_dbuf_store = NULL;
 566  564  
 567  565          stmf_free(pppt_global.global_pp);
 568  566          pppt_global.global_pp = NULL;
 569  567  }
 570  568  
 571  569  /*
 572  570   * STMF callbacks
 573  571   */
 574  572  
 575  573  /*ARGSUSED*/
 576  574  static stmf_data_buf_t *
 577  575  pppt_dbuf_alloc(scsi_task_t *task, uint32_t size, uint32_t *pminsize,
 578  576      uint32_t flags)
 579  577  {
 580  578          stmf_data_buf_t *result;
 581  579          pppt_buf_t      *pbuf;
 582  580          uint8_t         *buf;
 583  581  
 584  582          /* Get buffer */
 585  583          buf = kmem_alloc(size, KM_SLEEP);
 586  584  
 587  585          /*
 588  586           *  Allocate stmf buf with private port provider section
 589  587           * (pppt_buf_t)
 590  588           */
 591  589          result = stmf_alloc(STMF_STRUCT_DATA_BUF, sizeof (pppt_buf_t), 0);
 592  590          if (result != NULL) {
 593  591                  /* Fill in pppt_buf_t */
 594  592                  pbuf = result->db_port_private;
 595  593                  pbuf->pbuf_stmf_buf = result;
 596  594                  pbuf->pbuf_is_immed = B_FALSE;
 597  595  
 598  596                  /*
 599  597                   * Fill in stmf_data_buf_t.  DB_DONT CACHE tells
 600  598                   * stmf not to cache buffers but STMF doesn't do
 601  599                   * that yet so it's a no-op.  Port providers like
 602  600                   * FC and SRP that have buffers associated with the
 603  601                   * target port would want to let STMF cache
 604  602                   * the buffers.  Port providers like iSCSI would
 605  603                   * not want STMF to cache because the buffers are
 606  604                   * really associated with a connection, not an
 607  605                   * STMF target port so there is no way for STMF
 608  606                   * to cache the buffers effectively.  These port
 609  607                   * providers should cache buffers internally if
 610  608                   * there is significant buffer setup overhead.
 611  609                   *
 612  610                   * And of course, since STMF doesn't do any internal
 613  611                   * caching right now anyway, all port providers should
 614  612                   * do what they can to minimize buffer setup overhead.
 615  613                   */
 616  614                  result->db_flags = DB_DONT_CACHE;
 617  615                  result->db_buf_size = size;
 618  616                  result->db_data_size = size;
 619  617                  result->db_sglist_length = 1;
 620  618                  result->db_sglist[0].seg_addr = buf;
 621  619                  result->db_sglist[0].seg_length = size;
 622  620                  return (result);
 623  621          } else {
 624  622                  /*
 625  623                   * Couldn't get the stmf_data_buf_t so free the
 626  624                   * buffer
 627  625                   */
 628  626                  kmem_free(buf, size);
 629  627          }
 630  628  
 631  629          return (NULL);
 632  630  }
 633  631  
 634  632  /*ARGSUSED*/
 635  633  static void
 636  634  pppt_dbuf_free(stmf_dbuf_store_t *ds, stmf_data_buf_t *dbuf)
 637  635  {
 638  636          pppt_buf_t *pbuf = dbuf->db_port_private;
 639  637  
 640  638          if (pbuf->pbuf_is_immed) {
 641  639                  stmf_ic_msg_free(pbuf->pbuf_immed_msg);
 642  640          } else {
 643  641                  kmem_free(dbuf->db_sglist[0].seg_addr,
 644  642                      dbuf->db_sglist[0].seg_length);
 645  643                  stmf_free(dbuf);
 646  644          }
 647  645  }
 648  646  
 649  647  /*ARGSUSED*/
 650  648  stmf_status_t
 651  649  pppt_lport_xfer_data(scsi_task_t *task, stmf_data_buf_t *dbuf,
 652  650      uint32_t ioflags)
 653  651  {
 654  652          pppt_task_t             *pppt_task = task->task_port_private;
 655  653          pppt_buf_t              *pbuf = dbuf->db_port_private;
 656  654          stmf_ic_msg_t           *msg;
 657  655          stmf_ic_msg_status_t    ic_msg_status;
 658  656  
 659  657          /*
 660  658           * If we are aborting then we can ignore this request, otherwise
 661  659           * add a reference.
 662  660           */
 663  661          if (pppt_task_hold(pppt_task) != PPPT_STATUS_SUCCESS) {
 664  662                  return (STMF_SUCCESS);
 665  663          }
 666  664  
 667  665          /*
 668  666           * If it's not immediate data then start the transfer
 669  667           */
 670  668          ASSERT(pbuf->pbuf_is_immed == B_FALSE);
 671  669          if (dbuf->db_flags & DB_DIRECTION_TO_RPORT) {
 672  670  
 673  671                  /* Send read data */
 674  672                  msg = stmf_ic_scsi_data_msg_alloc(
 675  673                      pppt_task->pt_task_id,
 676  674                      pppt_task->pt_sess->ps_session_id,
 677  675                      pppt_task->pt_lun_id,
 678  676                      dbuf->db_sglist[0].seg_length,
 679  677                      dbuf->db_sglist[0].seg_addr, 0);
 680  678  
 681  679                  pppt_task->pt_read_buf = pbuf;
 682  680                  pppt_task->pt_read_xfer_msgid = msg->icm_msgid;
 683  681  
 684  682                  ic_msg_status = stmf_ic_tx_msg(msg);
 685  683                  pppt_task_rele(pppt_task);
 686  684                  if (ic_msg_status != STMF_IC_MSG_SUCCESS) {
 687  685                          return (STMF_FAILURE);
 688  686                  } else {
 689  687                          return (STMF_SUCCESS);
 690  688                  }
 691  689          } else if (dbuf->db_flags & DB_DIRECTION_FROM_RPORT) {
 692  690                  pppt_task_rele(pppt_task);
 693  691                  return (STMF_FAILURE);
 694  692          }
 695  693  
 696  694          pppt_task_rele(pppt_task);
 697  695  
 698  696          return (STMF_INVALID_ARG);
 699  697  }
 700  698  
 701  699  void
 702  700  pppt_xfer_read_complete(pppt_task_t *pppt_task, stmf_status_t status)
 703  701  {
 704  702          pppt_buf_t              *pppt_buf;
 705  703          stmf_data_buf_t         *dbuf;
 706  704  
 707  705          /*
 708  706           * Caller should have taken a task hold (likely via pppt_task_lookup)
 709  707           *
 710  708           * Get pppt_buf_t and stmf_data_buf_t pointers
 711  709           */
 712  710          pppt_buf = pppt_task->pt_read_buf;
 713  711          dbuf = pppt_buf->pbuf_stmf_buf;
 714  712          dbuf->db_xfer_status = (status == STMF_SUCCESS) ?
 715  713              STMF_SUCCESS : STMF_FAILURE;
 716  714  
 717  715          /*
 718  716           * COMSTAR currently requires port providers to support
 719  717           * the DB_SEND_STATUS_GOOD flag even if phase collapse is
 720  718           * not supported.  So we will roll our own... pretend we are
 721  719           * COMSTAR and ask for a status message.
 722  720           */
 723  721          if ((dbuf->db_flags & DB_SEND_STATUS_GOOD) &&
 724  722              (status == STMF_SUCCESS)) {
 725  723                  /*
 726  724                   * It's possible the task has been aborted since the time we
 727  725                   * looked it up.  We need to release the hold before calling
 728  726                   * pppt_lport_send_status and as soon as we release the hold
 729  727                   * the task may disappear.  Calling pppt_task_done allows us
 730  728                   * to determine whether the task has been aborted (in which
 731  729                   * case we will stop processing and return) and mark the task
 732  730                   * "done" which will prevent the task from being aborted while
 733  731                   * we are trying to send the status.
 734  732                   */
 735  733                  if (pppt_task_done(pppt_task) != PPPT_STATUS_SUCCESS) {
 736  734                          /* STMF will free task and buffer(s) */
 737  735                          pppt_task_rele(pppt_task);
 738  736                          return;
 739  737                  }
 740  738                  pppt_task_rele(pppt_task);
 741  739  
 742  740                  if (pppt_lport_send_status(pppt_task->pt_stmf_task, 0)
 743  741                      != STMF_SUCCESS) {
 744  742                          /* Failed to send status */
 745  743                          dbuf->db_xfer_status = STMF_FAILURE;
 746  744                          stmf_data_xfer_done(pppt_task->pt_stmf_task, dbuf,
 747  745                              STMF_IOF_LPORT_DONE);
 748  746                  }
 749  747          } else {
 750  748                  pppt_task_rele(pppt_task);
 751  749                  stmf_data_xfer_done(pppt_task->pt_stmf_task, dbuf, 0);
 752  750          }
 753  751  }
 754  752  
 755  753  /*ARGSUSED*/
 756  754  stmf_status_t
 757  755  pppt_lport_send_status(scsi_task_t *task, uint32_t ioflags)
 758  756  {
 759  757          pppt_task_t *ptask =            task->task_port_private;
 760  758          stmf_ic_msg_t                   *msg;
 761  759          stmf_ic_msg_status_t            ic_msg_status;
 762  760  
 763  761          /*
 764  762           * Mark task completed.  If the state indicates it was aborted
 765  763           * then we don't need to respond.
 766  764           */
 767  765          if (pppt_task_done(ptask) == PPPT_STATUS_ABORTED) {
 768  766                  return (STMF_SUCCESS);
 769  767          }
 770  768  
 771  769          /*
 772  770           * Send status.
 773  771           */
 774  772          msg = stmf_ic_scsi_status_msg_alloc(
 775  773              ptask->pt_task_id,
 776  774              ptask->pt_sess->ps_session_id,
 777  775              ptask->pt_lun_id,
 778  776              0,
 779  777              task->task_scsi_status,
 780  778              task->task_status_ctrl, task->task_resid,
 781  779              task->task_sense_length, task->task_sense_data, 0);
 782  780  
 783  781          ic_msg_status = stmf_ic_tx_msg(msg);
 784  782  
 785  783          if (ic_msg_status != STMF_IC_MSG_SUCCESS) {
 786  784                  pppt_task_sent_status(ptask);
 787  785                  stmf_send_status_done(ptask->pt_stmf_task,
 788  786                      STMF_FAILURE, STMF_IOF_LPORT_DONE);
 789  787                  return (STMF_FAILURE);
 790  788          } else {
 791  789                  pppt_task_sent_status(ptask);
 792  790                  stmf_send_status_done(ptask->pt_stmf_task,
 793  791                      STMF_SUCCESS, STMF_IOF_LPORT_DONE);
  
    | 
      ↓ open down ↓ | 
    648 lines elided | 
    
      ↑ open up ↑ | 
  
 794  792                  return (STMF_SUCCESS);
 795  793          }
 796  794  }
 797  795  
 798  796  void
 799  797  pppt_lport_task_free(scsi_task_t *task)
 800  798  {
 801  799          pppt_task_t *ptask = task->task_port_private;
 802  800          pppt_sess_t *ps = ptask->pt_sess;
 803  801  
 804      -        pppt_task_free(ptask);
      802 +        pppt_task_rele(ptask);
 805  803          pppt_sess_rele(ps);
 806  804  }
 807  805  
 808  806  /*ARGSUSED*/
 809  807  stmf_status_t
 810  808  pppt_lport_abort(stmf_local_port_t *lport, int abort_cmd, void *arg,
 811  809      uint32_t flags)
 812  810  {
 813  811          scsi_task_t     *st = (scsi_task_t *)arg;
 814  812          pppt_task_t     *ptask;
 815  813  
 816  814          ptask = st->task_port_private;
 817  815  
 818  816          if (pppt_task_try_abort(ptask) == PPPT_STATUS_DONE) {
 819  817                  /*
 820  818                   * This task is beyond the point where abort makes sense
 821  819                   * and we will soon be sending status.  Tell STMF to
 822  820                   * go away.
 823  821                   */
 824  822                  return (STMF_BUSY);
 825  823          } else {
 826  824                  return (STMF_ABORT_SUCCESS);
 827  825          }
 828  826          /*NOTREACHED*/
 829  827  }
 830  828  
 831  829  /*ARGSUSED*/
 832  830  void
 833  831  pppt_lport_ctl(stmf_local_port_t *lport, int cmd, void *arg)
 834  832  {
 835  833          switch (cmd) {
 836  834          case STMF_CMD_LPORT_ONLINE:
 837  835          case STMF_CMD_LPORT_OFFLINE:
 838  836          case STMF_ACK_LPORT_ONLINE_COMPLETE:
 839  837          case STMF_ACK_LPORT_OFFLINE_COMPLETE:
 840  838                  pppt_tgt_sm_ctl(lport, cmd, arg);
 841  839                  break;
 842  840  
 843  841          default:
 844  842                  ASSERT(0);
 845  843                  break;
 846  844          }
 847  845  }
 848  846  
 849  847  pppt_sess_t *
 850  848  pppt_sess_lookup_locked(uint64_t session_id,
 851  849      scsi_devid_desc_t *lport_devid, stmf_remote_port_t *rport)
 852  850  {
 853  851          pppt_tgt_t                              *tgt;
 854  852          pppt_sess_t                             *ps;
 855  853          int                                     lport_cmp;
 856  854  
 857  855          ASSERT(mutex_owned(&pppt_global.global_lock));
 858  856  
 859  857          /*
 860  858           * Look for existing session for this ID
 861  859           */
 862  860          ps = pppt_sess_lookup_by_id_locked(session_id);
 863  861          if (ps == NULL) {
 864  862                  PPPT_INC_STAT(es_sess_lookup_no_session);
 865  863                  return (NULL);
 866  864          }
 867  865  
 868  866          tgt = ps->ps_target;
 869  867  
 870  868          mutex_enter(&tgt->target_mutex);
 871  869  
 872  870          /* Validate local/remote port names */
 873  871          if ((lport_devid->ident_length !=
 874  872              tgt->target_stmf_lport->lport_id->ident_length) ||
 875  873              (rport->rport_tptid_sz !=
 876  874              ps->ps_stmf_sess->ss_rport->rport_tptid_sz)) {
 877  875                  mutex_exit(&tgt->target_mutex);
 878  876                  PPPT_INC_STAT(es_sess_lookup_ident_mismatch);
 879  877                  return (NULL);
 880  878          } else {
 881  879                  lport_cmp = bcmp(lport_devid->ident,
 882  880                      tgt->target_stmf_lport->lport_id->ident,
 883  881                      lport_devid->ident_length);
 884  882                  if (lport_cmp != 0 ||
 885  883                      (stmf_scsilib_tptid_compare(rport->rport_tptid,
 886  884                      ps->ps_stmf_sess->ss_rport->rport_tptid) != B_TRUE)) {
 887  885                          mutex_exit(&tgt->target_mutex);
 888  886                          PPPT_INC_STAT(es_sess_lookup_ident_mismatch);
 889  887                          return (NULL);
 890  888                  }
 891  889  
 892  890                  if (tgt->target_state != TS_STMF_ONLINE) {
 893  891                          mutex_exit(&tgt->target_mutex);
 894  892                          PPPT_INC_STAT(es_sess_lookup_bad_tgt_state);
 895  893                          return (NULL);
 896  894                  }
 897  895          }
 898  896          mutex_exit(&tgt->target_mutex);
 899  897  
 900  898          return (ps);
 901  899  }
 902  900  
 903  901  pppt_sess_t *
 904  902  pppt_sess_lookup_by_id_locked(uint64_t session_id)
 905  903  {
 906  904          pppt_sess_t             tmp_ps;
 907  905          pppt_sess_t             *ps;
 908  906  
 909  907          ASSERT(mutex_owned(&pppt_global.global_lock));
 910  908          tmp_ps.ps_session_id = session_id;
 911  909          tmp_ps.ps_closed = 0;
 912  910          ps = avl_find(&pppt_global.global_sess_list, &tmp_ps, NULL);
 913  911          if (ps != NULL) {
 914  912                  mutex_enter(&ps->ps_mutex);
 915  913                  if (!ps->ps_closed) {
 916  914                          ps->ps_refcnt++;
 917  915                          mutex_exit(&ps->ps_mutex);
 918  916                          return (ps);
 919  917                  }
 920  918                  mutex_exit(&ps->ps_mutex);
 921  919          }
 922  920  
 923  921          return (NULL);
 924  922  }
 925  923  
 926  924  /* New session */
 927  925  pppt_sess_t *
 928  926  pppt_sess_lookup_create(scsi_devid_desc_t *lport_devid,
 929  927      scsi_devid_desc_t *rport_devid, stmf_remote_port_t *rport,
 930  928      uint64_t session_id, stmf_status_t *statusp)
 931  929  {
 932  930          pppt_tgt_t              *tgt;
 933  931          pppt_sess_t             *ps;
 934  932          stmf_scsi_session_t     *ss;
 935  933          pppt_sess_t             tmp_ps;
 936  934          stmf_scsi_session_t     tmp_ss;
 937  935          *statusp = STMF_SUCCESS;
 938  936  
 939  937          PPPT_GLOBAL_LOCK();
 940  938  
 941  939          /*
 942  940           * Look for existing session for this ID
 943  941           */
 944  942          ps = pppt_sess_lookup_locked(session_id, lport_devid, rport);
 945  943  
 946  944          if (ps != NULL) {
 947  945                  PPPT_GLOBAL_UNLOCK();
 948  946                  return (ps);
 949  947          }
 950  948  
 951  949          /*
 952  950           * No session with that ID, look for another session corresponding
 953  951           * to the same IT nexus.
 954  952           */
 955  953          tgt = pppt_tgt_lookup_locked(lport_devid);
 956  954          if (tgt == NULL) {
 957  955                  *statusp = STMF_NOT_FOUND;
 958  956                  PPPT_GLOBAL_UNLOCK();
 959  957                  return (NULL);
 960  958          }
 961  959  
 962  960          mutex_enter(&tgt->target_mutex);
 963  961          if (tgt->target_state != TS_STMF_ONLINE) {
 964  962                  *statusp = STMF_NOT_FOUND;
 965  963                  mutex_exit(&tgt->target_mutex);
 966  964                  PPPT_GLOBAL_UNLOCK();
 967  965                  /* Can't create session to offline target */
 968  966                  return (NULL);
 969  967          }
 970  968  
 971  969          bzero(&tmp_ps, sizeof (tmp_ps));
 972  970          bzero(&tmp_ss, sizeof (tmp_ss));
 973  971          tmp_ps.ps_stmf_sess = &tmp_ss;
 974  972          tmp_ss.ss_rport = rport;
 975  973  
 976  974          /*
 977  975           * Look for an existing session on this IT nexus
 978  976           */
 979  977          ps = avl_find(&tgt->target_sess_list, &tmp_ps, NULL);
 980  978  
 981  979          if (ps != NULL) {
 982  980                  /*
 983  981                   * Now check the session ID.  It should not match because if
 984  982                   * it did we would have found it on the global session list.
 985  983                   * If the session ID in the command is higher than the existing
 986  984                   * session ID then we need to tear down the existing session.
 987  985                   */
 988  986                  mutex_enter(&ps->ps_mutex);
 989  987                  ASSERT(ps->ps_session_id != session_id);
 990  988                  if (ps->ps_session_id > session_id) {
 991  989                          /* Invalid session ID */
 992  990                          mutex_exit(&ps->ps_mutex);
 993  991                          mutex_exit(&tgt->target_mutex);
 994  992                          PPPT_GLOBAL_UNLOCK();
 995  993                          *statusp = STMF_INVALID_ARG;
 996  994                          return (NULL);
 997  995                  } else {
 998  996                          /* Existing session needs to be invalidated */
 999  997                          if (!ps->ps_closed) {
1000  998                                  pppt_sess_close_locked(ps);
1001  999                          }
1002 1000                  }
1003 1001                  mutex_exit(&ps->ps_mutex);
1004 1002  
1005 1003                  /* Fallthrough and create new session */
1006 1004          }
1007 1005  
1008 1006          /*
1009 1007           * Allocate and fill in pppt_session_t with the appropriate data
1010 1008           * for the protocol.
1011 1009           */
1012 1010          ps = kmem_zalloc(sizeof (*ps), KM_SLEEP);
1013 1011  
1014 1012          /* Fill in session fields */
1015 1013          ps->ps_target = tgt;
1016 1014          ps->ps_session_id = session_id;
1017 1015  
1018 1016          ss = stmf_alloc(STMF_STRUCT_SCSI_SESSION, 0,
1019 1017              0);
1020 1018          if (ss == NULL) {
1021 1019                  mutex_exit(&tgt->target_mutex);
1022 1020                  PPPT_GLOBAL_UNLOCK();
1023 1021                  kmem_free(ps, sizeof (*ps));
1024 1022                  *statusp = STMF_ALLOC_FAILURE;
1025 1023                  return (NULL);
1026 1024          }
1027 1025  
1028 1026          ss->ss_rport_id = kmem_zalloc(sizeof (scsi_devid_desc_t) +
1029 1027              rport_devid->ident_length + 1, KM_SLEEP);
1030 1028          bcopy(rport_devid, ss->ss_rport_id,
1031 1029              sizeof (scsi_devid_desc_t) + rport_devid->ident_length + 1);
1032 1030  
1033 1031          ss->ss_lport = tgt->target_stmf_lport;
1034 1032  
1035 1033          ss->ss_rport = stmf_remote_port_alloc(rport->rport_tptid_sz);
1036 1034          bcopy(rport->rport_tptid, ss->ss_rport->rport_tptid,
1037 1035              rport->rport_tptid_sz);
1038 1036  
1039 1037          if (stmf_register_scsi_session(tgt->target_stmf_lport, ss) !=
1040 1038              STMF_SUCCESS) {
1041 1039                  mutex_exit(&tgt->target_mutex);
1042 1040                  PPPT_GLOBAL_UNLOCK();
1043 1041                  kmem_free(ss->ss_rport_id,
1044 1042                      sizeof (scsi_devid_desc_t) + rport_devid->ident_length + 1);
1045 1043                  stmf_remote_port_free(ss->ss_rport);
1046 1044                  stmf_free(ss);
1047 1045                  kmem_free(ps, sizeof (*ps));
1048 1046                  *statusp = STMF_TARGET_FAILURE;
1049 1047                  return (NULL);
1050 1048          }
1051 1049  
1052 1050          ss->ss_port_private = ps;
1053 1051          mutex_init(&ps->ps_mutex, NULL, MUTEX_DEFAULT, NULL);
1054 1052          cv_init(&ps->ps_cv, NULL, CV_DEFAULT, NULL);
1055 1053          avl_create(&ps->ps_task_list, pppt_task_avl_compare,
1056 1054              sizeof (pppt_task_t), offsetof(pppt_task_t, pt_sess_ln));
1057 1055          ps->ps_refcnt = 1;
1058 1056          ps->ps_stmf_sess = ss;
1059 1057          avl_add(&tgt->target_sess_list, ps);
1060 1058          avl_add(&pppt_global.global_sess_list, ps);
1061 1059          mutex_exit(&tgt->target_mutex);
1062 1060          PPPT_GLOBAL_UNLOCK();
1063 1061          stmf_trace("pppt", "New session %p", (void *)ps);
1064 1062  
1065 1063          return (ps);
1066 1064  }
1067 1065  
1068 1066  void
1069 1067  pppt_sess_rele(pppt_sess_t *ps)
1070 1068  {
1071 1069          mutex_enter(&ps->ps_mutex);
1072 1070          pppt_sess_rele_locked(ps);
1073 1071          mutex_exit(&ps->ps_mutex);
1074 1072  }
1075 1073  
1076 1074  void
1077 1075  pppt_sess_rele_locked(pppt_sess_t *ps)
1078 1076  {
1079 1077          ASSERT(mutex_owned(&ps->ps_mutex));
1080 1078          ps->ps_refcnt--;
1081 1079          if (ps->ps_refcnt == 0) {
1082 1080                  cv_signal(&ps->ps_cv);
1083 1081          }
1084 1082  }
1085 1083  
1086 1084  static void pppt_sess_destroy_task(void *ps_void)
1087 1085  {
1088 1086          pppt_sess_t *ps = ps_void;
1089 1087          stmf_scsi_session_t     *ss;
1090 1088  
1091 1089          stmf_trace("pppt", "Session destroy task %p", (void *)ps);
1092 1090  
1093 1091          ss = ps->ps_stmf_sess;
1094 1092          mutex_enter(&ps->ps_mutex);
1095 1093          stmf_deregister_scsi_session(ss->ss_lport, ss);
1096 1094          kmem_free(ss->ss_rport_id,
1097 1095              sizeof (scsi_devid_desc_t) + ss->ss_rport_id->ident_length + 1);
1098 1096          stmf_remote_port_free(ss->ss_rport);
1099 1097          avl_destroy(&ps->ps_task_list);
1100 1098          mutex_exit(&ps->ps_mutex);
1101 1099          cv_destroy(&ps->ps_cv);
1102 1100          mutex_destroy(&ps->ps_mutex);
1103 1101          stmf_free(ps->ps_stmf_sess);
1104 1102          kmem_free(ps, sizeof (*ps));
1105 1103  
1106 1104          stmf_trace("pppt", "Session destroy task complete %p", (void *)ps);
1107 1105  }
1108 1106  
1109 1107  int
1110 1108  pppt_sess_avl_compare_by_id(const void *void_sess1, const void *void_sess2)
1111 1109  {
1112 1110          const   pppt_sess_t     *psess1 = void_sess1;
1113 1111          const   pppt_sess_t     *psess2 = void_sess2;
1114 1112  
1115 1113          if (psess1->ps_session_id < psess2->ps_session_id)
1116 1114                  return (-1);
1117 1115          else if (psess1->ps_session_id > psess2->ps_session_id)
1118 1116                  return (1);
1119 1117  
1120 1118          /* Allow multiple duplicate sessions if one is closed */
1121 1119          ASSERT(!(psess1->ps_closed && psess2->ps_closed));
1122 1120          if (psess1->ps_closed)
1123 1121                  return (-1);
1124 1122          else if (psess2->ps_closed)
1125 1123                  return (1);
1126 1124  
1127 1125          return (0);
1128 1126  }
1129 1127  
1130 1128  int
1131 1129  pppt_sess_avl_compare_by_name(const void *void_sess1, const void *void_sess2)
1132 1130  {
1133 1131          const   pppt_sess_t     *psess1 = void_sess1;
1134 1132          const   pppt_sess_t     *psess2 = void_sess2;
1135 1133          int                     result;
1136 1134  
1137 1135          /* Compare by tptid size */
1138 1136          if (psess1->ps_stmf_sess->ss_rport->rport_tptid_sz <
1139 1137              psess2->ps_stmf_sess->ss_rport->rport_tptid_sz) {
1140 1138                  return (-1);
1141 1139          } else if (psess1->ps_stmf_sess->ss_rport->rport_tptid_sz >
1142 1140              psess2->ps_stmf_sess->ss_rport->rport_tptid_sz) {
1143 1141                  return (1);
1144 1142          }
1145 1143  
1146 1144          /* Now compare tptid */
1147 1145          result = memcmp(psess1->ps_stmf_sess->ss_rport->rport_tptid,
1148 1146              psess2->ps_stmf_sess->ss_rport->rport_tptid,
1149 1147              psess1->ps_stmf_sess->ss_rport->rport_tptid_sz);
1150 1148  
1151 1149          if (result < 0) {
1152 1150                  return (-1);
1153 1151          } else if (result > 0) {
1154 1152                  return (1);
1155 1153          }
1156 1154  
1157 1155          return (0);
1158 1156  }
1159 1157  
1160 1158  void
1161 1159  pppt_sess_close_locked(pppt_sess_t *ps)
1162 1160  {
1163 1161          pppt_tgt_t      *tgt = ps->ps_target;
1164 1162          pppt_task_t     *ptask;
1165 1163  
1166 1164          stmf_trace("pppt", "Session close %p", (void *)ps);
1167 1165  
1168 1166          ASSERT(mutex_owned(&pppt_global.global_lock));
1169 1167          ASSERT(mutex_owned(&tgt->target_mutex));
1170 1168          ASSERT(mutex_owned(&ps->ps_mutex));
1171 1169          ASSERT(!ps->ps_closed); /* Caller should ensure session is not closed */
1172 1170  
1173 1171          ps->ps_closed = B_TRUE;
1174 1172          for (ptask = avl_first(&ps->ps_task_list); ptask != NULL;
1175 1173              ptask = AVL_NEXT(&ps->ps_task_list, ptask)) {
1176 1174                  mutex_enter(&ptask->pt_mutex);
1177 1175                  if (ptask->pt_state == PTS_ACTIVE) {
1178 1176                          stmf_abort(STMF_QUEUE_TASK_ABORT, ptask->pt_stmf_task,
1179 1177                              STMF_ABORTED, NULL);
1180 1178                  }
1181 1179                  mutex_exit(&ptask->pt_mutex);
1182 1180          }
1183 1181  
1184 1182          /*
1185 1183           * Now that all the tasks are aborting the session refcnt should
1186 1184           * go to 0.
1187 1185           */
1188 1186          while (ps->ps_refcnt != 0) {
1189 1187                  cv_wait(&ps->ps_cv, &ps->ps_mutex);
1190 1188          }
1191 1189  
1192 1190          avl_remove(&tgt->target_sess_list, ps);
1193 1191          avl_remove(&pppt_global.global_sess_list, ps);
1194 1192          (void) taskq_dispatch(pppt_global.global_sess_taskq,
1195 1193              &pppt_sess_destroy_task, ps, KM_SLEEP);
1196 1194  
1197 1195          stmf_trace("pppt", "Session close complete %p", (void *)ps);
1198 1196  }
1199 1197  
1200 1198  pppt_task_t *
1201 1199  pppt_task_alloc(void)
  
    | 
      ↓ open down ↓ | 
    387 lines elided | 
    
      ↑ open up ↑ | 
  
1202 1200  {
1203 1201          pppt_task_t     *ptask;
1204 1202          pppt_buf_t      *immed_pbuf;
1205 1203  
1206 1204          ptask = kmem_alloc(sizeof (pppt_task_t) + sizeof (pppt_buf_t) +
1207 1205              sizeof (stmf_data_buf_t), KM_NOSLEEP);
1208 1206          if (ptask != NULL) {
1209 1207                  ptask->pt_state = PTS_INIT;
1210 1208                  ptask->pt_read_buf = NULL;
1211 1209                  ptask->pt_read_xfer_msgid = 0;
1212      -                cv_init(&ptask->pt_cv, NULL, CV_DRIVER, NULL);
     1210 +                ptask->pt_refcnt = 0;
1213 1211                  mutex_init(&ptask->pt_mutex, NULL, MUTEX_DRIVER, NULL);
1214 1212                  immed_pbuf = (pppt_buf_t *)(ptask + 1);
1215 1213                  bzero(immed_pbuf, sizeof (*immed_pbuf));
1216 1214                  immed_pbuf->pbuf_is_immed = B_TRUE;
1217 1215                  immed_pbuf->pbuf_stmf_buf = (stmf_data_buf_t *)(immed_pbuf + 1);
1218 1216  
1219 1217                  bzero(immed_pbuf->pbuf_stmf_buf, sizeof (stmf_data_buf_t));
1220 1218                  immed_pbuf->pbuf_stmf_buf->db_port_private = immed_pbuf;
1221 1219                  immed_pbuf->pbuf_stmf_buf->db_sglist_length = 1;
1222 1220                  immed_pbuf->pbuf_stmf_buf->db_flags = DB_DIRECTION_FROM_RPORT |
1223 1221                      DB_DONT_CACHE;
1224 1222                  ptask->pt_immed_data = immed_pbuf;
  
    | 
      ↓ open down ↓ | 
    2 lines elided | 
    
      ↑ open up ↑ | 
  
1225 1223          }
1226 1224  
1227 1225          return (ptask);
1228 1226  
1229 1227  }
1230 1228  
1231 1229  void
1232 1230  pppt_task_free(pppt_task_t *ptask)
1233 1231  {
1234 1232          mutex_enter(&ptask->pt_mutex);
     1233 +        ASSERT(ptask->pt_refcnt == 0);
1235 1234          mutex_destroy(&ptask->pt_mutex);
1236      -        cv_destroy(&ptask->pt_cv);
1237 1235          kmem_free(ptask, sizeof (pppt_task_t) + sizeof (pppt_buf_t) +
1238 1236              sizeof (stmf_data_buf_t));
1239 1237  }
1240 1238  
1241 1239  pppt_status_t
1242 1240  pppt_task_start(pppt_task_t *ptask)
1243 1241  {
1244 1242          avl_index_t             where;
1245 1243  
1246 1244          ASSERT(ptask->pt_state == PTS_INIT);
1247 1245  
1248 1246          mutex_enter(&ptask->pt_sess->ps_mutex);
1249 1247          mutex_enter(&ptask->pt_mutex);
1250 1248          if (avl_find(&ptask->pt_sess->ps_task_list, ptask, &where) == NULL) {
1251 1249                  pppt_task_update_state(ptask, PTS_ACTIVE);
     1250 +                /* Manually increment refcnt, sincd we hold the mutex... */
     1251 +                ptask->pt_refcnt++;
1252 1252                  avl_insert(&ptask->pt_sess->ps_task_list, ptask, where);
1253 1253                  mutex_exit(&ptask->pt_mutex);
1254 1254                  mutex_exit(&ptask->pt_sess->ps_mutex);
1255 1255                  return (PPPT_STATUS_SUCCESS);
1256 1256          }
1257 1257          mutex_exit(&ptask->pt_mutex);
1258 1258          mutex_exit(&ptask->pt_sess->ps_mutex);
1259 1259  
1260 1260          return (PPPT_STATUS_FAIL);
1261 1261  }
1262 1262  
1263 1263  pppt_status_t
1264 1264  pppt_task_done(pppt_task_t *ptask)
1265 1265  {
1266 1266          pppt_status_t   pppt_status = PPPT_STATUS_SUCCESS;
1267 1267          boolean_t       remove = B_FALSE;
1268 1268  
1269 1269          mutex_enter(&ptask->pt_mutex);
1270 1270  
1271 1271          switch (ptask->pt_state) {
1272 1272          case PTS_ACTIVE:
1273 1273                  remove = B_TRUE;
1274 1274                  pppt_task_update_state(ptask, PTS_DONE);
1275 1275                  break;
1276 1276          case PTS_ABORTED:
1277 1277                  pppt_status = PPPT_STATUS_ABORTED;
1278 1278                  break;
1279 1279          case PTS_DONE:
1280 1280                  /* Repeat calls are OK.  Do nothing, return success */
1281 1281                  break;
  
    | 
      ↓ open down ↓ | 
    20 lines elided | 
    
      ↑ open up ↑ | 
  
1282 1282          default:
1283 1283                  ASSERT(0);
1284 1284          }
1285 1285  
1286 1286          mutex_exit(&ptask->pt_mutex);
1287 1287  
1288 1288          if (remove) {
1289 1289                  mutex_enter(&ptask->pt_sess->ps_mutex);
1290 1290                  avl_remove(&ptask->pt_sess->ps_task_list, ptask);
1291 1291                  mutex_exit(&ptask->pt_sess->ps_mutex);
     1292 +                /* Out of the AVL tree, so drop a reference. */
     1293 +                pppt_task_rele(ptask);
1292 1294          }
1293 1295  
1294 1296          return (pppt_status);
1295 1297  }
1296 1298  
1297 1299  void
1298 1300  pppt_task_sent_status(pppt_task_t *ptask)
1299 1301  {
1300 1302          /*
1301 1303           * If STMF tries to abort a task after the task state changed to
1302 1304           * PTS_DONE (meaning all task processing is complete from
1303 1305           * the port provider perspective) then we return STMF_BUSY
1304 1306           * from pppt_lport_abort.  STMF will return after a short interval
1305 1307           * but our calls to stmf_send_status_done will be ignored since
1306 1308           * STMF is aborting the task.  That's where this state comes in.
1307 1309           * This state essentially says we are calling stmf_send_status_done
1308 1310           * so we will not be touching the task again.  The next time
1309 1311           * STMF calls pppt_lport_abort we will return a success full
1310 1312           * status and the abort will succeed.
1311 1313           */
1312 1314          mutex_enter(&ptask->pt_mutex);
1313 1315          pppt_task_update_state(ptask, PTS_SENT_STATUS);
1314 1316          mutex_exit(&ptask->pt_mutex);
1315 1317  }
1316 1318  
1317 1319  pppt_task_t *
1318 1320  pppt_task_lookup(stmf_ic_msgid_t msgid)
1319 1321  {
1320 1322          pppt_tgt_t      *tgt;
1321 1323          pppt_sess_t     *sess;
1322 1324          pppt_task_t     lookup_task;
1323 1325          pppt_task_t     *result;
1324 1326  
1325 1327          bzero(&lookup_task, sizeof (lookup_task));
1326 1328          lookup_task.pt_task_id = msgid;
1327 1329          PPPT_GLOBAL_LOCK();
1328 1330          for (tgt = avl_first(&pppt_global.global_target_list); tgt != NULL;
1329 1331              tgt = AVL_NEXT(&pppt_global.global_target_list, tgt)) {
1330 1332  
1331 1333                  mutex_enter(&tgt->target_mutex);
1332 1334                  for (sess = avl_first(&tgt->target_sess_list); sess != NULL;
1333 1335                      sess = AVL_NEXT(&tgt->target_sess_list, sess)) {
1334 1336                          mutex_enter(&sess->ps_mutex);
1335 1337                          if ((result = avl_find(&sess->ps_task_list,
1336 1338                              &lookup_task, NULL)) != NULL) {
1337 1339                                  if (pppt_task_hold(result) !=
1338 1340                                      PPPT_STATUS_SUCCESS) {
1339 1341                                          result = NULL;
1340 1342                                  }
1341 1343                                  mutex_exit(&sess->ps_mutex);
1342 1344                                  mutex_exit(&tgt->target_mutex);
1343 1345                                  PPPT_GLOBAL_UNLOCK();
1344 1346                                  return (result);
1345 1347                          }
1346 1348                          mutex_exit(&sess->ps_mutex);
1347 1349                  }
1348 1350                  mutex_exit(&tgt->target_mutex);
1349 1351          }
1350 1352          PPPT_GLOBAL_UNLOCK();
1351 1353  
1352 1354          return (NULL);
1353 1355  }
1354 1356  
1355 1357  static int
1356 1358  pppt_task_avl_compare(const void *void_task1, const void *void_task2)
1357 1359  {
1358 1360          const pppt_task_t       *ptask1 = void_task1;
1359 1361          const pppt_task_t       *ptask2 = void_task2;
1360 1362  
1361 1363          if (ptask1->pt_task_id < ptask2->pt_task_id)
1362 1364                  return (-1);
1363 1365          else if (ptask1->pt_task_id > ptask2->pt_task_id)
1364 1366                  return (1);
1365 1367  
1366 1368          return (0);
1367 1369  }
1368 1370  
1369 1371  static pppt_status_t
1370 1372  pppt_task_try_abort(pppt_task_t *ptask)
1371 1373  {
1372 1374          boolean_t       remove = B_FALSE;
1373 1375          pppt_status_t   pppt_status = PPPT_STATUS_SUCCESS;
1374 1376  
1375 1377          mutex_enter(&ptask->pt_mutex);
1376 1378  
1377 1379          switch (ptask->pt_state) {
1378 1380          case PTS_ACTIVE:
1379 1381                  remove = B_TRUE;
1380 1382                  pppt_task_update_state(ptask, PTS_ABORTED);
1381 1383                  break;
1382 1384          case PTS_DONE:
1383 1385                  pppt_status = PPPT_STATUS_DONE;
1384 1386                  break;
1385 1387          case PTS_SENT_STATUS:
1386 1388                  /*
1387 1389                   * Already removed so leave remove set to B_FALSE
1388 1390                   * and leave status set to PPPT_STATUS_SUCCESS.
1389 1391                   */
1390 1392                  pppt_task_update_state(ptask, PTS_ABORTED);
1391 1393                  break;
1392 1394          case PTS_ABORTED:
1393 1395                  break;
  
    | 
      ↓ open down ↓ | 
    92 lines elided | 
    
      ↑ open up ↑ | 
  
1394 1396          default:
1395 1397                  ASSERT(0);
1396 1398          }
1397 1399  
1398 1400          mutex_exit(&ptask->pt_mutex);
1399 1401  
1400 1402          if (remove) {
1401 1403                  mutex_enter(&ptask->pt_sess->ps_mutex);
1402 1404                  avl_remove(&ptask->pt_sess->ps_task_list, ptask);
1403 1405                  mutex_exit(&ptask->pt_sess->ps_mutex);
     1406 +                /* Out of the AVL tree, so drop a reference. */
     1407 +                pppt_task_rele(ptask);
1404 1408          }
1405 1409  
1406 1410          return (pppt_status);
1407 1411  }
1408 1412  
1409      -static pppt_status_t
     1413 +pppt_status_t
1410 1414  pppt_task_hold(pppt_task_t *ptask)
1411 1415  {
1412 1416          pppt_status_t   pppt_status = PPPT_STATUS_SUCCESS;
1413 1417  
1414 1418          mutex_enter(&ptask->pt_mutex);
1415 1419          if (ptask->pt_state == PTS_ACTIVE) {
1416 1420                  ptask->pt_refcnt++;
1417 1421          } else {
1418 1422                  pppt_status = PPPT_STATUS_FAIL;
1419 1423          }
1420 1424          mutex_exit(&ptask->pt_mutex);
1421 1425  
1422 1426          return (pppt_status);
1423 1427  }
1424 1428  
1425 1429  static void
1426 1430  pppt_task_rele(pppt_task_t *ptask)
1427 1431  {
     1432 +        boolean_t freeit;
     1433 +
1428 1434          mutex_enter(&ptask->pt_mutex);
1429 1435          ptask->pt_refcnt--;
1430      -        cv_signal(&ptask->pt_cv);
     1436 +        freeit = (ptask->pt_refcnt == 0);
1431 1437          mutex_exit(&ptask->pt_mutex);
     1438 +        if (freeit)
     1439 +                pppt_task_free(ptask);
1432 1440  }
1433 1441  
1434 1442  static void
1435 1443  pppt_task_update_state(pppt_task_t *ptask,
1436 1444      pppt_task_state_t new_state)
1437 1445  {
1438 1446          PPPT_LOG(CE_NOTE, "task %p %d -> %d", (void *)ptask,
1439 1447              ptask->pt_state, new_state);
1440 1448  
1441 1449          ASSERT(mutex_owned(&ptask->pt_mutex));
1442 1450          ptask->pt_state = new_state;
1443      -        cv_signal(&ptask->pt_cv);
1444 1451  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX