Print this page
XXXX introduce drv_sectohz
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/comstar/port/iscsit/iscsit_tgt.c
+++ new/usr/src/uts/common/io/comstar/port/iscsit/iscsit_tgt.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
24 24 */
25 25
26 26 #include <sys/cpuvar.h>
27 27 #include <sys/types.h>
28 28 #include <sys/conf.h>
29 29 #include <sys/file.h>
30 30 #include <sys/ddi.h>
31 31 #include <sys/sunddi.h>
32 32 #include <sys/modctl.h>
33 33 #include <sys/sysmacros.h>
34 34 #include <sys/sdt.h>
35 35
36 36 #include <sys/socket.h>
37 37 #include <sys/strsubr.h>
38 38
39 39 #include <sys/stmf.h>
40 40 #include <sys/stmf_ioctl.h>
41 41 #include <sys/portif.h>
42 42 #include <sys/idm/idm.h>
43 43
44 44 #define ISCSIT_TGT_SM_STRINGS
45 45 #include "iscsit.h"
46 46 #include "iscsit_isns.h"
47 47
48 48 typedef struct {
49 49 list_node_t te_ctx_node;
50 50 iscsit_tgt_event_t te_ctx_event;
51 51 } tgt_event_ctx_t;
52 52
53 53 static void
54 54 tgt_sm_event_dispatch(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx);
55 55
56 56 static void
57 57 tgt_sm_created(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx);
58 58
59 59 static void
60 60 tgt_sm_onlining(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx);
61 61
62 62 static void
63 63 tgt_sm_online(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx);
64 64
65 65 static void
66 66 tgt_sm_stmf_online(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx);
67 67
68 68 static void
69 69 tgt_sm_deleting_need_offline(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx);
70 70
71 71 static void
72 72 tgt_sm_offlining(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx);
73 73
74 74 static void
75 75 tgt_sm_offline(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx);
76 76
77 77 static void
78 78 tgt_sm_stmf_offline(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx);
79 79
80 80 static void
81 81 tgt_sm_deleting_stmf_dereg(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx);
82 82
83 83 static void
84 84 tgt_sm_deleting_stmf_dereg_fail(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx);
85 85
86 86 static void
87 87 tgt_sm_deleting(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx);
88 88
89 89 static void
90 90 iscsit_tgt_dereg_retry(void *arg);
91 91
92 92 static void
93 93 iscsit_tgt_dereg_task(void *arg);
94 94
95 95 static void
96 96 tgt_sm_new_state(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx,
97 97 iscsit_tgt_state_t new_state);
98 98
99 99
100 100 static iscsit_tgt_t *
101 101 iscsit_tgt_create(it_tgt_t *cfg_tgt);
102 102
103 103 static void
104 104 iscsit_tgt_unref(void *tgt);
105 105
106 106 static void
107 107 iscsit_tgt_async_wait_ref(iscsit_tgt_t *tgt, idm_refcnt_cb_t *cb_func);
108 108
109 109 static void
110 110 iscsit_tgt_destroy(iscsit_tgt_t *tgt);
111 111
112 112 static iscsit_tpgt_t *
113 113 iscsit_tgt_lookup_tpgt_locked(iscsit_tgt_t *tgt, uint16_t tag);
114 114
115 115 static iscsit_tpg_t *
116 116 iscsit_tpg_lookup_locked(char *tpg_name);
117 117
118 118 static iscsit_portal_t *
119 119 iscsit_tpg_portal_lookup_locked(iscsit_tpg_t *tpg,
120 120 struct sockaddr_storage *sa);
121 121
122 122 static idm_status_t
123 123 iscsit_tgt_online(iscsit_tgt_t *tgt);
124 124
125 125 static void
126 126 iscsit_tgt_offline(iscsit_tgt_t *tgt);
127 127
128 128 static idm_status_t
129 129 iscsit_tgt_modify(iscsit_tgt_t *tgt, it_tgt_t *cfg_tgt);
130 130
131 131 static idm_status_t
132 132 iscsit_tgt_merge_tpgt(iscsit_tgt_t *tgt, it_tgt_t *cfg_tgt,
133 133 list_t *tpgt_del_list);
134 134
135 135 static iscsit_tpgt_t *
136 136 iscsit_tpgt_create(it_tpgt_t *cfg_tpgt);
137 137
138 138 static iscsit_tpgt_t *
139 139 iscsit_tpgt_create_default();
140 140
141 141 static void
142 142 iscsit_tpgt_destroy(iscsit_tpgt_t *tpgt);
143 143
144 144 static iscsit_tpg_t *
145 145 iscsit_tpg_create(it_tpg_t *tpg);
146 146
147 147 static void
148 148 iscsit_tpg_modify(iscsit_tpg_t *tpg, it_tpg_t *cfg_tpg);
149 149
150 150 static void
151 151 iscsit_tpg_destroy(iscsit_tpg_t *tpg);
152 152
153 153 static iscsit_portal_t *
154 154 iscsit_portal_create(iscsit_tpg_t *tpg, struct sockaddr_storage *sa);
155 155
156 156 static void
157 157 iscsit_portal_delete(iscsit_portal_t *portal);
158 158
159 159 static idm_status_t
160 160 iscsit_portal_online(iscsit_portal_t *portal);
161 161
162 162 static void
163 163 iscsit_portal_offline(iscsit_portal_t *portal);
164 164
165 165
166 166
167 167 /*
168 168 * Target state machine
169 169 */
170 170
171 171 void
172 172 iscsit_tgt_sm_event(iscsit_tgt_t *tgt, iscsit_tgt_event_t event)
173 173 {
174 174 mutex_enter(&tgt->target_mutex);
175 175 tgt_sm_event_locked(tgt, event);
176 176 mutex_exit(&tgt->target_mutex);
177 177 }
178 178
179 179 void
180 180 tgt_sm_event_locked(iscsit_tgt_t *tgt, iscsit_tgt_event_t event)
181 181 {
182 182 tgt_event_ctx_t *ctx;
183 183
184 184 iscsit_tgt_hold(tgt);
185 185
186 186 ctx = kmem_zalloc(sizeof (*ctx), KM_SLEEP);
187 187
188 188 ctx->te_ctx_event = event;
189 189
190 190 list_insert_tail(&tgt->target_events, ctx);
191 191 /*
192 192 * Use the target_sm_busy flag to keep the state machine single
193 193 * threaded. This also serves as recursion avoidance since this
194 194 * flag will always be set if we call iscsit_tgt_sm_event from
195 195 * within the state machine code.
196 196 */
197 197 if (!tgt->target_sm_busy) {
198 198 tgt->target_sm_busy = B_TRUE;
199 199 while (!list_is_empty(&tgt->target_events)) {
200 200 ctx = list_head(&tgt->target_events);
201 201 list_remove(&tgt->target_events, ctx);
202 202 idm_sm_audit_event(&tgt->target_state_audit,
203 203 SAS_ISCSIT_TGT, (int)tgt->target_state,
204 204 (int)ctx->te_ctx_event, 0);
205 205 mutex_exit(&tgt->target_mutex);
206 206 tgt_sm_event_dispatch(tgt, ctx);
207 207 mutex_enter(&tgt->target_mutex);
208 208 }
209 209 tgt->target_sm_busy = B_FALSE;
210 210
211 211 }
212 212
213 213 iscsit_tgt_rele(tgt);
214 214 }
215 215
216 216 static void
217 217 tgt_sm_event_dispatch(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx)
218 218 {
219 219 DTRACE_PROBE2(tgt__event, iscsit_tgt_t *, tgt,
220 220 tgt_event_ctx_t *, ctx);
221 221
222 222 IDM_SM_LOG(CE_NOTE, "tgt_sm_event_dispatch: tgt %p event %s(%d)",
223 223 (void *)tgt, iscsit_te_name[ctx->te_ctx_event], ctx->te_ctx_event);
224 224
225 225 /* State independent actions */
226 226 switch (ctx->te_ctx_event) {
227 227 case TE_DELETE:
228 228 tgt->target_deleting = B_TRUE;
229 229 break;
230 230 }
231 231
232 232 /* State dependent actions */
233 233 switch (tgt->target_state) {
234 234 case TS_CREATED:
235 235 tgt_sm_created(tgt, ctx);
236 236 break;
237 237 case TS_ONLINING:
238 238 tgt_sm_onlining(tgt, ctx);
239 239 break;
240 240 case TS_ONLINE:
241 241 tgt_sm_online(tgt, ctx);
242 242 break;
243 243 case TS_STMF_ONLINE:
244 244 tgt_sm_stmf_online(tgt, ctx);
245 245 break;
246 246 case TS_DELETING_NEED_OFFLINE:
247 247 tgt_sm_deleting_need_offline(tgt, ctx);
248 248 break;
249 249 case TS_OFFLINING:
250 250 tgt_sm_offlining(tgt, ctx);
251 251 break;
252 252 case TS_OFFLINE:
253 253 tgt_sm_offline(tgt, ctx);
254 254 break;
255 255 case TS_STMF_OFFLINE:
256 256 tgt_sm_stmf_offline(tgt, ctx);
257 257 break;
258 258 case TS_DELETING_STMF_DEREG:
259 259 tgt_sm_deleting_stmf_dereg(tgt, ctx);
260 260 break;
261 261 case TS_DELETING_STMF_DEREG_FAIL:
262 262 tgt_sm_deleting_stmf_dereg_fail(tgt, ctx);
263 263 break;
264 264 case TS_DELETING:
265 265 tgt_sm_deleting(tgt, ctx);
266 266 break;
267 267 default:
268 268 ASSERT(0);
269 269 }
270 270
271 271 kmem_free(ctx, sizeof (*ctx));
272 272 }
273 273
274 274 static void
275 275 tgt_sm_created(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx)
276 276 {
277 277 stmf_change_status_t scs;
278 278
279 279 switch (ctx->te_ctx_event) {
280 280 case TE_STMF_ONLINE_REQ:
281 281 tgt_sm_new_state(tgt, ctx, TS_ONLINING);
282 282 break;
283 283 case TE_DELETE:
284 284 tgt_sm_new_state(tgt, ctx, TS_DELETING_STMF_DEREG);
285 285 break;
286 286 case TE_STMF_OFFLINE_REQ:
287 287 /*
288 288 * We're already offline but update to an equivelant
289 289 * state just to note that STMF talked to us.
290 290 */
291 291 scs.st_completion_status = STMF_SUCCESS;
292 292 scs.st_additional_info = NULL;
293 293 tgt_sm_new_state(tgt, ctx, TS_OFFLINE);
294 294 (void) stmf_ctl(STMF_CMD_LPORT_OFFLINE_COMPLETE,
295 295 tgt->target_stmf_lport, &scs);
296 296 break;
297 297 case TE_STMF_ONLINE_COMPLETE_ACK:
298 298 case TE_STMF_OFFLINE_COMPLETE_ACK:
299 299 /* Ignore */
300 300 break;
301 301 default:
302 302 ASSERT(0);
303 303 }
304 304 }
305 305
306 306 static void
307 307 tgt_sm_onlining(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx)
308 308 {
309 309 stmf_change_status_t scs;
310 310
311 311 switch (ctx->te_ctx_event) {
312 312 case TE_ONLINE_SUCCESS:
313 313 tgt_sm_new_state(tgt, ctx, TS_ONLINE);
314 314 break;
315 315 case TE_ONLINE_FAIL:
316 316 tgt_sm_new_state(tgt, ctx, TS_STMF_OFFLINE);
317 317 break;
318 318 case TE_DELETE:
319 319 /* TE_DELETE is handled in tgt_sm_event_dispatch() */
320 320 break;
321 321 case TE_STMF_ONLINE_REQ:
322 322 case TE_STMF_OFFLINE_REQ:
323 323 /*
324 324 * We can't complete STMF's request since we are busy going
325 325 * online.
326 326 */
327 327 scs.st_completion_status = STMF_INVALID_ARG;
328 328 scs.st_additional_info = NULL;
329 329 (void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ?
330 330 STMF_CMD_LPORT_ONLINE_COMPLETE :
331 331 STMF_CMD_LPORT_OFFLINE_COMPLETE,
332 332 tgt->target_stmf_lport, &scs);
333 333 break;
334 334 case TE_STMF_ONLINE_COMPLETE_ACK:
335 335 case TE_STMF_OFFLINE_COMPLETE_ACK:
336 336 /* Ignore */
337 337 break;
338 338 default:
339 339 ASSERT(0);
340 340 }
341 341 }
342 342
343 343 static void
344 344 tgt_sm_online(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx)
345 345 {
346 346 stmf_change_status_t scs;
347 347
348 348 switch (ctx->te_ctx_event) {
349 349 case TE_STMF_ONLINE_COMPLETE_ACK:
350 350 if (tgt->target_deleting) {
351 351 tgt_sm_new_state(tgt, ctx, TS_DELETING_NEED_OFFLINE);
352 352 } else {
353 353 tgt_sm_new_state(tgt, ctx, TS_STMF_ONLINE);
354 354 }
355 355 break;
356 356 case TE_DELETE:
357 357 /* TE_DELETE is handled in tgt_sm_event_dispatch() */
358 358 break;
359 359 case TE_STMF_ONLINE_REQ:
360 360 case TE_STMF_OFFLINE_REQ:
361 361 /*
362 362 * We can't complete STMF's request since we are busy going
363 363 * online (waiting for acknowlegement from STMF)
364 364 */
365 365 scs.st_completion_status = STMF_INVALID_ARG;
366 366 scs.st_additional_info = NULL;
367 367 (void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ?
368 368 STMF_CMD_LPORT_ONLINE_COMPLETE :
369 369 STMF_CMD_LPORT_OFFLINE_COMPLETE,
370 370 tgt->target_stmf_lport, &scs);
371 371 break;
372 372 case TE_STMF_OFFLINE_COMPLETE_ACK:
373 373 /* Ignore */
374 374 break;
375 375 default:
376 376 ASSERT(0);
377 377 }
378 378 }
379 379
380 380
381 381 static void
382 382 tgt_sm_stmf_online(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx)
383 383 {
384 384 stmf_change_status_t scs;
385 385
386 386 /* Deregister target with iSNS whenever we leave this state */
387 387
388 388 switch (ctx->te_ctx_event) {
389 389 case TE_DELETE:
390 390 (void) iscsit_isns_deregister(tgt);
391 391 tgt_sm_new_state(tgt, ctx, TS_DELETING_NEED_OFFLINE);
392 392 break;
393 393 case TE_STMF_OFFLINE_REQ:
394 394 (void) iscsit_isns_deregister(tgt);
395 395 tgt_sm_new_state(tgt, ctx, TS_OFFLINING);
396 396 break;
397 397 case TE_STMF_ONLINE_REQ:
398 398 /* Already online */
399 399 scs.st_completion_status = STMF_ALREADY;
400 400 scs.st_additional_info = NULL;
401 401 (void) stmf_ctl(STMF_CMD_LPORT_ONLINE_COMPLETE,
402 402 tgt->target_stmf_lport, &scs);
403 403 break;
404 404 case TE_STMF_ONLINE_COMPLETE_ACK:
405 405 case TE_STMF_OFFLINE_COMPLETE_ACK:
406 406 /* Ignore */
407 407 break;
408 408 default:
409 409 ASSERT(0);
410 410 }
411 411 }
412 412
413 413
414 414 static void
415 415 tgt_sm_deleting_need_offline(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx)
416 416 {
417 417 stmf_change_status_t scs;
418 418
419 419 switch (ctx->te_ctx_event) {
420 420 case TE_STMF_OFFLINE_REQ:
421 421 tgt_sm_new_state(tgt, ctx, TS_OFFLINING);
422 422 break;
423 423 case TE_DELETE:
424 424 /* TE_DELETE is handled in tgt_sm_event_dispatch() */
425 425 break;
426 426 case TE_STMF_ONLINE_REQ:
427 427 /*
428 428 * We can't complete STMF's request since we need to be offlined
429 429 */
430 430 scs.st_completion_status = STMF_INVALID_ARG;
431 431 scs.st_additional_info = NULL;
432 432 (void) stmf_ctl(STMF_CMD_LPORT_ONLINE_COMPLETE,
433 433 tgt->target_stmf_lport, &scs);
434 434 break;
435 435 case TE_STMF_ONLINE_COMPLETE_ACK:
436 436 case TE_STMF_OFFLINE_COMPLETE_ACK:
437 437 /* Ignore */
438 438 break;
439 439 default:
440 440 ASSERT(0);
441 441 }
442 442 }
443 443
444 444
445 445 static void
446 446 tgt_sm_offlining(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx)
447 447 {
448 448 stmf_change_status_t scs;
449 449
450 450 switch (ctx->te_ctx_event) {
451 451 case TE_OFFLINE_COMPLETE:
452 452 tgt_sm_new_state(tgt, ctx, TS_OFFLINE);
453 453 break;
454 454 case TE_DELETE:
455 455 /* TE_DELETE is handled in tgt_sm_event_dispatch() */
456 456 break;
457 457 case TE_STMF_ONLINE_REQ:
458 458 case TE_STMF_OFFLINE_REQ:
459 459 /*
460 460 * We can't complete STMF's request since we are busy going
461 461 * offline.
462 462 */
463 463 scs.st_completion_status = STMF_INVALID_ARG;
464 464 scs.st_additional_info = NULL;
465 465 (void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ?
466 466 STMF_CMD_LPORT_ONLINE_COMPLETE :
467 467 STMF_CMD_LPORT_OFFLINE_COMPLETE,
468 468 tgt->target_stmf_lport, &scs);
469 469 break;
470 470 case TE_STMF_ONLINE_COMPLETE_ACK:
471 471 case TE_STMF_OFFLINE_COMPLETE_ACK:
472 472 /* Ignore */
473 473 break;
474 474 default:
475 475 ASSERT(0);
476 476 }
477 477 }
478 478
479 479
480 480 static void
481 481 tgt_sm_offline(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx)
482 482 {
483 483 stmf_change_status_t scs;
484 484
485 485 switch (ctx->te_ctx_event) {
486 486 case TE_STMF_OFFLINE_COMPLETE_ACK:
487 487 if (tgt->target_deleting) {
488 488 tgt_sm_new_state(tgt, ctx, TS_DELETING_STMF_DEREG);
489 489 } else {
490 490 tgt_sm_new_state(tgt, ctx, TS_STMF_OFFLINE);
491 491 }
492 492 break;
493 493 case TE_DELETE:
494 494 /* TE_DELETE is handled in tgt_sm_event_dispatch() */
495 495 break;
496 496 case TE_STMF_ONLINE_REQ:
497 497 case TE_STMF_OFFLINE_REQ:
498 498 /*
499 499 * We can't complete STMF's request since we are busy going
500 500 * offline.
501 501 */
502 502 scs.st_completion_status = STMF_INVALID_ARG;
503 503 scs.st_additional_info = NULL;
504 504 (void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ?
505 505 STMF_CMD_LPORT_ONLINE_COMPLETE :
506 506 STMF_CMD_LPORT_OFFLINE_COMPLETE,
507 507 tgt->target_stmf_lport, &scs);
508 508 break;
509 509 case TE_STMF_ONLINE_COMPLETE_ACK:
510 510 /* Ignore */
511 511 break;
512 512 default:
513 513 ASSERT(0);
514 514 }
515 515 }
516 516
517 517
518 518 static void
519 519 tgt_sm_stmf_offline(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx)
520 520 {
521 521 stmf_change_status_t scs;
522 522
523 523 switch (ctx->te_ctx_event) {
524 524 case TE_STMF_ONLINE_REQ:
525 525 tgt_sm_new_state(tgt, ctx, TS_ONLINING);
526 526 break;
527 527 case TE_DELETE:
528 528 tgt_sm_new_state(tgt, ctx, TS_DELETING_STMF_DEREG);
529 529 break;
530 530 case TE_STMF_OFFLINE_REQ:
531 531 /* Already offline */
532 532 scs.st_completion_status = STMF_ALREADY;
533 533 scs.st_additional_info = NULL;
534 534 (void) stmf_ctl(STMF_CMD_LPORT_OFFLINE_COMPLETE,
535 535 tgt->target_stmf_lport, &scs);
536 536 break;
537 537 case TE_STMF_ONLINE_COMPLETE_ACK:
538 538 case TE_STMF_OFFLINE_COMPLETE_ACK:
539 539 /* Ignore */
540 540 break;
541 541 default:
542 542 ASSERT(0);
543 543 }
544 544 }
545 545
546 546
547 547 static void
548 548 tgt_sm_deleting_stmf_dereg(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx)
549 549 {
550 550 stmf_change_status_t scs;
551 551
552 552 /* Terminal state, no events */
553 553 switch (ctx->te_ctx_event) {
554 554 case TE_STMF_ONLINE_REQ:
555 555 case TE_STMF_OFFLINE_REQ:
556 556 /*
557 557 * We can't complete STMF's request since we are being deleted
558 558 */
559 559 scs.st_completion_status = STMF_INVALID_ARG;
560 560 scs.st_additional_info = NULL;
561 561 (void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ?
562 562 STMF_CMD_LPORT_ONLINE_COMPLETE :
563 563 STMF_CMD_LPORT_OFFLINE_COMPLETE,
564 564 tgt->target_stmf_lport, &scs);
565 565 break;
566 566 case TE_STMF_ONLINE_COMPLETE_ACK:
567 567 case TE_STMF_OFFLINE_COMPLETE_ACK:
568 568 /* Ignore */
569 569 break;
570 570 case TE_STMF_DEREG_SUCCESS:
571 571 tgt_sm_new_state(tgt, ctx, TS_DELETING);
572 572 break;
573 573 case TE_STMF_DEREG_FAIL:
574 574 tgt_sm_new_state(tgt, ctx, TS_DELETING_STMF_DEREG_FAIL);
575 575 break;
576 576 default:
577 577 ASSERT(0);
578 578 }
579 579 }
580 580
581 581 static void
582 582 tgt_sm_deleting_stmf_dereg_fail(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx)
583 583 {
584 584 stmf_change_status_t scs;
585 585
586 586 /* Terminal state, no events */
587 587 switch (ctx->te_ctx_event) {
588 588 case TE_STMF_ONLINE_REQ:
589 589 case TE_STMF_OFFLINE_REQ:
590 590 /*
591 591 * We can't complete STMF's request since we are being deleted
592 592 */
593 593 scs.st_completion_status = STMF_INVALID_ARG;
594 594 scs.st_additional_info = NULL;
595 595 (void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ?
596 596 STMF_CMD_LPORT_ONLINE_COMPLETE :
597 597 STMF_CMD_LPORT_OFFLINE_COMPLETE,
598 598 tgt->target_stmf_lport, &scs);
599 599 break;
600 600 case TE_STMF_ONLINE_COMPLETE_ACK:
601 601 case TE_STMF_OFFLINE_COMPLETE_ACK:
602 602 /* Ignore */
603 603 break;
604 604 case TE_STMF_DEREG_RETRY:
605 605 tgt_sm_new_state(tgt, ctx, TS_DELETING_STMF_DEREG);
606 606 break;
607 607 default:
608 608 ASSERT(0);
609 609 }
610 610 }
611 611
612 612 static void
613 613 tgt_sm_deleting(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx)
614 614 {
615 615 stmf_change_status_t scs;
616 616
617 617 /* Terminal state, no events */
618 618 switch (ctx->te_ctx_event) {
619 619 case TE_STMF_ONLINE_REQ:
620 620 case TE_STMF_OFFLINE_REQ:
621 621 /*
622 622 * We can't complete STMF's request since we are being deleted
623 623 */
624 624 scs.st_completion_status = STMF_INVALID_ARG;
625 625 scs.st_additional_info = NULL;
626 626 (void) stmf_ctl((ctx->te_ctx_event == TE_STMF_ONLINE_REQ) ?
627 627 STMF_CMD_LPORT_ONLINE_COMPLETE :
628 628 STMF_CMD_LPORT_OFFLINE_COMPLETE,
629 629 tgt->target_stmf_lport, &scs);
630 630 break;
631 631 case TE_STMF_ONLINE_COMPLETE_ACK:
632 632 case TE_STMF_OFFLINE_COMPLETE_ACK:
633 633 /* Ignore */
634 634 break;
635 635 default:
636 636 ASSERT(0);
637 637 }
638 638 }
639 639
640 640
641 641 static void
642 642 iscsit_tgt_dereg_retry(void *arg)
643 643 {
644 644 iscsit_tgt_t *tgt = arg;
645 645
↓ open down ↓ |
645 lines elided |
↑ open up ↑ |
646 646 /*
647 647 * Rather than guaranteeing the target state machine code will not
648 648 * block for long periods of time (tying up this callout thread)
649 649 * we will queue a task on the taskq to send the retry event.
650 650 * If it fails we'll setup another timeout and try again later.
651 651 */
652 652 if (taskq_dispatch(iscsit_global.global_dispatch_taskq,
653 653 iscsit_tgt_dereg_task, tgt, DDI_NOSLEEP) == NULL) {
654 654 /* Dispatch failed, try again later */
655 655 (void) timeout(iscsit_tgt_dereg_retry, tgt,
656 - drv_usectohz(TGT_DEREG_RETRY_SECONDS * 1000000));
656 + drv_sectohz(TGT_DEREG_RETRY_SECONDS));
657 657 }
658 658 }
659 659
660 660 static void
661 661 iscsit_tgt_dereg_task(void *arg)
662 662 {
663 663 iscsit_tgt_t *tgt = arg;
664 664
665 665 iscsit_tgt_sm_event(tgt, TE_STMF_DEREG_RETRY);
666 666 }
667 667
668 668 static void
669 669 tgt_sm_new_state(iscsit_tgt_t *tgt, tgt_event_ctx_t *ctx,
670 670 iscsit_tgt_state_t new_state)
671 671 {
672 672 stmf_local_port_t *lport = tgt->target_stmf_lport;
673 673 stmf_change_status_t scs;
674 674 stmf_state_change_info_t sci;
675 675 idm_status_t idmrc;
676 676 stmf_status_t stmfrc;
677 677
678 678 scs.st_completion_status = STMF_SUCCESS;
679 679 scs.st_additional_info = NULL;
680 680
681 681 /*
682 682 * Validate new state
683 683 */
684 684 ASSERT(new_state != TS_UNDEFINED);
685 685 ASSERT3U(new_state, <, TS_MAX_STATE);
686 686
687 687 new_state = (new_state < TS_MAX_STATE) ?
688 688 new_state : TS_UNDEFINED;
689 689
690 690 IDM_SM_LOG(CE_NOTE, "tgt_sm_new_state: tgt %p, %s(%d) --> %s(%d)\n",
691 691 (void *) tgt, iscsit_ts_name[tgt->target_state], tgt->target_state,
692 692 iscsit_ts_name[new_state], new_state);
693 693 DTRACE_PROBE3(target__state__change,
694 694 iscsit_tgt_t *, tgt, tgt_event_ctx_t *, ctx,
695 695 iscsit_tgt_state_t, new_state);
696 696
697 697 mutex_enter(&tgt->target_mutex);
698 698 idm_sm_audit_state_change(&tgt->target_state_audit, SAS_ISCSIT_TGT,
699 699 (int)tgt->target_state, (int)new_state);
700 700 tgt->target_last_state = tgt->target_state;
701 701 tgt->target_state = new_state;
702 702 mutex_exit(&tgt->target_mutex);
703 703
704 704 switch (tgt->target_state) {
705 705 case TS_ONLINING:
706 706 idmrc = iscsit_tgt_online(tgt);
707 707 if (idmrc != IDM_STATUS_SUCCESS) {
708 708 scs.st_completion_status = STMF_TARGET_FAILURE;
709 709 iscsit_tgt_sm_event(tgt, TE_ONLINE_FAIL);
710 710 } else {
711 711 iscsit_tgt_sm_event(tgt, TE_ONLINE_SUCCESS);
712 712 }
713 713 /*
714 714 * Let STMF know the how the online operation completed.
715 715 * STMF will respond with an acknowlege later
716 716 */
717 717 (void) stmf_ctl(STMF_CMD_LPORT_ONLINE_COMPLETE, lport, &scs);
718 718 break;
719 719 case TS_ONLINE:
720 720 break;
721 721 case TS_STMF_ONLINE:
722 722 (void) iscsit_isns_register(tgt);
723 723 break;
724 724 case TS_DELETING_NEED_OFFLINE:
725 725 sci.st_rflags = STMF_RFLAG_STAY_OFFLINED;
726 726 sci.st_additional_info = "Offline for delete";
727 727 (void) stmf_ctl(STMF_CMD_LPORT_OFFLINE, lport, &sci);
728 728 break;
729 729 case TS_OFFLINING:
730 730 /* Async callback generates completion event */
731 731 iscsit_tgt_offline(tgt);
732 732 break;
733 733 case TS_OFFLINE:
734 734 break;
735 735 case TS_STMF_OFFLINE:
736 736 break;
737 737 case TS_DELETING_STMF_DEREG:
738 738 stmfrc = stmf_deregister_local_port(tgt->target_stmf_lport);
739 739 if (stmfrc == STMF_SUCCESS) {
740 740 iscsit_tgt_sm_event(tgt, TE_STMF_DEREG_SUCCESS);
741 741 } else {
742 742 iscsit_tgt_sm_event(tgt, TE_STMF_DEREG_FAIL);
743 743 }
744 744 break;
745 745 case TS_DELETING_STMF_DEREG_FAIL:
746 746 /* Retry dereg in 1 second */
747 747 (void) timeout(iscsit_tgt_dereg_retry, tgt,
748 748 drv_usectohz(TGT_DEREG_RETRY_SECONDS * 1000000));
749 749 break;
750 750 case TS_DELETING:
751 751 iscsit_tgt_async_wait_ref(tgt, iscsit_tgt_unref);
752 752 break;
753 753 default:
754 754 ASSERT(0);
755 755 }
756 756 }
757 757
758 758
759 759 /*
760 760 * Target, TPGT, TPG utility functions
761 761 */
762 762
763 763 it_cfg_status_t
764 764 iscsit_config_merge_tgt(it_config_t *cfg)
765 765 {
766 766 it_tgt_t *cfg_tgt;
767 767 iscsit_tgt_t *tgt, *next_tgt;
768 768 it_cfg_status_t itrc = ITCFG_SUCCESS;
769 769
770 770
771 771 /*
772 772 * 1. >> Lock <<
773 773 * 2. Removing deleted objects
774 774 * 3. Add deleted targets to global delete list
775 775 * 4. "delete" event to target state machine
776 776 * 5. >> Unlock <<
777 777 * 6. Create new targets, update modified targets
778 778 */
779 779 for (tgt = avl_first(&iscsit_global.global_target_list);
780 780 tgt != NULL;
781 781 tgt = next_tgt) {
782 782 next_tgt = AVL_NEXT(&iscsit_global.global_target_list, tgt);
783 783
784 784 if (it_tgt_lookup(cfg, tgt->target_name) == NULL) {
785 785 avl_remove(&iscsit_global.global_target_list, tgt);
786 786 list_insert_tail(
787 787 &iscsit_global.global_deleted_target_list, tgt);
788 788 iscsit_tgt_sm_event(tgt, TE_DELETE);
789 789 }
790 790 }
791 791
792 792 /* Now walk through the list of configured targets */
793 793 for (cfg_tgt = cfg->config_tgt_list;
794 794 cfg_tgt != NULL;
795 795 cfg_tgt = cfg_tgt->tgt_next) {
796 796 /* See if we have an existing target */
797 797 tgt = iscsit_tgt_lookup_locked(cfg_tgt->tgt_name);
798 798
799 799 if (tgt == NULL) {
800 800 tgt = iscsit_tgt_create(cfg_tgt);
801 801 if (tgt == NULL)
802 802 return (ITCFG_TGT_CREATE_ERR);
803 803 avl_add(&iscsit_global.global_target_list, tgt);
804 804 } else {
805 805 if (iscsit_tgt_modify(tgt, cfg_tgt) !=
806 806 IDM_STATUS_SUCCESS)
807 807 itrc = ITCFG_MISC_ERR;
808 808 iscsit_tgt_rele(tgt);
809 809 }
810 810 }
811 811
812 812 /*
813 813 * Targets on the iscsit_global.global_deleted_target_list will remove
814 814 * and destroy themselves when their associated state machines reach
815 815 * the TS_DELETED state and all references are released.
816 816 */
817 817 return (itrc);
818 818 }
819 819
820 820 iscsit_tgt_t *
821 821 iscsit_tgt_lookup(char *target_name)
822 822 {
823 823 iscsit_tgt_t *result;
824 824
825 825 ISCSIT_GLOBAL_LOCK(RW_READER);
826 826 result = iscsit_tgt_lookup_locked(target_name);
827 827 ISCSIT_GLOBAL_UNLOCK();
828 828
829 829 return (result);
830 830 }
831 831
832 832 iscsit_tgt_t *
833 833 iscsit_tgt_lookup_locked(char *target_name)
834 834 {
835 835 iscsit_tgt_t tmp_tgt;
836 836 iscsit_tgt_t *result;
837 837
838 838 /*
839 839 * Use a dummy target for lookup, filling in all fields used in AVL
840 840 * comparison.
841 841 */
842 842 tmp_tgt.target_name = target_name;
843 843 if ((result = avl_find(&iscsit_global.global_target_list,
844 844 &tmp_tgt, NULL)) != NULL) {
845 845 iscsit_tgt_hold(result);
846 846 }
847 847
848 848 return (result);
849 849 }
850 850
851 851 iscsit_tgt_t *
852 852 iscsit_tgt_create(it_tgt_t *cfg_tgt)
853 853 {
854 854 iscsit_tgt_t *result;
855 855 stmf_local_port_t *lport;
856 856 char *alias;
857 857
858 858 /*
859 859 * Each target is an STMF local port.
860 860 */
861 861 lport = stmf_alloc(STMF_STRUCT_STMF_LOCAL_PORT,
862 862 sizeof (iscsit_tgt_t) + sizeof (scsi_devid_desc_t) +
863 863 strnlen(cfg_tgt->tgt_name, MAX_ISCSI_NODENAMELEN) + 1, 0);
864 864 if (lport == NULL) {
865 865 return (NULL);
866 866 }
867 867
868 868 result = lport->lport_port_private;
869 869 result->target_state = TS_CREATED;
870 870 result->target_stmf_lport_registered = 0;
871 871 /* Use pointer arithmetic to find scsi_devid_desc_t */
872 872 result->target_devid = (scsi_devid_desc_t *)(result + 1);
873 873 (void) strcpy((char *)result->target_devid->ident, cfg_tgt->tgt_name);
874 874 result->target_devid->ident_length =
875 875 strnlen(cfg_tgt->tgt_name, MAX_ISCSI_NODENAMELEN);
876 876 result->target_devid->protocol_id = PROTOCOL_iSCSI;
877 877 result->target_devid->piv = 1;
878 878 result->target_devid->code_set = CODE_SET_ASCII;
879 879 result->target_devid->association = ID_IS_TARGET_PORT;
880 880
881 881 /* Store a shortcut to the target name */
882 882 result->target_name = (char *)result->target_devid->ident;
883 883 idm_sm_audit_init(&result->target_state_audit);
884 884 mutex_init(&result->target_mutex, NULL, MUTEX_DEFAULT, NULL);
885 885 avl_create(&result->target_sess_list, iscsit_sess_avl_compare,
886 886 sizeof (iscsit_sess_t), offsetof(iscsit_sess_t, ist_tgt_ln));
887 887 avl_create(&result->target_tpgt_list, iscsit_tpgt_avl_compare,
888 888 sizeof (iscsit_tpgt_t), offsetof(iscsit_tpgt_t, tpgt_tgt_ln));
889 889 list_create(&result->target_events, sizeof (tgt_event_ctx_t),
890 890 offsetof(tgt_event_ctx_t, te_ctx_node));
891 891 idm_refcnt_init(&result->target_refcnt, result);
892 892 idm_refcnt_init(&result->target_sess_refcnt, result);
893 893
894 894 /* Set target alias */
895 895 if (nvlist_lookup_string(cfg_tgt->tgt_properties, "alias", &alias) == 0)
896 896 lport->lport_alias = strdup(alias);
897 897
898 898 /* Finish initializing local port */
899 899 /*
900 900 * Would like infinite timeout, but this is about as long as can
901 901 * be specified to stmf on a 32 bit kernel.
902 902 */
903 903 lport->lport_abort_timeout = 2000; /* seconds */
904 904 lport->lport_id = result->target_devid;
905 905 lport->lport_pp = iscsit_global.global_pp;
906 906 lport->lport_ds = iscsit_global.global_dbuf_store;
907 907 lport->lport_xfer_data = &iscsit_xfer_scsi_data;
908 908 lport->lport_send_status = &iscsit_send_scsi_status;
909 909 lport->lport_task_free = &iscsit_lport_task_free;
910 910 lport->lport_abort = &iscsit_abort;
911 911 lport->lport_ctl = &iscsit_ctl;
912 912 result->target_stmf_lport = lport;
913 913
914 914 /*
915 915 * We need a global hold until the STMF-ONLINE state machine
916 916 * completes. Acquire that hold now, in case we need to call
917 917 * iscsit_tgt_destroy, which will also release the hold.
918 918 */
919 919 iscsit_global_hold();
920 920
921 921 /*
922 922 * Additional target modifications from config
923 923 */
924 924 if (iscsit_tgt_modify(result, cfg_tgt) != IDM_STATUS_SUCCESS) {
925 925 iscsit_tgt_destroy(result);
926 926 return (NULL);
927 927 }
928 928
929 929 /*
930 930 * Register the target with STMF but not until we have all the
931 931 * TPGT bindings and any other additional config setup. STMF
932 932 * may immediately ask us to go online.
933 933 */
934 934 if (stmf_register_local_port(lport) != STMF_SUCCESS) {
935 935 iscsit_tgt_destroy(result);
936 936 return (NULL);
937 937 }
938 938 result->target_stmf_lport_registered = 1;
939 939
940 940 return (result);
941 941 }
942 942
943 943 static idm_status_t
944 944 iscsit_tgt_modify(iscsit_tgt_t *tgt, it_tgt_t *cfg_tgt)
945 945 {
946 946 idm_status_t idmrc = IDM_STATUS_SUCCESS;
947 947 list_t tpgt_del_list;
948 948 char *alias;
949 949
950 950 /* Merge TPGT */
951 951 list_create(&tpgt_del_list, sizeof (iscsit_tpgt_t),
952 952 offsetof(iscsit_tpgt_t, tpgt_delete_ln));
953 953
954 954 mutex_enter(&tgt->target_mutex);
955 955 if (tgt->target_props) {
956 956 nvlist_free(tgt->target_props);
957 957 tgt->target_props = NULL;
958 958 }
959 959 (void) nvlist_dup(cfg_tgt->tgt_properties, &tgt->target_props,
960 960 KM_SLEEP);
961 961
962 962 /* Update alias */
963 963 if (tgt->target_stmf_lport->lport_alias) {
964 964 strfree(tgt->target_stmf_lport->lport_alias);
965 965 tgt->target_stmf_lport->lport_alias = NULL;
966 966 }
967 967 if (nvlist_lookup_string(tgt->target_props, "alias", &alias) == 0)
968 968 tgt->target_stmf_lport->lport_alias = strdup(alias);
969 969
970 970 if ((idmrc = iscsit_tgt_merge_tpgt(tgt, cfg_tgt, &tpgt_del_list)) !=
971 971 IDM_STATUS_SUCCESS) {
972 972 /* This should never happen */
973 973 cmn_err(CE_WARN, "Fail to configure TPGTs for "
974 974 "target %s, the target modification could not be "
975 975 "completed.", tgt->target_name);
976 976 }
977 977
978 978 mutex_exit(&tgt->target_mutex);
979 979
980 980 iscsit_config_destroy_tpgts(&tpgt_del_list);
981 981
982 982 /*
983 983 * If the target is truly modified (not newly created),
984 984 * inform iSNS to update the target registration.
985 985 */
986 986 if ((tgt->target_generation > 0) &&
987 987 (cfg_tgt->tgt_generation > tgt->target_generation)) {
988 988 iscsit_isns_target_update(tgt);
989 989 }
990 990
991 991 tgt->target_generation = cfg_tgt->tgt_generation;
992 992
993 993 return (idmrc);
994 994 }
995 995
996 996 void
997 997 iscsit_config_destroy_tpgts(list_t *tpgt_del_list)
998 998 {
999 999 iscsit_tpgt_t *tpgt, *next_tpgt;
1000 1000
1001 1001 for (tpgt = list_head(tpgt_del_list);
1002 1002 tpgt != NULL;
1003 1003 tpgt = next_tpgt) {
1004 1004 next_tpgt = list_next(tpgt_del_list, tpgt);
1005 1005
1006 1006 list_remove(tpgt_del_list, tpgt);
1007 1007 idm_refcnt_wait_ref(&tpgt->tpgt_refcnt);
1008 1008 iscsit_tpgt_destroy(tpgt);
1009 1009 }
1010 1010 }
1011 1011
1012 1012 void
1013 1013 iscsit_tgt_unref(void *tgt_void)
1014 1014 {
1015 1015 iscsit_tgt_t *tgt = tgt_void;
1016 1016
1017 1017 ISCSIT_GLOBAL_LOCK(RW_WRITER);
1018 1018 list_remove(&iscsit_global.global_deleted_target_list, tgt);
1019 1019 ISCSIT_GLOBAL_UNLOCK();
1020 1020 iscsit_tgt_destroy(tgt);
1021 1021 }
1022 1022
1023 1023 void
1024 1024 iscsit_tgt_async_wait_ref(iscsit_tgt_t *tgt, idm_refcnt_cb_t *cb_func)
1025 1025 {
1026 1026 idm_refcnt_async_wait_ref(&tgt->target_refcnt, cb_func);
1027 1027 }
1028 1028
1029 1029 static void
1030 1030 iscsit_tgt_destroy(iscsit_tgt_t *tgt)
1031 1031 {
1032 1032 iscsit_tpgt_t *tpgt, *next_tpgt;
1033 1033
1034 1034 ASSERT(tgt->target_state == TS_DELETING ||
1035 1035 (tgt->target_state == TS_CREATED &&
1036 1036 tgt->target_stmf_lport_registered == 0));
1037 1037
1038 1038 /*
1039 1039 * Destroy all target portal group tags
1040 1040 */
1041 1041 mutex_enter(&tgt->target_mutex);
1042 1042 for (tpgt = avl_first(&tgt->target_tpgt_list);
1043 1043 tpgt != NULL;
1044 1044 tpgt = next_tpgt) {
1045 1045 next_tpgt = AVL_NEXT(&tgt->target_tpgt_list, tpgt);
1046 1046 avl_remove(&tgt->target_tpgt_list, tpgt);
1047 1047 iscsit_tpgt_destroy(tpgt);
1048 1048 }
1049 1049
1050 1050 if (tgt->target_props) {
1051 1051 nvlist_free(tgt->target_props);
1052 1052 }
1053 1053 mutex_exit(&tgt->target_mutex);
1054 1054
1055 1055 /*
1056 1056 * Destroy target
1057 1057 */
1058 1058 idm_refcnt_destroy(&tgt->target_sess_refcnt);
1059 1059 idm_refcnt_destroy(&tgt->target_refcnt);
1060 1060 list_destroy(&tgt->target_events);
1061 1061 avl_destroy(&tgt->target_tpgt_list);
1062 1062 avl_destroy(&tgt->target_sess_list);
1063 1063 mutex_destroy(&tgt->target_mutex);
1064 1064 if (tgt->target_stmf_lport->lport_alias)
1065 1065 strfree(tgt->target_stmf_lport->lport_alias);
1066 1066 stmf_free(tgt->target_stmf_lport); /* Also frees "tgt' */
1067 1067 iscsit_global_rele();
1068 1068 }
1069 1069
1070 1070 void
1071 1071 iscsit_tgt_hold(iscsit_tgt_t *tgt)
1072 1072 {
1073 1073 idm_refcnt_hold(&tgt->target_refcnt);
1074 1074 }
1075 1075
1076 1076 void
1077 1077 iscsit_tgt_rele(iscsit_tgt_t *tgt)
1078 1078 {
1079 1079 idm_refcnt_rele(&tgt->target_refcnt);
1080 1080 }
1081 1081
1082 1082 int
1083 1083 iscsit_tgt_avl_compare(const void *void_tgt1, const void *void_tgt2)
1084 1084 {
1085 1085 const iscsit_tgt_t *tgt1 = void_tgt1;
1086 1086 const iscsit_tgt_t *tgt2 = void_tgt2;
1087 1087 int result;
1088 1088
1089 1089 /*
1090 1090 * Sort by ISID first then TSIH
1091 1091 */
1092 1092 result = strcmp(tgt1->target_name, tgt2->target_name);
1093 1093 if (result < 0) {
1094 1094 return (-1);
1095 1095 } else if (result > 0) {
1096 1096 return (1);
1097 1097 }
1098 1098
1099 1099 return (0);
1100 1100 }
1101 1101
1102 1102
1103 1103 iscsit_tpgt_t *
1104 1104 iscsit_tgt_lookup_tpgt(iscsit_tgt_t *tgt, uint16_t tag)
1105 1105 {
1106 1106 iscsit_tpgt_t *result;
1107 1107
1108 1108 mutex_enter(&tgt->target_mutex);
1109 1109 result = iscsit_tgt_lookup_tpgt_locked(tgt, tag);
1110 1110 mutex_exit(&tgt->target_mutex);
1111 1111
1112 1112 return (result);
1113 1113 }
1114 1114
1115 1115 static iscsit_tpgt_t *
1116 1116 iscsit_tgt_lookup_tpgt_locked(iscsit_tgt_t *tgt, uint16_t tag)
1117 1117 {
1118 1118 iscsit_tpgt_t tmp_tpgt;
1119 1119 iscsit_tpgt_t *result;
1120 1120
1121 1121 /* Caller holds tgt->target_mutex */
1122 1122 tmp_tpgt.tpgt_tag = tag;
1123 1123 if ((result = avl_find(&tgt->target_tpgt_list, &tmp_tpgt, NULL)) !=
1124 1124 NULL) {
1125 1125 iscsit_tpgt_hold(result);
1126 1126 }
1127 1127
1128 1128 return (result);
1129 1129 }
1130 1130
1131 1131 iscsit_portal_t *
1132 1132 iscsit_tgt_lookup_portal(iscsit_tgt_t *tgt, struct sockaddr_storage *sa,
1133 1133 iscsit_tpgt_t **output_tpgt)
1134 1134 {
1135 1135 iscsit_tpgt_t *tpgt;
1136 1136 iscsit_portal_t *portal;
1137 1137
1138 1138 /* Caller holds tgt->target_mutex */
1139 1139 ASSERT(mutex_owned(&tgt->target_mutex));
1140 1140 for (tpgt = avl_first(&tgt->target_tpgt_list);
1141 1141 tpgt != NULL;
1142 1142 tpgt = AVL_NEXT(&tgt->target_tpgt_list, tpgt)) {
1143 1143 portal = iscsit_tpg_portal_lookup(tpgt->tpgt_tpg, sa);
1144 1144 if (portal) {
1145 1145 iscsit_tpgt_hold(tpgt);
1146 1146 *output_tpgt = tpgt;
1147 1147 return (portal);
1148 1148 }
1149 1149 }
1150 1150
1151 1151 return (NULL);
1152 1152 }
1153 1153
1154 1154
1155 1155 void
1156 1156 iscsit_tgt_bind_sess(iscsit_tgt_t *tgt, iscsit_sess_t *sess)
1157 1157 {
1158 1158 if (tgt) {
1159 1159 sess->ist_lport = tgt->target_stmf_lport;
1160 1160 iscsit_tgt_hold(tgt);
1161 1161 idm_refcnt_hold(&tgt->target_sess_refcnt);
1162 1162 mutex_enter(&tgt->target_mutex);
1163 1163 avl_add(&tgt->target_sess_list, sess);
1164 1164 mutex_exit(&tgt->target_mutex);
1165 1165 } else {
1166 1166 /* Discovery session */
1167 1167 sess->ist_lport = NULL;
1168 1168 ISCSIT_GLOBAL_LOCK(RW_WRITER);
1169 1169 avl_add(&iscsit_global.global_discovery_sessions, sess);
1170 1170 ISCSIT_GLOBAL_UNLOCK();
1171 1171 }
1172 1172 }
1173 1173
1174 1174 void
1175 1175 iscsit_tgt_unbind_sess(iscsit_tgt_t *tgt, iscsit_sess_t *sess)
1176 1176 {
1177 1177 if (tgt) {
1178 1178 mutex_enter(&tgt->target_mutex);
1179 1179 avl_remove(&tgt->target_sess_list, sess);
1180 1180 mutex_exit(&tgt->target_mutex);
1181 1181 sess->ist_tgt = (iscsit_tgt_t *)SESS_UNBOUND_FROM_TGT;
1182 1182 idm_refcnt_rele(&tgt->target_sess_refcnt);
1183 1183 iscsit_tgt_rele(tgt);
1184 1184 } else {
1185 1185 /* Discovery session */
1186 1186 ISCSIT_GLOBAL_LOCK(RW_WRITER);
1187 1187 avl_remove(&iscsit_global.global_discovery_sessions, sess);
1188 1188 ISCSIT_GLOBAL_UNLOCK();
1189 1189 }
1190 1190 }
1191 1191
1192 1192 #define LOCK_FOR_SESS_LOOKUP(lookup_tgt) { \
1193 1193 if ((lookup_tgt) == NULL) { \
1194 1194 ISCSIT_GLOBAL_LOCK(RW_READER); \
1195 1195 } else { \
1196 1196 mutex_enter(&(lookup_tgt)->target_mutex); \
1197 1197 } \
1198 1198 }
1199 1199
1200 1200 #define UNLOCK_FOR_SESS_LOOKUP(lookup_tgt) { \
1201 1201 if ((lookup_tgt) == NULL) { \
1202 1202 ISCSIT_GLOBAL_UNLOCK(); \
1203 1203 } else { \
1204 1204 mutex_exit(&(lookup_tgt)->target_mutex); \
1205 1205 } \
1206 1206 }
1207 1207
1208 1208 iscsit_sess_t *
1209 1209 iscsit_tgt_lookup_sess(iscsit_tgt_t *tgt, char *initiator_name,
1210 1210 uint8_t *isid, uint16_t tsih, uint16_t tag)
1211 1211 {
1212 1212 iscsit_sess_t tmp_sess;
1213 1213 avl_tree_t *sess_avl;
1214 1214 avl_index_t where;
1215 1215 iscsit_sess_t *result;
1216 1216
1217 1217 /*
1218 1218 * If tgt is NULL then we are looking for a discovery session
1219 1219 */
1220 1220 if (tgt == NULL) {
1221 1221 sess_avl = &iscsit_global.global_discovery_sessions;
1222 1222 } else {
1223 1223 sess_avl = &tgt->target_sess_list;
1224 1224 }
1225 1225
1226 1226 LOCK_FOR_SESS_LOOKUP(tgt);
1227 1227 if (avl_numnodes(sess_avl) == NULL) {
1228 1228 UNLOCK_FOR_SESS_LOOKUP(tgt);
1229 1229 return (NULL);
1230 1230 }
1231 1231
1232 1232 /*
1233 1233 * We'll try to find a session matching ISID + TSIH first. If we
1234 1234 * can't find one then we will return the closest match. If the
1235 1235 * caller needs an exact match it must compare the TSIH after
1236 1236 * the session is returned.
1237 1237 *
1238 1238 * The reason we do this "fuzzy matching" is to allow matching
1239 1239 * sessions with different TSIH values on the same AVL list. This
1240 1240 * makes session reinstatement much easier since the new session can
1241 1241 * live on the list at the same time as the old session is cleaning up.
1242 1242 */
1243 1243 bcopy(isid, tmp_sess.ist_isid, ISCSI_ISID_LEN);
1244 1244 tmp_sess.ist_initiator_name = initiator_name;
1245 1245 tmp_sess.ist_tsih = tsih;
1246 1246 tmp_sess.ist_tpgt_tag = tag;
1247 1247
1248 1248 result = avl_find(sess_avl, &tmp_sess, &where);
1249 1249 if (result != NULL) {
1250 1250 goto found_result;
1251 1251 }
1252 1252
1253 1253 /*
1254 1254 * avl_find_nearest() may return a result with a different ISID so
1255 1255 * we should only return a result if the name and ISID match
1256 1256 */
1257 1257 result = avl_nearest(sess_avl, where, AVL_BEFORE);
1258 1258 if ((result != NULL) &&
1259 1259 (strcmp(result->ist_initiator_name, initiator_name) == 0) &&
1260 1260 (memcmp(result->ist_isid, isid, ISCSI_ISID_LEN) == 0) &&
1261 1261 (result->ist_tpgt_tag == tag)) {
1262 1262 goto found_result;
1263 1263 }
1264 1264
1265 1265 result = avl_nearest(sess_avl, where, AVL_AFTER);
1266 1266 if ((result != NULL) &&
1267 1267 (strcmp(result->ist_initiator_name, initiator_name) == 0) &&
1268 1268 (memcmp(result->ist_isid, isid, ISCSI_ISID_LEN) == 0) &&
1269 1269 (result->ist_tpgt_tag == tag)) {
1270 1270 goto found_result;
1271 1271 }
1272 1272
1273 1273 result = NULL;
1274 1274
1275 1275 found_result:
1276 1276 if ((result != NULL) &&
1277 1277 (iscsit_sess_check_hold(result) != IDM_STATUS_SUCCESS)) {
1278 1278 result = NULL;
1279 1279 }
1280 1280 UNLOCK_FOR_SESS_LOOKUP(tgt);
1281 1281 return (result);
1282 1282 }
1283 1283
1284 1284 static idm_status_t
1285 1285 iscsit_tgt_merge_tpgt(iscsit_tgt_t *tgt, it_tgt_t *cfg_tgt,
1286 1286 list_t *tpgt_del_list)
1287 1287 {
1288 1288 iscsit_tpgt_t *tpgt, *next_tpgt;
1289 1289 it_tpgt_t *cfg_tpgt;
1290 1290 idm_status_t status = IDM_STATUS_SUCCESS;
1291 1291
1292 1292 /*
1293 1293 * 1. >> Lock <<
1294 1294 * 2. Removing all objects and place on a temp list
1295 1295 * 3. Add new objects
1296 1296 * 4. >> Unlock <<
1297 1297 * 5. tpgt_del_list contains deleted objects
1298 1298 */
1299 1299 ASSERT(avl_is_empty(&tgt->target_tpgt_list) ||
1300 1300 (tpgt_del_list != NULL));
1301 1301
1302 1302 if (tpgt_del_list) {
1303 1303 for (tpgt = avl_first(&tgt->target_tpgt_list);
1304 1304 tpgt != NULL; tpgt = next_tpgt) {
1305 1305 next_tpgt = AVL_NEXT(&tgt->target_tpgt_list, tpgt);
1306 1306 avl_remove(&tgt->target_tpgt_list, tpgt);
1307 1307 if (tgt->target_state == TS_STMF_ONLINE) {
1308 1308 tpgt->tpgt_needs_tpg_offline = B_TRUE;
1309 1309 }
1310 1310 list_insert_tail(tpgt_del_list, tpgt);
1311 1311 }
1312 1312 }
1313 1313
1314 1314 if (cfg_tgt->tgt_tpgt_list != NULL) {
1315 1315 /* Add currently defined TPGTs */
1316 1316 for (cfg_tpgt = cfg_tgt->tgt_tpgt_list;
1317 1317 cfg_tpgt != NULL;
1318 1318 cfg_tpgt = cfg_tpgt->tpgt_next) {
1319 1319 tpgt = iscsit_tpgt_create(cfg_tpgt);
1320 1320 if (tpgt == NULL) {
1321 1321 /*
1322 1322 * There is a problem in the configuration we
1323 1323 * received from the ioctl -- a missing tpg.
1324 1324 * All the unbind operations have already
1325 1325 * taken place. To leave the system in a
1326 1326 * non-panic'd state, use the default tpgt.
1327 1327 */
1328 1328 status = IDM_STATUS_FAIL;
1329 1329 continue;
1330 1330 }
1331 1331 if (tgt->target_state == TS_STMF_ONLINE) {
1332 1332 (void) iscsit_tpg_online(tpgt->tpgt_tpg);
1333 1333 }
1334 1334 avl_add(&tgt->target_tpgt_list, tpgt);
1335 1335 }
1336 1336 }
1337 1337
1338 1338 /* If no TPGTs defined, add the default TPGT */
1339 1339 if (avl_numnodes(&tgt->target_tpgt_list) == 0) {
1340 1340 tpgt = iscsit_tpgt_create_default();
1341 1341 if (tgt->target_state == TS_STMF_ONLINE) {
1342 1342 (void) iscsit_tpg_online(tpgt->tpgt_tpg);
1343 1343 }
1344 1344 avl_add(&tgt->target_tpgt_list, tpgt);
1345 1345 }
1346 1346
1347 1347 return (status);
1348 1348 }
1349 1349
1350 1350 static iscsit_tpgt_t *
1351 1351 iscsit_tpgt_create(it_tpgt_t *cfg_tpgt)
1352 1352 {
1353 1353 iscsit_tpg_t *tpg;
1354 1354 iscsit_tpgt_t *result;
1355 1355
1356 1356 /* This takes a reference on the TPG */
1357 1357 tpg = iscsit_tpg_lookup_locked(cfg_tpgt->tpgt_tpg_name);
1358 1358 if (tpg == NULL)
1359 1359 return (NULL);
1360 1360
1361 1361 result = kmem_zalloc(sizeof (*result), KM_SLEEP);
1362 1362
1363 1363 result->tpgt_tpg = tpg;
1364 1364 result->tpgt_tag = cfg_tpgt->tpgt_tag;
1365 1365
1366 1366 return (result);
1367 1367 }
1368 1368
1369 1369 iscsit_tpgt_t *
1370 1370 iscsit_tpgt_create_default()
1371 1371 {
1372 1372 iscsit_tpgt_t *result;
1373 1373
1374 1374 result = kmem_zalloc(sizeof (*result), KM_SLEEP);
1375 1375
1376 1376 result->tpgt_tpg = iscsit_global.global_default_tpg;
1377 1377 iscsit_tpg_hold(result->tpgt_tpg);
1378 1378 result->tpgt_tag = ISCSIT_DEFAULT_TPGT;
1379 1379
1380 1380 return (result);
1381 1381 }
1382 1382
1383 1383 void
1384 1384 iscsit_tpgt_destroy(iscsit_tpgt_t *tpgt)
1385 1385 {
1386 1386 if (tpgt->tpgt_needs_tpg_offline) {
1387 1387 iscsit_tpg_offline(tpgt->tpgt_tpg);
1388 1388 }
1389 1389 iscsit_tpg_rele(tpgt->tpgt_tpg);
1390 1390 kmem_free(tpgt, sizeof (*tpgt));
1391 1391 }
1392 1392
1393 1393 void
1394 1394 iscsit_tpgt_hold(iscsit_tpgt_t *tpgt)
1395 1395 {
1396 1396 idm_refcnt_hold(&tpgt->tpgt_refcnt);
1397 1397 }
1398 1398
1399 1399 void
1400 1400 iscsit_tpgt_rele(iscsit_tpgt_t *tpgt)
1401 1401 {
1402 1402 idm_refcnt_rele(&tpgt->tpgt_refcnt);
1403 1403 }
1404 1404
1405 1405 int
1406 1406 iscsit_tpgt_avl_compare(const void *void_tpgt1, const void *void_tpgt2)
1407 1407 {
1408 1408 const iscsit_tpgt_t *tpgt1 = void_tpgt1;
1409 1409 const iscsit_tpgt_t *tpgt2 = void_tpgt2;
1410 1410
1411 1411 if (tpgt1->tpgt_tag < tpgt2->tpgt_tag)
1412 1412 return (-1);
1413 1413 else if (tpgt1->tpgt_tag > tpgt2->tpgt_tag)
1414 1414 return (1);
1415 1415
1416 1416 return (0);
1417 1417 }
1418 1418
1419 1419 static idm_status_t
1420 1420 iscsit_tgt_online(iscsit_tgt_t *tgt)
1421 1421 {
1422 1422 iscsit_tpgt_t *tpgt, *tpgt_fail;
1423 1423 idm_status_t rc;
1424 1424
1425 1425 mutex_enter(&tgt->target_mutex);
1426 1426
1427 1427 ASSERT(tgt->target_sess_list.avl_numnodes == 0);
1428 1428 idm_refcnt_reset(&tgt->target_sess_refcnt);
1429 1429 for (tpgt = avl_first(&tgt->target_tpgt_list);
1430 1430 tpgt != NULL;
1431 1431 tpgt = AVL_NEXT(&tgt->target_tpgt_list, tpgt)) {
1432 1432 rc = iscsit_tpg_online(tpgt->tpgt_tpg);
1433 1433 if (rc != IDM_STATUS_SUCCESS) {
1434 1434 tpgt_fail = tpgt;
1435 1435 goto tgt_online_fail;
1436 1436 }
1437 1437 }
1438 1438
1439 1439 mutex_exit(&tgt->target_mutex);
1440 1440
1441 1441 return (IDM_STATUS_SUCCESS);
1442 1442
1443 1443 tgt_online_fail:
1444 1444 /* Offline all the tpgs we successfully onlined up to the failure */
1445 1445 for (tpgt = avl_first(&tgt->target_tpgt_list);
1446 1446 tpgt != tpgt_fail;
1447 1447 tpgt = AVL_NEXT(&tgt->target_tpgt_list, tpgt)) {
1448 1448 iscsit_tpg_offline(tpgt->tpgt_tpg);
1449 1449 }
1450 1450 mutex_exit(&tgt->target_mutex);
1451 1451 return (rc);
1452 1452 }
1453 1453
1454 1454 static void
1455 1455 iscsit_tgt_offline_cb(void *tgt_void)
1456 1456 {
1457 1457 iscsit_tgt_t *tgt = tgt_void;
1458 1458 stmf_change_status_t scs;
1459 1459
1460 1460 iscsit_tgt_sm_event(tgt, TE_OFFLINE_COMPLETE);
1461 1461
1462 1462 scs.st_completion_status = STMF_SUCCESS;
1463 1463 scs.st_additional_info = NULL;
1464 1464 (void) stmf_ctl(STMF_CMD_LPORT_OFFLINE_COMPLETE,
1465 1465 tgt->target_stmf_lport, &scs);
1466 1466 }
1467 1467
1468 1468 static void
1469 1469 iscsit_tgt_offline(iscsit_tgt_t *tgt)
1470 1470 {
1471 1471 iscsit_tpgt_t *tpgt;
1472 1472 iscsit_sess_t *ist;
1473 1473
1474 1474 mutex_enter(&tgt->target_mutex);
1475 1475
1476 1476 /* Offline target portal groups */
1477 1477 for (tpgt = avl_first(&tgt->target_tpgt_list);
1478 1478 tpgt != NULL;
1479 1479 tpgt = AVL_NEXT(&tgt->target_tpgt_list, tpgt)) {
1480 1480 iscsit_tpg_offline(tpgt->tpgt_tpg);
1481 1481 }
1482 1482
1483 1483 /* Close any active sessions */
1484 1484 for (ist = avl_first(&tgt->target_sess_list);
1485 1485 ist != NULL;
1486 1486 ist = AVL_NEXT(&tgt->target_sess_list, ist)) {
1487 1487 /*
1488 1488 * This is not a synchronous operation but after all
1489 1489 * sessions have been cleaned up there will be no
1490 1490 * more session-related holds on the target.
1491 1491 */
1492 1492 iscsit_sess_close(ist);
1493 1493 }
1494 1494
1495 1495 mutex_exit(&tgt->target_mutex);
1496 1496
1497 1497 /*
1498 1498 * Wait for all the sessions to quiesce.
1499 1499 */
1500 1500 idm_refcnt_async_wait_ref(&tgt->target_sess_refcnt,
1501 1501 &iscsit_tgt_offline_cb);
1502 1502 }
1503 1503
1504 1504 it_cfg_status_t
1505 1505 iscsit_config_merge_tpg(it_config_t *cfg, list_t *tpg_del_list)
1506 1506 {
1507 1507 it_tpg_t *cfg_tpg;
1508 1508 iscsit_tpg_t *tpg, *next_tpg;
1509 1509
1510 1510 /*
1511 1511 * 1. >> Lock <<
1512 1512 * 2. Removing deleted objects and place on a temp list
1513 1513 * 3. Add new objects
1514 1514 * 4. >> Unlock <<
1515 1515 * 5. tpg_del_list contains objects to destroy
1516 1516 */
1517 1517 for (tpg = avl_first(&iscsit_global.global_tpg_list);
1518 1518 tpg != NULL;
1519 1519 tpg = next_tpg) {
1520 1520 next_tpg = AVL_NEXT(&iscsit_global.global_tpg_list, tpg);
1521 1521
1522 1522 if (it_tpg_lookup(cfg, tpg->tpg_name) == NULL) {
1523 1523 /*
1524 1524 * The policy around when to allow a target portal
1525 1525 * group to be deleted is implemented in libiscsit.
1526 1526 * By the time the request gets to the kernel module
1527 1527 * we expect that it conforms to policy so we will
1528 1528 * cleanup all references to TPG and destroy it if it
1529 1529 * is possible to do so.
1530 1530 *
1531 1531 */
1532 1532 avl_remove(&iscsit_global.global_tpg_list, tpg);
1533 1533 list_insert_tail(tpg_del_list, tpg);
1534 1534 }
1535 1535 }
1536 1536
1537 1537 /* Now walk through the list of configured target portal groups */
1538 1538 for (cfg_tpg = cfg->config_tpg_list;
1539 1539 cfg_tpg != NULL;
1540 1540 cfg_tpg = cfg_tpg->tpg_next) {
1541 1541 /* See if we have an existing target portal group */
1542 1542 tpg = iscsit_tpg_lookup_locked(cfg_tpg->tpg_name);
1543 1543
1544 1544 if (tpg == NULL) {
1545 1545 tpg = iscsit_tpg_create(cfg_tpg);
1546 1546 ASSERT(tpg != NULL);
1547 1547 avl_add(&iscsit_global.global_tpg_list, tpg);
1548 1548 } else {
1549 1549 mutex_enter(&tpg->tpg_mutex);
1550 1550 iscsit_tpg_modify(tpg, cfg_tpg);
1551 1551 mutex_exit(&tpg->tpg_mutex);
1552 1552 iscsit_tpg_rele(tpg);
1553 1553 }
1554 1554 }
1555 1555
1556 1556 return (ITCFG_SUCCESS);
1557 1557 }
1558 1558
1559 1559
1560 1560 void
1561 1561 iscsit_config_destroy_tpgs(list_t *tpg_del_list)
1562 1562 {
1563 1563 iscsit_tpg_t *tpg, *next_tpg;
1564 1564
1565 1565 /* Now finish destroying the target portal groups */
1566 1566 for (tpg = list_head(tpg_del_list);
1567 1567 tpg != NULL;
1568 1568 tpg = next_tpg) {
1569 1569 next_tpg = list_next(tpg_del_list, tpg);
1570 1570 list_remove(tpg_del_list, tpg);
1571 1571 idm_refcnt_wait_ref(&tpg->tpg_refcnt);
1572 1572
1573 1573 /* Kill it */
1574 1574 iscsit_tpg_destroy(tpg);
1575 1575 }
1576 1576 }
1577 1577
1578 1578 iscsit_tpg_t *
1579 1579 iscsit_tpg_lookup(char *tpg_name)
1580 1580 {
1581 1581 iscsit_tpg_t *result;
1582 1582
1583 1583 ISCSIT_GLOBAL_LOCK(RW_READER);
1584 1584 result = iscsit_tpg_lookup_locked(tpg_name);
1585 1585 ISCSIT_GLOBAL_UNLOCK();
1586 1586
1587 1587 return (result);
1588 1588 }
1589 1589
1590 1590 static iscsit_tpg_t *
1591 1591 iscsit_tpg_lookup_locked(char *tpg_name)
1592 1592 {
1593 1593 iscsit_tpg_t tmp_tpg;
1594 1594 iscsit_tpg_t *result;
1595 1595
1596 1596 (void) strlcpy(tmp_tpg.tpg_name, tpg_name, MAX_ISCSI_NODENAMELEN);
1597 1597 if ((result = avl_find(&iscsit_global.global_tpg_list,
1598 1598 &tmp_tpg, NULL)) != NULL) {
1599 1599 iscsit_tpg_hold(result);
1600 1600 }
1601 1601
1602 1602 return (result);
1603 1603 }
1604 1604
1605 1605 iscsit_tpg_t *
1606 1606 iscsit_tpg_create(it_tpg_t *cfg_tpg)
1607 1607 {
1608 1608 iscsit_tpg_t *tpg;
1609 1609
1610 1610 tpg = kmem_zalloc(sizeof (*tpg), KM_SLEEP);
1611 1611
1612 1612 mutex_init(&tpg->tpg_mutex, NULL, MUTEX_DEFAULT, NULL);
1613 1613 (void) strlcpy(tpg->tpg_name, cfg_tpg->tpg_name, MAX_TPG_NAMELEN);
1614 1614 avl_create(&tpg->tpg_portal_list, iscsit_portal_avl_compare,
1615 1615 sizeof (iscsit_portal_t), offsetof(iscsit_portal_t, portal_tpg_ln));
1616 1616 idm_refcnt_init(&tpg->tpg_refcnt, tpg);
1617 1617
1618 1618 mutex_enter(&tpg->tpg_mutex);
1619 1619 iscsit_tpg_modify(tpg, cfg_tpg);
1620 1620 mutex_exit(&tpg->tpg_mutex);
1621 1621 iscsit_global_hold();
1622 1622
1623 1623 return (tpg);
1624 1624 }
1625 1625
1626 1626 static void
1627 1627 iscsit_tpg_modify(iscsit_tpg_t *tpg, it_tpg_t *cfg_tpg)
1628 1628 {
1629 1629 iscsit_portal_t *portal, *next_portal;
1630 1630 it_portal_t *cfg_portal;
1631 1631
1632 1632 /* Update portals */
1633 1633 for (portal = avl_first(&tpg->tpg_portal_list);
1634 1634 portal != NULL;
1635 1635 portal = next_portal) {
1636 1636 next_portal = AVL_NEXT(&tpg->tpg_portal_list, portal);
1637 1637 if (it_portal_lookup(cfg_tpg, &portal->portal_addr) == NULL) {
1638 1638 avl_remove(&tpg->tpg_portal_list, portal);
1639 1639 iscsit_portal_delete(portal);
1640 1640 /*
1641 1641 * If the last portal is deleted from the target
1642 1642 * portal group, then the tpg->tpg_online count
1643 1643 * must be decremented. The other two callers of
1644 1644 * iscsit_portal_delete() destroy the target portal
1645 1645 * after deleting the portal so it is not necessary
1646 1646 * to decrement the tpg->tpg_online count.
1647 1647 */
1648 1648 if (avl_is_empty(&tpg->tpg_portal_list)) {
1649 1649 tpg->tpg_online--;
1650 1650 }
1651 1651 }
1652 1652 }
1653 1653
1654 1654 for (cfg_portal = cfg_tpg->tpg_portal_list;
1655 1655 cfg_portal != NULL;
1656 1656 cfg_portal = cfg_portal->portal_next) {
1657 1657 if ((portal = iscsit_tpg_portal_lookup_locked(tpg,
1658 1658 &cfg_portal->portal_addr)) == NULL) {
1659 1659 (void) iscsit_portal_create(tpg,
1660 1660 &cfg_portal->portal_addr);
1661 1661 } else {
1662 1662 iscsit_portal_rele(portal);
1663 1663 }
1664 1664 }
1665 1665 }
1666 1666
1667 1667 void
1668 1668 iscsit_tpg_destroy(iscsit_tpg_t *tpg)
1669 1669 {
1670 1670 iscsit_portal_t *portal, *next_portal;
1671 1671
1672 1672 for (portal = avl_first(&tpg->tpg_portal_list);
1673 1673 portal != NULL;
1674 1674 portal = next_portal) {
1675 1675 next_portal = AVL_NEXT(&tpg->tpg_portal_list, portal);
1676 1676 avl_remove(&tpg->tpg_portal_list, portal);
1677 1677 iscsit_portal_delete(portal);
1678 1678 }
1679 1679
1680 1680 idm_refcnt_wait_ref(&tpg->tpg_refcnt);
1681 1681 idm_refcnt_destroy(&tpg->tpg_refcnt);
1682 1682 avl_destroy(&tpg->tpg_portal_list);
1683 1683 mutex_destroy(&tpg->tpg_mutex);
1684 1684 kmem_free(tpg, sizeof (*tpg));
1685 1685 iscsit_global_rele();
1686 1686 }
1687 1687
1688 1688 void
1689 1689 iscsit_tpg_hold(iscsit_tpg_t *tpg)
1690 1690 {
1691 1691 idm_refcnt_hold(&tpg->tpg_refcnt);
1692 1692 }
1693 1693
1694 1694 void
1695 1695 iscsit_tpg_rele(iscsit_tpg_t *tpg)
1696 1696 {
1697 1697 idm_refcnt_rele(&tpg->tpg_refcnt);
1698 1698 }
1699 1699
1700 1700 iscsit_tpg_t *
1701 1701 iscsit_tpg_createdefault()
1702 1702 {
1703 1703 iscsit_tpg_t *tpg;
1704 1704
1705 1705 tpg = kmem_zalloc(sizeof (*tpg), KM_SLEEP);
1706 1706
1707 1707 mutex_init(&tpg->tpg_mutex, NULL, MUTEX_DEFAULT, NULL);
1708 1708 (void) strlcpy(tpg->tpg_name, ISCSIT_DEFAULT_TPG, MAX_TPG_NAMELEN);
1709 1709 avl_create(&tpg->tpg_portal_list, iscsit_portal_avl_compare,
1710 1710 sizeof (iscsit_portal_t), offsetof(iscsit_portal_t, portal_tpg_ln));
1711 1711 idm_refcnt_init(&tpg->tpg_refcnt, tpg);
1712 1712
1713 1713 /* Now create default portal */
1714 1714 if (iscsit_portal_create(tpg, NULL) == NULL) {
1715 1715 iscsit_tpg_destroy(tpg);
1716 1716 return (NULL);
1717 1717 }
1718 1718
1719 1719 return (tpg);
1720 1720 }
1721 1721
1722 1722 void
1723 1723 iscsit_tpg_destroydefault(iscsit_tpg_t *tpg)
1724 1724 {
1725 1725 iscsit_portal_t *portal;
1726 1726
1727 1727 portal = avl_first(&tpg->tpg_portal_list);
1728 1728 ASSERT(portal != NULL);
1729 1729 avl_remove(&tpg->tpg_portal_list, portal);
1730 1730 iscsit_portal_delete(portal);
1731 1731
1732 1732 idm_refcnt_wait_ref(&tpg->tpg_refcnt);
1733 1733 idm_refcnt_destroy(&tpg->tpg_refcnt);
1734 1734 avl_destroy(&tpg->tpg_portal_list);
1735 1735 mutex_destroy(&tpg->tpg_mutex);
1736 1736 kmem_free(tpg, sizeof (*tpg));
1737 1737 }
1738 1738
1739 1739 int
1740 1740 iscsit_tpg_avl_compare(const void *void_tpg1, const void *void_tpg2)
1741 1741 {
1742 1742 const iscsit_tpg_t *tpg1 = void_tpg1;
1743 1743 const iscsit_tpg_t *tpg2 = void_tpg2;
1744 1744 int result;
1745 1745
1746 1746 /*
1747 1747 * Sort by ISID first then TSIH
1748 1748 */
1749 1749 result = strcmp(tpg1->tpg_name, tpg2->tpg_name);
1750 1750 if (result < 0) {
1751 1751 return (-1);
1752 1752 } else if (result > 0) {
1753 1753 return (1);
1754 1754 }
1755 1755
1756 1756 return (0);
1757 1757 }
1758 1758
1759 1759 idm_status_t
1760 1760 iscsit_tpg_online(iscsit_tpg_t *tpg)
1761 1761 {
1762 1762 iscsit_portal_t *portal, *portal_fail;
1763 1763 idm_status_t rc;
1764 1764
1765 1765 mutex_enter(&tpg->tpg_mutex);
1766 1766 if (tpg->tpg_online == 0) {
1767 1767 for (portal = avl_first(&tpg->tpg_portal_list);
1768 1768 portal != NULL;
1769 1769 portal = AVL_NEXT(&tpg->tpg_portal_list, portal)) {
1770 1770 rc = iscsit_portal_online(portal);
1771 1771 if (rc != IDM_STATUS_SUCCESS) {
1772 1772 portal_fail = portal;
1773 1773 goto tpg_online_fail;
1774 1774 }
1775 1775 }
1776 1776 }
1777 1777 tpg->tpg_online++;
1778 1778
1779 1779 mutex_exit(&tpg->tpg_mutex);
1780 1780 return (IDM_STATUS_SUCCESS);
1781 1781
1782 1782 tpg_online_fail:
1783 1783 /* Offline all the portals we successfully onlined up to the failure */
1784 1784 for (portal = avl_first(&tpg->tpg_portal_list);
1785 1785 portal != portal_fail;
1786 1786 portal = AVL_NEXT(&tpg->tpg_portal_list, portal)) {
1787 1787 iscsit_portal_offline(portal);
1788 1788 }
1789 1789 mutex_exit(&tpg->tpg_mutex);
1790 1790 return (rc);
1791 1791 }
1792 1792
1793 1793 void
1794 1794 iscsit_tpg_offline(iscsit_tpg_t *tpg)
1795 1795 {
1796 1796 iscsit_portal_t *portal;
1797 1797
1798 1798 mutex_enter(&tpg->tpg_mutex);
1799 1799 tpg->tpg_online--;
1800 1800 if (tpg->tpg_online == 0) {
1801 1801 for (portal = avl_first(&tpg->tpg_portal_list);
1802 1802 portal != NULL;
1803 1803 portal = AVL_NEXT(&tpg->tpg_portal_list, portal)) {
1804 1804 iscsit_portal_offline(portal);
1805 1805 }
1806 1806 }
1807 1807 mutex_exit(&tpg->tpg_mutex);
1808 1808 }
1809 1809
1810 1810 iscsit_portal_t *
1811 1811 iscsit_tpg_portal_lookup(iscsit_tpg_t *tpg, struct sockaddr_storage *sa)
1812 1812 {
1813 1813 iscsit_portal_t *result;
1814 1814
1815 1815 mutex_enter(&tpg->tpg_mutex);
1816 1816 result = iscsit_tpg_portal_lookup_locked(tpg, sa);
1817 1817 mutex_exit(&tpg->tpg_mutex);
1818 1818
1819 1819 return (result);
1820 1820 }
1821 1821
1822 1822 static iscsit_portal_t *
1823 1823 iscsit_tpg_portal_lookup_locked(iscsit_tpg_t *tpg,
1824 1824 struct sockaddr_storage *sa)
1825 1825 {
1826 1826 iscsit_portal_t tmp_portal;
1827 1827 iscsit_portal_t *result;
1828 1828
1829 1829 /* Caller holds tpg->tpg_mutex */
1830 1830 bcopy(sa, &tmp_portal.portal_addr, sizeof (*sa));
1831 1831 if ((result = avl_find(&tpg->tpg_portal_list, &tmp_portal, NULL)) !=
1832 1832 NULL) {
1833 1833 iscsit_portal_hold(result);
1834 1834 }
1835 1835
1836 1836 return (result);
1837 1837 }
1838 1838
1839 1839 iscsit_portal_t *
1840 1840 iscsit_portal_create(iscsit_tpg_t *tpg, struct sockaddr_storage *sa)
1841 1841 {
1842 1842 iscsit_portal_t *portal;
1843 1843
1844 1844 portal = kmem_zalloc(sizeof (*portal), KM_SLEEP);
1845 1845 /*
1846 1846 * If (sa == NULL) then we are being asked to create the default
1847 1847 * portal -- targets will use this portal when no portals are
1848 1848 * explicitly configured.
1849 1849 */
1850 1850 if (sa == NULL) {
1851 1851 portal->portal_default = B_TRUE;
1852 1852 } else {
1853 1853 portal->portal_default = B_FALSE;
1854 1854 bcopy(sa, &portal->portal_addr, sizeof (*sa));
1855 1855 }
1856 1856
1857 1857 idm_refcnt_init(&portal->portal_refcnt, portal);
1858 1858
1859 1859 /*
1860 1860 * Add this portal to the list
1861 1861 */
1862 1862 avl_add(&tpg->tpg_portal_list, portal);
1863 1863
1864 1864 return (portal);
1865 1865 }
1866 1866
1867 1867 void
1868 1868 iscsit_portal_delete(iscsit_portal_t *portal)
1869 1869 {
1870 1870 if (portal->portal_online > 0) {
1871 1871 iscsit_portal_offline(portal);
1872 1872 }
1873 1873
1874 1874 if (portal->portal_online == 0) {
1875 1875 ASSERT(portal->portal_svc == NULL);
1876 1876 idm_refcnt_destroy(&portal->portal_refcnt);
1877 1877 kmem_free(portal, sizeof (*portal));
1878 1878 }
1879 1879 }
1880 1880
1881 1881 void
1882 1882 iscsit_portal_hold(iscsit_portal_t *portal)
1883 1883 {
1884 1884 idm_refcnt_hold(&portal->portal_refcnt);
1885 1885 }
1886 1886
1887 1887 void
1888 1888 iscsit_portal_rele(iscsit_portal_t *portal)
1889 1889 {
1890 1890 idm_refcnt_rele(&portal->portal_refcnt);
1891 1891 }
1892 1892
1893 1893 int
1894 1894 iscsit_portal_avl_compare(const void *void_portal1, const void *void_portal2)
1895 1895 {
1896 1896 const iscsit_portal_t *portal1 = void_portal1;
1897 1897 const iscsit_portal_t *portal2 = void_portal2;
1898 1898 const struct sockaddr_storage *ss1, *ss2;
1899 1899 const struct in_addr *in1, *in2;
1900 1900 const struct in6_addr *in61, *in62;
1901 1901 int i;
1902 1902
1903 1903 /*
1904 1904 * Compare ports, then address family, then ip address
1905 1905 */
1906 1906 ss1 = &portal1->portal_addr;
1907 1907 ss2 = &portal2->portal_addr;
1908 1908 if (((struct sockaddr_in *)ss1)->sin_port !=
1909 1909 ((struct sockaddr_in *)ss2)->sin_port) {
1910 1910 if (((struct sockaddr_in *)ss1)->sin_port >
1911 1911 ((struct sockaddr_in *)ss2)->sin_port)
1912 1912 return (1);
1913 1913 else
1914 1914 return (-1);
1915 1915 }
1916 1916
1917 1917 /*
1918 1918 * ports are the same
1919 1919 */
1920 1920 if (ss1->ss_family != ss2->ss_family) {
1921 1921 if (ss1->ss_family == AF_INET)
1922 1922 return (1);
1923 1923 else
1924 1924 return (-1);
1925 1925 }
1926 1926 /*
1927 1927 * address families are the same
1928 1928 */
1929 1929 if (ss1->ss_family == AF_INET) {
1930 1930 in1 = &((struct sockaddr_in *)ss1)->sin_addr;
1931 1931 in2 = &((struct sockaddr_in *)ss2)->sin_addr;
1932 1932
1933 1933 if (in1->s_addr > in2->s_addr)
1934 1934 return (1);
1935 1935 else if (in1->s_addr < in2->s_addr)
1936 1936 return (-1);
1937 1937 else
1938 1938 return (0);
1939 1939 } else if (ss1->ss_family == AF_INET6) {
1940 1940 in61 = &((struct sockaddr_in6 *)ss1)->sin6_addr;
1941 1941 in62 = &((struct sockaddr_in6 *)ss2)->sin6_addr;
1942 1942
1943 1943 for (i = 0; i < 4; i++) {
1944 1944 if (in61->s6_addr32[i] > in62->s6_addr32[i])
1945 1945 return (1);
1946 1946 else if (in61->s6_addr32[i] < in62->s6_addr32[i])
1947 1947 return (-1);
1948 1948 }
1949 1949 return (0);
1950 1950 } else
1951 1951 cmn_err(CE_WARN,
1952 1952 "iscsit_portal_avl_compare: unknown ss_family %d",
1953 1953 ss1->ss_family);
1954 1954
1955 1955 return (1);
1956 1956 }
1957 1957
1958 1958
1959 1959 idm_status_t
1960 1960 iscsit_portal_online(iscsit_portal_t *portal)
1961 1961 {
1962 1962 idm_status_t rc = 0;
1963 1963 idm_svc_t *svc;
1964 1964 idm_svc_req_t sr;
1965 1965 uint16_t port;
1966 1966 struct sockaddr_in *sin;
1967 1967
1968 1968 /* Caller holds parent TPG mutex */
1969 1969 if (portal->portal_online == 0) {
1970 1970 /*
1971 1971 * If there is no existing IDM service instance for this port,
1972 1972 * create one. If the service exists, then the lookup,
1973 1973 * creates a reference on the existing service.
1974 1974 */
1975 1975 sin = (struct sockaddr_in *)&portal->portal_addr;
1976 1976 port = ntohs(sin->sin_port);
1977 1977 if (port == 0)
1978 1978 port = ISCSI_LISTEN_PORT;
1979 1979 ASSERT(portal->portal_svc == NULL);
1980 1980 if ((svc = idm_tgt_svc_lookup(port)) == NULL) {
1981 1981 sr.sr_port = port;
1982 1982 sr.sr_li = iscsit_global.global_li;
1983 1983 sr.sr_conn_ops.icb_rx_scsi_cmd = &iscsit_op_scsi_cmd;
1984 1984 sr.sr_conn_ops.icb_rx_scsi_rsp = NULL;
1985 1985 sr.sr_conn_ops.icb_rx_misc = &iscsit_rx_pdu;
1986 1986 sr.sr_conn_ops.icb_rx_error = &iscsit_rx_pdu_error;
1987 1987 sr.sr_conn_ops.icb_task_aborted = &iscsit_task_aborted;
1988 1988 sr.sr_conn_ops.icb_client_notify =
1989 1989 &iscsit_client_notify;
1990 1990 sr.sr_conn_ops.icb_build_hdr = &iscsit_build_hdr;
1991 1991 sr.sr_conn_ops.icb_update_statsn =
1992 1992 &iscsit_update_statsn;
1993 1993 sr.sr_conn_ops.icb_keepalive = &iscsit_keepalive;
1994 1994
1995 1995 if (idm_tgt_svc_create(&sr, &svc) !=
1996 1996 IDM_STATUS_SUCCESS) {
1997 1997 return (IDM_STATUS_FAIL);
1998 1998 }
1999 1999
2000 2000 /* Get reference on the service we just created */
2001 2001 idm_tgt_svc_hold(svc);
2002 2002 }
2003 2003 if ((rc = idm_tgt_svc_online(svc)) != IDM_STATUS_SUCCESS) {
2004 2004 idm_tgt_svc_rele_and_destroy(svc);
2005 2005 return (IDM_STATUS_FAIL);
2006 2006 }
2007 2007 portal->portal_svc = svc;
2008 2008
2009 2009 /*
2010 2010 * Only call iSNS for first online
2011 2011 */
2012 2012 iscsit_isns_portal_online(portal);
2013 2013 }
2014 2014
2015 2015 portal->portal_online++;
2016 2016
2017 2017 return (rc);
2018 2018 }
2019 2019
2020 2020 void
2021 2021 iscsit_portal_offline(iscsit_portal_t *portal)
2022 2022 {
2023 2023 portal->portal_online--;
2024 2024
2025 2025 if (portal->portal_online == 0) {
2026 2026 /*
2027 2027 * Only call iSNS for last offline
2028 2028 */
2029 2029 iscsit_isns_portal_offline(portal);
2030 2030 idm_tgt_svc_offline(portal->portal_svc);
2031 2031 /* If service is unreferenced, destroy it too */
2032 2032 idm_tgt_svc_rele_and_destroy(portal->portal_svc);
2033 2033 portal->portal_svc = NULL;
2034 2034 }
2035 2035
2036 2036 }
2037 2037
2038 2038 it_cfg_status_t
2039 2039 iscsit_config_merge_ini(it_config_t *cfg)
2040 2040 {
2041 2041 iscsit_ini_t *ini, *next_ini;
2042 2042 it_ini_t *cfg_ini;
2043 2043
2044 2044 /*
2045 2045 * Initiator objects are so simple we will just destroy all the current
2046 2046 * objects and build new ones. Nothing should ever reference an
2047 2047 * initator object.. instead just lookup the initiator object and
2048 2048 * grab the properties while holding the global config lock.
2049 2049 */
2050 2050 for (ini = avl_first(&iscsit_global.global_ini_list);
2051 2051 ini != NULL;
2052 2052 ini = next_ini) {
2053 2053 next_ini = AVL_NEXT(&iscsit_global.global_ini_list, ini);
2054 2054 avl_remove(&iscsit_global.global_ini_list, ini);
2055 2055 nvlist_free(ini->ini_props);
2056 2056 kmem_free(ini, sizeof (*ini));
2057 2057 iscsit_global_rele();
2058 2058 }
2059 2059
2060 2060 for (cfg_ini = cfg->config_ini_list;
2061 2061 cfg_ini != NULL;
2062 2062 cfg_ini = cfg_ini->ini_next) {
2063 2063 ini = kmem_zalloc(sizeof (iscsit_ini_t), KM_SLEEP);
2064 2064 (void) strlcpy(ini->ini_name, cfg_ini->ini_name,
2065 2065 MAX_ISCSI_NODENAMELEN);
2066 2066 (void) nvlist_dup(cfg_ini->ini_properties, &ini->ini_props,
2067 2067 KM_SLEEP);
2068 2068 avl_add(&iscsit_global.global_ini_list, ini);
2069 2069 iscsit_global_hold();
2070 2070 }
2071 2071
2072 2072 return (ITCFG_SUCCESS);
2073 2073 }
2074 2074
2075 2075 int
2076 2076 iscsit_ini_avl_compare(const void *void_ini1, const void *void_ini2)
2077 2077 {
2078 2078 const iscsit_ini_t *ini1 = void_ini1;
2079 2079 const iscsit_ini_t *ini2 = void_ini2;
2080 2080 int result;
2081 2081
2082 2082 /*
2083 2083 * Sort by ISID first then TSIH
2084 2084 */
2085 2085 result = strcmp(ini1->ini_name, ini2->ini_name);
2086 2086 if (result < 0) {
2087 2087 return (-1);
2088 2088 } else if (result > 0) {
2089 2089 return (1);
2090 2090 }
2091 2091
2092 2092 return (0);
2093 2093 }
2094 2094
2095 2095 iscsit_ini_t *
2096 2096 iscsit_ini_lookup_locked(char *ini_name)
2097 2097 {
2098 2098 iscsit_ini_t tmp_ini;
2099 2099 iscsit_ini_t *result;
2100 2100
2101 2101 /*
2102 2102 * Use a dummy target for lookup, filling in all fields used in AVL
2103 2103 * comparison.
2104 2104 */
2105 2105 (void) strlcpy(tmp_ini.ini_name, ini_name, MAX_ISCSI_NODENAMELEN);
2106 2106 result = avl_find(&iscsit_global.global_ini_list, &tmp_ini, NULL);
2107 2107
2108 2108 return (result);
2109 2109 }
↓ open down ↓ |
1443 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX