1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  23  */
  24 
  25 #include <sys/cpuvar.h>
  26 #include <sys/types.h>
  27 #include <sys/conf.h>
  28 #include <sys/file.h>
  29 #include <sys/ddi.h>
  30 #include <sys/sunddi.h>
  31 #include <sys/modctl.h>
  32 #include <sys/sysmacros.h>
  33 
  34 #include <sys/socket.h>
  35 #include <sys/strsubr.h>
  36 #include <sys/door.h>
  37 #include <sys/note.h>
  38 #include <sys/sdt.h>
  39 
  40 #include <sys/stmf.h>
  41 #include <sys/stmf_ioctl.h>
  42 #include <sys/portif.h>
  43 #define PPPT_TGT_SM_STRINGS
  44 #include "pppt.h"
  45 
  46 typedef struct {
  47         list_node_t             te_ctx_node;
  48         pppt_tgt_event_t        te_ctx_event;
  49 } tgt_event_ctx_t;
  50 
  51 static void
  52 pppt_tgt_sm_event(pppt_tgt_t *tgt, pppt_tgt_event_t event);
  53 
  54 static void
  55 tgt_sm_event_locked(pppt_tgt_t *tgt, pppt_tgt_event_t event);
  56 
  57 static void
  58 tgt_sm_event_dispatch(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx);
  59 
  60 static void
  61 tgt_sm_created(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx);
  62 
  63 static void
  64 tgt_sm_onlining(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx);
  65 
  66 static void
  67 tgt_sm_online(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx);
  68 
  69 static void
  70 tgt_sm_stmf_online(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx);
  71 
  72 static void
  73 tgt_sm_deleting_need_offline(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx);
  74 
  75 static void
  76 tgt_sm_offlining(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx);
  77 
  78 static void
  79 tgt_sm_offline(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx);
  80 
  81 static void
  82 tgt_sm_stmf_offline(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx);
  83 
  84 static void
  85 tgt_sm_deleting_stmf_dereg(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx);
  86 
  87 static void
  88 tgt_sm_deleting_stmf_dereg_fail(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx);
  89 
  90 static void
  91 tgt_sm_deleting(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx);
  92 
  93 static void
  94 pppt_tgt_offline_task(void *arg);
  95 
  96 static void
  97 pppt_tgt_dereg_retry(void *arg);
  98 
  99 static void
 100 pppt_tgt_dereg_task(void *arg);
 101 
 102 static void
 103 tgt_sm_new_state(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx,
 104     pppt_tgt_state_t new_state);
 105 
 106 /*ARGSUSED*/
 107 void
 108 pppt_tgt_sm_ctl(stmf_local_port_t *lport, int cmd, void *arg)
 109 {
 110         pppt_tgt_t              *pppt_tgt;
 111 
 112         pppt_tgt = (pppt_tgt_t *)lport->lport_port_private;
 113 
 114         switch (cmd) {
 115         case STMF_CMD_LPORT_ONLINE:
 116                 pppt_tgt_sm_event(pppt_tgt, TE_STMF_ONLINE_REQ);
 117                 break;
 118         case STMF_CMD_LPORT_OFFLINE:
 119                 pppt_tgt_sm_event(pppt_tgt, TE_STMF_OFFLINE_REQ);
 120                 break;
 121         case STMF_ACK_LPORT_ONLINE_COMPLETE:
 122                 pppt_tgt_sm_event(pppt_tgt, TE_STMF_ONLINE_COMPLETE_ACK);
 123                 break;
 124         case STMF_ACK_LPORT_OFFLINE_COMPLETE:
 125                 pppt_tgt_sm_event(pppt_tgt, TE_STMF_OFFLINE_COMPLETE_ACK);
 126                 break;
 127 
 128         default:
 129                 ASSERT(0);
 130                 break;
 131         }
 132 }
 133 
 134 pppt_tgt_t *
 135 pppt_tgt_create(stmf_ic_reg_port_msg_t *reg_port, stmf_status_t *msg_errcode)
 136 {
 137         pppt_tgt_t              *result;
 138         stmf_local_port_t       *lport;
 139         int                     total_devid_len;
 140 
 141         total_devid_len = sizeof (scsi_devid_desc_t) +
 142             reg_port->icrp_port_id->ident_length - 1;
 143 
 144         /*
 145          * Each target is an STMF local port.  Allocate an STMF local port
 146          * including enough space to store a scsi_devid_desc_t for this target.
 147          */
 148         lport = stmf_alloc(STMF_STRUCT_STMF_LOCAL_PORT,
 149             sizeof (pppt_tgt_t) + total_devid_len, 0);
 150         if (lport == NULL) {
 151                 *msg_errcode = STMF_ALLOC_FAILURE;
 152                 return (NULL);
 153         }
 154 
 155         result = lport->lport_port_private;
 156         result->target_state = TS_CREATED;
 157         /* Use pointer arithmetic to find scsi_devid_desc_t */
 158         result->target_devid = (scsi_devid_desc_t *)(result + 1);
 159         bcopy(reg_port->icrp_port_id, result->target_devid, total_devid_len);
 160         result->target_devid->piv = 1;
 161         result->target_devid->code_set = CODE_SET_ASCII;
 162         result->target_devid->association = ID_IS_TARGET_PORT;
 163 
 164         mutex_init(&result->target_mutex, NULL, MUTEX_DEFAULT, NULL);
 165         cv_init(&result->target_cv, NULL, CV_DEFAULT, NULL);
 166         list_create(&result->target_events, sizeof (tgt_event_ctx_t),
 167             offsetof(tgt_event_ctx_t, te_ctx_node));
 168         avl_create(&result->target_sess_list, pppt_sess_avl_compare_by_name,
 169             sizeof (pppt_sess_t), offsetof(pppt_sess_t, ps_target_ln));
 170 
 171         lport->lport_abort_timeout = 120; /* seconds */
 172         lport->lport_id = result->target_devid;
 173         lport->lport_pp = pppt_global.global_pp;
 174         lport->lport_ds = pppt_global.global_dbuf_store;
 175         lport->lport_xfer_data = &pppt_lport_xfer_data;
 176         lport->lport_send_status = &pppt_lport_send_status;
 177         lport->lport_task_free = &pppt_lport_task_free;
 178         lport->lport_abort = &pppt_lport_abort;
 179         lport->lport_ctl = &pppt_lport_ctl;
 180         result->target_stmf_lport = lport;
 181 
 182         /*
 183          * Since this is a proxy port we need to do set the relative
 184          * target port identifier before registering it with STMF.
 185          */
 186         stmf_set_port_standby(lport, reg_port->icrp_relative_port_id);
 187 
 188         /*
 189          * Register the target with STMF.  STMF may immediately ask us to go
 190          * online so insure any additional config setup is complete.
 191          */
 192         if (stmf_register_local_port(lport) != STMF_SUCCESS) {
 193                 *msg_errcode = STMF_FAILURE;
 194                 pppt_tgt_destroy(result);
 195                 return (NULL);
 196         }
 197 
 198         return (result);
 199 
 200 }
 201 
 202 void
 203 pppt_tgt_destroy(pppt_tgt_t *tgt)
 204 {
 205         /* Destroy target */
 206         avl_destroy(&tgt->target_sess_list);
 207         list_destroy(&tgt->target_events);
 208         cv_destroy(&tgt->target_cv);
 209         mutex_destroy(&tgt->target_mutex);
 210         stmf_free(tgt->target_stmf_lport); /* Also frees "tgt' */
 211 }
 212 
 213 pppt_tgt_t *
 214 pppt_tgt_lookup(scsi_devid_desc_t *tgt_devid)
 215 {
 216         pppt_tgt_t      *result;
 217         PPPT_GLOBAL_LOCK();
 218         result = pppt_tgt_lookup_locked(tgt_devid);
 219         PPPT_GLOBAL_UNLOCK();
 220 
 221         return (result);
 222 }
 223 
 224 pppt_tgt_t *
 225 pppt_tgt_lookup_locked(scsi_devid_desc_t *tgt_devid)
 226 {
 227         pppt_tgt_t      *result;
 228         pppt_tgt_t      tmptgt;
 229 
 230         bzero(&tmptgt, sizeof (tmptgt));
 231         tmptgt.target_devid = tgt_devid;
 232 
 233         result = avl_find(&pppt_global.global_target_list, &tmptgt, NULL);
 234 
 235         return (result);
 236 }
 237 
 238 void
 239 pppt_tgt_async_delete(pppt_tgt_t *tgt)
 240 {
 241         /* Generate TE_DELETE event to target state machine */
 242         pppt_tgt_sm_event(tgt, TE_DELETE);
 243 }
 244 
 245 int
 246 pppt_tgt_avl_compare(const void *void_tgt1, const void *void_tgt2)
 247 {
 248         const   pppt_tgt_t      *ptgt1 = void_tgt1;
 249         const   pppt_tgt_t      *ptgt2 = void_tgt2;
 250         int                     result;
 251 
 252         /* Sort by code set then ident */
 253         if (ptgt1->target_devid->code_set <
 254             ptgt2->target_devid->code_set) {
 255                 return (-1);
 256         } else if (ptgt1->target_devid->code_set >
 257             ptgt2->target_devid->code_set) {
 258                 return (1);
 259         }
 260 
 261         /* Next by ident length */
 262         if (ptgt1->target_devid->ident_length <
 263             ptgt2->target_devid->ident_length) {
 264                 return (-1);
 265         } else if (ptgt1->target_devid->ident_length >
 266             ptgt2->target_devid->ident_length) {
 267                 return (1);
 268         }
 269 
 270         /* Code set and ident length both match, now compare idents */
 271         result = memcmp(ptgt1->target_devid->ident, ptgt2->target_devid->ident,
 272             ptgt1->target_devid->ident_length);
 273 
 274         if (result < 0) {
 275                 return (-1);
 276         } else if (result > 0) {
 277                 return (1);
 278         }
 279 
 280         return (0);
 281 }
 282 
 283 /*
 284  * Target state machine
 285  */
 286 
 287 static void
 288 pppt_tgt_sm_event(pppt_tgt_t *tgt, pppt_tgt_event_t event)
 289 {
 290         mutex_enter(&tgt->target_mutex);
 291         tgt_sm_event_locked(tgt, event);
 292         mutex_exit(&tgt->target_mutex);
 293 }
 294 
 295 static void
 296 tgt_sm_event_locked(pppt_tgt_t *tgt, pppt_tgt_event_t event)
 297 {
 298         tgt_event_ctx_t *ctx;
 299 
 300         event = (event < TE_MAX_EVENT) ? event : TE_UNDEFINED;
 301         DTRACE_PROBE2(pppt__tgt__event, pppt_tgt_t *, tgt,
 302             pppt_tgt_event_t, event);
 303         stmf_trace("pppt", "pppt_tgt_event: tgt %p event %s(%d)",
 304             (void *)tgt, pppt_te_name[event], event);
 305 
 306         tgt->target_refcount++;
 307 
 308         ctx = kmem_zalloc(sizeof (*ctx), KM_SLEEP);
 309 
 310         ctx->te_ctx_event = event;
 311 
 312         list_insert_tail(&tgt->target_events, ctx);
 313 
 314         /*
 315          * Use the target_sm_busy flag to keep the state machine single
 316          * threaded.  This also serves as recursion avoidance since this
 317          * flag will always be set if we call pppt_tgt_sm_event from
 318          * within the state machine code.
 319          */
 320         if (!tgt->target_sm_busy) {
 321                 tgt->target_sm_busy = B_TRUE;
 322                 while (!list_is_empty(&tgt->target_events)) {
 323                         ctx = list_head(&tgt->target_events);
 324                         list_remove(&tgt->target_events, ctx);
 325                         mutex_exit(&tgt->target_mutex);
 326                         tgt_sm_event_dispatch(tgt, ctx);
 327                         mutex_enter(&tgt->target_mutex);
 328                 }
 329                 tgt->target_sm_busy = B_FALSE;
 330 
 331         }
 332 
 333         tgt->target_refcount--;
 334         cv_signal(&tgt->target_cv);
 335 }
 336 
 337 static void
 338 tgt_sm_event_dispatch(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx)
 339 {
 340         stmf_trace("pppt", "pppt_tgt_event_dispatch: tgt %p event %s(%d)",
 341             (void *)tgt, pppt_te_name[ctx->te_ctx_event], ctx->te_ctx_event);
 342 
 343         /* State independent actions */
 344         switch (ctx->te_ctx_event) {
 345         case TE_DELETE:
 346                 tgt->target_deleting = B_TRUE;
 347                 break;
 348         }
 349 
 350         /* State dependent actions */
 351         switch (tgt->target_state) {
 352         case TS_CREATED:
 353                 tgt_sm_created(tgt, ctx);
 354                 break;
 355         case TS_ONLINING:
 356                 tgt_sm_onlining(tgt, ctx);
 357                 break;
 358         case TS_ONLINE:
 359                 tgt_sm_online(tgt, ctx);
 360                 break;
 361         case TS_STMF_ONLINE:
 362                 tgt_sm_stmf_online(tgt, ctx);
 363                 break;
 364         case TS_DELETING_NEED_OFFLINE:
 365                 tgt_sm_deleting_need_offline(tgt, ctx);
 366                 break;
 367         case TS_OFFLINING:
 368                 tgt_sm_offlining(tgt, ctx);
 369                 break;
 370         case TS_OFFLINE:
 371                 tgt_sm_offline(tgt, ctx);
 372                 break;
 373         case TS_STMF_OFFLINE:
 374                 tgt_sm_stmf_offline(tgt, ctx);
 375                 break;
 376         case TS_DELETING_STMF_DEREG:
 377                 tgt_sm_deleting_stmf_dereg(tgt, ctx);
 378                 break;
 379         case TS_DELETING_STMF_DEREG_FAIL:
 380                 tgt_sm_deleting_stmf_dereg_fail(tgt, ctx);
 381                 break;
 382         case TS_DELETING:
 383                 tgt_sm_deleting(tgt, ctx);
 384                 break;
 385         default:
 386                 ASSERT(0);
 387         }
 388 
 389         kmem_free(ctx, sizeof (*ctx));
 390 }
 391 
 392 static void
 393 tgt_sm_created(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx)
 394 {
 395         stmf_change_status_t    scs;
 396 
 397         switch (ctx->te_ctx_event) {
 398         case TE_STMF_ONLINE_REQ:
 399                 tgt_sm_new_state(tgt, ctx, TS_ONLINING);
 400                 break;
 401         case TE_DELETE:
 402                 tgt_sm_new_state(tgt, ctx, TS_DELETING_STMF_DEREG);
 403                 break;
 404         case TE_STMF_OFFLINE_REQ:
 405                 /*
 406                  * We're already offline but update to an equivelant
 407                  * state just to note that STMF talked to us.
 408                  */
 409                 scs.st_completion_status = STMF_SUCCESS;
 410                 scs.st_additional_info = NULL;
 411                 tgt_sm_new_state(tgt, ctx, TS_OFFLINE);
 412                 (void) stmf_ctl(STMF_CMD_LPORT_OFFLINE_COMPLETE,
 413                     tgt->target_stmf_lport, &scs);
 414                 break;
 415         case TE_STMF_ONLINE_COMPLETE_ACK:
 416         case TE_STMF_OFFLINE_COMPLETE_ACK:
 417                 /* Ignore */
 418                 break;
 419         default:
 420                 ASSERT(0);
 421         }
 422 }
 423 
 424 static void
 425 tgt_sm_onlining(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx)
 426 {
 427         stmf_change_status_t    scs;
 428 
 429         switch (ctx->te_ctx_event) {
 430         case TE_ONLINE_SUCCESS:
 431                 tgt_sm_new_state(tgt, ctx, TS_ONLINE);
 432                 break;
 433         case TE_ONLINE_FAIL:
 434                 tgt_sm_new_state(tgt, ctx, TS_STMF_OFFLINE);
 435                 break;
 436         case TE_DELETE:
 437                 /* TE_DELETE is handled in tgt_sm_event_dispatch() */
 438                 break;
 439         case TE_STMF_ONLINE_REQ:
 440         case TE_STMF_OFFLINE_REQ:
 441                 /*
 442                  * We can't complete STMF's request since we are busy going
 443                  * online.
 444                  */
 445                 scs.st_completion_status = STMF_INVALID_ARG;
 446                 scs.st_additional_info = NULL;
 447                 (void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ?
 448                     STMF_CMD_LPORT_ONLINE_COMPLETE :
 449                     STMF_CMD_LPORT_OFFLINE_COMPLETE,
 450                     tgt->target_stmf_lport, &scs);
 451                 break;
 452         case TE_STMF_ONLINE_COMPLETE_ACK:
 453         case TE_STMF_OFFLINE_COMPLETE_ACK:
 454                 /* Ignore */
 455                 break;
 456         default:
 457                 ASSERT(0);
 458         }
 459 }
 460 
 461 static void
 462 tgt_sm_online(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx)
 463 {
 464         stmf_change_status_t    scs;
 465 
 466         switch (ctx->te_ctx_event) {
 467         case TE_STMF_ONLINE_COMPLETE_ACK:
 468                 if (tgt->target_deleting) {
 469                         tgt_sm_new_state(tgt, ctx, TS_DELETING_NEED_OFFLINE);
 470                 } else {
 471                         tgt_sm_new_state(tgt, ctx, TS_STMF_ONLINE);
 472                 }
 473                 break;
 474         case TE_DELETE:
 475                 /* TE_DELETE is handled in tgt_sm_event_dispatch() */
 476                 break;
 477         case TE_STMF_ONLINE_REQ:
 478         case TE_STMF_OFFLINE_REQ:
 479                 /*
 480                  * We can't complete STMF's request since we are busy going
 481                  * online (waiting for acknowlegement from STMF)
 482                  */
 483                 scs.st_completion_status = STMF_INVALID_ARG;
 484                 scs.st_additional_info = NULL;
 485                 (void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ?
 486                     STMF_CMD_LPORT_ONLINE_COMPLETE :
 487                     STMF_CMD_LPORT_OFFLINE_COMPLETE,
 488                     tgt->target_stmf_lport, &scs);
 489                 break;
 490         case TE_STMF_OFFLINE_COMPLETE_ACK:
 491                 /* Ignore */
 492                 break;
 493         default:
 494                 ASSERT(0);
 495         }
 496 }
 497 
 498 
 499 static void
 500 tgt_sm_stmf_online(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx)
 501 {
 502         stmf_change_status_t    scs;
 503 
 504         switch (ctx->te_ctx_event) {
 505         case TE_DELETE:
 506                 tgt_sm_new_state(tgt, ctx, TS_DELETING_NEED_OFFLINE);
 507                 break;
 508         case TE_STMF_OFFLINE_REQ:
 509                 tgt_sm_new_state(tgt, ctx, TS_OFFLINING);
 510                 break;
 511         case TE_STMF_ONLINE_REQ:
 512                 /* Already online */
 513                 scs.st_completion_status = STMF_ALREADY;
 514                 scs.st_additional_info = NULL;
 515                 (void) stmf_ctl(STMF_CMD_LPORT_ONLINE_COMPLETE,
 516                     tgt->target_stmf_lport, &scs);
 517                 break;
 518         case TE_STMF_ONLINE_COMPLETE_ACK:
 519         case TE_STMF_OFFLINE_COMPLETE_ACK:
 520                 /* Ignore */
 521                 break;
 522         default:
 523                 ASSERT(0);
 524         }
 525 }
 526 
 527 
 528 static void
 529 tgt_sm_deleting_need_offline(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx)
 530 {
 531         stmf_change_status_t    scs;
 532 
 533         switch (ctx->te_ctx_event) {
 534         case TE_STMF_OFFLINE_REQ:
 535                 tgt_sm_new_state(tgt, ctx, TS_OFFLINING);
 536                 break;
 537         case TE_DELETE:
 538                 /* TE_DELETE is handled in tgt_sm_event_dispatch() */
 539                 break;
 540         case TE_STMF_ONLINE_REQ:
 541                 /*
 542                  * We can't complete STMF's request since we need to be offlined
 543                  */
 544                 scs.st_completion_status = STMF_INVALID_ARG;
 545                 scs.st_additional_info = NULL;
 546                 (void) stmf_ctl(STMF_CMD_LPORT_ONLINE_COMPLETE,
 547                     tgt->target_stmf_lport, &scs);
 548                 break;
 549         case TE_STMF_ONLINE_COMPLETE_ACK:
 550         case TE_STMF_OFFLINE_COMPLETE_ACK:
 551                 /* Ignore */
 552                 break;
 553         default:
 554                 ASSERT(0);
 555         }
 556 }
 557 
 558 
 559 static void
 560 tgt_sm_offlining(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx)
 561 {
 562         stmf_change_status_t    scs;
 563 
 564         switch (ctx->te_ctx_event) {
 565         case TE_OFFLINE_COMPLETE:
 566                 tgt_sm_new_state(tgt, ctx, TS_OFFLINE);
 567                 break;
 568         case TE_DELETE:
 569                 /* TE_DELETE is handled in tgt_sm_event_dispatch() */
 570                 break;
 571         case TE_STMF_ONLINE_REQ:
 572         case TE_STMF_OFFLINE_REQ:
 573                 /*
 574                  * We can't complete STMF's request since we are busy going
 575                  * offline.
 576                  */
 577                 scs.st_completion_status = STMF_INVALID_ARG;
 578                 scs.st_additional_info = NULL;
 579                 (void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ?
 580                     STMF_CMD_LPORT_ONLINE_COMPLETE :
 581                     STMF_CMD_LPORT_OFFLINE_COMPLETE,
 582                     tgt->target_stmf_lport, &scs);
 583                 break;
 584         case TE_STMF_ONLINE_COMPLETE_ACK:
 585         case TE_STMF_OFFLINE_COMPLETE_ACK:
 586                 /* Ignore */
 587                 break;
 588         default:
 589                 ASSERT(0);
 590         }
 591 }
 592 
 593 
 594 static void
 595 tgt_sm_offline(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx)
 596 {
 597         stmf_change_status_t    scs;
 598 
 599         switch (ctx->te_ctx_event) {
 600         case TE_STMF_OFFLINE_COMPLETE_ACK:
 601                 if (tgt->target_deleting) {
 602                         tgt_sm_new_state(tgt, ctx, TS_DELETING_STMF_DEREG);
 603                 } else {
 604                         tgt_sm_new_state(tgt, ctx, TS_STMF_OFFLINE);
 605                 }
 606                 break;
 607         case TE_DELETE:
 608                 /* TE_DELETE is handled in tgt_sm_event_dispatch() */
 609                 break;
 610         case TE_STMF_ONLINE_REQ:
 611         case TE_STMF_OFFLINE_REQ:
 612                 /*
 613                  * We can't complete STMF's request since we are busy going
 614                  * offline.
 615                  */
 616                 scs.st_completion_status = STMF_INVALID_ARG;
 617                 scs.st_additional_info = NULL;
 618                 (void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ?
 619                     STMF_CMD_LPORT_ONLINE_COMPLETE :
 620                     STMF_CMD_LPORT_OFFLINE_COMPLETE,
 621                     tgt->target_stmf_lport, &scs);
 622                 break;
 623         case TE_STMF_ONLINE_COMPLETE_ACK:
 624                 /* Ignore */
 625                 break;
 626         default:
 627                 ASSERT(0);
 628         }
 629 }
 630 
 631 
 632 static void
 633 tgt_sm_stmf_offline(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx)
 634 {
 635         stmf_change_status_t    scs;
 636 
 637         switch (ctx->te_ctx_event) {
 638         case TE_STMF_ONLINE_REQ:
 639                 tgt_sm_new_state(tgt, ctx, TS_ONLINING);
 640                 break;
 641         case TE_DELETE:
 642                 tgt_sm_new_state(tgt, ctx, TS_DELETING_STMF_DEREG);
 643                 break;
 644         case TE_STMF_OFFLINE_REQ:
 645                 /* Already offline */
 646                 scs.st_completion_status = STMF_ALREADY;
 647                 scs.st_additional_info = NULL;
 648                 (void) stmf_ctl(STMF_CMD_LPORT_OFFLINE_COMPLETE,
 649                     tgt->target_stmf_lport, &scs);
 650                 break;
 651         case TE_STMF_ONLINE_COMPLETE_ACK:
 652         case TE_STMF_OFFLINE_COMPLETE_ACK:
 653                 /* Ignore */
 654                 break;
 655         default:
 656                 ASSERT(0);
 657         }
 658 }
 659 
 660 
 661 static void
 662 tgt_sm_deleting_stmf_dereg(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx)
 663 {
 664         stmf_change_status_t    scs;
 665 
 666         /* Terminal state, no events */
 667         switch (ctx->te_ctx_event) {
 668         case TE_STMF_ONLINE_REQ:
 669         case TE_STMF_OFFLINE_REQ:
 670                 /*
 671                  * We can't complete STMF's request since we are being deleted
 672                  */
 673                 scs.st_completion_status = STMF_INVALID_ARG;
 674                 scs.st_additional_info = NULL;
 675                 (void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ?
 676                     STMF_CMD_LPORT_ONLINE_COMPLETE :
 677                     STMF_CMD_LPORT_OFFLINE_COMPLETE,
 678                     tgt->target_stmf_lport, &scs);
 679                 break;
 680         case TE_STMF_ONLINE_COMPLETE_ACK:
 681         case TE_STMF_OFFLINE_COMPLETE_ACK:
 682                 /* Ignore */
 683                 break;
 684         case TE_STMF_DEREG_SUCCESS:
 685                 tgt_sm_new_state(tgt, ctx, TS_DELETING);
 686                 break;
 687         case TE_STMF_DEREG_FAIL:
 688                 tgt_sm_new_state(tgt, ctx, TS_DELETING_STMF_DEREG_FAIL);
 689                 break;
 690         default:
 691                 ASSERT(0);
 692         }
 693 }
 694 
 695 static void
 696 tgt_sm_deleting_stmf_dereg_fail(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx)
 697 {
 698         stmf_change_status_t    scs;
 699 
 700         /* Terminal state, no events */
 701         switch (ctx->te_ctx_event) {
 702         case TE_STMF_ONLINE_REQ:
 703         case TE_STMF_OFFLINE_REQ:
 704                 /*
 705                  * We can't complete STMF's request since we are being deleted
 706                  */
 707                 scs.st_completion_status = STMF_INVALID_ARG;
 708                 scs.st_additional_info = NULL;
 709                 (void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ?
 710                     STMF_CMD_LPORT_ONLINE_COMPLETE :
 711                     STMF_CMD_LPORT_OFFLINE_COMPLETE,
 712                     tgt->target_stmf_lport, &scs);
 713                 break;
 714         case TE_STMF_ONLINE_COMPLETE_ACK:
 715         case TE_STMF_OFFLINE_COMPLETE_ACK:
 716                 /* Ignore */
 717                 break;
 718         case TE_STMF_DEREG_RETRY:
 719                 tgt_sm_new_state(tgt, ctx, TS_DELETING_STMF_DEREG);
 720                 break;
 721         default:
 722                 ASSERT(0);
 723         }
 724 }
 725 
 726 static void
 727 tgt_sm_deleting(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx)
 728 {
 729         stmf_change_status_t    scs;
 730 
 731         /* Terminal state, no events */
 732         switch (ctx->te_ctx_event) {
 733         case TE_STMF_ONLINE_REQ:
 734         case TE_STMF_OFFLINE_REQ:
 735                 /*
 736                  * We can't complete STMF's request since we are being deleted
 737                  */
 738                 scs.st_completion_status = STMF_INVALID_ARG;
 739                 scs.st_additional_info = NULL;
 740                 (void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ?
 741                     STMF_CMD_LPORT_ONLINE_COMPLETE :
 742                     STMF_CMD_LPORT_OFFLINE_COMPLETE,
 743                     tgt->target_stmf_lport, &scs);
 744                 break;
 745         case TE_STMF_ONLINE_COMPLETE_ACK:
 746         case TE_STMF_OFFLINE_COMPLETE_ACK:
 747                 /* Ignore */
 748                 break;
 749         default:
 750                 ASSERT(0);
 751         }
 752 }
 753 
 754 static void
 755 pppt_tgt_offline(pppt_tgt_t *tgt)
 756 {
 757         (void) taskq_dispatch(pppt_global.global_dispatch_taskq,
 758             pppt_tgt_offline_task, tgt, KM_SLEEP);
 759 }
 760 
 761 static void
 762 pppt_tgt_offline_task(void *arg)
 763 {
 764         pppt_tgt_t              *tgt = arg;
 765         pppt_sess_t             *ps, *next_ps;
 766         stmf_change_status_t    scs;
 767 
 768         stmf_trace("pppt", "pppt_tgt_offline %p", (void *)tgt);
 769 
 770         PPPT_GLOBAL_LOCK();
 771         mutex_enter(&tgt->target_mutex);
 772         for (ps = avl_first(&tgt->target_sess_list); ps != NULL; ps = next_ps) {
 773                 next_ps = AVL_NEXT(&tgt->target_sess_list, ps);
 774                 mutex_enter(&ps->ps_mutex);
 775                 if (!ps->ps_closed) {
 776                         pppt_sess_close_locked(ps);
 777                 }
 778                 mutex_exit(&ps->ps_mutex);
 779         }
 780         mutex_exit(&tgt->target_mutex);
 781         PPPT_GLOBAL_UNLOCK();
 782 
 783         pppt_tgt_sm_event(tgt, TE_OFFLINE_COMPLETE);
 784 
 785         scs.st_completion_status = STMF_SUCCESS;
 786         scs.st_additional_info = NULL;
 787         (void) stmf_ctl(STMF_CMD_LPORT_OFFLINE_COMPLETE,
 788             tgt->target_stmf_lport, &scs);
 789 
 790         stmf_trace("pppt", "pppt_tgt_offline complete %p", (void *)tgt);
 791 }
 792 
 793 static void
 794 pppt_tgt_dereg_retry(void *arg)
 795 {
 796         pppt_tgt_t *tgt = arg;
 797 
 798         /*
 799          * Rather than guaranteeing the target state machine code will not
 800          * block for long periods of time (tying up this callout thread)
 801          * we will queue a task on the taskq to send the retry event.
 802          * If it fails we'll setup another timeout and try again later.
 803          */
 804         if (taskq_dispatch(pppt_global.global_dispatch_taskq,
 805             pppt_tgt_dereg_task, tgt, KM_NOSLEEP) == NULL) {
 806                 /* Dispatch failed, try again later */
 807                 (void) timeout(pppt_tgt_dereg_retry, tgt,
 808                     drv_usectohz(TGT_DEREG_RETRY_SECONDS * 1000000));
 809         }
 810 }
 811 
 812 static void
 813 pppt_tgt_dereg_task(void *arg)
 814 {
 815         pppt_tgt_t *tgt = arg;
 816 
 817         pppt_tgt_sm_event(tgt, TE_STMF_DEREG_RETRY);
 818 }
 819 
 820 /*ARGSUSED*/
 821 static void
 822 tgt_sm_new_state(pppt_tgt_t *tgt, tgt_event_ctx_t *ctx,
 823     pppt_tgt_state_t new_state)
 824 {
 825         stmf_local_port_t               *lport = tgt->target_stmf_lport;
 826         stmf_change_status_t            scs;
 827         stmf_state_change_info_t        sci;
 828         stmf_status_t                   stmfrc;
 829 
 830         scs.st_completion_status = STMF_SUCCESS;
 831         scs.st_additional_info = NULL;
 832 
 833         /*
 834          * Validate new state
 835          */
 836         ASSERT(new_state != TS_UNDEFINED);
 837         ASSERT3U(new_state, <, TS_MAX_STATE);
 838 
 839         new_state = (new_state < TS_MAX_STATE) ?
 840             new_state : TS_UNDEFINED;
 841 
 842         stmf_trace("pppt", "pppt_target_state_change: "
 843             "tgt %p, %s(%d) --> %s(%d)\n",
 844             (void *) tgt, pppt_ts_name[tgt->target_state], tgt->target_state,
 845             pppt_ts_name[new_state], new_state);
 846         DTRACE_PROBE3(pppt__target__state__change,
 847             pppt_tgt_t *, tgt, tgt_event_ctx_t *, ctx,
 848             pppt_tgt_state_t, new_state);
 849 
 850         mutex_enter(&tgt->target_mutex);
 851         tgt->target_last_state = tgt->target_state;
 852         tgt->target_state = new_state;
 853         cv_signal(&tgt->target_cv);
 854         mutex_exit(&tgt->target_mutex);
 855 
 856         switch (tgt->target_state) {
 857         case TS_ONLINING:
 858                 pppt_tgt_sm_event(tgt, TE_ONLINE_SUCCESS);
 859 
 860                 /*
 861                  * Let STMF know the how the online operation completed.
 862                  * STMF will respond with an acknowlege later
 863                  */
 864                 (void) stmf_ctl(STMF_CMD_LPORT_ONLINE_COMPLETE, lport, &scs);
 865                 break;
 866         case TS_ONLINE:
 867                 break;
 868         case TS_STMF_ONLINE:
 869                 break;
 870         case TS_DELETING_NEED_OFFLINE:
 871                 sci.st_rflags = STMF_RFLAG_STAY_OFFLINED;
 872                 sci.st_additional_info = "Offline for delete";
 873                 (void) stmf_ctl(STMF_CMD_LPORT_OFFLINE, lport, &sci);
 874                 break;
 875         case TS_OFFLINING:
 876                 /* Async callback generates completion event */
 877                 pppt_tgt_offline(tgt);
 878                 break;
 879         case TS_OFFLINE:
 880                 break;
 881         case TS_STMF_OFFLINE:
 882                 break;
 883         case TS_DELETING_STMF_DEREG:
 884                 stmfrc = stmf_deregister_local_port(tgt->target_stmf_lport);
 885                 if (stmfrc == STMF_SUCCESS) {
 886                         pppt_tgt_sm_event(tgt, TE_STMF_DEREG_SUCCESS);
 887                 } else {
 888                         pppt_tgt_sm_event(tgt, TE_STMF_DEREG_FAIL);
 889                 }
 890                 break;
 891         case TS_DELETING_STMF_DEREG_FAIL:
 892                 /* Retry dereg in 1 second */
 893                 (void) timeout(pppt_tgt_dereg_retry, tgt,
 894                     drv_usectohz(TGT_DEREG_RETRY_SECONDS * 1000000));
 895                 break;
 896         case TS_DELETING:
 897                 break;
 898         default:
 899                 ASSERT(0);
 900         }
 901 }