Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/comstar/port/pppt/pppt.c
+++ new/usr/src/uts/common/io/comstar/port/pppt/pppt.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) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 * Copyright 2013, 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/stat.h>
30 30 #include <sys/file.h>
31 31 #include <sys/ddi.h>
32 32 #include <sys/sunddi.h>
33 33 #include <sys/modctl.h>
34 34 #include <sys/sysmacros.h>
35 35 #include <sys/nvpair.h>
36 36 #include <sys/door.h>
37 37 #include <sys/sdt.h>
38 38
39 39 #include <sys/stmf.h>
40 40 #include <sys/stmf_ioctl.h>
41 41 #include <sys/pppt_ioctl.h>
42 42 #include <sys/portif.h>
43 43
44 44 #include "pppt.h"
45 45
46 46 #define PPPT_VERSION BUILD_DATE "-1.18dev"
47 47 #define PPPT_NAME_VERSION "COMSTAR PPPT v" PPPT_VERSION
48 48
49 49 /*
50 50 * DDI entry points.
51 51 */
52 52 static int pppt_drv_attach(dev_info_t *, ddi_attach_cmd_t);
53 53 static int pppt_drv_detach(dev_info_t *, ddi_detach_cmd_t);
54 54 static int pppt_drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
55 55 static int pppt_drv_open(dev_t *, int, int, cred_t *);
56 56 static int pppt_drv_close(dev_t, int, int, cred_t *);
57 57 static boolean_t pppt_drv_busy(void);
58 58 static int pppt_drv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
59 59
60 60 extern pppt_status_t pppt_ic_so_enable(boolean_t);
61 61 extern void pppt_ic_so_disable();
62 62 extern void stmf_ic_rx_msg(char *, size_t);
63 63
64 64 extern struct mod_ops mod_miscops;
65 65
66 66 static struct cb_ops pppt_cb_ops = {
67 67 pppt_drv_open, /* cb_open */
68 68 pppt_drv_close, /* cb_close */
69 69 nodev, /* cb_strategy */
70 70 nodev, /* cb_print */
71 71 nodev, /* cb_dump */
72 72 nodev, /* cb_read */
73 73 nodev, /* cb_write */
74 74 pppt_drv_ioctl, /* cb_ioctl */
75 75 nodev, /* cb_devmap */
76 76 nodev, /* cb_mmap */
77 77 nodev, /* cb_segmap */
78 78 nochpoll, /* cb_chpoll */
79 79 ddi_prop_op, /* cb_prop_op */
80 80 NULL, /* cb_streamtab */
81 81 D_MP, /* cb_flag */
82 82 CB_REV, /* cb_rev */
83 83 nodev, /* cb_aread */
84 84 nodev, /* cb_awrite */
85 85 };
86 86
87 87 static struct dev_ops pppt_dev_ops = {
88 88 DEVO_REV, /* devo_rev */
89 89 0, /* devo_refcnt */
90 90 pppt_drv_getinfo, /* devo_getinfo */
91 91 nulldev, /* devo_identify */
92 92 nulldev, /* devo_probe */
93 93 pppt_drv_attach, /* devo_attach */
94 94 pppt_drv_detach, /* devo_detach */
95 95 nodev, /* devo_reset */
96 96 &pppt_cb_ops, /* devo_cb_ops */
97 97 NULL, /* devo_bus_ops */
98 98 NULL, /* devo_power */
99 99 ddi_quiesce_not_needed, /* quiesce */
↓ open down ↓ |
99 lines elided |
↑ open up ↑ |
100 100 };
101 101
102 102 static struct modldrv modldrv = {
103 103 &mod_driverops,
104 104 "Proxy Port Provider",
105 105 &pppt_dev_ops,
106 106 };
107 107
108 108 static struct modlinkage modlinkage = {
109 109 MODREV_1,
110 - &modldrv,
111 - NULL,
110 + { &modldrv, NULL }
112 111 };
113 112
114 113 pppt_global_t pppt_global;
115 114
116 115 int pppt_logging = 0;
117 116
118 117 static int pppt_enable_svc(void);
119 118
120 119 static void pppt_disable_svc(void);
121 120
122 121 static int pppt_task_avl_compare(const void *tgt1, const void *tgt2);
123 122
124 123 static stmf_data_buf_t *pppt_dbuf_alloc(scsi_task_t *task,
125 124 uint32_t size, uint32_t *pminsize, uint32_t flags);
126 125
127 126 static void pppt_dbuf_free(stmf_dbuf_store_t *ds, stmf_data_buf_t *dbuf);
128 127
129 128 static void pppt_sess_destroy_task(void *ps_void);
130 129
131 130 static void pppt_task_sent_status(pppt_task_t *ptask);
132 131
133 132 static pppt_status_t pppt_task_try_abort(pppt_task_t *ptask);
134 133
135 134 static void pppt_task_rele(pppt_task_t *ptask);
136 135
137 136 static void pppt_task_update_state(pppt_task_t *ptask,
138 137 pppt_task_state_t new_state);
139 138
140 139 /*
141 140 * Lock order: global --> target --> session --> task
142 141 */
143 142
144 143 int
145 144 _init(void)
146 145 {
147 146 int rc;
148 147
149 148 mutex_init(&pppt_global.global_lock, NULL, MUTEX_DEFAULT, NULL);
150 149 mutex_init(&pppt_global.global_door_lock, NULL, MUTEX_DEFAULT, NULL);
151 150 pppt_global.global_svc_state = PSS_DETACHED;
152 151
153 152 if ((rc = mod_install(&modlinkage)) != 0) {
154 153 mutex_destroy(&pppt_global.global_door_lock);
155 154 mutex_destroy(&pppt_global.global_lock);
156 155 return (rc);
157 156 }
158 157
159 158 return (rc);
160 159 }
161 160
162 161 int
163 162 _info(struct modinfo *modinfop)
164 163 {
165 164 return (mod_info(&modlinkage, modinfop));
166 165 }
167 166
168 167 int
169 168 _fini(void)
170 169 {
171 170 int rc;
172 171
173 172 rc = mod_remove(&modlinkage);
174 173
175 174 if (rc == 0) {
176 175 mutex_destroy(&pppt_global.global_lock);
177 176 mutex_destroy(&pppt_global.global_door_lock);
178 177 }
179 178
180 179 return (rc);
181 180 }
182 181
183 182 /*
184 183 * DDI entry points.
185 184 */
186 185
187 186 /* ARGSUSED */
188 187 static int
189 188 pppt_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
190 189 void **result)
191 190 {
192 191 ulong_t instance = getminor((dev_t)arg);
193 192
194 193 switch (cmd) {
195 194 case DDI_INFO_DEVT2DEVINFO:
196 195 *result = pppt_global.global_dip;
197 196 return (DDI_SUCCESS);
198 197
199 198 case DDI_INFO_DEVT2INSTANCE:
200 199 *result = (void *)instance;
201 200 return (DDI_SUCCESS);
202 201
203 202 default:
204 203 break;
205 204 }
206 205
207 206 return (DDI_FAILURE);
208 207 }
209 208
210 209 static int
211 210 pppt_drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
212 211 {
213 212 if (cmd != DDI_ATTACH) {
214 213 return (DDI_FAILURE);
215 214 }
216 215
217 216 if (ddi_get_instance(dip) != 0) {
218 217 /* we only allow instance 0 to attach */
219 218 return (DDI_FAILURE);
220 219 }
221 220
222 221 /* create the minor node */
223 222 if (ddi_create_minor_node(dip, PPPT_MODNAME, S_IFCHR, 0,
224 223 DDI_PSEUDO, 0) != DDI_SUCCESS) {
225 224 cmn_err(CE_WARN, "pppt_drv_attach: "
226 225 "failed creating minor node");
227 226 return (DDI_FAILURE);
228 227 }
229 228
230 229 pppt_global.global_svc_state = PSS_DISABLED;
231 230 pppt_global.global_dip = dip;
232 231
233 232 return (DDI_SUCCESS);
234 233 }
235 234
236 235 /*ARGSUSED*/
237 236 static int
238 237 pppt_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
239 238 {
240 239 if (cmd != DDI_DETACH)
241 240 return (DDI_FAILURE);
242 241
243 242 PPPT_GLOBAL_LOCK();
244 243 if (pppt_drv_busy()) {
245 244 PPPT_GLOBAL_UNLOCK();
246 245 return (EBUSY);
247 246 }
248 247
249 248 ddi_remove_minor_node(dip, NULL);
250 249 ddi_prop_remove_all(dip);
251 250
252 251 pppt_global.global_svc_state = PSS_DETACHED;
253 252
254 253 PPPT_GLOBAL_UNLOCK();
255 254
256 255 return (DDI_SUCCESS);
257 256 }
258 257
259 258 /*ARGSUSED*/
260 259 static int
261 260 pppt_drv_open(dev_t *devp, int flag, int otyp, cred_t *credp)
262 261 {
263 262 int rc = 0;
264 263
265 264 PPPT_GLOBAL_LOCK();
266 265
267 266 switch (pppt_global.global_svc_state) {
268 267 case PSS_DISABLED:
269 268 pppt_global.global_svc_state = PSS_ENABLING;
270 269 PPPT_GLOBAL_UNLOCK();
271 270 rc = pppt_enable_svc();
272 271 PPPT_GLOBAL_LOCK();
273 272 if (rc == 0) {
274 273 pppt_global.global_svc_state = PSS_ENABLED;
275 274 } else {
276 275 pppt_global.global_svc_state = PSS_DISABLED;
277 276 }
278 277 break;
279 278 case PSS_DISABLING:
280 279 case PSS_ENABLING:
281 280 case PSS_ENABLED:
282 281 rc = EBUSY;
283 282 break;
284 283 default:
285 284 rc = EFAULT;
286 285 break;
287 286 }
288 287
289 288 PPPT_GLOBAL_UNLOCK();
290 289
291 290 return (rc);
292 291 }
293 292
294 293 /* ARGSUSED */
295 294 static int
296 295 pppt_drv_close(dev_t dev, int flag, int otyp, cred_t *credp)
297 296 {
298 297 int rc = 0;
299 298
300 299 PPPT_GLOBAL_LOCK();
301 300
302 301 switch (pppt_global.global_svc_state) {
303 302 case PSS_ENABLED:
304 303 pppt_global.global_svc_state = PSS_DISABLING;
305 304 PPPT_GLOBAL_UNLOCK();
306 305 pppt_disable_svc();
307 306 PPPT_GLOBAL_LOCK();
308 307 pppt_global.global_svc_state = PSS_DISABLED;
309 308 /*
310 309 * release the door to the daemon
311 310 */
312 311 mutex_enter(&pppt_global.global_door_lock);
313 312 if (pppt_global.global_door != NULL) {
314 313 door_ki_rele(pppt_global.global_door);
315 314 pppt_global.global_door = NULL;
316 315 }
317 316 mutex_exit(&pppt_global.global_door_lock);
318 317 break;
319 318 default:
320 319 rc = EFAULT;
321 320 break;
322 321 }
323 322
324 323 PPPT_GLOBAL_UNLOCK();
325 324
326 325 return (rc);
327 326 }
328 327
329 328 static boolean_t
330 329 pppt_drv_busy(void)
331 330 {
332 331 switch (pppt_global.global_svc_state) {
333 332 case PSS_DISABLED:
334 333 case PSS_DETACHED:
335 334 return (B_FALSE);
336 335 default:
337 336 return (B_TRUE);
338 337 }
339 338 /* NOTREACHED */
340 339 }
341 340
342 341 /* ARGSUSED */
343 342 static int
344 343 pppt_drv_ioctl(dev_t drv, int cmd, intptr_t argp, int flag, cred_t *cred,
345 344 int *retval)
346 345 {
347 346 int rc;
348 347 void *buf;
349 348 size_t buf_size;
350 349 pppt_iocdata_t iocd;
351 350 door_handle_t new_handle;
352 351
353 352 if (drv_priv(cred) != 0) {
354 353 return (EPERM);
355 354 }
356 355
357 356 rc = ddi_copyin((void *)argp, &iocd, sizeof (iocd), flag);
358 357 if (rc)
359 358 return (EFAULT);
360 359
361 360 if (iocd.pppt_version != PPPT_VERSION_1)
362 361 return (EINVAL);
363 362
364 363 switch (cmd) {
365 364 case PPPT_MESSAGE:
366 365
367 366 /* XXX limit buf_size ? */
368 367 buf_size = (size_t)iocd.pppt_buf_size;
369 368 buf = kmem_alloc(buf_size, KM_SLEEP);
370 369 if (buf == NULL)
371 370 return (ENOMEM);
372 371
373 372 rc = ddi_copyin((void *)(unsigned long)iocd.pppt_buf,
374 373 buf, buf_size, flag);
375 374 if (rc) {
376 375 kmem_free(buf, buf_size);
377 376 return (EFAULT);
378 377 }
379 378
380 379 stmf_ic_rx_msg(buf, buf_size);
381 380
382 381 kmem_free(buf, buf_size);
383 382 break;
384 383 case PPPT_INSTALL_DOOR:
385 384
386 385 new_handle = door_ki_lookup((int)iocd.pppt_door_fd);
387 386 if (new_handle == NULL)
388 387 return (EINVAL);
389 388
390 389 mutex_enter(&pppt_global.global_door_lock);
391 390 ASSERT(pppt_global.global_svc_state == PSS_ENABLED);
392 391 if (pppt_global.global_door != NULL) {
393 392 /*
394 393 * There can only be one door installed
395 394 */
396 395 mutex_exit(&pppt_global.global_door_lock);
397 396 door_ki_rele(new_handle);
398 397 return (EBUSY);
399 398 }
400 399 pppt_global.global_door = new_handle;
401 400 mutex_exit(&pppt_global.global_door_lock);
402 401 break;
403 402 }
404 403
405 404 return (rc);
406 405 }
407 406
408 407 /*
409 408 * pppt_enable_svc
410 409 *
411 410 * registers all the configured targets and target portals with STMF
412 411 */
413 412 static int
414 413 pppt_enable_svc(void)
415 414 {
416 415 stmf_port_provider_t *pp;
417 416 stmf_dbuf_store_t *dbuf_store;
418 417 int rc = 0;
419 418
420 419 ASSERT(pppt_global.global_svc_state == PSS_ENABLING);
421 420
422 421 /*
423 422 * Make sure that can tell if we have partially allocated
424 423 * in case we need to exit and tear down anything allocated.
425 424 */
426 425 pppt_global.global_dbuf_store = NULL;
427 426 pp = NULL;
428 427 pppt_global.global_pp = NULL;
429 428 pppt_global.global_dispatch_taskq = NULL;
430 429 pppt_global.global_sess_taskq = NULL;
431 430
432 431 avl_create(&pppt_global.global_target_list,
433 432 pppt_tgt_avl_compare, sizeof (pppt_tgt_t),
434 433 offsetof(pppt_tgt_t, target_global_ln));
435 434
436 435 avl_create(&pppt_global.global_sess_list,
437 436 pppt_sess_avl_compare_by_id, sizeof (pppt_sess_t),
438 437 offsetof(pppt_sess_t, ps_global_ln));
439 438
440 439 /*
441 440 * Setup STMF dbuf store. Tf buffers are associated with a particular
442 441 * lport (FC, SRP) then the dbuf_store should stored in the lport
443 442 * context, otherwise (iSCSI) the dbuf_store should be global.
444 443 */
445 444 dbuf_store = stmf_alloc(STMF_STRUCT_DBUF_STORE, 0, 0);
446 445 if (dbuf_store == NULL) {
447 446 rc = ENOMEM;
448 447 goto tear_down_and_return;
449 448 }
450 449 dbuf_store->ds_alloc_data_buf = pppt_dbuf_alloc;
451 450 dbuf_store->ds_free_data_buf = pppt_dbuf_free;
452 451 dbuf_store->ds_port_private = NULL;
453 452 pppt_global.global_dbuf_store = dbuf_store;
454 453
455 454 /* Register port provider */
456 455 pp = stmf_alloc(STMF_STRUCT_PORT_PROVIDER, 0, 0);
457 456 if (pp == NULL) {
458 457 rc = ENOMEM;
459 458 goto tear_down_and_return;
460 459 }
461 460
462 461 pp->pp_portif_rev = PORTIF_REV_1;
463 462 pp->pp_instance = 0;
464 463 pp->pp_name = PPPT_MODNAME;
465 464 pp->pp_cb = NULL;
466 465
467 466 pppt_global.global_pp = pp;
468 467
469 468 if (stmf_register_port_provider(pp) != STMF_SUCCESS) {
470 469 rc = EIO;
471 470 goto tear_down_and_return;
472 471 }
473 472
474 473 pppt_global.global_dispatch_taskq = taskq_create("pppt_dispatch",
475 474 1, minclsyspri, 1, INT_MAX, TASKQ_PREPOPULATE);
476 475
477 476 pppt_global.global_sess_taskq = taskq_create("pppt_session",
478 477 1, minclsyspri, 1, INT_MAX, TASKQ_PREPOPULATE);
479 478
480 479 return (0);
481 480
482 481 tear_down_and_return:
483 482
484 483 if (pppt_global.global_sess_taskq) {
485 484 taskq_destroy(pppt_global.global_sess_taskq);
486 485 pppt_global.global_sess_taskq = NULL;
487 486 }
488 487
489 488 if (pppt_global.global_dispatch_taskq) {
490 489 taskq_destroy(pppt_global.global_dispatch_taskq);
491 490 pppt_global.global_dispatch_taskq = NULL;
492 491 }
493 492
494 493 if (pppt_global.global_pp)
495 494 pppt_global.global_pp = NULL;
496 495
497 496 if (pp)
498 497 stmf_free(pp);
499 498
500 499 if (pppt_global.global_dbuf_store) {
501 500 stmf_free(pppt_global.global_dbuf_store);
502 501 pppt_global.global_dbuf_store = NULL;
503 502 }
504 503
505 504 avl_destroy(&pppt_global.global_sess_list);
506 505 avl_destroy(&pppt_global.global_target_list);
507 506
508 507 return (rc);
509 508 }
510 509
511 510 /*
512 511 * pppt_disable_svc
513 512 *
514 513 * clean up all existing sessions and deregister targets from STMF
515 514 */
516 515 static void
517 516 pppt_disable_svc(void)
518 517 {
519 518 pppt_tgt_t *tgt, *next_tgt;
520 519 avl_tree_t delete_target_list;
521 520
522 521 ASSERT(pppt_global.global_svc_state == PSS_DISABLING);
523 522
524 523 avl_create(&delete_target_list,
525 524 pppt_tgt_avl_compare, sizeof (pppt_tgt_t),
526 525 offsetof(pppt_tgt_t, target_global_ln));
527 526
528 527 PPPT_GLOBAL_LOCK();
529 528 for (tgt = avl_first(&pppt_global.global_target_list);
530 529 tgt != NULL;
531 530 tgt = next_tgt) {
532 531 next_tgt = AVL_NEXT(&pppt_global.global_target_list, tgt);
533 532 avl_remove(&pppt_global.global_target_list, tgt);
534 533 avl_add(&delete_target_list, tgt);
535 534 pppt_tgt_async_delete(tgt);
536 535 }
537 536 PPPT_GLOBAL_UNLOCK();
538 537
539 538 for (tgt = avl_first(&delete_target_list);
540 539 tgt != NULL;
541 540 tgt = next_tgt) {
542 541 next_tgt = AVL_NEXT(&delete_target_list, tgt);
543 542 mutex_enter(&tgt->target_mutex);
544 543 while ((tgt->target_refcount > 0) ||
545 544 (tgt->target_state != TS_DELETING)) {
546 545 cv_wait(&tgt->target_cv, &tgt->target_mutex);
547 546 }
548 547 mutex_exit(&tgt->target_mutex);
549 548
550 549 avl_remove(&delete_target_list, tgt);
551 550 pppt_tgt_destroy(tgt);
552 551 }
553 552
554 553 taskq_destroy(pppt_global.global_sess_taskq);
555 554
556 555 taskq_destroy(pppt_global.global_dispatch_taskq);
557 556
558 557 avl_destroy(&pppt_global.global_sess_list);
559 558 avl_destroy(&pppt_global.global_target_list);
560 559
561 560 (void) stmf_deregister_port_provider(pppt_global.global_pp);
562 561
563 562 stmf_free(pppt_global.global_dbuf_store);
564 563 pppt_global.global_dbuf_store = NULL;
565 564
566 565 stmf_free(pppt_global.global_pp);
567 566 pppt_global.global_pp = NULL;
568 567 }
569 568
570 569 /*
571 570 * STMF callbacks
572 571 */
573 572
574 573 /*ARGSUSED*/
575 574 static stmf_data_buf_t *
576 575 pppt_dbuf_alloc(scsi_task_t *task, uint32_t size, uint32_t *pminsize,
577 576 uint32_t flags)
578 577 {
579 578 stmf_data_buf_t *result;
580 579 pppt_buf_t *pbuf;
581 580 uint8_t *buf;
582 581
583 582 /* Get buffer */
584 583 buf = kmem_alloc(size, KM_SLEEP);
585 584
586 585 /*
587 586 * Allocate stmf buf with private port provider section
588 587 * (pppt_buf_t)
589 588 */
590 589 result = stmf_alloc(STMF_STRUCT_DATA_BUF, sizeof (pppt_buf_t), 0);
591 590 if (result != NULL) {
592 591 /* Fill in pppt_buf_t */
593 592 pbuf = result->db_port_private;
594 593 pbuf->pbuf_stmf_buf = result;
595 594 pbuf->pbuf_is_immed = B_FALSE;
596 595
597 596 /*
598 597 * Fill in stmf_data_buf_t. DB_DONT CACHE tells
599 598 * stmf not to cache buffers but STMF doesn't do
600 599 * that yet so it's a no-op. Port providers like
601 600 * FC and SRP that have buffers associated with the
602 601 * target port would want to let STMF cache
603 602 * the buffers. Port providers like iSCSI would
604 603 * not want STMF to cache because the buffers are
605 604 * really associated with a connection, not an
606 605 * STMF target port so there is no way for STMF
607 606 * to cache the buffers effectively. These port
608 607 * providers should cache buffers internally if
609 608 * there is significant buffer setup overhead.
610 609 *
611 610 * And of course, since STMF doesn't do any internal
612 611 * caching right now anyway, all port providers should
613 612 * do what they can to minimize buffer setup overhead.
614 613 */
615 614 result->db_flags = DB_DONT_CACHE;
616 615 result->db_buf_size = size;
617 616 result->db_data_size = size;
618 617 result->db_sglist_length = 1;
619 618 result->db_sglist[0].seg_addr = buf;
620 619 result->db_sglist[0].seg_length = size;
621 620 return (result);
622 621 } else {
623 622 /*
624 623 * Couldn't get the stmf_data_buf_t so free the
625 624 * buffer
626 625 */
627 626 kmem_free(buf, size);
628 627 }
629 628
630 629 return (NULL);
631 630 }
632 631
633 632 /*ARGSUSED*/
634 633 static void
635 634 pppt_dbuf_free(stmf_dbuf_store_t *ds, stmf_data_buf_t *dbuf)
636 635 {
637 636 pppt_buf_t *pbuf = dbuf->db_port_private;
638 637
639 638 if (pbuf->pbuf_is_immed) {
640 639 stmf_ic_msg_free(pbuf->pbuf_immed_msg);
641 640 } else {
642 641 kmem_free(dbuf->db_sglist[0].seg_addr,
643 642 dbuf->db_sglist[0].seg_length);
644 643 stmf_free(dbuf);
645 644 }
646 645 }
647 646
648 647 /*ARGSUSED*/
649 648 stmf_status_t
650 649 pppt_lport_xfer_data(scsi_task_t *task, stmf_data_buf_t *dbuf,
651 650 uint32_t ioflags)
652 651 {
653 652 pppt_task_t *pppt_task = task->task_port_private;
654 653 pppt_buf_t *pbuf = dbuf->db_port_private;
655 654 stmf_ic_msg_t *msg;
656 655 stmf_ic_msg_status_t ic_msg_status;
657 656
658 657 /*
659 658 * If we are aborting then we can ignore this request, otherwise
660 659 * add a reference.
661 660 */
662 661 if (pppt_task_hold(pppt_task) != PPPT_STATUS_SUCCESS) {
663 662 return (STMF_SUCCESS);
664 663 }
665 664
666 665 /*
667 666 * If it's not immediate data then start the transfer
668 667 */
669 668 ASSERT(pbuf->pbuf_is_immed == B_FALSE);
670 669 if (dbuf->db_flags & DB_DIRECTION_TO_RPORT) {
671 670
672 671 /* Send read data */
673 672 msg = stmf_ic_scsi_data_msg_alloc(
674 673 pppt_task->pt_task_id,
675 674 pppt_task->pt_sess->ps_session_id,
676 675 pppt_task->pt_lun_id,
677 676 dbuf->db_sglist[0].seg_length,
678 677 dbuf->db_sglist[0].seg_addr, 0);
679 678
680 679 pppt_task->pt_read_buf = pbuf;
681 680 pppt_task->pt_read_xfer_msgid = msg->icm_msgid;
682 681
683 682 ic_msg_status = stmf_ic_tx_msg(msg);
684 683 pppt_task_rele(pppt_task);
685 684 if (ic_msg_status != STMF_IC_MSG_SUCCESS) {
686 685 return (STMF_FAILURE);
687 686 } else {
688 687 return (STMF_SUCCESS);
689 688 }
690 689 } else if (dbuf->db_flags & DB_DIRECTION_FROM_RPORT) {
691 690 pppt_task_rele(pppt_task);
692 691 return (STMF_FAILURE);
693 692 }
694 693
695 694 pppt_task_rele(pppt_task);
696 695
697 696 return (STMF_INVALID_ARG);
698 697 }
699 698
700 699 void
701 700 pppt_xfer_read_complete(pppt_task_t *pppt_task, stmf_status_t status)
702 701 {
703 702 pppt_buf_t *pppt_buf;
704 703 stmf_data_buf_t *dbuf;
705 704
706 705 /*
707 706 * Caller should have taken a task hold (likely via pppt_task_lookup)
708 707 *
709 708 * Get pppt_buf_t and stmf_data_buf_t pointers
710 709 */
711 710 pppt_buf = pppt_task->pt_read_buf;
712 711 dbuf = pppt_buf->pbuf_stmf_buf;
713 712 dbuf->db_xfer_status = (status == STMF_SUCCESS) ?
714 713 STMF_SUCCESS : STMF_FAILURE;
715 714
716 715 /*
717 716 * COMSTAR currently requires port providers to support
718 717 * the DB_SEND_STATUS_GOOD flag even if phase collapse is
719 718 * not supported. So we will roll our own... pretend we are
720 719 * COMSTAR and ask for a status message.
721 720 */
722 721 if ((dbuf->db_flags & DB_SEND_STATUS_GOOD) &&
723 722 (status == STMF_SUCCESS)) {
724 723 /*
725 724 * It's possible the task has been aborted since the time we
726 725 * looked it up. We need to release the hold before calling
727 726 * pppt_lport_send_status and as soon as we release the hold
728 727 * the task may disappear. Calling pppt_task_done allows us
729 728 * to determine whether the task has been aborted (in which
730 729 * case we will stop processing and return) and mark the task
731 730 * "done" which will prevent the task from being aborted while
732 731 * we are trying to send the status.
733 732 */
734 733 if (pppt_task_done(pppt_task) != PPPT_STATUS_SUCCESS) {
735 734 /* STMF will free task and buffer(s) */
736 735 pppt_task_rele(pppt_task);
737 736 return;
738 737 }
739 738 pppt_task_rele(pppt_task);
740 739
741 740 if (pppt_lport_send_status(pppt_task->pt_stmf_task, 0)
742 741 != STMF_SUCCESS) {
743 742 /* Failed to send status */
744 743 dbuf->db_xfer_status = STMF_FAILURE;
745 744 stmf_data_xfer_done(pppt_task->pt_stmf_task, dbuf,
746 745 STMF_IOF_LPORT_DONE);
747 746 }
748 747 } else {
749 748 pppt_task_rele(pppt_task);
750 749 stmf_data_xfer_done(pppt_task->pt_stmf_task, dbuf, 0);
751 750 }
752 751 }
753 752
754 753 /*ARGSUSED*/
755 754 stmf_status_t
756 755 pppt_lport_send_status(scsi_task_t *task, uint32_t ioflags)
757 756 {
758 757 pppt_task_t *ptask = task->task_port_private;
759 758 stmf_ic_msg_t *msg;
760 759 stmf_ic_msg_status_t ic_msg_status;
761 760
762 761 /*
763 762 * Mark task completed. If the state indicates it was aborted
764 763 * then we don't need to respond.
765 764 */
766 765 if (pppt_task_done(ptask) == PPPT_STATUS_ABORTED) {
767 766 return (STMF_SUCCESS);
768 767 }
769 768
770 769 /*
771 770 * Send status.
772 771 */
773 772 msg = stmf_ic_scsi_status_msg_alloc(
774 773 ptask->pt_task_id,
775 774 ptask->pt_sess->ps_session_id,
776 775 ptask->pt_lun_id,
777 776 0,
778 777 task->task_scsi_status,
779 778 task->task_status_ctrl, task->task_resid,
780 779 task->task_sense_length, task->task_sense_data, 0);
781 780
782 781 ic_msg_status = stmf_ic_tx_msg(msg);
783 782
784 783 if (ic_msg_status != STMF_IC_MSG_SUCCESS) {
785 784 pppt_task_sent_status(ptask);
786 785 stmf_send_status_done(ptask->pt_stmf_task,
787 786 STMF_FAILURE, STMF_IOF_LPORT_DONE);
788 787 return (STMF_FAILURE);
789 788 } else {
790 789 pppt_task_sent_status(ptask);
791 790 stmf_send_status_done(ptask->pt_stmf_task,
792 791 STMF_SUCCESS, STMF_IOF_LPORT_DONE);
793 792 return (STMF_SUCCESS);
794 793 }
795 794 }
796 795
797 796 void
798 797 pppt_lport_task_free(scsi_task_t *task)
799 798 {
800 799 pppt_task_t *ptask = task->task_port_private;
801 800 pppt_sess_t *ps = ptask->pt_sess;
802 801
803 802 pppt_task_rele(ptask);
804 803 pppt_sess_rele(ps);
805 804 }
806 805
807 806 /*ARGSUSED*/
808 807 stmf_status_t
809 808 pppt_lport_abort(stmf_local_port_t *lport, int abort_cmd, void *arg,
810 809 uint32_t flags)
811 810 {
812 811 scsi_task_t *st = (scsi_task_t *)arg;
813 812 pppt_task_t *ptask;
814 813
815 814 ptask = st->task_port_private;
816 815
817 816 if (pppt_task_try_abort(ptask) == PPPT_STATUS_DONE) {
818 817 /*
819 818 * This task is beyond the point where abort makes sense
820 819 * and we will soon be sending status. Tell STMF to
821 820 * go away.
822 821 */
823 822 return (STMF_BUSY);
824 823 } else {
825 824 return (STMF_ABORT_SUCCESS);
826 825 }
827 826 /*NOTREACHED*/
828 827 }
829 828
830 829 /*ARGSUSED*/
831 830 void
832 831 pppt_lport_ctl(stmf_local_port_t *lport, int cmd, void *arg)
833 832 {
834 833 switch (cmd) {
835 834 case STMF_CMD_LPORT_ONLINE:
836 835 case STMF_CMD_LPORT_OFFLINE:
837 836 case STMF_ACK_LPORT_ONLINE_COMPLETE:
838 837 case STMF_ACK_LPORT_OFFLINE_COMPLETE:
839 838 pppt_tgt_sm_ctl(lport, cmd, arg);
840 839 break;
841 840
842 841 default:
843 842 ASSERT(0);
844 843 break;
845 844 }
846 845 }
847 846
848 847 pppt_sess_t *
849 848 pppt_sess_lookup_locked(uint64_t session_id,
850 849 scsi_devid_desc_t *lport_devid, stmf_remote_port_t *rport)
851 850 {
852 851 pppt_tgt_t *tgt;
853 852 pppt_sess_t *ps;
854 853 int lport_cmp;
855 854
856 855 ASSERT(mutex_owned(&pppt_global.global_lock));
857 856
858 857 /*
859 858 * Look for existing session for this ID
860 859 */
861 860 ps = pppt_sess_lookup_by_id_locked(session_id);
862 861 if (ps == NULL) {
863 862 PPPT_INC_STAT(es_sess_lookup_no_session);
864 863 return (NULL);
865 864 }
866 865
867 866 tgt = ps->ps_target;
868 867
869 868 mutex_enter(&tgt->target_mutex);
870 869
871 870 /* Validate local/remote port names */
872 871 if ((lport_devid->ident_length !=
873 872 tgt->target_stmf_lport->lport_id->ident_length) ||
874 873 (rport->rport_tptid_sz !=
875 874 ps->ps_stmf_sess->ss_rport->rport_tptid_sz)) {
876 875 mutex_exit(&tgt->target_mutex);
877 876 PPPT_INC_STAT(es_sess_lookup_ident_mismatch);
878 877 return (NULL);
879 878 } else {
880 879 lport_cmp = bcmp(lport_devid->ident,
881 880 tgt->target_stmf_lport->lport_id->ident,
882 881 lport_devid->ident_length);
883 882 if (lport_cmp != 0 ||
884 883 (stmf_scsilib_tptid_compare(rport->rport_tptid,
885 884 ps->ps_stmf_sess->ss_rport->rport_tptid) != B_TRUE)) {
886 885 mutex_exit(&tgt->target_mutex);
887 886 PPPT_INC_STAT(es_sess_lookup_ident_mismatch);
888 887 return (NULL);
889 888 }
890 889
891 890 if (tgt->target_state != TS_STMF_ONLINE) {
892 891 mutex_exit(&tgt->target_mutex);
893 892 PPPT_INC_STAT(es_sess_lookup_bad_tgt_state);
894 893 return (NULL);
895 894 }
896 895 }
897 896 mutex_exit(&tgt->target_mutex);
898 897
899 898 return (ps);
900 899 }
901 900
902 901 pppt_sess_t *
903 902 pppt_sess_lookup_by_id_locked(uint64_t session_id)
904 903 {
905 904 pppt_sess_t tmp_ps;
906 905 pppt_sess_t *ps;
907 906
908 907 ASSERT(mutex_owned(&pppt_global.global_lock));
909 908 tmp_ps.ps_session_id = session_id;
910 909 tmp_ps.ps_closed = 0;
911 910 ps = avl_find(&pppt_global.global_sess_list, &tmp_ps, NULL);
912 911 if (ps != NULL) {
913 912 mutex_enter(&ps->ps_mutex);
914 913 if (!ps->ps_closed) {
915 914 ps->ps_refcnt++;
916 915 mutex_exit(&ps->ps_mutex);
917 916 return (ps);
918 917 }
919 918 mutex_exit(&ps->ps_mutex);
920 919 }
921 920
922 921 return (NULL);
923 922 }
924 923
925 924 /* New session */
926 925 pppt_sess_t *
927 926 pppt_sess_lookup_create(scsi_devid_desc_t *lport_devid,
928 927 scsi_devid_desc_t *rport_devid, stmf_remote_port_t *rport,
929 928 uint64_t session_id, stmf_status_t *statusp)
930 929 {
931 930 pppt_tgt_t *tgt;
932 931 pppt_sess_t *ps;
933 932 stmf_scsi_session_t *ss;
934 933 pppt_sess_t tmp_ps;
935 934 stmf_scsi_session_t tmp_ss;
936 935 *statusp = STMF_SUCCESS;
937 936
938 937 PPPT_GLOBAL_LOCK();
939 938
940 939 /*
941 940 * Look for existing session for this ID
942 941 */
943 942 ps = pppt_sess_lookup_locked(session_id, lport_devid, rport);
944 943
945 944 if (ps != NULL) {
946 945 PPPT_GLOBAL_UNLOCK();
947 946 return (ps);
948 947 }
949 948
950 949 /*
951 950 * No session with that ID, look for another session corresponding
952 951 * to the same IT nexus.
953 952 */
954 953 tgt = pppt_tgt_lookup_locked(lport_devid);
955 954 if (tgt == NULL) {
956 955 *statusp = STMF_NOT_FOUND;
957 956 PPPT_GLOBAL_UNLOCK();
958 957 return (NULL);
959 958 }
960 959
961 960 mutex_enter(&tgt->target_mutex);
962 961 if (tgt->target_state != TS_STMF_ONLINE) {
963 962 *statusp = STMF_NOT_FOUND;
964 963 mutex_exit(&tgt->target_mutex);
965 964 PPPT_GLOBAL_UNLOCK();
966 965 /* Can't create session to offline target */
967 966 return (NULL);
968 967 }
969 968
970 969 bzero(&tmp_ps, sizeof (tmp_ps));
971 970 bzero(&tmp_ss, sizeof (tmp_ss));
972 971 tmp_ps.ps_stmf_sess = &tmp_ss;
973 972 tmp_ss.ss_rport = rport;
974 973
975 974 /*
976 975 * Look for an existing session on this IT nexus
977 976 */
978 977 ps = avl_find(&tgt->target_sess_list, &tmp_ps, NULL);
979 978
980 979 if (ps != NULL) {
981 980 /*
982 981 * Now check the session ID. It should not match because if
983 982 * it did we would have found it on the global session list.
984 983 * If the session ID in the command is higher than the existing
985 984 * session ID then we need to tear down the existing session.
986 985 */
987 986 mutex_enter(&ps->ps_mutex);
988 987 ASSERT(ps->ps_session_id != session_id);
989 988 if (ps->ps_session_id > session_id) {
990 989 /* Invalid session ID */
991 990 mutex_exit(&ps->ps_mutex);
992 991 mutex_exit(&tgt->target_mutex);
993 992 PPPT_GLOBAL_UNLOCK();
994 993 *statusp = STMF_INVALID_ARG;
995 994 return (NULL);
996 995 } else {
997 996 /* Existing session needs to be invalidated */
998 997 if (!ps->ps_closed) {
999 998 pppt_sess_close_locked(ps);
1000 999 }
1001 1000 }
1002 1001 mutex_exit(&ps->ps_mutex);
1003 1002
1004 1003 /* Fallthrough and create new session */
1005 1004 }
1006 1005
1007 1006 /*
1008 1007 * Allocate and fill in pppt_session_t with the appropriate data
1009 1008 * for the protocol.
1010 1009 */
1011 1010 ps = kmem_zalloc(sizeof (*ps), KM_SLEEP);
1012 1011
1013 1012 /* Fill in session fields */
1014 1013 ps->ps_target = tgt;
1015 1014 ps->ps_session_id = session_id;
1016 1015
1017 1016 ss = stmf_alloc(STMF_STRUCT_SCSI_SESSION, 0,
1018 1017 0);
1019 1018 if (ss == NULL) {
1020 1019 mutex_exit(&tgt->target_mutex);
1021 1020 PPPT_GLOBAL_UNLOCK();
1022 1021 kmem_free(ps, sizeof (*ps));
1023 1022 *statusp = STMF_ALLOC_FAILURE;
1024 1023 return (NULL);
1025 1024 }
1026 1025
1027 1026 ss->ss_rport_id = kmem_zalloc(sizeof (scsi_devid_desc_t) +
1028 1027 rport_devid->ident_length + 1, KM_SLEEP);
1029 1028 bcopy(rport_devid, ss->ss_rport_id,
1030 1029 sizeof (scsi_devid_desc_t) + rport_devid->ident_length + 1);
1031 1030
1032 1031 ss->ss_lport = tgt->target_stmf_lport;
1033 1032
1034 1033 ss->ss_rport = stmf_remote_port_alloc(rport->rport_tptid_sz);
1035 1034 bcopy(rport->rport_tptid, ss->ss_rport->rport_tptid,
1036 1035 rport->rport_tptid_sz);
1037 1036
1038 1037 if (stmf_register_scsi_session(tgt->target_stmf_lport, ss) !=
1039 1038 STMF_SUCCESS) {
1040 1039 mutex_exit(&tgt->target_mutex);
1041 1040 PPPT_GLOBAL_UNLOCK();
1042 1041 kmem_free(ss->ss_rport_id,
1043 1042 sizeof (scsi_devid_desc_t) + rport_devid->ident_length + 1);
1044 1043 stmf_remote_port_free(ss->ss_rport);
1045 1044 stmf_free(ss);
1046 1045 kmem_free(ps, sizeof (*ps));
1047 1046 *statusp = STMF_TARGET_FAILURE;
1048 1047 return (NULL);
1049 1048 }
1050 1049
1051 1050 ss->ss_port_private = ps;
1052 1051 mutex_init(&ps->ps_mutex, NULL, MUTEX_DEFAULT, NULL);
1053 1052 cv_init(&ps->ps_cv, NULL, CV_DEFAULT, NULL);
1054 1053 avl_create(&ps->ps_task_list, pppt_task_avl_compare,
1055 1054 sizeof (pppt_task_t), offsetof(pppt_task_t, pt_sess_ln));
1056 1055 ps->ps_refcnt = 1;
1057 1056 ps->ps_stmf_sess = ss;
1058 1057 avl_add(&tgt->target_sess_list, ps);
1059 1058 avl_add(&pppt_global.global_sess_list, ps);
1060 1059 mutex_exit(&tgt->target_mutex);
1061 1060 PPPT_GLOBAL_UNLOCK();
1062 1061 stmf_trace("pppt", "New session %p", (void *)ps);
1063 1062
1064 1063 return (ps);
1065 1064 }
1066 1065
1067 1066 void
1068 1067 pppt_sess_rele(pppt_sess_t *ps)
1069 1068 {
1070 1069 mutex_enter(&ps->ps_mutex);
1071 1070 pppt_sess_rele_locked(ps);
1072 1071 mutex_exit(&ps->ps_mutex);
1073 1072 }
1074 1073
1075 1074 void
1076 1075 pppt_sess_rele_locked(pppt_sess_t *ps)
1077 1076 {
1078 1077 ASSERT(mutex_owned(&ps->ps_mutex));
1079 1078 ps->ps_refcnt--;
1080 1079 if (ps->ps_refcnt == 0) {
1081 1080 cv_signal(&ps->ps_cv);
1082 1081 }
1083 1082 }
1084 1083
1085 1084 static void pppt_sess_destroy_task(void *ps_void)
1086 1085 {
1087 1086 pppt_sess_t *ps = ps_void;
1088 1087 stmf_scsi_session_t *ss;
1089 1088
1090 1089 stmf_trace("pppt", "Session destroy task %p", (void *)ps);
1091 1090
1092 1091 ss = ps->ps_stmf_sess;
1093 1092 mutex_enter(&ps->ps_mutex);
1094 1093 stmf_deregister_scsi_session(ss->ss_lport, ss);
1095 1094 kmem_free(ss->ss_rport_id,
1096 1095 sizeof (scsi_devid_desc_t) + ss->ss_rport_id->ident_length + 1);
1097 1096 stmf_remote_port_free(ss->ss_rport);
1098 1097 avl_destroy(&ps->ps_task_list);
1099 1098 mutex_exit(&ps->ps_mutex);
1100 1099 cv_destroy(&ps->ps_cv);
1101 1100 mutex_destroy(&ps->ps_mutex);
1102 1101 stmf_free(ps->ps_stmf_sess);
1103 1102 kmem_free(ps, sizeof (*ps));
1104 1103
1105 1104 stmf_trace("pppt", "Session destroy task complete %p", (void *)ps);
1106 1105 }
1107 1106
1108 1107 int
1109 1108 pppt_sess_avl_compare_by_id(const void *void_sess1, const void *void_sess2)
1110 1109 {
1111 1110 const pppt_sess_t *psess1 = void_sess1;
1112 1111 const pppt_sess_t *psess2 = void_sess2;
1113 1112
1114 1113 if (psess1->ps_session_id < psess2->ps_session_id)
1115 1114 return (-1);
1116 1115 else if (psess1->ps_session_id > psess2->ps_session_id)
1117 1116 return (1);
1118 1117
1119 1118 /* Allow multiple duplicate sessions if one is closed */
1120 1119 ASSERT(!(psess1->ps_closed && psess2->ps_closed));
1121 1120 if (psess1->ps_closed)
1122 1121 return (-1);
1123 1122 else if (psess2->ps_closed)
1124 1123 return (1);
1125 1124
1126 1125 return (0);
1127 1126 }
1128 1127
1129 1128 int
1130 1129 pppt_sess_avl_compare_by_name(const void *void_sess1, const void *void_sess2)
1131 1130 {
1132 1131 const pppt_sess_t *psess1 = void_sess1;
1133 1132 const pppt_sess_t *psess2 = void_sess2;
1134 1133 int result;
1135 1134
1136 1135 /* Compare by tptid size */
1137 1136 if (psess1->ps_stmf_sess->ss_rport->rport_tptid_sz <
1138 1137 psess2->ps_stmf_sess->ss_rport->rport_tptid_sz) {
1139 1138 return (-1);
1140 1139 } else if (psess1->ps_stmf_sess->ss_rport->rport_tptid_sz >
1141 1140 psess2->ps_stmf_sess->ss_rport->rport_tptid_sz) {
1142 1141 return (1);
1143 1142 }
1144 1143
1145 1144 /* Now compare tptid */
1146 1145 result = memcmp(psess1->ps_stmf_sess->ss_rport->rport_tptid,
1147 1146 psess2->ps_stmf_sess->ss_rport->rport_tptid,
1148 1147 psess1->ps_stmf_sess->ss_rport->rport_tptid_sz);
1149 1148
1150 1149 if (result < 0) {
1151 1150 return (-1);
1152 1151 } else if (result > 0) {
1153 1152 return (1);
1154 1153 }
1155 1154
1156 1155 return (0);
1157 1156 }
1158 1157
1159 1158 void
1160 1159 pppt_sess_close_locked(pppt_sess_t *ps)
1161 1160 {
1162 1161 pppt_tgt_t *tgt = ps->ps_target;
1163 1162 pppt_task_t *ptask;
1164 1163
1165 1164 stmf_trace("pppt", "Session close %p", (void *)ps);
1166 1165
1167 1166 ASSERT(mutex_owned(&pppt_global.global_lock));
1168 1167 ASSERT(mutex_owned(&tgt->target_mutex));
1169 1168 ASSERT(mutex_owned(&ps->ps_mutex));
1170 1169 ASSERT(!ps->ps_closed); /* Caller should ensure session is not closed */
1171 1170
1172 1171 ps->ps_closed = B_TRUE;
1173 1172 for (ptask = avl_first(&ps->ps_task_list); ptask != NULL;
1174 1173 ptask = AVL_NEXT(&ps->ps_task_list, ptask)) {
1175 1174 mutex_enter(&ptask->pt_mutex);
1176 1175 if (ptask->pt_state == PTS_ACTIVE) {
1177 1176 stmf_abort(STMF_QUEUE_TASK_ABORT, ptask->pt_stmf_task,
1178 1177 STMF_ABORTED, NULL);
1179 1178 }
1180 1179 mutex_exit(&ptask->pt_mutex);
1181 1180 }
1182 1181
1183 1182 /*
1184 1183 * Now that all the tasks are aborting the session refcnt should
1185 1184 * go to 0.
1186 1185 */
1187 1186 while (ps->ps_refcnt != 0) {
1188 1187 cv_wait(&ps->ps_cv, &ps->ps_mutex);
1189 1188 }
1190 1189
1191 1190 avl_remove(&tgt->target_sess_list, ps);
1192 1191 avl_remove(&pppt_global.global_sess_list, ps);
1193 1192 (void) taskq_dispatch(pppt_global.global_sess_taskq,
1194 1193 &pppt_sess_destroy_task, ps, KM_SLEEP);
1195 1194
1196 1195 stmf_trace("pppt", "Session close complete %p", (void *)ps);
1197 1196 }
1198 1197
1199 1198 pppt_task_t *
1200 1199 pppt_task_alloc(void)
1201 1200 {
1202 1201 pppt_task_t *ptask;
1203 1202 pppt_buf_t *immed_pbuf;
1204 1203
1205 1204 ptask = kmem_alloc(sizeof (pppt_task_t) + sizeof (pppt_buf_t) +
1206 1205 sizeof (stmf_data_buf_t), KM_NOSLEEP);
1207 1206 if (ptask != NULL) {
1208 1207 ptask->pt_state = PTS_INIT;
1209 1208 ptask->pt_read_buf = NULL;
1210 1209 ptask->pt_read_xfer_msgid = 0;
1211 1210 ptask->pt_refcnt = 0;
1212 1211 mutex_init(&ptask->pt_mutex, NULL, MUTEX_DRIVER, NULL);
1213 1212 immed_pbuf = (pppt_buf_t *)(ptask + 1);
1214 1213 bzero(immed_pbuf, sizeof (*immed_pbuf));
1215 1214 immed_pbuf->pbuf_is_immed = B_TRUE;
1216 1215 immed_pbuf->pbuf_stmf_buf = (stmf_data_buf_t *)(immed_pbuf + 1);
1217 1216
1218 1217 bzero(immed_pbuf->pbuf_stmf_buf, sizeof (stmf_data_buf_t));
1219 1218 immed_pbuf->pbuf_stmf_buf->db_port_private = immed_pbuf;
1220 1219 immed_pbuf->pbuf_stmf_buf->db_sglist_length = 1;
1221 1220 immed_pbuf->pbuf_stmf_buf->db_flags = DB_DIRECTION_FROM_RPORT |
1222 1221 DB_DONT_CACHE;
1223 1222 ptask->pt_immed_data = immed_pbuf;
1224 1223 }
1225 1224
1226 1225 return (ptask);
1227 1226
1228 1227 }
1229 1228
1230 1229 void
1231 1230 pppt_task_free(pppt_task_t *ptask)
1232 1231 {
1233 1232 mutex_enter(&ptask->pt_mutex);
1234 1233 ASSERT(ptask->pt_refcnt == 0);
1235 1234 mutex_destroy(&ptask->pt_mutex);
1236 1235 kmem_free(ptask, sizeof (pppt_task_t) + sizeof (pppt_buf_t) +
1237 1236 sizeof (stmf_data_buf_t));
1238 1237 }
1239 1238
1240 1239 pppt_status_t
1241 1240 pppt_task_start(pppt_task_t *ptask)
1242 1241 {
1243 1242 avl_index_t where;
1244 1243
1245 1244 ASSERT(ptask->pt_state == PTS_INIT);
1246 1245
1247 1246 mutex_enter(&ptask->pt_sess->ps_mutex);
1248 1247 mutex_enter(&ptask->pt_mutex);
1249 1248 if (avl_find(&ptask->pt_sess->ps_task_list, ptask, &where) == NULL) {
1250 1249 pppt_task_update_state(ptask, PTS_ACTIVE);
1251 1250 /* Manually increment refcnt, sincd we hold the mutex... */
1252 1251 ptask->pt_refcnt++;
1253 1252 avl_insert(&ptask->pt_sess->ps_task_list, ptask, where);
1254 1253 mutex_exit(&ptask->pt_mutex);
1255 1254 mutex_exit(&ptask->pt_sess->ps_mutex);
1256 1255 return (PPPT_STATUS_SUCCESS);
1257 1256 }
1258 1257 mutex_exit(&ptask->pt_mutex);
1259 1258 mutex_exit(&ptask->pt_sess->ps_mutex);
1260 1259
1261 1260 return (PPPT_STATUS_FAIL);
1262 1261 }
1263 1262
1264 1263 pppt_status_t
1265 1264 pppt_task_done(pppt_task_t *ptask)
1266 1265 {
1267 1266 pppt_status_t pppt_status = PPPT_STATUS_SUCCESS;
1268 1267 boolean_t remove = B_FALSE;
1269 1268
1270 1269 mutex_enter(&ptask->pt_mutex);
1271 1270
1272 1271 switch (ptask->pt_state) {
1273 1272 case PTS_ACTIVE:
1274 1273 remove = B_TRUE;
1275 1274 pppt_task_update_state(ptask, PTS_DONE);
1276 1275 break;
1277 1276 case PTS_ABORTED:
1278 1277 pppt_status = PPPT_STATUS_ABORTED;
1279 1278 break;
1280 1279 case PTS_DONE:
1281 1280 /* Repeat calls are OK. Do nothing, return success */
1282 1281 break;
1283 1282 default:
1284 1283 ASSERT(0);
1285 1284 }
1286 1285
1287 1286 mutex_exit(&ptask->pt_mutex);
1288 1287
1289 1288 if (remove) {
1290 1289 mutex_enter(&ptask->pt_sess->ps_mutex);
1291 1290 avl_remove(&ptask->pt_sess->ps_task_list, ptask);
1292 1291 mutex_exit(&ptask->pt_sess->ps_mutex);
1293 1292 /* Out of the AVL tree, so drop a reference. */
1294 1293 pppt_task_rele(ptask);
1295 1294 }
1296 1295
1297 1296 return (pppt_status);
1298 1297 }
1299 1298
1300 1299 void
1301 1300 pppt_task_sent_status(pppt_task_t *ptask)
1302 1301 {
1303 1302 /*
1304 1303 * If STMF tries to abort a task after the task state changed to
1305 1304 * PTS_DONE (meaning all task processing is complete from
1306 1305 * the port provider perspective) then we return STMF_BUSY
1307 1306 * from pppt_lport_abort. STMF will return after a short interval
1308 1307 * but our calls to stmf_send_status_done will be ignored since
1309 1308 * STMF is aborting the task. That's where this state comes in.
1310 1309 * This state essentially says we are calling stmf_send_status_done
1311 1310 * so we will not be touching the task again. The next time
1312 1311 * STMF calls pppt_lport_abort we will return a success full
1313 1312 * status and the abort will succeed.
1314 1313 */
1315 1314 mutex_enter(&ptask->pt_mutex);
1316 1315 pppt_task_update_state(ptask, PTS_SENT_STATUS);
1317 1316 mutex_exit(&ptask->pt_mutex);
1318 1317 }
1319 1318
1320 1319 pppt_task_t *
1321 1320 pppt_task_lookup(stmf_ic_msgid_t msgid)
1322 1321 {
1323 1322 pppt_tgt_t *tgt;
1324 1323 pppt_sess_t *sess;
1325 1324 pppt_task_t lookup_task;
1326 1325 pppt_task_t *result;
1327 1326
1328 1327 bzero(&lookup_task, sizeof (lookup_task));
1329 1328 lookup_task.pt_task_id = msgid;
1330 1329 PPPT_GLOBAL_LOCK();
1331 1330 for (tgt = avl_first(&pppt_global.global_target_list); tgt != NULL;
1332 1331 tgt = AVL_NEXT(&pppt_global.global_target_list, tgt)) {
1333 1332
1334 1333 mutex_enter(&tgt->target_mutex);
1335 1334 for (sess = avl_first(&tgt->target_sess_list); sess != NULL;
1336 1335 sess = AVL_NEXT(&tgt->target_sess_list, sess)) {
1337 1336 mutex_enter(&sess->ps_mutex);
1338 1337 if ((result = avl_find(&sess->ps_task_list,
1339 1338 &lookup_task, NULL)) != NULL) {
1340 1339 if (pppt_task_hold(result) !=
1341 1340 PPPT_STATUS_SUCCESS) {
1342 1341 result = NULL;
1343 1342 }
1344 1343 mutex_exit(&sess->ps_mutex);
1345 1344 mutex_exit(&tgt->target_mutex);
1346 1345 PPPT_GLOBAL_UNLOCK();
1347 1346 return (result);
1348 1347 }
1349 1348 mutex_exit(&sess->ps_mutex);
1350 1349 }
1351 1350 mutex_exit(&tgt->target_mutex);
1352 1351 }
1353 1352 PPPT_GLOBAL_UNLOCK();
1354 1353
1355 1354 return (NULL);
1356 1355 }
1357 1356
1358 1357 static int
1359 1358 pppt_task_avl_compare(const void *void_task1, const void *void_task2)
1360 1359 {
1361 1360 const pppt_task_t *ptask1 = void_task1;
1362 1361 const pppt_task_t *ptask2 = void_task2;
1363 1362
1364 1363 if (ptask1->pt_task_id < ptask2->pt_task_id)
1365 1364 return (-1);
1366 1365 else if (ptask1->pt_task_id > ptask2->pt_task_id)
1367 1366 return (1);
1368 1367
1369 1368 return (0);
1370 1369 }
1371 1370
1372 1371 static pppt_status_t
1373 1372 pppt_task_try_abort(pppt_task_t *ptask)
1374 1373 {
1375 1374 boolean_t remove = B_FALSE;
1376 1375 pppt_status_t pppt_status = PPPT_STATUS_SUCCESS;
1377 1376
1378 1377 mutex_enter(&ptask->pt_mutex);
1379 1378
1380 1379 switch (ptask->pt_state) {
1381 1380 case PTS_ACTIVE:
1382 1381 remove = B_TRUE;
1383 1382 pppt_task_update_state(ptask, PTS_ABORTED);
1384 1383 break;
1385 1384 case PTS_DONE:
1386 1385 pppt_status = PPPT_STATUS_DONE;
1387 1386 break;
1388 1387 case PTS_SENT_STATUS:
1389 1388 /*
1390 1389 * Already removed so leave remove set to B_FALSE
1391 1390 * and leave status set to PPPT_STATUS_SUCCESS.
1392 1391 */
1393 1392 pppt_task_update_state(ptask, PTS_ABORTED);
1394 1393 break;
1395 1394 case PTS_ABORTED:
1396 1395 break;
1397 1396 default:
1398 1397 ASSERT(0);
1399 1398 }
1400 1399
1401 1400 mutex_exit(&ptask->pt_mutex);
1402 1401
1403 1402 if (remove) {
1404 1403 mutex_enter(&ptask->pt_sess->ps_mutex);
1405 1404 avl_remove(&ptask->pt_sess->ps_task_list, ptask);
1406 1405 mutex_exit(&ptask->pt_sess->ps_mutex);
1407 1406 /* Out of the AVL tree, so drop a reference. */
1408 1407 pppt_task_rele(ptask);
1409 1408 }
1410 1409
1411 1410 return (pppt_status);
1412 1411 }
1413 1412
1414 1413 pppt_status_t
1415 1414 pppt_task_hold(pppt_task_t *ptask)
1416 1415 {
1417 1416 pppt_status_t pppt_status = PPPT_STATUS_SUCCESS;
1418 1417
1419 1418 mutex_enter(&ptask->pt_mutex);
1420 1419 if (ptask->pt_state == PTS_ACTIVE) {
1421 1420 ptask->pt_refcnt++;
1422 1421 } else {
1423 1422 pppt_status = PPPT_STATUS_FAIL;
1424 1423 }
1425 1424 mutex_exit(&ptask->pt_mutex);
1426 1425
1427 1426 return (pppt_status);
1428 1427 }
1429 1428
1430 1429 static void
1431 1430 pppt_task_rele(pppt_task_t *ptask)
1432 1431 {
1433 1432 boolean_t freeit;
1434 1433
1435 1434 mutex_enter(&ptask->pt_mutex);
1436 1435 ptask->pt_refcnt--;
1437 1436 freeit = (ptask->pt_refcnt == 0);
1438 1437 mutex_exit(&ptask->pt_mutex);
1439 1438 if (freeit)
1440 1439 pppt_task_free(ptask);
1441 1440 }
1442 1441
1443 1442 static void
1444 1443 pppt_task_update_state(pppt_task_t *ptask,
1445 1444 pppt_task_state_t new_state)
1446 1445 {
1447 1446 PPPT_LOG(CE_NOTE, "task %p %d -> %d", (void *)ptask,
1448 1447 ptask->pt_state, new_state);
1449 1448
1450 1449 ASSERT(mutex_owned(&ptask->pt_mutex));
1451 1450 ptask->pt_state = new_state;
1452 1451 }
↓ open down ↓ |
1331 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX