Print this page
    
re #13365 rb4427 - pppt "mutex_enter: bad mutex" panic (son of 8564)
re #8564, rb4224 "mutex_enter: bad mutex" panic when under heavy load
re #12375 rb4141 Create ALUA Support on NexentaStor; Failover causes loss of storage
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/io/comstar/port/pppt/pppt_msg.c
          +++ new/usr/src/uts/common/io/comstar/port/pppt/pppt_msg.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
  
    | 
      ↓ open down ↓ | 
    10 lines elided | 
    
      ↑ open up ↑ | 
  
  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   23   * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  23      - * Copyright 2013, Nexenta Systems, Inc. All rights reserved.
       24 + * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
  24   25   */
  25   26  
  26   27  #include <sys/cpuvar.h>
  27   28  #include <sys/types.h>
  28   29  #include <sys/conf.h>
  29   30  #include <sys/file.h>
  30   31  #include <sys/ddi.h>
  31   32  #include <sys/sunddi.h>
  32   33  #include <sys/modctl.h>
  33   34  #include <sys/sysmacros.h>
  34   35  
  35   36  #include <sys/socket.h>
  36   37  #include <sys/strsubr.h>
  37   38  #include <sys/door.h>
  38   39  
  39   40  #include <sys/stmf.h>
  40   41  #include <sys/stmf_ioctl.h>
  41   42  #include <sys/portif.h>
  42   43  
  43   44  #include "pppt.h"
  44   45  
  45   46  static void pppt_msg_tgt_register(stmf_ic_msg_t *reg_port);
  46   47  
  47   48  static void pppt_msg_tgt_deregister(stmf_ic_msg_t *msg);
  48   49  
  49   50  static void pppt_msg_session_destroy(stmf_ic_msg_t *msg);
  50   51  
  51   52  static void pppt_msg_scsi_cmd(stmf_ic_msg_t *msg);
  52   53  
  53   54  static void pppt_msg_data_xfer_done(stmf_ic_msg_t *msg);
  54   55  
  55   56  static void pppt_msg_handle_status(stmf_ic_msg_t *msg);
  56   57  
  57   58  void
  58   59  pppt_msg_rx(stmf_ic_msg_t *msg)
  59   60  {
  60   61          switch (msg->icm_msg_type) {
  61   62          case STMF_ICM_REGISTER_PROXY_PORT:
  62   63                  pppt_msg_tgt_register(msg);
  63   64                  break;
  64   65          case STMF_ICM_DEREGISTER_PROXY_PORT:
  65   66                  pppt_msg_tgt_deregister(msg);
  66   67                  break;
  67   68          case STMF_ICM_SESSION_CREATE:
  68   69                  pppt_msg_tx_status(msg, STMF_NOT_SUPPORTED);
  69   70                  stmf_ic_msg_free(msg);
  70   71                  break;
  71   72          case STMF_ICM_SESSION_DESTROY:
  72   73                  pppt_msg_session_destroy(msg);
  73   74                  break;
  74   75          case STMF_ICM_SCSI_CMD:
  75   76                  pppt_msg_scsi_cmd(msg);
  76   77                  break;
  77   78          case STMF_ICM_SCSI_DATA_XFER_DONE:
  78   79                  pppt_msg_data_xfer_done(msg);
  79   80                  break;
  80   81          case STMF_ICM_SCSI_DATA:
  81   82                  /* Ignore, all proxy data will be immediate for now */
  82   83                  pppt_msg_tx_status(msg, STMF_NOT_SUPPORTED);
  83   84                  stmf_ic_msg_free(msg);
  84   85                  break;
  85   86          case STMF_ICM_STATUS:
  86   87                  pppt_msg_handle_status(msg);
  87   88                  break;
  88   89          default:
  89   90                  /* Other message types are not allowed */
  90   91                  ASSERT(0);
  91   92                  break;
  92   93          }
  93   94  }
  94   95  
  95   96  void
  96   97  pppt_msg_tx_status(stmf_ic_msg_t *orig_msg, stmf_status_t status)
  97   98  {
  98   99          stmf_ic_msg_t   *msg;
  99  100  
 100  101          /*
 101  102           * If TX of status fails it should be treated the same as a loss of
 102  103           * connection.  We expect the remote node to handle it.
 103  104           */
 104  105          msg = stmf_ic_status_msg_alloc(status, orig_msg->icm_msg_type,
 105  106              orig_msg->icm_msgid);
 106  107  
 107  108          if (msg != NULL) {
 108  109                  (void) stmf_ic_tx_msg(msg);
 109  110          }
 110  111  }
 111  112  
 112  113  static void
 113  114  pppt_msg_tgt_register(stmf_ic_msg_t *msg)
 114  115  {
 115  116          stmf_ic_reg_port_msg_t  *reg_port;
 116  117          pppt_tgt_t              *result;
 117  118          stmf_status_t           stmf_status;
 118  119  
 119  120          reg_port = msg->icm_msg;
 120  121  
 121  122          PPPT_GLOBAL_LOCK();
 122  123          if (pppt_global.global_svc_state != PSS_ENABLED) {
 123  124                  stmf_status = STMF_FAILURE;
 124  125                  PPPT_INC_STAT(es_tgt_reg_svc_disabled);
 125  126                  goto pppt_register_tgt_done;
 126  127          }
 127  128  
 128  129          /*
 129  130           * For now we assume that the marshall/unmarshall code is responsible
 130  131           * for validating the message length and ensuring the resulting
 131  132           * request structure is self consistent.  Make sure this
 132  133           * target doesn't already exist.
 133  134           */
 134  135          if ((result = pppt_tgt_lookup_locked(reg_port->icrp_port_id)) != NULL) {
 135  136                  stmf_status = STMF_ALREADY;
 136  137                  PPPT_INC_STAT(es_tgt_reg_duplicate);
 137  138                  goto pppt_register_tgt_done;
 138  139          }
 139  140  
 140  141          result = pppt_tgt_create(reg_port, &stmf_status);
 141  142  
 142  143          if (result == NULL) {
 143  144                  stmf_status = STMF_TARGET_FAILURE;
 144  145                  PPPT_INC_STAT(es_tgt_reg_create_fail);
 145  146                  goto pppt_register_tgt_done;
 146  147          }
 147  148  
 148  149          avl_add(&pppt_global.global_target_list, result);
 149  150  
 150  151          stmf_status = STMF_SUCCESS;
 151  152  
 152  153  pppt_register_tgt_done:
 153  154          PPPT_GLOBAL_UNLOCK();
 154  155          pppt_msg_tx_status(msg, stmf_status);
 155  156          stmf_ic_msg_free(msg);
 156  157  }
 157  158  
 158  159  static void
 159  160  pppt_msg_tgt_deregister(stmf_ic_msg_t *msg)
 160  161  {
 161  162          stmf_ic_dereg_port_msg_t        *dereg_port;
 162  163          stmf_status_t                   stmf_status;
 163  164          pppt_tgt_t                      *tgt;
 164  165  
 165  166          PPPT_GLOBAL_LOCK();
 166  167          if (pppt_global.global_svc_state != PSS_ENABLED) {
 167  168                  PPPT_GLOBAL_UNLOCK();
 168  169                  stmf_status = STMF_FAILURE;
 169  170                  PPPT_INC_STAT(es_tgt_dereg_svc_disabled);
 170  171                  goto pppt_deregister_tgt_done;
 171  172          }
 172  173  
 173  174          dereg_port = msg->icm_msg;
 174  175  
 175  176          /* Lookup target */
 176  177          if ((tgt = pppt_tgt_lookup_locked(dereg_port->icdp_port_id)) == NULL) {
 177  178                  PPPT_GLOBAL_UNLOCK();
 178  179                  stmf_status = STMF_NOT_FOUND;
 179  180                  PPPT_INC_STAT(es_tgt_dereg_not_found);
 180  181                  goto pppt_deregister_tgt_done;
 181  182          }
 182  183          avl_remove(&pppt_global.global_target_list, tgt);
 183  184          pppt_tgt_async_delete(tgt);
 184  185  
 185  186          PPPT_GLOBAL_UNLOCK();
 186  187  
 187  188          /* Wait for delete to complete */
 188  189          mutex_enter(&tgt->target_mutex);
 189  190          while ((tgt->target_refcount > 0) ||
 190  191              (tgt->target_state != TS_DELETING)) {
 191  192                  cv_wait(&tgt->target_cv, &tgt->target_mutex);
 192  193          }
 193  194          mutex_exit(&tgt->target_mutex);
 194  195  
 195  196          pppt_tgt_destroy(tgt);
 196  197          stmf_status = STMF_SUCCESS;
 197  198  
 198  199  pppt_deregister_tgt_done:
 199  200          pppt_msg_tx_status(msg, stmf_status);
 200  201          stmf_ic_msg_free(msg);
 201  202  }
 202  203  
 203  204  static void
 204  205  pppt_msg_session_destroy(stmf_ic_msg_t *msg)
 205  206  {
 206  207          stmf_ic_session_create_destroy_msg_t    *sess_destroy;
 207  208          pppt_tgt_t                              *tgt;
 208  209          pppt_sess_t                             *ps;
 209  210  
 210  211          sess_destroy = msg->icm_msg;
 211  212  
 212  213          PPPT_GLOBAL_LOCK();
 213  214  
 214  215          /*
 215  216           * Look for existing session for this ID
 216  217           */
 217  218          ps = pppt_sess_lookup_locked(sess_destroy->icscd_session_id,
 218  219              sess_destroy->icscd_tgt_devid, sess_destroy->icscd_rport);
 219  220  
 220  221          if (ps == NULL) {
 221  222                  PPPT_GLOBAL_UNLOCK();
 222  223                  stmf_ic_msg_free(msg);
 223  224                  PPPT_INC_STAT(es_sess_destroy_no_session);
 224  225                  return;
 225  226          }
 226  227  
 227  228          tgt = ps->ps_target;
 228  229  
 229  230          mutex_enter(&tgt->target_mutex);
 230  231          mutex_enter(&ps->ps_mutex);
 231  232  
 232  233          /* Release the reference from the lookup */
 233  234          pppt_sess_rele_locked(ps);
 234  235  
 235  236          /* Make sure another thread is not already closing the session */
 236  237          if (!ps->ps_closed) {
 237  238                  /* Found matching open session, quiesce... */
 238  239                  pppt_sess_close_locked(ps);
 239  240          }
 240  241          mutex_exit(&ps->ps_mutex);
 241  242          mutex_exit(&tgt->target_mutex);
 242  243          PPPT_GLOBAL_UNLOCK();
 243  244  
 244  245          stmf_ic_msg_free(msg);
 245  246  }
 246  247  
 247  248  static void
 248  249  pppt_msg_scsi_cmd(stmf_ic_msg_t *msg)
 249  250  {
 250  251          pppt_sess_t                     *pppt_sess;
 251  252          pppt_buf_t                      *pbuf;
 252  253          stmf_ic_scsi_cmd_msg_t          *scmd;
 253  254          pppt_task_t                     *ptask;
 254  255          scsi_task_t                     *task;
 255  256          pppt_status_t                   pppt_status;
 256  257          stmf_local_port_t               *lport;
 257  258          stmf_scsi_session_t             *stmf_sess;
 258  259          stmf_status_t                   stmf_status;
 259  260  
 260  261          /*
 261  262           * Get a task context
 262  263           */
 263  264          ptask = pppt_task_alloc();
 264  265          if (ptask == NULL) {
 265  266                  /*
 266  267                   * We must be very low on memory.  Just free the message
 267  268                   * and let the command timeout.
 268  269                   */
 269  270                  stmf_ic_msg_free(msg);
 270  271                  PPPT_INC_STAT(es_scmd_ptask_alloc_fail);
 271  272                  return;
 272  273          }
 273  274  
 274  275          scmd = msg->icm_msg;
 275  276  
 276  277          /*
 277  278           * Session are created implicitly on the first use of an
 278  279           * IT nexus
 279  280           */
 280  281          pppt_sess = pppt_sess_lookup_create(scmd->icsc_tgt_devid,
 281  282              scmd->icsc_ini_devid, scmd->icsc_rport,
 282  283              scmd->icsc_session_id, &stmf_status);
 283  284          if (pppt_sess == NULL) {
 284  285                  pppt_task_free(ptask);
 285  286                  pppt_msg_tx_status(msg, stmf_status);
 286  287                  stmf_ic_msg_free(msg);
 287  288                  PPPT_INC_STAT(es_scmd_sess_create_fail);
 288  289                  return;
 289  290          }
 290  291  
 291  292          ptask->pt_sess = pppt_sess;
 292  293          ptask->pt_task_id = scmd->icsc_task_msgid;
 293  294          stmf_sess = pppt_sess->ps_stmf_sess;
 294  295          lport = stmf_sess->ss_lport;
 295  296  
 296  297          /*
 297  298           * Add task to our internal task set.
 298  299           */
 299  300          pppt_status = pppt_task_start(ptask);
 300  301  
 301  302          if (pppt_status != 0) {
 302  303                  /* Release hold from pppt_sess_lookup_create() */
 303  304                  PPPT_LOG(CE_WARN, "Duplicate taskid from remote node 0x%llx",
 304  305                      (longlong_t)scmd->icsc_task_msgid);
 305  306                  pppt_task_free(ptask);
 306  307                  pppt_sess_rele(pppt_sess);
 307  308                  pppt_msg_tx_status(msg, STMF_ALREADY);
 308  309                  stmf_ic_msg_free(msg);
 309  310                  PPPT_INC_STAT(es_scmd_dup_task_count);
 310  311                  return;
 311  312          }
 312  313  
 313  314          /*
 314  315           * Allocate STMF task context
 315  316           */
 316  317          ptask->pt_stmf_task = stmf_task_alloc(lport, stmf_sess,
 317  318              scmd->icsc_task_lun_no,
 318  319              scmd->icsc_task_cdb_length, 0);
 319  320          if (ptask->pt_stmf_task == NULL) {
 320  321                  /* NOTE: pppt_task_done() will free ptask. */
 321  322                  (void) pppt_task_done(ptask);
 322  323                  pppt_sess_rele(pppt_sess);
 323  324                  pppt_msg_tx_status(msg, STMF_ALLOC_FAILURE);
  
    | 
      ↓ open down ↓ | 
    290 lines elided | 
    
      ↑ open up ↑ | 
  
 324  325                  stmf_ic_msg_free(msg);
 325  326                  PPPT_INC_STAT(es_scmd_stask_alloc_fail);
 326  327                  return;
 327  328          }
 328  329  
 329  330          task = ptask->pt_stmf_task;
 330  331          /* task_port_private reference is a real reference. */
 331  332          (void) pppt_task_hold(ptask);
 332  333          task->task_port_private = ptask;
 333  334          task->task_flags = scmd->icsc_task_flags;
 334      -        task->task_additional_flags = 0;
      335 +        task->task_additional_flags = TASK_AF_PPPT_TASK;
 335  336          task->task_priority = 0;
 336  337  
 337  338          /*
 338  339           * Set task->task_mgmt_function to TM_NONE for a normal SCSI task
 339  340           * or one of these values for a task management command:
 340  341           *
 341  342           * TM_ABORT_TASK ***
 342  343           * TM_ABORT_TASK_SET
 343  344           * TM_CLEAR_ACA
 344  345           * TM_CLEAR_TASK_SET
 345  346           * TM_LUN_RESET
 346  347           * TM_TARGET_WARM_RESET
 347  348           * TM_TARGET_COLD_RESET
 348  349           *
 349  350           * *** Note that STMF does not currently support TM_ABORT_TASK so
 350  351           * port providers must implement this command on their own
 351  352           * (e.g. lookup the desired task and call stmf_abort).
 352  353           */
 353  354          task->task_mgmt_function = scmd->icsc_task_mgmt_function;
 354  355  
 355  356          task->task_max_nbufs = 1; /* Don't allow parallel xfers */
 356  357          task->task_cmd_seq_no = msg->icm_msgid;
 357  358          task->task_expected_xfer_length =
 358  359              scmd->icsc_task_expected_xfer_length;
 359  360  
 360  361          if (scmd->icsc_task_cdb_length) {
 361  362                  bcopy(scmd->icsc_task_cdb, task->task_cdb,
 362  363                      scmd->icsc_task_cdb_length);
 363  364          }
 364  365          bcopy(scmd->icsc_lun_id, ptask->pt_lun_id, 16);
 365  366  
 366  367          if (scmd->icsc_immed_data_len) {
 367  368                  pbuf = ptask->pt_immed_data;
 368  369                  pbuf->pbuf_immed_msg = msg;
 369  370                  pbuf->pbuf_stmf_buf->db_data_size = scmd->icsc_immed_data_len;
 370  371                  pbuf->pbuf_stmf_buf->db_buf_size = scmd->icsc_immed_data_len;
 371  372                  pbuf->pbuf_stmf_buf->db_relative_offset = 0;
 372  373                  pbuf->pbuf_stmf_buf->db_sglist[0].seg_length =
 373  374                      scmd->icsc_immed_data_len;
 374  375                  pbuf->pbuf_stmf_buf->db_sglist[0].seg_addr =
 375  376                      scmd->icsc_immed_data;
 376  377  
 377  378                  stmf_post_task(task, pbuf->pbuf_stmf_buf);
 378  379          } else {
 379  380                  stmf_post_task(task, NULL);
 380  381                  stmf_ic_msg_free(msg);
 381  382          }
 382  383  }
 383  384  
 384  385  static void
 385  386  pppt_msg_data_xfer_done(stmf_ic_msg_t *msg)
 386  387  {
 387  388          pppt_task_t                             *pppt_task;
 388  389          stmf_ic_scsi_data_xfer_done_msg_t       *data_xfer_done;
 389  390  
 390  391          data_xfer_done = msg->icm_msg;
 391  392  
 392  393          /*
 393  394           * Find task
 394  395           */
 395  396          pppt_task = pppt_task_lookup(data_xfer_done->icsx_task_msgid);
 396  397  
 397  398          /* If we found one, complete the transfer */
 398  399          if (pppt_task != NULL) {
 399  400                  pppt_xfer_read_complete(pppt_task, data_xfer_done->icsx_status);
 400  401          }
 401  402  
 402  403          stmf_ic_msg_free(msg);
 403  404  }
 404  405  
 405  406  static void
 406  407  pppt_msg_handle_status(stmf_ic_msg_t *msg)
 407  408  {
 408  409          /* Don't care for now */
 409  410          stmf_ic_msg_free(msg);
 410  411  }
  
    | 
      ↓ open down ↓ | 
    66 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX