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