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