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