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