Print this page
653 incorrect handling in iscsit of duplicate PDUs with cmdsn > expsn
Reviewed by: Garrett D'Amore <garrett@damore.org>
Reviewed by: Jason King <jason.brian.king@gmail.com>
Reviewed by: Gary Mills <gary_mills@fastmail.fm>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/io/comstar/port/iscsit/iscsit.c
+++ new/usr/src/uts/common/io/comstar/port/iscsit/iscsit.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 *
|
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23 + *
24 + * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
23 25 */
24 -/*
25 - * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
26 - */
27 26
28 27 #include <sys/cpuvar.h>
29 28 #include <sys/types.h>
30 29 #include <sys/conf.h>
31 30 #include <sys/stat.h>
32 31 #include <sys/file.h>
33 32 #include <sys/ddi.h>
34 33 #include <sys/sunddi.h>
35 34 #include <sys/modctl.h>
36 35 #include <sys/sysmacros.h>
37 36 #include <sys/socket.h>
38 37 #include <sys/strsubr.h>
39 38 #include <sys/nvpair.h>
40 39
41 40 #include <sys/stmf.h>
42 41 #include <sys/stmf_ioctl.h>
43 42 #include <sys/portif.h>
44 43 #include <sys/idm/idm.h>
45 44 #include <sys/idm/idm_conn_sm.h>
46 45
47 46 #include "iscsit_isns.h"
48 47 #include "iscsit.h"
49 48
50 49 #define ISCSIT_VERSION BUILD_DATE "-1.18dev"
51 50 #define ISCSIT_NAME_VERSION "COMSTAR ISCSIT v" ISCSIT_VERSION
52 51
53 52 /*
54 53 * DDI entry points.
55 54 */
56 55 static int iscsit_drv_attach(dev_info_t *, ddi_attach_cmd_t);
57 56 static int iscsit_drv_detach(dev_info_t *, ddi_detach_cmd_t);
58 57 static int iscsit_drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
59 58 static int iscsit_drv_open(dev_t *, int, int, cred_t *);
60 59 static int iscsit_drv_close(dev_t, int, int, cred_t *);
61 60 static boolean_t iscsit_drv_busy(void);
62 61 static int iscsit_drv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
63 62
64 63 extern struct mod_ops mod_miscops;
65 64
66 65
67 66 static struct cb_ops iscsit_cb_ops = {
68 67 iscsit_drv_open, /* cb_open */
69 68 iscsit_drv_close, /* cb_close */
70 69 nodev, /* cb_strategy */
71 70 nodev, /* cb_print */
72 71 nodev, /* cb_dump */
73 72 nodev, /* cb_read */
74 73 nodev, /* cb_write */
75 74 iscsit_drv_ioctl, /* cb_ioctl */
76 75 nodev, /* cb_devmap */
77 76 nodev, /* cb_mmap */
78 77 nodev, /* cb_segmap */
79 78 nochpoll, /* cb_chpoll */
80 79 ddi_prop_op, /* cb_prop_op */
81 80 NULL, /* cb_streamtab */
82 81 D_MP, /* cb_flag */
83 82 CB_REV, /* cb_rev */
84 83 nodev, /* cb_aread */
85 84 nodev, /* cb_awrite */
86 85 };
87 86
88 87 static struct dev_ops iscsit_dev_ops = {
89 88 DEVO_REV, /* devo_rev */
90 89 0, /* devo_refcnt */
91 90 iscsit_drv_getinfo, /* devo_getinfo */
92 91 nulldev, /* devo_identify */
93 92 nulldev, /* devo_probe */
94 93 iscsit_drv_attach, /* devo_attach */
95 94 iscsit_drv_detach, /* devo_detach */
96 95 nodev, /* devo_reset */
97 96 &iscsit_cb_ops, /* devo_cb_ops */
98 97 NULL, /* devo_bus_ops */
99 98 NULL, /* devo_power */
100 99 ddi_quiesce_not_needed, /* quiesce */
101 100 };
102 101
103 102 static struct modldrv modldrv = {
104 103 &mod_driverops,
105 104 "iSCSI Target",
106 105 &iscsit_dev_ops,
107 106 };
108 107
109 108 static struct modlinkage modlinkage = {
110 109 MODREV_1,
111 110 &modldrv,
112 111 NULL,
113 112 };
114 113
115 114
116 115 iscsit_global_t iscsit_global;
117 116
118 117 kmem_cache_t *iscsit_status_pdu_cache;
119 118
120 119 boolean_t iscsit_sm_logging = B_FALSE;
121 120
122 121 kmutex_t login_sm_session_mutex;
123 122
124 123 static idm_status_t iscsit_init(dev_info_t *dip);
125 124 static idm_status_t iscsit_enable_svc(iscsit_hostinfo_t *hostinfo);
126 125 static void iscsit_disable_svc(void);
127 126
128 127 static int
129 128 iscsit_check_cmdsn_and_queue(idm_pdu_t *rx_pdu);
130 129
131 130 static void
132 131 iscsit_add_pdu_to_queue(iscsit_sess_t *ist, idm_pdu_t *rx_pdu);
133 132
134 133 static idm_pdu_t *
135 134 iscsit_remove_pdu_from_queue(iscsit_sess_t *ist, uint32_t cmdsn);
136 135
137 136 static void
138 137 iscsit_process_pdu_in_queue(iscsit_sess_t *ist);
139 138
140 139 static void
141 140 iscsit_rxpdu_queue_monitor_session(iscsit_sess_t *ist);
142 141
143 142 static void
144 143 iscsit_rxpdu_queue_monitor(void *arg);
145 144
146 145 static void
147 146 iscsit_post_staged_pdu(idm_pdu_t *rx_pdu);
148 147
149 148 static void
150 149 iscsit_post_scsi_cmd(idm_conn_t *ic, idm_pdu_t *rx_pdu);
151 150
152 151 static void
153 152 iscsit_op_scsi_task_mgmt(iscsit_conn_t *ict, idm_pdu_t *rx_pdu);
154 153
155 154 static void
156 155 iscsit_pdu_op_noop(iscsit_conn_t *ict, idm_pdu_t *rx_pdu);
157 156
158 157 static void
159 158 iscsit_pdu_op_login_cmd(iscsit_conn_t *ict, idm_pdu_t *rx_pdu);
160 159
161 160 void
162 161 iscsit_pdu_op_text_cmd(iscsit_conn_t *ict, idm_pdu_t *rx_pdu);
163 162
164 163 static void
165 164 iscsit_pdu_op_logout_cmd(iscsit_conn_t *ict, idm_pdu_t *rx_pdu);
166 165
167 166 int iscsit_cmd_window();
168 167
169 168 static int
170 169 iscsit_sna_lt(uint32_t sn1, uint32_t sn2);
171 170
172 171 void
173 172 iscsit_set_cmdsn(iscsit_conn_t *ict, idm_pdu_t *rx_pdu);
174 173
175 174 static void
176 175 iscsit_deferred_dispatch(idm_pdu_t *rx_pdu);
177 176
178 177 static void
179 178 iscsit_deferred(void *rx_pdu_void);
180 179
181 180 static idm_status_t
182 181 iscsit_conn_accept(idm_conn_t *ic);
183 182
184 183 static idm_status_t
185 184 iscsit_ffp_enabled(idm_conn_t *ic);
186 185
187 186 static idm_status_t
188 187 iscsit_ffp_disabled(idm_conn_t *ic, idm_ffp_disable_t disable_class);
189 188
190 189 static idm_status_t
191 190 iscsit_conn_lost(idm_conn_t *ic);
192 191
193 192 static idm_status_t
194 193 iscsit_conn_destroy(idm_conn_t *ic);
195 194
196 195 static stmf_data_buf_t *
197 196 iscsit_dbuf_alloc(scsi_task_t *task, uint32_t size, uint32_t *pminsize,
198 197 uint32_t flags);
199 198
200 199 static void
201 200 iscsit_dbuf_free(stmf_dbuf_store_t *ds, stmf_data_buf_t *dbuf);
202 201
203 202 static void
204 203 iscsit_buf_xfer_cb(idm_buf_t *idb, idm_status_t status);
205 204
206 205 static void
207 206 iscsit_send_good_status_done(idm_pdu_t *pdu, idm_status_t status);
208 207
209 208 static void
210 209 iscsit_send_status_done(idm_pdu_t *pdu, idm_status_t status);
211 210
212 211 static stmf_status_t
213 212 iscsit_idm_to_stmf(idm_status_t idmrc);
214 213
215 214 static iscsit_task_t *
216 215 iscsit_task_alloc(iscsit_conn_t *ict);
217 216
218 217 static void
219 218 iscsit_task_free(iscsit_task_t *itask);
220 219
221 220 static iscsit_task_t *
222 221 iscsit_tm_task_alloc(iscsit_conn_t *ict);
223 222
224 223 static void
225 224 iscsit_tm_task_free(iscsit_task_t *itask);
226 225
227 226 static idm_status_t
228 227 iscsit_task_start(iscsit_task_t *itask);
229 228
230 229 static void
231 230 iscsit_task_done(iscsit_task_t *itask);
232 231
233 232 static int
234 233 iscsit_status_pdu_constructor(void *pdu_void, void *arg, int flags);
235 234
236 235 static void
237 236 iscsit_pp_cb(struct stmf_port_provider *pp, int cmd, void *arg, uint32_t flags);
238 237
239 238 static it_cfg_status_t
240 239 iscsit_config_merge(it_config_t *cfg);
241 240
242 241 static idm_status_t
243 242 iscsit_login_fail(idm_conn_t *ic);
244 243
245 244 static boolean_t iscsit_cmdsn_in_window(iscsit_conn_t *ict, uint32_t cmdsn);
246 245 static void iscsit_send_direct_scsi_resp(iscsit_conn_t *ict, idm_pdu_t *rx_pdu,
247 246 uint8_t response, uint8_t cmd_status);
248 247 static void iscsit_send_task_mgmt_resp(idm_pdu_t *tm_resp_pdu,
249 248 uint8_t tm_status);
250 249
251 250 /*
252 251 * MC/S: Out-of-order commands are staged on a session-wide wait
253 252 * queue until a system-tunable threshold is reached. A separate
254 253 * thread is used to scan the staging queue on all the session,
255 254 * If a delayed PDU does not arrive within a timeout, the target
256 255 * will advance to the staged PDU that is next in sequence, skipping
257 256 * over the missing PDU(s) to go past a hole in the sequence.
258 257 */
259 258 volatile int rxpdu_queue_threshold = ISCSIT_RXPDU_QUEUE_THRESHOLD;
260 259
261 260 static kmutex_t iscsit_rxpdu_queue_monitor_mutex;
262 261 kthread_t *iscsit_rxpdu_queue_monitor_thr_id;
263 262 static kt_did_t iscsit_rxpdu_queue_monitor_thr_did;
264 263 static boolean_t iscsit_rxpdu_queue_monitor_thr_running;
265 264 static kcondvar_t iscsit_rxpdu_queue_monitor_cv;
266 265
267 266 int
268 267 _init(void)
269 268 {
270 269 int rc;
271 270
272 271 rw_init(&iscsit_global.global_rwlock, NULL, RW_DRIVER, NULL);
273 272 mutex_init(&iscsit_global.global_state_mutex, NULL,
274 273 MUTEX_DRIVER, NULL);
275 274 iscsit_global.global_svc_state = ISE_DETACHED;
276 275
277 276 mutex_init(&iscsit_rxpdu_queue_monitor_mutex, NULL,
278 277 MUTEX_DRIVER, NULL);
279 278 mutex_init(&login_sm_session_mutex, NULL, MUTEX_DRIVER, NULL);
280 279 iscsit_rxpdu_queue_monitor_thr_id = NULL;
281 280 iscsit_rxpdu_queue_monitor_thr_running = B_FALSE;
282 281 cv_init(&iscsit_rxpdu_queue_monitor_cv, NULL, CV_DEFAULT, NULL);
283 282
284 283 if ((rc = mod_install(&modlinkage)) != 0) {
285 284 mutex_destroy(&iscsit_global.global_state_mutex);
286 285 rw_destroy(&iscsit_global.global_rwlock);
287 286 return (rc);
288 287 }
289 288
290 289 return (rc);
291 290 }
292 291
293 292 int
294 293 _info(struct modinfo *modinfop)
295 294 {
296 295 return (mod_info(&modlinkage, modinfop));
297 296 }
298 297
299 298 int
300 299 _fini(void)
301 300 {
302 301 int rc;
303 302
304 303 rc = mod_remove(&modlinkage);
305 304
306 305 if (rc == 0) {
307 306 mutex_destroy(&iscsit_rxpdu_queue_monitor_mutex);
308 307 mutex_destroy(&login_sm_session_mutex);
309 308 cv_destroy(&iscsit_rxpdu_queue_monitor_cv);
310 309 mutex_destroy(&iscsit_global.global_state_mutex);
311 310 rw_destroy(&iscsit_global.global_rwlock);
312 311 }
313 312
314 313 return (rc);
315 314 }
316 315
317 316 /*
318 317 * DDI entry points.
319 318 */
320 319
321 320 /* ARGSUSED */
322 321 static int
323 322 iscsit_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
324 323 void **result)
325 324 {
326 325 ulong_t instance = getminor((dev_t)arg);
327 326
328 327 switch (cmd) {
329 328 case DDI_INFO_DEVT2DEVINFO:
330 329 *result = iscsit_global.global_dip;
331 330 return (DDI_SUCCESS);
332 331
333 332 case DDI_INFO_DEVT2INSTANCE:
334 333 *result = (void *)instance;
335 334 return (DDI_SUCCESS);
336 335
337 336 default:
338 337 break;
339 338 }
340 339
341 340 return (DDI_FAILURE);
342 341 }
343 342
344 343 static int
345 344 iscsit_drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
346 345 {
347 346 if (cmd != DDI_ATTACH) {
348 347 return (DDI_FAILURE);
349 348 }
350 349
351 350 if (ddi_get_instance(dip) != 0) {
352 351 /* we only allow instance 0 to attach */
353 352 return (DDI_FAILURE);
354 353 }
355 354
356 355 /* create the minor node */
357 356 if (ddi_create_minor_node(dip, ISCSIT_MODNAME, S_IFCHR, 0,
358 357 DDI_PSEUDO, 0) != DDI_SUCCESS) {
359 358 cmn_err(CE_WARN, "iscsit_drv_attach: "
360 359 "failed creating minor node");
361 360 return (DDI_FAILURE);
362 361 }
363 362
364 363 if (iscsit_init(dip) != IDM_STATUS_SUCCESS) {
365 364 cmn_err(CE_WARN, "iscsit_drv_attach: "
366 365 "failed to initialize");
367 366 ddi_remove_minor_node(dip, NULL);
368 367 return (DDI_FAILURE);
369 368 }
370 369
371 370 iscsit_global.global_svc_state = ISE_DISABLED;
372 371 iscsit_global.global_dip = dip;
373 372
374 373 return (DDI_SUCCESS);
375 374 }
376 375
377 376 /*ARGSUSED*/
378 377 static int
379 378 iscsit_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
380 379 {
381 380 if (cmd != DDI_DETACH)
382 381 return (DDI_FAILURE);
383 382
384 383 /*
385 384 * drv_detach is called in a context that owns the
386 385 * device node for the /dev/pseudo device. If this thread blocks
387 386 * for any resource, other threads that need the /dev/pseudo device
388 387 * may end up in a deadlock with this thread.Hence, we use a
389 388 * separate lock just for the structures that drv_detach needs
390 389 * to access.
391 390 */
392 391 mutex_enter(&iscsit_global.global_state_mutex);
393 392 if (iscsit_drv_busy()) {
394 393 mutex_exit(&iscsit_global.global_state_mutex);
395 394 return (EBUSY);
396 395 }
397 396
398 397 iscsit_global.global_dip = NULL;
399 398 ddi_remove_minor_node(dip, NULL);
400 399
401 400 ldi_ident_release(iscsit_global.global_li);
402 401 iscsit_global.global_svc_state = ISE_DETACHED;
403 402
404 403 mutex_exit(&iscsit_global.global_state_mutex);
405 404
406 405 return (DDI_SUCCESS);
407 406 }
408 407
409 408 /*ARGSUSED*/
410 409 static int
411 410 iscsit_drv_open(dev_t *devp, int flag, int otyp, cred_t *credp)
412 411 {
413 412 return (0);
414 413 }
415 414
416 415 /* ARGSUSED */
417 416 static int
418 417 iscsit_drv_close(dev_t dev, int flag, int otyp, cred_t *credp)
419 418 {
420 419 return (0);
421 420 }
422 421
423 422 static boolean_t
424 423 iscsit_drv_busy(void)
425 424 {
426 425 ASSERT(MUTEX_HELD(&iscsit_global.global_state_mutex));
427 426
428 427 switch (iscsit_global.global_svc_state) {
429 428 case ISE_DISABLED:
430 429 case ISE_DETACHED:
431 430 return (B_FALSE);
432 431 default:
433 432 return (B_TRUE);
434 433 }
435 434 /* NOTREACHED */
436 435 }
437 436
438 437 /* ARGSUSED */
439 438 static int
440 439 iscsit_drv_ioctl(dev_t drv, int cmd, intptr_t argp, int flag, cred_t *cred,
441 440 int *retval)
442 441 {
443 442 iscsit_ioc_set_config_t setcfg;
444 443 iscsit_ioc_set_config32_t setcfg32;
445 444 char *cfg_pnvlist = NULL;
446 445 nvlist_t *cfg_nvlist = NULL;
447 446 it_config_t *cfg = NULL;
448 447 idm_status_t idmrc;
449 448 int rc = 0;
450 449
451 450 if (drv_priv(cred) != 0) {
452 451 return (EPERM);
453 452 }
454 453
455 454 mutex_enter(&iscsit_global.global_state_mutex);
456 455
457 456 /*
458 457 * Validate ioctl requests against global service state
459 458 */
460 459 switch (iscsit_global.global_svc_state) {
461 460 case ISE_ENABLED:
462 461 if (cmd == ISCSIT_IOC_DISABLE_SVC) {
463 462 iscsit_global.global_svc_state = ISE_DISABLING;
464 463 } else if (cmd == ISCSIT_IOC_ENABLE_SVC) {
465 464 /* Already enabled */
466 465 mutex_exit(&iscsit_global.global_state_mutex);
467 466 return (0);
468 467 } else {
469 468 iscsit_global.global_svc_state = ISE_BUSY;
470 469 }
471 470 break;
472 471 case ISE_DISABLED:
473 472 if (cmd == ISCSIT_IOC_ENABLE_SVC) {
474 473 iscsit_global.global_svc_state = ISE_ENABLING;
475 474 } else if (cmd == ISCSIT_IOC_DISABLE_SVC) {
476 475 /* Already disabled */
477 476 mutex_exit(&iscsit_global.global_state_mutex);
478 477 return (0);
479 478 } else {
480 479 rc = EFAULT;
481 480 }
482 481 break;
483 482 case ISE_BUSY:
484 483 case ISE_ENABLING:
485 484 case ISE_DISABLING:
486 485 rc = EAGAIN;
487 486 break;
488 487 case ISE_DETACHED:
489 488 default:
490 489 rc = EFAULT;
491 490 break;
492 491 }
493 492
494 493 mutex_exit(&iscsit_global.global_state_mutex);
495 494 if (rc != 0)
496 495 return (rc);
497 496
498 497 /* Handle ioctl request (enable/disable have already been handled) */
499 498 switch (cmd) {
500 499 case ISCSIT_IOC_SET_CONFIG:
501 500 /* Any errors must set state back to ISE_ENABLED */
502 501 switch (ddi_model_convert_from(flag & FMODELS)) {
503 502 case DDI_MODEL_ILP32:
504 503 if (ddi_copyin((void *)argp, &setcfg32,
505 504 sizeof (iscsit_ioc_set_config32_t), flag) != 0) {
506 505 rc = EFAULT;
507 506 goto cleanup;
508 507 }
509 508
510 509 setcfg.set_cfg_pnvlist =
511 510 (char *)((uintptr_t)setcfg32.set_cfg_pnvlist);
512 511 setcfg.set_cfg_vers = setcfg32.set_cfg_vers;
513 512 setcfg.set_cfg_pnvlist_len =
514 513 setcfg32.set_cfg_pnvlist_len;
515 514 break;
516 515 case DDI_MODEL_NONE:
517 516 if (ddi_copyin((void *)argp, &setcfg,
518 517 sizeof (iscsit_ioc_set_config_t), flag) != 0) {
519 518 rc = EFAULT;
520 519 goto cleanup;
521 520 }
522 521 break;
523 522 default:
524 523 rc = EFAULT;
525 524 goto cleanup;
526 525 }
527 526
528 527 /* Check API version */
529 528 if (setcfg.set_cfg_vers != ISCSIT_API_VERS0) {
530 529 rc = EINVAL;
531 530 goto cleanup;
532 531 }
533 532
534 533 /* Config is in packed nvlist format so unpack it */
535 534 cfg_pnvlist = kmem_alloc(setcfg.set_cfg_pnvlist_len,
536 535 KM_SLEEP);
537 536 ASSERT(cfg_pnvlist != NULL);
538 537
539 538 if (ddi_copyin(setcfg.set_cfg_pnvlist, cfg_pnvlist,
540 539 setcfg.set_cfg_pnvlist_len, flag) != 0) {
541 540 rc = EFAULT;
542 541 goto cleanup;
543 542 }
544 543
545 544 rc = nvlist_unpack(cfg_pnvlist, setcfg.set_cfg_pnvlist_len,
546 545 &cfg_nvlist, KM_SLEEP);
547 546 if (rc != 0) {
548 547 goto cleanup;
549 548 }
550 549
551 550 /* Translate nvlist */
552 551 rc = it_nv_to_config(cfg_nvlist, &cfg);
553 552 if (rc != 0) {
554 553 cmn_err(CE_WARN, "Configuration is invalid");
555 554 goto cleanup;
556 555 }
557 556
558 557 /* Update config */
559 558 rc = iscsit_config_merge(cfg);
560 559 /* FALLTHROUGH */
561 560
562 561 cleanup:
563 562 if (cfg)
564 563 it_config_free_cmn(cfg);
565 564 if (cfg_pnvlist)
566 565 kmem_free(cfg_pnvlist, setcfg.set_cfg_pnvlist_len);
567 566 if (cfg_nvlist)
568 567 nvlist_free(cfg_nvlist);
569 568
570 569 /*
571 570 * Now that the reconfig is complete set our state back to
572 571 * enabled.
573 572 */
574 573 mutex_enter(&iscsit_global.global_state_mutex);
575 574 iscsit_global.global_svc_state = ISE_ENABLED;
576 575 mutex_exit(&iscsit_global.global_state_mutex);
577 576 break;
578 577 case ISCSIT_IOC_ENABLE_SVC: {
579 578 iscsit_hostinfo_t hostinfo;
580 579
581 580 if (ddi_copyin((void *)argp, &hostinfo.length,
582 581 sizeof (hostinfo.length), flag) != 0) {
583 582 mutex_enter(&iscsit_global.global_state_mutex);
584 583 iscsit_global.global_svc_state = ISE_DISABLED;
585 584 mutex_exit(&iscsit_global.global_state_mutex);
586 585 return (EFAULT);
587 586 }
588 587
589 588 if (hostinfo.length > sizeof (hostinfo.fqhn))
590 589 hostinfo.length = sizeof (hostinfo.fqhn);
591 590
592 591 if (ddi_copyin((void *)((caddr_t)argp +
593 592 sizeof (hostinfo.length)), &hostinfo.fqhn,
594 593 hostinfo.length, flag) != 0) {
595 594 mutex_enter(&iscsit_global.global_state_mutex);
596 595 iscsit_global.global_svc_state = ISE_DISABLED;
597 596 mutex_exit(&iscsit_global.global_state_mutex);
598 597 return (EFAULT);
599 598 }
600 599
601 600 idmrc = iscsit_enable_svc(&hostinfo);
602 601 mutex_enter(&iscsit_global.global_state_mutex);
603 602 if (idmrc == IDM_STATUS_SUCCESS) {
604 603 iscsit_global.global_svc_state = ISE_ENABLED;
605 604 } else {
606 605 rc = EIO;
607 606 iscsit_global.global_svc_state = ISE_DISABLED;
608 607 }
609 608 mutex_exit(&iscsit_global.global_state_mutex);
610 609 break;
611 610 }
612 611 case ISCSIT_IOC_DISABLE_SVC:
613 612 iscsit_disable_svc();
614 613 mutex_enter(&iscsit_global.global_state_mutex);
615 614 iscsit_global.global_svc_state = ISE_DISABLED;
616 615 mutex_exit(&iscsit_global.global_state_mutex);
617 616 break;
618 617
619 618 default:
620 619 rc = EINVAL;
621 620 mutex_enter(&iscsit_global.global_state_mutex);
622 621 iscsit_global.global_svc_state = ISE_ENABLED;
623 622 mutex_exit(&iscsit_global.global_state_mutex);
624 623 }
625 624
626 625 return (rc);
627 626 }
628 627
629 628 static idm_status_t
630 629 iscsit_init(dev_info_t *dip)
631 630 {
632 631 int rc;
633 632
634 633 rc = ldi_ident_from_dip(dip, &iscsit_global.global_li);
635 634 ASSERT(rc == 0); /* Failure indicates invalid argument */
636 635
637 636 iscsit_global.global_svc_state = ISE_DISABLED;
638 637
639 638 return (IDM_STATUS_SUCCESS);
640 639 }
641 640
642 641 /*
643 642 * iscsit_enable_svc
644 643 *
645 644 * registers all the configured targets and target portals with STMF
646 645 */
647 646 static idm_status_t
648 647 iscsit_enable_svc(iscsit_hostinfo_t *hostinfo)
649 648 {
650 649 stmf_port_provider_t *pp;
651 650 stmf_dbuf_store_t *dbuf_store;
652 651 boolean_t did_iscsit_isns_init;
653 652 idm_status_t retval = IDM_STATUS_SUCCESS;
654 653
655 654 ASSERT(iscsit_global.global_svc_state == ISE_ENABLING);
656 655
657 656 /*
658 657 * Make sure that can tell if we have partially allocated
659 658 * in case we need to exit and tear down anything allocated.
660 659 */
661 660 iscsit_global.global_tsih_pool = NULL;
662 661 iscsit_global.global_dbuf_store = NULL;
663 662 iscsit_status_pdu_cache = NULL;
664 663 pp = NULL;
665 664 iscsit_global.global_pp = NULL;
666 665 iscsit_global.global_default_tpg = NULL;
667 666 did_iscsit_isns_init = B_FALSE;
668 667 iscsit_global.global_dispatch_taskq = NULL;
669 668
670 669 /* Setup remaining fields in iscsit_global_t */
671 670 idm_refcnt_init(&iscsit_global.global_refcnt,
672 671 &iscsit_global);
673 672
674 673 avl_create(&iscsit_global.global_discovery_sessions,
675 674 iscsit_sess_avl_compare, sizeof (iscsit_sess_t),
676 675 offsetof(iscsit_sess_t, ist_tgt_ln));
677 676
678 677 avl_create(&iscsit_global.global_target_list,
679 678 iscsit_tgt_avl_compare, sizeof (iscsit_tgt_t),
680 679 offsetof(iscsit_tgt_t, target_global_ln));
681 680
682 681 list_create(&iscsit_global.global_deleted_target_list,
683 682 sizeof (iscsit_tgt_t),
684 683 offsetof(iscsit_tgt_t, target_global_deleted_ln));
685 684
686 685 avl_create(&iscsit_global.global_tpg_list,
687 686 iscsit_tpg_avl_compare, sizeof (iscsit_tpg_t),
688 687 offsetof(iscsit_tpg_t, tpg_global_ln));
689 688
690 689 avl_create(&iscsit_global.global_ini_list,
691 690 iscsit_ini_avl_compare, sizeof (iscsit_ini_t),
692 691 offsetof(iscsit_ini_t, ini_global_ln));
693 692
694 693 iscsit_global.global_tsih_pool = vmem_create("iscsit_tsih_pool",
695 694 (void *)1, ISCSI_MAX_TSIH, 1, NULL, NULL, NULL, 0,
696 695 VM_SLEEP | VMC_IDENTIFIER);
697 696
698 697 /*
699 698 * Setup STMF dbuf store. Our buffers are bound to a specific
700 699 * connection so we really can't let STMF cache buffers for us.
701 700 * Consequently we'll just allocate one global buffer store.
702 701 */
703 702 dbuf_store = stmf_alloc(STMF_STRUCT_DBUF_STORE, 0, 0);
704 703 if (dbuf_store == NULL) {
705 704 retval = IDM_STATUS_FAIL;
706 705 goto tear_down_and_return;
707 706 }
708 707 dbuf_store->ds_alloc_data_buf = iscsit_dbuf_alloc;
709 708 dbuf_store->ds_free_data_buf = iscsit_dbuf_free;
710 709 dbuf_store->ds_port_private = NULL;
711 710 iscsit_global.global_dbuf_store = dbuf_store;
712 711
713 712 /* Status PDU cache */
714 713 iscsit_status_pdu_cache = kmem_cache_create("iscsit_status_pdu_cache",
715 714 sizeof (idm_pdu_t) + sizeof (iscsi_scsi_rsp_hdr_t), 8,
716 715 &iscsit_status_pdu_constructor,
717 716 NULL, NULL, NULL, NULL, KM_SLEEP);
718 717
719 718 /* Default TPG and portal */
720 719 iscsit_global.global_default_tpg = iscsit_tpg_createdefault();
721 720 if (iscsit_global.global_default_tpg == NULL) {
722 721 retval = IDM_STATUS_FAIL;
723 722 goto tear_down_and_return;
724 723 }
725 724
726 725 /* initialize isns client */
727 726 (void) iscsit_isns_init(hostinfo);
728 727 did_iscsit_isns_init = B_TRUE;
729 728
730 729 /* Register port provider */
731 730 pp = stmf_alloc(STMF_STRUCT_PORT_PROVIDER, 0, 0);
732 731 if (pp == NULL) {
733 732 retval = IDM_STATUS_FAIL;
734 733 goto tear_down_and_return;
735 734 }
736 735
737 736 pp->pp_portif_rev = PORTIF_REV_1;
738 737 pp->pp_instance = 0;
739 738 pp->pp_name = ISCSIT_MODNAME;
740 739 pp->pp_cb = iscsit_pp_cb;
741 740
742 741 iscsit_global.global_pp = pp;
743 742
744 743
745 744 if (stmf_register_port_provider(pp) != STMF_SUCCESS) {
746 745 retval = IDM_STATUS_FAIL;
747 746 goto tear_down_and_return;
748 747 }
749 748
750 749 iscsit_global.global_dispatch_taskq = taskq_create("iscsit_dispatch",
751 750 1, minclsyspri, 16, 16, TASKQ_PREPOPULATE);
752 751
753 752 /* Scan staged PDUs, meaningful in MC/S situations */
754 753 iscsit_rxpdu_queue_monitor_start();
755 754
756 755 return (IDM_STATUS_SUCCESS);
757 756
758 757 tear_down_and_return:
759 758
760 759 if (iscsit_global.global_dispatch_taskq) {
761 760 taskq_destroy(iscsit_global.global_dispatch_taskq);
762 761 iscsit_global.global_dispatch_taskq = NULL;
763 762 }
764 763
765 764 if (did_iscsit_isns_init)
766 765 iscsit_isns_fini();
767 766
768 767 if (iscsit_global.global_default_tpg) {
769 768 iscsit_tpg_destroydefault(iscsit_global.global_default_tpg);
770 769 iscsit_global.global_default_tpg = NULL;
771 770 }
772 771
773 772 if (iscsit_global.global_pp)
774 773 iscsit_global.global_pp = NULL;
775 774
776 775 if (pp)
777 776 stmf_free(pp);
778 777
779 778 if (iscsit_status_pdu_cache) {
780 779 kmem_cache_destroy(iscsit_status_pdu_cache);
781 780 iscsit_status_pdu_cache = NULL;
782 781 }
783 782
784 783 if (iscsit_global.global_dbuf_store) {
785 784 stmf_free(iscsit_global.global_dbuf_store);
786 785 iscsit_global.global_dbuf_store = NULL;
787 786 }
788 787
789 788 if (iscsit_global.global_tsih_pool) {
790 789 vmem_destroy(iscsit_global.global_tsih_pool);
791 790 iscsit_global.global_tsih_pool = NULL;
792 791 }
793 792
794 793 avl_destroy(&iscsit_global.global_ini_list);
795 794 avl_destroy(&iscsit_global.global_tpg_list);
796 795 list_destroy(&iscsit_global.global_deleted_target_list);
797 796 avl_destroy(&iscsit_global.global_target_list);
798 797 avl_destroy(&iscsit_global.global_discovery_sessions);
799 798
800 799 idm_refcnt_destroy(&iscsit_global.global_refcnt);
801 800
802 801 return (retval);
803 802 }
804 803
805 804 /*
806 805 * iscsit_disable_svc
807 806 *
808 807 * clean up all existing connections and deregister targets from STMF
809 808 */
810 809 static void
811 810 iscsit_disable_svc(void)
812 811 {
813 812 iscsit_sess_t *sess;
814 813
815 814 ASSERT(iscsit_global.global_svc_state == ISE_DISABLING);
816 815
817 816 iscsit_rxpdu_queue_monitor_stop();
818 817
819 818 /* tear down discovery sessions */
820 819 for (sess = avl_first(&iscsit_global.global_discovery_sessions);
821 820 sess != NULL;
822 821 sess = AVL_NEXT(&iscsit_global.global_discovery_sessions, sess))
823 822 iscsit_sess_close(sess);
824 823
825 824 /*
826 825 * Passing NULL to iscsit_config_merge tells it to go to an empty
827 826 * config.
828 827 */
829 828 (void) iscsit_config_merge(NULL);
830 829
831 830 /*
832 831 * Wait until there are no more global references
833 832 */
834 833 idm_refcnt_wait_ref(&iscsit_global.global_refcnt);
835 834 idm_refcnt_destroy(&iscsit_global.global_refcnt);
836 835
837 836 /*
838 837 * Default TPG must be destroyed after global_refcnt is 0.
839 838 */
840 839 iscsit_tpg_destroydefault(iscsit_global.global_default_tpg);
841 840
842 841 avl_destroy(&iscsit_global.global_discovery_sessions);
843 842 list_destroy(&iscsit_global.global_deleted_target_list);
844 843 avl_destroy(&iscsit_global.global_target_list);
845 844 avl_destroy(&iscsit_global.global_tpg_list);
846 845 avl_destroy(&iscsit_global.global_ini_list);
847 846
848 847 taskq_destroy(iscsit_global.global_dispatch_taskq);
849 848
850 849 iscsit_isns_fini();
851 850
852 851 stmf_free(iscsit_global.global_dbuf_store);
853 852 iscsit_global.global_dbuf_store = NULL;
854 853
855 854 (void) stmf_deregister_port_provider(iscsit_global.global_pp);
856 855 stmf_free(iscsit_global.global_pp);
857 856 iscsit_global.global_pp = NULL;
858 857
859 858 kmem_cache_destroy(iscsit_status_pdu_cache);
860 859 iscsit_status_pdu_cache = NULL;
861 860
862 861 vmem_destroy(iscsit_global.global_tsih_pool);
863 862 iscsit_global.global_tsih_pool = NULL;
864 863 }
865 864
866 865 void
867 866 iscsit_global_hold()
868 867 {
869 868 /*
870 869 * To take out a global hold, we must either own the global
871 870 * state mutex or we must be running inside of an ioctl that
872 871 * has set the global state to ISE_BUSY, ISE_DISABLING, or
873 872 * ISE_ENABLING. We don't track the "owner" for these flags,
874 873 * so just checking if they are set is enough for now.
875 874 */
876 875 ASSERT((iscsit_global.global_svc_state == ISE_ENABLING) ||
877 876 (iscsit_global.global_svc_state == ISE_DISABLING) ||
878 877 (iscsit_global.global_svc_state == ISE_BUSY) ||
879 878 MUTEX_HELD(&iscsit_global.global_state_mutex));
880 879
881 880 idm_refcnt_hold(&iscsit_global.global_refcnt);
882 881 }
883 882
884 883 void
885 884 iscsit_global_rele()
886 885 {
887 886 idm_refcnt_rele(&iscsit_global.global_refcnt);
888 887 }
889 888
890 889 void
891 890 iscsit_global_wait_ref()
892 891 {
893 892 idm_refcnt_wait_ref(&iscsit_global.global_refcnt);
894 893 }
895 894
896 895 /*
897 896 * IDM callbacks
898 897 */
899 898
900 899 /*ARGSUSED*/
901 900 void
902 901 iscsit_rx_pdu(idm_conn_t *ic, idm_pdu_t *rx_pdu)
903 902 {
904 903 iscsit_conn_t *ict = ic->ic_handle;
905 904 switch (IDM_PDU_OPCODE(rx_pdu)) {
906 905 case ISCSI_OP_SCSI_CMD:
907 906 ASSERT(0); /* Shouldn't happen */
908 907 idm_pdu_complete(rx_pdu, IDM_STATUS_SUCCESS);
909 908 break;
910 909 case ISCSI_OP_SNACK_CMD:
911 910 /*
912 911 * We'll need to handle this when we support ERL1/2. For
913 912 * now we treat it as a protocol error.
914 913 */
915 914 idm_pdu_complete(rx_pdu, IDM_STATUS_SUCCESS);
916 915 idm_conn_event(ic, CE_TRANSPORT_FAIL, NULL);
917 916 break;
918 917 case ISCSI_OP_SCSI_TASK_MGT_MSG:
919 918 if (iscsit_check_cmdsn_and_queue(rx_pdu)) {
920 919 iscsit_set_cmdsn(ict, rx_pdu);
921 920 iscsit_op_scsi_task_mgmt(ict, rx_pdu);
922 921 }
923 922 break;
924 923 case ISCSI_OP_NOOP_OUT:
925 924 case ISCSI_OP_LOGIN_CMD:
926 925 case ISCSI_OP_TEXT_CMD:
927 926 case ISCSI_OP_LOGOUT_CMD:
928 927 /*
929 928 * If/when we switch to userland processing these PDU's
930 929 * will be handled by iscsitd.
931 930 */
932 931 iscsit_deferred_dispatch(rx_pdu);
933 932 break;
934 933 default:
935 934 /* Protocol error */
936 935 idm_pdu_complete(rx_pdu, IDM_STATUS_SUCCESS);
937 936 idm_conn_event(ic, CE_TRANSPORT_FAIL, NULL);
938 937 break;
939 938 }
940 939 }
941 940
942 941 /*ARGSUSED*/
943 942 void
944 943 iscsit_rx_pdu_error(idm_conn_t *ic, idm_pdu_t *rx_pdu, idm_status_t status)
945 944 {
946 945 idm_pdu_complete(rx_pdu, IDM_STATUS_SUCCESS);
947 946 }
948 947
949 948 void
950 949 iscsit_task_aborted(idm_task_t *idt, idm_status_t status)
951 950 {
952 951 iscsit_task_t *itask = idt->idt_private;
953 952
954 953 switch (status) {
955 954 case IDM_STATUS_SUSPENDED:
956 955 break;
957 956 case IDM_STATUS_ABORTED:
958 957 mutex_enter(&itask->it_mutex);
959 958 itask->it_aborted = B_TRUE;
960 959 /*
961 960 * We rely on the fact that STMF tracks outstanding
962 961 * buffer transfers and will free all of our buffers
963 962 * before freeing the task so we don't need to
964 963 * explicitly free the buffers from iscsit/idm
965 964 */
966 965 if (itask->it_stmf_abort) {
967 966 mutex_exit(&itask->it_mutex);
968 967 /*
969 968 * Task is no longer active
970 969 */
971 970 iscsit_task_done(itask);
972 971
973 972 /*
974 973 * STMF has already asked for this task to be aborted
975 974 *
976 975 * STMF specification is wrong... says to return
977 976 * STMF_ABORTED, the code actually looks for
978 977 * STMF_ABORT_SUCCESS.
979 978 */
980 979 stmf_task_lport_aborted(itask->it_stmf_task,
981 980 STMF_ABORT_SUCCESS, STMF_IOF_LPORT_DONE);
982 981 return;
983 982 } else {
984 983 mutex_exit(&itask->it_mutex);
985 984 /*
986 985 * Tell STMF to stop processing the task.
987 986 */
988 987 stmf_abort(STMF_QUEUE_TASK_ABORT, itask->it_stmf_task,
989 988 STMF_ABORTED, NULL);
990 989 return;
991 990 }
992 991 /*NOTREACHED*/
993 992 default:
994 993 ASSERT(0);
995 994 }
996 995 }
997 996
998 997 /*ARGSUSED*/
999 998 idm_status_t
1000 999 iscsit_client_notify(idm_conn_t *ic, idm_client_notify_t icn,
1001 1000 uintptr_t data)
1002 1001 {
1003 1002 idm_status_t rc = IDM_STATUS_SUCCESS;
1004 1003
1005 1004 /*
1006 1005 * IDM client notifications will never occur at interrupt level
1007 1006 * since they are generated from the connection state machine which
1008 1007 * running on taskq threads.
1009 1008 *
1010 1009 */
1011 1010 switch (icn) {
1012 1011 case CN_CONNECT_ACCEPT:
1013 1012 rc = iscsit_conn_accept(ic); /* No data */
1014 1013 break;
1015 1014 case CN_FFP_ENABLED:
1016 1015 rc = iscsit_ffp_enabled(ic); /* No data */
1017 1016 break;
1018 1017 case CN_FFP_DISABLED:
1019 1018 /*
1020 1019 * Data indicates whether this was the result of an
1021 1020 * explicit logout request.
1022 1021 */
1023 1022 rc = iscsit_ffp_disabled(ic, (idm_ffp_disable_t)data);
1024 1023 break;
1025 1024 case CN_CONNECT_LOST:
1026 1025 rc = iscsit_conn_lost(ic);
1027 1026 break;
1028 1027 case CN_CONNECT_DESTROY:
1029 1028 rc = iscsit_conn_destroy(ic);
1030 1029 break;
1031 1030 case CN_LOGIN_FAIL:
1032 1031 /*
1033 1032 * Force the login state machine to completion
1034 1033 */
1035 1034 rc = iscsit_login_fail(ic);
1036 1035 break;
1037 1036 default:
1038 1037 rc = IDM_STATUS_REJECT;
1039 1038 break;
1040 1039 }
1041 1040
1042 1041 return (rc);
1043 1042 }
1044 1043
1045 1044 /*
1046 1045 * iscsit_update_statsn is invoked for all the PDUs which have the StatSN
1047 1046 * field in the header. The StatSN is incremented if the IDM_PDU_ADVANCE_STATSN
1048 1047 * flag is set in the pdu flags field. The StatSN is connection-wide and is
1049 1048 * protected by the mutex ict_statsn_mutex. For Data-In PDUs, if the flag
1050 1049 * IDM_TASK_PHASECOLLAPSE_REQ is set, the status (phase-collapse) is also filled
1051 1050 */
1052 1051 void
1053 1052 iscsit_update_statsn(idm_task_t *idm_task, idm_pdu_t *pdu)
1054 1053 {
1055 1054 iscsi_scsi_rsp_hdr_t *rsp = (iscsi_scsi_rsp_hdr_t *)pdu->isp_hdr;
1056 1055 iscsit_conn_t *ict = (iscsit_conn_t *)pdu->isp_ic->ic_handle;
1057 1056 iscsit_task_t *itask = NULL;
1058 1057 scsi_task_t *task = NULL;
1059 1058
1060 1059 mutex_enter(&ict->ict_statsn_mutex);
1061 1060 rsp->statsn = htonl(ict->ict_statsn);
1062 1061 if (pdu->isp_flags & IDM_PDU_ADVANCE_STATSN)
1063 1062 ict->ict_statsn++;
1064 1063 mutex_exit(&ict->ict_statsn_mutex);
1065 1064
1066 1065 /*
1067 1066 * The last SCSI Data PDU passed for a command may also contain the
1068 1067 * status if the status indicates termination with no expections, i.e.
1069 1068 * no sense data or response involved. If the command completes with
1070 1069 * an error, then the response and sense data will be sent in a
1071 1070 * separate iSCSI Response PDU.
1072 1071 */
1073 1072 if ((idm_task) && (idm_task->idt_flags & IDM_TASK_PHASECOLLAPSE_REQ)) {
1074 1073 itask = idm_task->idt_private;
1075 1074 task = itask->it_stmf_task;
1076 1075
1077 1076 rsp->cmd_status = task->task_scsi_status;
1078 1077 rsp->flags |= ISCSI_FLAG_DATA_STATUS;
1079 1078 if (task->task_status_ctrl & TASK_SCTRL_OVER) {
1080 1079 rsp->flags |= ISCSI_FLAG_CMD_OVERFLOW;
1081 1080 } else if (task->task_status_ctrl & TASK_SCTRL_UNDER) {
1082 1081 rsp->flags |= ISCSI_FLAG_CMD_UNDERFLOW;
1083 1082 }
1084 1083 rsp->residual_count = htonl(task->task_resid);
1085 1084
1086 1085 /*
1087 1086 * Removing the task from the session task list
1088 1087 * just before the status is sent in the last
1089 1088 * Data PDU transfer
1090 1089 */
1091 1090 iscsit_task_done(itask);
1092 1091 }
1093 1092 }
1094 1093
1095 1094 void
1096 1095 iscsit_build_hdr(idm_task_t *idm_task, idm_pdu_t *pdu, uint8_t opcode)
1097 1096 {
1098 1097 iscsit_task_t *itask = idm_task->idt_private;
1099 1098 iscsi_data_rsp_hdr_t *dh = (iscsi_data_rsp_hdr_t *)pdu->isp_hdr;
1100 1099
1101 1100 /*
1102 1101 * We acquired iscsit_sess_t.ist_sn_mutex in iscsit_xfer_scsi_data
1103 1102 */
1104 1103 ASSERT(MUTEX_HELD(&itask->it_ict->ict_sess->ist_sn_mutex));
1105 1104 /*
1106 1105 * On incoming data, the target transfer tag and Lun is only
1107 1106 * provided by the target if the A bit is set, Since the target
1108 1107 * does not currently support Error Recovery Level 1, the A
1109 1108 * bit is never set.
1110 1109 */
1111 1110 dh->opcode = opcode;
1112 1111 dh->itt = itask->it_itt;
1113 1112 dh->ttt = ((opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_SCSI_DATA_RSP) ?
1114 1113 ISCSI_RSVD_TASK_TAG : itask->it_ttt;
1115 1114
1116 1115 dh->expcmdsn = htonl(itask->it_ict->ict_sess->ist_expcmdsn);
1117 1116 dh->maxcmdsn = htonl(itask->it_ict->ict_sess->ist_maxcmdsn);
1118 1117
1119 1118 /*
1120 1119 * IDM must set:
1121 1120 *
1122 1121 * data.flags and rtt.flags
1123 1122 * data.dlength
1124 1123 * data.datasn
1125 1124 * data.offset
1126 1125 * statsn, residual_count and cmd_status (for phase collapse)
1127 1126 * rtt.rttsn
1128 1127 * rtt.data_offset
1129 1128 * rtt.data_length
1130 1129 */
1131 1130 }
1132 1131
1133 1132 void
1134 1133 iscsit_keepalive(idm_conn_t *ic)
1135 1134 {
1136 1135 idm_pdu_t *nop_in_pdu;
1137 1136 iscsi_nop_in_hdr_t *nop_in;
1138 1137 iscsit_conn_t *ict = ic->ic_handle;
1139 1138
1140 1139 /*
1141 1140 * IDM noticed the connection has been idle for too long so it's
1142 1141 * time to provoke some activity. Build and transmit an iSCSI
1143 1142 * nop-in PDU -- when the initiator responds it will be counted
1144 1143 * as "activity" and keep the connection alive.
1145 1144 *
1146 1145 * We don't actually care about the response here at the iscsit level
1147 1146 * so we will just throw it away without looking at it when it arrives.
1148 1147 */
1149 1148 nop_in_pdu = idm_pdu_alloc(sizeof (*nop_in), 0);
1150 1149 idm_pdu_init(nop_in_pdu, ic, NULL, NULL);
1151 1150 nop_in = (iscsi_nop_in_hdr_t *)nop_in_pdu->isp_hdr;
1152 1151 bzero(nop_in, sizeof (*nop_in));
1153 1152 nop_in->opcode = ISCSI_OP_NOOP_IN;
1154 1153 nop_in->flags = ISCSI_FLAG_FINAL;
1155 1154 nop_in->itt = ISCSI_RSVD_TASK_TAG;
1156 1155 /*
1157 1156 * When the target sends a NOP-In as a Ping, the target transfer tag
1158 1157 * is set to a valid (not reserved) value and the initiator task tag
1159 1158 * is set to ISCSI_RSVD_TASK_TAG (0xffffffff). In this case the StatSN
1160 1159 * will always contain the next sequence number but the StatSN for the
1161 1160 * connection is not advanced after this PDU is sent.
1162 1161 */
1163 1162 nop_in_pdu->isp_flags |= IDM_PDU_SET_STATSN;
1164 1163 /*
1165 1164 * This works because we don't currently allocate ttt's anywhere else
1166 1165 * in iscsit so as long as we stay out of IDM's range we are safe.
1167 1166 * If we need to allocate ttt's for other PDU's in the future this will
1168 1167 * need to be improved.
1169 1168 */
1170 1169 mutex_enter(&ict->ict_mutex);
1171 1170 nop_in->ttt = ict->ict_keepalive_ttt;
1172 1171 ict->ict_keepalive_ttt++;
1173 1172 if (ict->ict_keepalive_ttt == ISCSI_RSVD_TASK_TAG)
1174 1173 ict->ict_keepalive_ttt = IDM_TASKIDS_MAX;
1175 1174 mutex_exit(&ict->ict_mutex);
1176 1175
1177 1176 iscsit_pdu_tx(nop_in_pdu);
1178 1177 }
1179 1178
1180 1179 static idm_status_t
1181 1180 iscsit_conn_accept(idm_conn_t *ic)
1182 1181 {
1183 1182 iscsit_conn_t *ict;
1184 1183
1185 1184 /*
1186 1185 * We need to get a global hold here to ensure that the service
1187 1186 * doesn't get shutdown prior to establishing a session. This
1188 1187 * gets released in iscsit_conn_destroy().
1189 1188 */
1190 1189 mutex_enter(&iscsit_global.global_state_mutex);
1191 1190 if (iscsit_global.global_svc_state != ISE_ENABLED) {
1192 1191 mutex_exit(&iscsit_global.global_state_mutex);
1193 1192 return (IDM_STATUS_FAIL);
1194 1193 }
1195 1194 iscsit_global_hold();
1196 1195 mutex_exit(&iscsit_global.global_state_mutex);
1197 1196
1198 1197 /*
1199 1198 * Allocate an associated iscsit structure to represent this
1200 1199 * connection. We shouldn't really create a session until we
1201 1200 * get the first login PDU.
1202 1201 */
1203 1202 ict = kmem_zalloc(sizeof (*ict), KM_SLEEP);
1204 1203
1205 1204 ict->ict_ic = ic;
1206 1205 ict->ict_statsn = 1;
1207 1206 ict->ict_keepalive_ttt = IDM_TASKIDS_MAX; /* Avoid IDM TT range */
1208 1207 ic->ic_handle = ict;
1209 1208 mutex_init(&ict->ict_mutex, NULL, MUTEX_DRIVER, NULL);
1210 1209 mutex_init(&ict->ict_statsn_mutex, NULL, MUTEX_DRIVER, NULL);
1211 1210 idm_refcnt_init(&ict->ict_refcnt, ict);
1212 1211
1213 1212 /*
1214 1213 * Initialize login state machine
1215 1214 */
1216 1215 if (iscsit_login_sm_init(ict) != IDM_STATUS_SUCCESS) {
1217 1216 iscsit_global_rele();
1218 1217 /*
1219 1218 * Cleanup the ict after idm notifies us about this failure
1220 1219 */
1221 1220 return (IDM_STATUS_FAIL);
1222 1221 }
1223 1222
1224 1223 return (IDM_STATUS_SUCCESS);
1225 1224 }
1226 1225
1227 1226 idm_status_t
1228 1227 iscsit_conn_reinstate(iscsit_conn_t *reinstate_ict, iscsit_conn_t *new_ict)
1229 1228 {
1230 1229 idm_status_t result;
1231 1230
1232 1231 /*
1233 1232 * Note in new connection state that this connection is
1234 1233 * reinstating an existing connection.
1235 1234 */
1236 1235 new_ict->ict_reinstating = B_TRUE;
1237 1236 new_ict->ict_reinstate_conn = reinstate_ict;
1238 1237 new_ict->ict_statsn = reinstate_ict->ict_statsn;
1239 1238
1240 1239 /*
1241 1240 * Now generate connection state machine event to existing connection
1242 1241 * so that it starts the cleanup process.
1243 1242 */
1244 1243 result = idm_conn_reinstate_event(reinstate_ict->ict_ic,
1245 1244 new_ict->ict_ic);
1246 1245
1247 1246 return (result);
1248 1247 }
1249 1248
1250 1249 void
1251 1250 iscsit_conn_hold(iscsit_conn_t *ict)
1252 1251 {
1253 1252 idm_refcnt_hold(&ict->ict_refcnt);
1254 1253 }
1255 1254
1256 1255 void
1257 1256 iscsit_conn_rele(iscsit_conn_t *ict)
1258 1257 {
1259 1258 idm_refcnt_rele(&ict->ict_refcnt);
1260 1259 }
1261 1260
1262 1261 void
1263 1262 iscsit_conn_dispatch_hold(iscsit_conn_t *ict)
1264 1263 {
1265 1264 idm_refcnt_hold(&ict->ict_dispatch_refcnt);
1266 1265 }
1267 1266
1268 1267 void
1269 1268 iscsit_conn_dispatch_rele(iscsit_conn_t *ict)
1270 1269 {
1271 1270 idm_refcnt_rele(&ict->ict_dispatch_refcnt);
1272 1271 }
1273 1272
1274 1273 static idm_status_t
1275 1274 iscsit_login_fail(idm_conn_t *ic)
1276 1275 {
1277 1276 iscsit_conn_t *ict = ic->ic_handle;
1278 1277
1279 1278 /* Generate login state machine event */
1280 1279 iscsit_login_sm_event(ict, ILE_LOGIN_CONN_ERROR, NULL);
1281 1280
1282 1281 return (IDM_STATUS_SUCCESS);
1283 1282 }
1284 1283
1285 1284 static idm_status_t
1286 1285 iscsit_ffp_enabled(idm_conn_t *ic)
1287 1286 {
1288 1287 iscsit_conn_t *ict = ic->ic_handle;
1289 1288
1290 1289 /* Generate session state machine event */
1291 1290 iscsit_sess_sm_event(ict->ict_sess, SE_CONN_LOGGED_IN, ict);
1292 1291
1293 1292 return (IDM_STATUS_SUCCESS);
1294 1293 }
1295 1294
1296 1295 static idm_status_t
1297 1296 iscsit_ffp_disabled(idm_conn_t *ic, idm_ffp_disable_t disable_class)
1298 1297 {
1299 1298 iscsit_conn_t *ict = ic->ic_handle;
1300 1299
1301 1300 /* Generate session state machine event */
1302 1301 switch (disable_class) {
1303 1302 case FD_CONN_FAIL:
1304 1303 iscsit_sess_sm_event(ict->ict_sess, SE_CONN_FFP_FAIL, ict);
1305 1304 break;
1306 1305 case FD_CONN_LOGOUT:
1307 1306 iscsit_sess_sm_event(ict->ict_sess, SE_CONN_FFP_DISABLE, ict);
1308 1307 break;
1309 1308 case FD_SESS_LOGOUT:
1310 1309 iscsit_sess_sm_event(ict->ict_sess, SE_SESSION_CLOSE, ict);
1311 1310 break;
1312 1311 default:
1313 1312 ASSERT(0);
1314 1313 }
1315 1314
1316 1315 return (IDM_STATUS_SUCCESS);
1317 1316 }
1318 1317
1319 1318 static idm_status_t
1320 1319 iscsit_conn_lost(idm_conn_t *ic)
1321 1320 {
1322 1321 iscsit_conn_t *ict = ic->ic_handle;
1323 1322 iscsit_sess_t *ist = ict->ict_sess;
1324 1323 iscsit_cbuf_t *cbuf;
1325 1324 idm_pdu_t *rx_pdu;
1326 1325 int i;
1327 1326
1328 1327 mutex_enter(&ict->ict_mutex);
1329 1328 ict->ict_lost = B_TRUE;
1330 1329 mutex_exit(&ict->ict_mutex);
1331 1330 /*
1332 1331 * scrub the staging queue for all PDUs on this connection
1333 1332 */
1334 1333 if (ist != NULL) {
1335 1334 mutex_enter(&ist->ist_sn_mutex);
1336 1335 for (cbuf = ist->ist_rxpdu_queue, i = 0;
1337 1336 ((cbuf->cb_num_elems > 0) && (i < ISCSIT_RXPDU_QUEUE_LEN));
1338 1337 i++) {
1339 1338 if (((rx_pdu = cbuf->cb_buffer[i]) != NULL) &&
1340 1339 (rx_pdu->isp_ic == ic)) {
1341 1340 /* conn is lost, drop the pdu */
1342 1341 DTRACE_PROBE3(scrubbing__staging__queue,
1343 1342 iscsit_sess_t *, ist, idm_conn_t *, ic,
1344 1343 idm_pdu_t *, rx_pdu);
1345 1344 idm_pdu_complete(rx_pdu, IDM_STATUS_FAIL);
1346 1345 cbuf->cb_buffer[i] = NULL;
1347 1346 cbuf->cb_num_elems--;
1348 1347 iscsit_conn_dispatch_rele(ict);
1349 1348 }
1350 1349 }
1351 1350 mutex_exit(&ist->ist_sn_mutex);
1352 1351 }
1353 1352 /*
1354 1353 * Make sure there aren't any PDU's transitioning from the receive
1355 1354 * handler to the dispatch taskq.
1356 1355 */
1357 1356 idm_refcnt_wait_ref(&ict->ict_dispatch_refcnt);
1358 1357
1359 1358 return (IDM_STATUS_SUCCESS);
1360 1359 }
1361 1360
1362 1361 static idm_status_t
1363 1362 iscsit_conn_destroy(idm_conn_t *ic)
1364 1363 {
1365 1364 iscsit_conn_t *ict = ic->ic_handle;
1366 1365
1367 1366 mutex_enter(&ict->ict_mutex);
1368 1367 ict->ict_destroyed = B_TRUE;
1369 1368 mutex_exit(&ict->ict_mutex);
1370 1369
1371 1370 /* Generate session state machine event */
1372 1371 if (ict->ict_sess != NULL) {
1373 1372 /*
1374 1373 * Session state machine will call iscsit_conn_destroy_done()
1375 1374 * when it has removed references to this connection.
1376 1375 */
1377 1376 iscsit_sess_sm_event(ict->ict_sess, SE_CONN_FAIL, ict);
1378 1377 }
1379 1378
1380 1379 idm_refcnt_wait_ref(&ict->ict_refcnt);
1381 1380 /*
1382 1381 * The session state machine does not need to post
1383 1382 * events to IDM any longer, so it is safe to set
1384 1383 * the idm connection reference to NULL
1385 1384 */
1386 1385 ict->ict_ic = NULL;
1387 1386
1388 1387 /* Reap the login state machine */
1389 1388 iscsit_login_sm_fini(ict);
1390 1389
1391 1390 /* Clean up any text command remnants */
1392 1391 iscsit_text_cmd_fini(ict);
1393 1392
1394 1393 mutex_destroy(&ict->ict_mutex);
1395 1394 idm_refcnt_destroy(&ict->ict_refcnt);
1396 1395 kmem_free(ict, sizeof (*ict));
1397 1396
1398 1397 iscsit_global_rele();
1399 1398
1400 1399 return (IDM_STATUS_SUCCESS);
1401 1400 }
1402 1401
1403 1402 void
1404 1403 iscsit_conn_logout(iscsit_conn_t *ict)
1405 1404 {
1406 1405 /*
1407 1406 * If the iscsi connection is active, then
1408 1407 * logout the IDM connection by sending a
1409 1408 * CE_LOGOUT_SESSION_SUCCESS, else, no action
1410 1409 * needs to be taken because the connection
1411 1410 * is already in the teardown process.
1412 1411 */
1413 1412 mutex_enter(&ict->ict_mutex);
1414 1413 if (ict->ict_lost == B_FALSE && ict->ict_destroyed == B_FALSE) {
1415 1414 idm_conn_event(ict->ict_ic, CE_LOGOUT_SESSION_SUCCESS, NULL);
1416 1415 }
1417 1416 mutex_exit(&ict->ict_mutex);
1418 1417 }
1419 1418
1420 1419 /*
1421 1420 * STMF-related functions
1422 1421 *
1423 1422 * iSCSI to STMF mapping
1424 1423 *
1425 1424 * Session == ?
1426 1425 * Connection == bound to local port but not itself a local port
1427 1426 * Target
1428 1427 * Target portal (group?) == local port (really but we're not going to do this)
1429 1428 * iscsit needs to map connections to local ports (whatever we decide
1430 1429 * they are)
1431 1430 * Target == ?
1432 1431 */
1433 1432
1434 1433 /*ARGSUSED*/
1435 1434 static stmf_data_buf_t *
1436 1435 iscsit_dbuf_alloc(scsi_task_t *task, uint32_t size, uint32_t *pminsize,
1437 1436 uint32_t flags)
1438 1437 {
1439 1438 iscsit_task_t *itask = task->task_port_private;
1440 1439 idm_buf_t *idm_buffer;
1441 1440 iscsit_buf_t *ibuf;
1442 1441 stmf_data_buf_t *result;
1443 1442 uint32_t bsize;
1444 1443
1445 1444 /*
1446 1445 * If the requested size is larger than MaxBurstLength and the
1447 1446 * given pminsize is also larger than MaxBurstLength, then the
1448 1447 * allocation fails (dbuf = NULL) and pminsize is modified to
1449 1448 * be equal to MaxBurstLength. stmf/sbd then should re-invoke
1450 1449 * this function with the corrected values for transfer.
1451 1450 */
1452 1451 ASSERT(pminsize);
1453 1452 if (size <= itask->it_ict->ict_op.op_max_burst_length) {
1454 1453 bsize = size;
1455 1454 } else if (*pminsize <= itask->it_ict->ict_op.op_max_burst_length) {
1456 1455 bsize = itask->it_ict->ict_op.op_max_burst_length;
1457 1456 } else {
1458 1457 *pminsize = itask->it_ict->ict_op.op_max_burst_length;
1459 1458 return (NULL);
1460 1459 }
1461 1460
1462 1461 /* Alloc buffer */
1463 1462 idm_buffer = idm_buf_alloc(itask->it_ict->ict_ic, NULL, bsize);
1464 1463 if (idm_buffer != NULL) {
1465 1464 result = stmf_alloc(STMF_STRUCT_DATA_BUF,
1466 1465 sizeof (iscsit_buf_t), 0);
1467 1466 if (result != NULL) {
1468 1467 /* Fill in stmf_data_buf_t */
1469 1468 ibuf = result->db_port_private;
1470 1469 ibuf->ibuf_idm_buf = idm_buffer;
1471 1470 ibuf->ibuf_stmf_buf = result;
1472 1471 ibuf->ibuf_is_immed = B_FALSE;
1473 1472 result->db_flags = DB_DONT_CACHE;
1474 1473 result->db_buf_size = bsize;
1475 1474 result->db_data_size = bsize;
1476 1475 result->db_sglist_length = 1;
1477 1476 result->db_sglist[0].seg_addr = idm_buffer->idb_buf;
1478 1477 result->db_sglist[0].seg_length =
1479 1478 idm_buffer->idb_buflen;
1480 1479 return (result);
1481 1480 }
1482 1481
1483 1482 /* Couldn't get the stmf_data_buf_t so free the buffer */
1484 1483 idm_buf_free(idm_buffer);
1485 1484 }
1486 1485
1487 1486 return (NULL);
1488 1487 }
1489 1488
1490 1489 /*ARGSUSED*/
1491 1490 static void
1492 1491 iscsit_dbuf_free(stmf_dbuf_store_t *ds, stmf_data_buf_t *dbuf)
1493 1492 {
1494 1493 iscsit_buf_t *ibuf = dbuf->db_port_private;
1495 1494
1496 1495 if (ibuf->ibuf_is_immed) {
1497 1496 /*
1498 1497 * The iscsit_buf_t structure itself will be freed with its
1499 1498 * associated task. Here we just need to free the PDU that
1500 1499 * held the immediate data.
1501 1500 */
1502 1501 idm_pdu_complete(ibuf->ibuf_immed_data_pdu, IDM_STATUS_SUCCESS);
1503 1502 ibuf->ibuf_immed_data_pdu = 0;
1504 1503 } else {
1505 1504 idm_buf_free(ibuf->ibuf_idm_buf);
1506 1505 stmf_free(dbuf);
1507 1506 }
1508 1507 }
1509 1508
1510 1509 /*ARGSUSED*/
1511 1510 stmf_status_t
1512 1511 iscsit_xfer_scsi_data(scsi_task_t *task, stmf_data_buf_t *dbuf,
1513 1512 uint32_t ioflags)
1514 1513 {
1515 1514 iscsit_task_t *iscsit_task = task->task_port_private;
1516 1515 iscsit_sess_t *ict_sess = iscsit_task->it_ict->ict_sess;
1517 1516 iscsit_buf_t *ibuf = dbuf->db_port_private;
1518 1517 int idm_rc;
1519 1518
1520 1519 /*
1521 1520 * If we are aborting then we can ignore this request
1522 1521 */
1523 1522 if (iscsit_task->it_stmf_abort) {
1524 1523 return (STMF_SUCCESS);
1525 1524 }
1526 1525
1527 1526 /*
1528 1527 * If it's not immediate data then start the transfer
1529 1528 */
1530 1529 ASSERT(ibuf->ibuf_is_immed == B_FALSE);
1531 1530 if (dbuf->db_flags & DB_DIRECTION_TO_RPORT) {
1532 1531 /*
1533 1532 * The DB_SEND_STATUS_GOOD flag in the STMF data buffer allows
1534 1533 * the port provider to phase-collapse, i.e. send the status
1535 1534 * along with the final data PDU for the command. The port
1536 1535 * provider passes this request to the transport layer by
1537 1536 * setting a flag IDM_TASK_PHASECOLLAPSE_REQ in the task.
1538 1537 */
1539 1538 if (dbuf->db_flags & DB_SEND_STATUS_GOOD)
1540 1539 iscsit_task->it_idm_task->idt_flags |=
1541 1540 IDM_TASK_PHASECOLLAPSE_REQ;
1542 1541 /*
1543 1542 * IDM will call iscsit_build_hdr so lock now to serialize
1544 1543 * access to the SN values. We need to lock here to enforce
1545 1544 * lock ordering
1546 1545 */
1547 1546 mutex_enter(&ict_sess->ist_sn_mutex);
1548 1547 idm_rc = idm_buf_tx_to_ini(iscsit_task->it_idm_task,
1549 1548 ibuf->ibuf_idm_buf, dbuf->db_relative_offset,
1550 1549 dbuf->db_data_size, &iscsit_buf_xfer_cb, dbuf);
1551 1550 mutex_exit(&ict_sess->ist_sn_mutex);
1552 1551
1553 1552 return (iscsit_idm_to_stmf(idm_rc));
1554 1553 } else if (dbuf->db_flags & DB_DIRECTION_FROM_RPORT) {
1555 1554 /* Grab the SN lock (see comment above) */
1556 1555 mutex_enter(&ict_sess->ist_sn_mutex);
1557 1556 idm_rc = idm_buf_rx_from_ini(iscsit_task->it_idm_task,
1558 1557 ibuf->ibuf_idm_buf, dbuf->db_relative_offset,
1559 1558 dbuf->db_data_size, &iscsit_buf_xfer_cb, dbuf);
1560 1559 mutex_exit(&ict_sess->ist_sn_mutex);
1561 1560
1562 1561 return (iscsit_idm_to_stmf(idm_rc));
1563 1562 }
1564 1563
1565 1564 /* What are we supposed to do if there is no direction? */
1566 1565 return (STMF_INVALID_ARG);
1567 1566 }
1568 1567
1569 1568 static void
1570 1569 iscsit_buf_xfer_cb(idm_buf_t *idb, idm_status_t status)
1571 1570 {
1572 1571 iscsit_task_t *itask = idb->idb_task_binding->idt_private;
1573 1572 stmf_data_buf_t *dbuf = idb->idb_cb_arg;
1574 1573
1575 1574 dbuf->db_xfer_status = iscsit_idm_to_stmf(status);
1576 1575
1577 1576 /*
1578 1577 * If the task has been aborted then we don't need to call STMF
1579 1578 */
1580 1579 if (itask->it_stmf_abort) {
1581 1580 return;
1582 1581 }
1583 1582
1584 1583 /*
1585 1584 * For ISCSI over TCP (not iSER), the last SCSI Data PDU passed
1586 1585 * for a successful command contains the status as requested by
1587 1586 * by COMSTAR (via the DB_SEND_STATUS_GOOD flag). But the iSER
1588 1587 * transport does not support phase-collapse. So pretend we are
1589 1588 * COMSTAR and send the status in a separate PDU now.
1590 1589 */
1591 1590 if (idb->idb_task_binding->idt_flags & IDM_TASK_PHASECOLLAPSE_SUCCESS) {
1592 1591 /*
1593 1592 * Mark task complete and notify COMSTAR
1594 1593 * that the status has been sent.
1595 1594 */
1596 1595 itask->it_idm_task->idt_state = TASK_COMPLETE;
1597 1596 stmf_send_status_done(itask->it_stmf_task,
1598 1597 iscsit_idm_to_stmf(status), STMF_IOF_LPORT_DONE);
1599 1598 } else if ((dbuf->db_flags & DB_SEND_STATUS_GOOD) &&
1600 1599 status == IDM_STATUS_SUCCESS) {
1601 1600
1602 1601 /*
1603 1602 * The iscsi target port provider - for iSER, emulates the
1604 1603 * DB_SEND_STATUS_GOOD optimization if requested by STMF;
1605 1604 * it sends the status in a separate PDU after the data
1606 1605 * transfer. In this case the port provider should first
1607 1606 * call stmf_data_xfer_done() to mark the transfer complete
1608 1607 * and then send the status. Although STMF will free the
1609 1608 * buffer at the time the task is freed, even if the transfer
1610 1609 * is not marked complete, this behavior makes statistics
1611 1610 * gathering and task state tracking more difficult than it
1612 1611 * needs to be.
1613 1612 */
1614 1613 stmf_data_xfer_done(itask->it_stmf_task, dbuf, 0);
1615 1614 if (iscsit_send_scsi_status(itask->it_stmf_task, 0)
1616 1615 != STMF_SUCCESS) {
1617 1616 stmf_send_status_done(itask->it_stmf_task,
1618 1617 STMF_FAILURE, STMF_IOF_LPORT_DONE);
1619 1618 }
1620 1619 } else {
1621 1620 stmf_data_xfer_done(itask->it_stmf_task, dbuf, 0);
1622 1621 /* don't touch dbuf after stmf_data_xfer_done */
1623 1622 }
1624 1623 }
1625 1624
1626 1625
1627 1626 /*ARGSUSED*/
1628 1627 stmf_status_t
1629 1628 iscsit_send_scsi_status(scsi_task_t *task, uint32_t ioflags)
1630 1629 {
1631 1630 iscsit_task_t *itask = task->task_port_private;
1632 1631 iscsi_scsi_rsp_hdr_t *rsp;
1633 1632 idm_pdu_t *pdu;
1634 1633 int resp_datalen;
1635 1634
1636 1635 /*
1637 1636 * If this task is aborted then we don't need to respond.
1638 1637 */
1639 1638 if (itask->it_stmf_abort) {
1640 1639 return (STMF_SUCCESS);
1641 1640 }
1642 1641
1643 1642 /*
1644 1643 * If this is a task management status, handle it elsewhere.
1645 1644 */
1646 1645 if (task->task_mgmt_function != TM_NONE) {
1647 1646 /*
1648 1647 * Don't wait for the PDU completion to tell STMF
1649 1648 * the task is done -- it doesn't really matter and
1650 1649 * it makes life complicated if STMF later asks us to
1651 1650 * abort the request and we don't know whether the
1652 1651 * status has been sent or not.
1653 1652 */
1654 1653 itask->it_tm_responded = B_TRUE;
1655 1654 iscsit_send_task_mgmt_resp(itask->it_tm_pdu,
1656 1655 (task->task_completion_status == STMF_SUCCESS) ?
1657 1656 SCSI_TCP_TM_RESP_COMPLETE : SCSI_TCP_TM_RESP_FUNC_NOT_SUPP);
1658 1657 stmf_send_status_done(task, STMF_SUCCESS,
1659 1658 STMF_IOF_LPORT_DONE);
1660 1659 return (STMF_SUCCESS);
1661 1660 }
1662 1661
1663 1662 /*
1664 1663 * Remove the task from the session task list
1665 1664 */
1666 1665 iscsit_task_done(itask);
1667 1666
1668 1667 /*
1669 1668 * Send status
1670 1669 */
1671 1670 mutex_enter(&itask->it_idm_task->idt_mutex);
1672 1671 if ((itask->it_idm_task->idt_state == TASK_ACTIVE) &&
1673 1672 (task->task_completion_status == STMF_SUCCESS) &&
1674 1673 (task->task_sense_length == 0) &&
1675 1674 (task->task_resid == 0)) {
1676 1675 itask->it_idm_task->idt_state = TASK_COMPLETE;
1677 1676 /* PDU callback releases task hold */
1678 1677 idm_task_hold(itask->it_idm_task);
1679 1678 mutex_exit(&itask->it_idm_task->idt_mutex);
1680 1679 /*
1681 1680 * Fast path. Cached status PDU's are already
1682 1681 * initialized. We just need to fill in
1683 1682 * connection and task information. StatSN is
1684 1683 * incremented by 1 for every status sent a
1685 1684 * connection.
1686 1685 */
1687 1686 pdu = kmem_cache_alloc(iscsit_status_pdu_cache, KM_SLEEP);
1688 1687 pdu->isp_ic = itask->it_ict->ict_ic;
1689 1688 pdu->isp_private = itask;
1690 1689 pdu->isp_flags |= IDM_PDU_SET_STATSN | IDM_PDU_ADVANCE_STATSN;
1691 1690
1692 1691 rsp = (iscsi_scsi_rsp_hdr_t *)pdu->isp_hdr;
1693 1692 rsp->itt = itask->it_itt;
1694 1693 /*
1695 1694 * ExpDataSN is the number of R2T and Data-In (read)
1696 1695 * PDUs the target has sent for the SCSI command.
1697 1696 *
1698 1697 * Since there is no support for bidirectional transfer
1699 1698 * yet, either idt_exp_datasn or idt_exp_rttsn, but not
1700 1699 * both is valid at any time
1701 1700 */
1702 1701 rsp->expdatasn = (itask->it_idm_task->idt_exp_datasn != 0) ?
1703 1702 htonl(itask->it_idm_task->idt_exp_datasn):
1704 1703 htonl(itask->it_idm_task->idt_exp_rttsn);
1705 1704 rsp->cmd_status = task->task_scsi_status;
1706 1705 iscsit_pdu_tx(pdu);
1707 1706 return (STMF_SUCCESS);
1708 1707 } else {
1709 1708 if (itask->it_idm_task->idt_state != TASK_ACTIVE) {
1710 1709 mutex_exit(&itask->it_idm_task->idt_mutex);
1711 1710 return (STMF_FAILURE);
1712 1711 }
1713 1712 itask->it_idm_task->idt_state = TASK_COMPLETE;
1714 1713 /* PDU callback releases task hold */
1715 1714 idm_task_hold(itask->it_idm_task);
1716 1715 mutex_exit(&itask->it_idm_task->idt_mutex);
1717 1716
1718 1717 resp_datalen = (task->task_sense_length == 0) ? 0 :
1719 1718 (task->task_sense_length + sizeof (uint16_t));
1720 1719
1721 1720 pdu = idm_pdu_alloc(sizeof (iscsi_hdr_t), resp_datalen);
1722 1721 idm_pdu_init(pdu, itask->it_ict->ict_ic, itask,
1723 1722 iscsit_send_status_done);
1724 1723 pdu->isp_flags |= IDM_PDU_SET_STATSN | IDM_PDU_ADVANCE_STATSN;
1725 1724
1726 1725 rsp = (iscsi_scsi_rsp_hdr_t *)pdu->isp_hdr;
1727 1726 bzero(rsp, sizeof (*rsp));
1728 1727 rsp->opcode = ISCSI_OP_SCSI_RSP;
1729 1728
1730 1729 rsp->flags = ISCSI_FLAG_FINAL;
1731 1730 if (task->task_status_ctrl & TASK_SCTRL_OVER) {
1732 1731 rsp->flags |= ISCSI_FLAG_CMD_OVERFLOW;
1733 1732 } else if (task->task_status_ctrl & TASK_SCTRL_UNDER) {
1734 1733 rsp->flags |= ISCSI_FLAG_CMD_UNDERFLOW;
1735 1734 }
1736 1735
1737 1736 rsp->bi_residual_count = 0;
1738 1737 rsp->residual_count = htonl(task->task_resid);
1739 1738 rsp->itt = itask->it_itt;
1740 1739 rsp->response = ISCSI_STATUS_CMD_COMPLETED;
1741 1740 rsp->expdatasn = (itask->it_idm_task->idt_exp_datasn != 0) ?
1742 1741 htonl(itask->it_idm_task->idt_exp_datasn):
1743 1742 htonl(itask->it_idm_task->idt_exp_rttsn);
1744 1743 rsp->cmd_status = task->task_scsi_status;
1745 1744 if (task->task_sense_length != 0) {
1746 1745 /*
1747 1746 * Add a byte to provide the sense length in
1748 1747 * the response
1749 1748 */
1750 1749 *(uint16_t *)((void *)pdu->isp_data) =
1751 1750 htons(task->task_sense_length);
1752 1751 bcopy(task->task_sense_data,
1753 1752 (uint8_t *)pdu->isp_data +
1754 1753 sizeof (uint16_t),
1755 1754 task->task_sense_length);
1756 1755 hton24(rsp->dlength, resp_datalen);
1757 1756 }
1758 1757
1759 1758 DTRACE_PROBE5(iscsi__scsi__response,
1760 1759 iscsit_conn_t *, itask->it_ict,
1761 1760 uint8_t, rsp->response,
1762 1761 uint8_t, rsp->cmd_status,
1763 1762 idm_pdu_t *, pdu,
1764 1763 scsi_task_t *, task);
1765 1764
1766 1765 iscsit_pdu_tx(pdu);
1767 1766
1768 1767 return (STMF_SUCCESS);
1769 1768 }
1770 1769 }
1771 1770
1772 1771 /*ARGSUSED*/
1773 1772 static void
1774 1773 iscsit_send_good_status_done(idm_pdu_t *pdu, idm_status_t status)
1775 1774 {
1776 1775 iscsit_task_t *itask;
1777 1776 boolean_t aborted;
1778 1777
1779 1778 itask = pdu->isp_private;
1780 1779 aborted = itask->it_stmf_abort;
1781 1780
1782 1781 /*
1783 1782 * After releasing the hold the task may be freed at any time so
1784 1783 * don't touch it.
1785 1784 */
1786 1785 idm_task_rele(itask->it_idm_task);
1787 1786 if (!aborted) {
1788 1787 stmf_send_status_done(itask->it_stmf_task,
1789 1788 iscsit_idm_to_stmf(pdu->isp_status), STMF_IOF_LPORT_DONE);
1790 1789 }
1791 1790 kmem_cache_free(iscsit_status_pdu_cache, pdu);
1792 1791 }
1793 1792
1794 1793 /*ARGSUSED*/
1795 1794 static void
1796 1795 iscsit_send_status_done(idm_pdu_t *pdu, idm_status_t status)
1797 1796 {
1798 1797 iscsit_task_t *itask;
1799 1798 boolean_t aborted;
1800 1799
1801 1800 itask = pdu->isp_private;
1802 1801 aborted = itask->it_stmf_abort;
1803 1802
1804 1803 /*
1805 1804 * After releasing the hold the task may be freed at any time so
1806 1805 * don't touch it.
1807 1806 */
1808 1807 idm_task_rele(itask->it_idm_task);
1809 1808 if (!aborted) {
1810 1809 stmf_send_status_done(itask->it_stmf_task,
1811 1810 iscsit_idm_to_stmf(pdu->isp_status), STMF_IOF_LPORT_DONE);
1812 1811 }
1813 1812 idm_pdu_free(pdu);
1814 1813 }
1815 1814
1816 1815
1817 1816 void
1818 1817 iscsit_lport_task_free(scsi_task_t *task)
1819 1818 {
1820 1819 iscsit_task_t *itask = task->task_port_private;
1821 1820
1822 1821 /* We only call idm_task_start for regular tasks, not task management */
1823 1822 if (task->task_mgmt_function == TM_NONE) {
1824 1823 idm_task_done(itask->it_idm_task);
1825 1824 iscsit_task_free(itask);
1826 1825 return;
1827 1826 } else {
1828 1827 iscsit_tm_task_free(itask);
1829 1828 }
1830 1829 }
1831 1830
1832 1831 /*ARGSUSED*/
1833 1832 stmf_status_t
1834 1833 iscsit_abort(stmf_local_port_t *lport, int abort_cmd, void *arg, uint32_t flags)
1835 1834 {
1836 1835 scsi_task_t *st = (scsi_task_t *)arg;
1837 1836 iscsit_task_t *iscsit_task;
1838 1837 idm_task_t *idt;
1839 1838
1840 1839 /*
1841 1840 * If this is a task management request then there's really not much to
1842 1841 * do.
1843 1842 */
1844 1843 if (st->task_mgmt_function != TM_NONE) {
1845 1844 return (STMF_ABORT_SUCCESS);
1846 1845 }
1847 1846
1848 1847 /*
1849 1848 * Regular task, start cleaning up
1850 1849 */
1851 1850 iscsit_task = st->task_port_private;
1852 1851 idt = iscsit_task->it_idm_task;
1853 1852 mutex_enter(&iscsit_task->it_mutex);
1854 1853 iscsit_task->it_stmf_abort = B_TRUE;
1855 1854 if (iscsit_task->it_aborted) {
1856 1855 mutex_exit(&iscsit_task->it_mutex);
1857 1856 /*
1858 1857 * Task is no longer active
1859 1858 */
1860 1859 iscsit_task_done(iscsit_task);
1861 1860
1862 1861 /*
1863 1862 * STMF specification is wrong... says to return
1864 1863 * STMF_ABORTED, the code actually looks for
1865 1864 * STMF_ABORT_SUCCESS.
1866 1865 */
1867 1866 return (STMF_ABORT_SUCCESS);
1868 1867 } else {
1869 1868 mutex_exit(&iscsit_task->it_mutex);
1870 1869 /*
1871 1870 * Call IDM to abort the task. Due to a variety of
1872 1871 * circumstances the task may already be in the process of
1873 1872 * aborting.
1874 1873 * We'll let IDM worry about rationalizing all that except
1875 1874 * for one particular instance. If the state of the task
1876 1875 * is TASK_COMPLETE, we need to indicate to the framework
1877 1876 * that we are in fact done. This typically happens with
1878 1877 * framework-initiated task management type requests
1879 1878 * (e.g. abort task).
1880 1879 */
1881 1880 if (idt->idt_state == TASK_COMPLETE) {
1882 1881 idm_refcnt_wait_ref(&idt->idt_refcnt);
1883 1882 return (STMF_ABORT_SUCCESS);
1884 1883 } else {
1885 1884 idm_task_abort(idt->idt_ic, idt, AT_TASK_MGMT_ABORT);
1886 1885 return (STMF_SUCCESS);
1887 1886 }
1888 1887 }
1889 1888
1890 1889 /*NOTREACHED*/
1891 1890 }
1892 1891
1893 1892 /*ARGSUSED*/
1894 1893 void
1895 1894 iscsit_ctl(stmf_local_port_t *lport, int cmd, void *arg)
1896 1895 {
1897 1896 iscsit_tgt_t *iscsit_tgt;
1898 1897
1899 1898 ASSERT((cmd == STMF_CMD_LPORT_ONLINE) ||
1900 1899 (cmd == STMF_ACK_LPORT_ONLINE_COMPLETE) ||
1901 1900 (cmd == STMF_CMD_LPORT_OFFLINE) ||
1902 1901 (cmd == STMF_ACK_LPORT_OFFLINE_COMPLETE));
1903 1902
1904 1903 iscsit_tgt = (iscsit_tgt_t *)lport->lport_port_private;
1905 1904
1906 1905 switch (cmd) {
1907 1906 case STMF_CMD_LPORT_ONLINE:
1908 1907 iscsit_tgt_sm_event(iscsit_tgt, TE_STMF_ONLINE_REQ);
1909 1908 break;
1910 1909 case STMF_CMD_LPORT_OFFLINE:
1911 1910 iscsit_tgt_sm_event(iscsit_tgt, TE_STMF_OFFLINE_REQ);
1912 1911 break;
1913 1912 case STMF_ACK_LPORT_ONLINE_COMPLETE:
1914 1913 iscsit_tgt_sm_event(iscsit_tgt, TE_STMF_ONLINE_COMPLETE_ACK);
1915 1914 break;
1916 1915 case STMF_ACK_LPORT_OFFLINE_COMPLETE:
1917 1916 iscsit_tgt_sm_event(iscsit_tgt, TE_STMF_OFFLINE_COMPLETE_ACK);
1918 1917 break;
1919 1918
1920 1919 default:
1921 1920 break;
1922 1921 }
1923 1922 }
1924 1923
1925 1924 static stmf_status_t
1926 1925 iscsit_idm_to_stmf(idm_status_t idmrc)
1927 1926 {
1928 1927 switch (idmrc) {
1929 1928 case IDM_STATUS_SUCCESS:
1930 1929 return (STMF_SUCCESS);
1931 1930 default:
1932 1931 return (STMF_FAILURE);
1933 1932 }
1934 1933 /*NOTREACHED*/
1935 1934 }
1936 1935
1937 1936 void
1938 1937 iscsit_op_scsi_cmd(idm_conn_t *ic, idm_pdu_t *rx_pdu)
1939 1938 {
1940 1939 iscsit_conn_t *ict = ic->ic_handle;
1941 1940
1942 1941 if (iscsit_check_cmdsn_and_queue(rx_pdu)) {
1943 1942 iscsit_post_scsi_cmd(ic, rx_pdu);
1944 1943 }
1945 1944 iscsit_process_pdu_in_queue(ict->ict_sess);
1946 1945 }
1947 1946
1948 1947 /*
1949 1948 * ISCSI protocol
1950 1949 */
1951 1950
1952 1951 void
1953 1952 iscsit_post_scsi_cmd(idm_conn_t *ic, idm_pdu_t *rx_pdu)
1954 1953 {
1955 1954 iscsit_conn_t *ict;
1956 1955 iscsit_task_t *itask;
1957 1956 scsi_task_t *task;
1958 1957 iscsit_buf_t *ibuf;
1959 1958 iscsi_scsi_cmd_hdr_t *iscsi_scsi =
1960 1959 (iscsi_scsi_cmd_hdr_t *)rx_pdu->isp_hdr;
1961 1960 iscsi_addl_hdr_t *ahs_hdr;
1962 1961 uint16_t addl_cdb_len = 0;
1963 1962
1964 1963 ict = ic->ic_handle;
1965 1964
1966 1965 itask = iscsit_task_alloc(ict);
1967 1966 if (itask == NULL) {
1968 1967 /* Finish processing request */
1969 1968 iscsit_set_cmdsn(ict, rx_pdu);
1970 1969
1971 1970 iscsit_send_direct_scsi_resp(ict, rx_pdu,
1972 1971 ISCSI_STATUS_CMD_COMPLETED, STATUS_BUSY);
1973 1972 idm_pdu_complete(rx_pdu, IDM_STATUS_SUCCESS);
1974 1973 return;
1975 1974 }
1976 1975
1977 1976 /*
1978 1977 * Note CmdSN and ITT in task. IDM will have already validated this
1979 1978 * request against the connection state so we don't need to check
1980 1979 * that (the connection may have changed state in the meantime but
1981 1980 * we will catch that when we try to send a response)
1982 1981 */
1983 1982 itask->it_cmdsn = ntohl(iscsi_scsi->cmdsn);
1984 1983 itask->it_itt = iscsi_scsi->itt;
1985 1984
1986 1985 /*
1987 1986 * Check for extended CDB AHS
1988 1987 */
1989 1988 if (iscsi_scsi->hlength > 0) {
1990 1989 ahs_hdr = (iscsi_addl_hdr_t *)iscsi_scsi;
1991 1990 addl_cdb_len = ((ahs_hdr->ahs_hlen_hi << 8) |
1992 1991 ahs_hdr->ahs_hlen_lo) - 1; /* Adjust for reserved byte */
1993 1992 if (((addl_cdb_len + 4) / sizeof (uint32_t)) >
1994 1993 iscsi_scsi->hlength) {
1995 1994 /* Mangled header info, drop it */
1996 1995 idm_pdu_complete(rx_pdu, IDM_STATUS_SUCCESS);
1997 1996 return;
1998 1997 }
1999 1998 }
2000 1999
2001 2000 ict = rx_pdu->isp_ic->ic_handle; /* IDM client private */
2002 2001
2003 2002 /*
2004 2003 * Add task to session list. This function will also check to
2005 2004 * ensure that the task does not already exist.
2006 2005 */
2007 2006 if (iscsit_task_start(itask) != IDM_STATUS_SUCCESS) {
2008 2007 /*
2009 2008 * Task exists, free all resources and reject. Don't
2010 2009 * update expcmdsn in this case because RFC 3720 says
2011 2010 * "The CmdSN of the rejected command PDU (if it is a
2012 2011 * non-immediate command) MUST NOT be considered received
2013 2012 * by the target (i.e., a command sequence gap must be
2014 2013 * assumed for the CmdSN), even though the CmdSN of the
2015 2014 * rejected command PDU may be reliably ascertained. Upon
2016 2015 * receiving the Reject, the initiator MUST plug the CmdSN
2017 2016 * gap in order to continue to use the session. The gap
2018 2017 * may be plugged either by transmitting a command PDU
2019 2018 * with the same CmdSN, or by aborting the task (see section
2020 2019 * 6.9 on how an abort may plug a CmdSN gap)." (Section 6.3)
2021 2020 */
2022 2021 iscsit_task_free(itask);
2023 2022 iscsit_send_reject(ict, rx_pdu, ISCSI_REJECT_TASK_IN_PROGRESS);
2024 2023 idm_pdu_complete(rx_pdu, IDM_STATUS_SUCCESS);
2025 2024 return;
2026 2025 }
2027 2026
2028 2027 /* Update sequence numbers */
2029 2028 iscsit_set_cmdsn(ict, rx_pdu);
2030 2029
2031 2030 /*
2032 2031 * Allocate STMF task
2033 2032 */
2034 2033 itask->it_stmf_task = stmf_task_alloc(
2035 2034 itask->it_ict->ict_sess->ist_lport,
2036 2035 itask->it_ict->ict_sess->ist_stmf_sess, iscsi_scsi->lun,
2037 2036 16 + addl_cdb_len, 0);
2038 2037 if (itask->it_stmf_task == NULL) {
2039 2038 /*
2040 2039 * Either stmf really couldn't get memory for a task or,
2041 2040 * more likely, the LU is currently in reset. Either way
2042 2041 * we have no choice but to fail the request.
2043 2042 */
2044 2043 iscsit_task_done(itask);
2045 2044 iscsit_task_free(itask);
2046 2045 iscsit_send_direct_scsi_resp(ict, rx_pdu,
2047 2046 ISCSI_STATUS_CMD_COMPLETED, STATUS_BUSY);
2048 2047 idm_pdu_complete(rx_pdu, IDM_STATUS_SUCCESS);
2049 2048 return;
2050 2049 }
2051 2050
2052 2051 task = itask->it_stmf_task;
2053 2052 task->task_port_private = itask;
2054 2053
2055 2054 bcopy(iscsi_scsi->lun, task->task_lun_no, sizeof (task->task_lun_no));
2056 2055
2057 2056 /*
2058 2057 * iSCSI and Comstar use the same values. Should we rely on this
2059 2058 * or translate them bit-wise?
2060 2059 */
2061 2060
2062 2061 task->task_flags =
2063 2062 (((iscsi_scsi->flags & ISCSI_FLAG_CMD_READ) ? TF_READ_DATA : 0) |
2064 2063 ((iscsi_scsi->flags & ISCSI_FLAG_CMD_WRITE) ? TF_WRITE_DATA : 0) |
2065 2064 ((rx_pdu->isp_datalen == 0) ? 0 : TF_INITIAL_BURST));
2066 2065
2067 2066 switch (iscsi_scsi->flags & ISCSI_FLAG_CMD_ATTR_MASK) {
2068 2067 case ISCSI_ATTR_UNTAGGED:
2069 2068 break;
2070 2069 case ISCSI_ATTR_SIMPLE:
2071 2070 task->task_additional_flags |= TF_ATTR_SIMPLE_QUEUE;
2072 2071 break;
2073 2072 case ISCSI_ATTR_ORDERED:
2074 2073 task->task_additional_flags |= TF_ATTR_ORDERED_QUEUE;
2075 2074 break;
2076 2075 case ISCSI_ATTR_HEAD_OF_QUEUE:
2077 2076 task->task_additional_flags |= TF_ATTR_HEAD_OF_QUEUE;
2078 2077 break;
2079 2078 case ISCSI_ATTR_ACA:
2080 2079 task->task_additional_flags |= TF_ATTR_ACA;
2081 2080 break;
2082 2081 default:
2083 2082 /* Protocol error but just take it, treat as untagged */
2084 2083 break;
2085 2084 }
2086 2085
2087 2086
2088 2087 task->task_additional_flags = 0;
2089 2088 task->task_priority = 0;
2090 2089 task->task_mgmt_function = TM_NONE;
2091 2090
2092 2091 /*
2093 2092 * This "task_max_nbufs" doesn't map well to BIDI. We probably need
2094 2093 * parameter for each direction. "MaxOutstandingR2T" may very well
2095 2094 * be set to one which could prevent us from doing simultaneous
2096 2095 * transfers in each direction.
2097 2096 */
2098 2097 task->task_max_nbufs = (iscsi_scsi->flags & ISCSI_FLAG_CMD_WRITE) ?
2099 2098 ict->ict_op.op_max_outstanding_r2t : STMF_BUFS_MAX;
2100 2099 task->task_cmd_seq_no = ntohl(iscsi_scsi->itt);
2101 2100 task->task_expected_xfer_length = ntohl(iscsi_scsi->data_length);
2102 2101
2103 2102 /* Copy CDB */
2104 2103 bcopy(iscsi_scsi->scb, task->task_cdb, 16);
2105 2104 if (addl_cdb_len > 0) {
2106 2105 bcopy(ahs_hdr->ahs_extscb, task->task_cdb + 16, addl_cdb_len);
2107 2106 }
2108 2107
2109 2108 DTRACE_ISCSI_3(scsi__command, idm_conn_t *, ic,
2110 2109 iscsi_scsi_cmd_hdr_t *, (iscsi_scsi_cmd_hdr_t *)rx_pdu->isp_hdr,
2111 2110 scsi_task_t *, task);
2112 2111
2113 2112 /*
2114 2113 * Copy the transport header into the task handle from the PDU
2115 2114 * handle. The transport header describes this task's remote tagged
2116 2115 * buffer.
2117 2116 */
2118 2117 if (rx_pdu->isp_transport_hdrlen != 0) {
2119 2118 bcopy(rx_pdu->isp_transport_hdr,
2120 2119 itask->it_idm_task->idt_transport_hdr,
2121 2120 rx_pdu->isp_transport_hdrlen);
2122 2121 }
2123 2122
2124 2123 /*
2125 2124 * Tell IDM about our new active task
2126 2125 */
2127 2126 idm_task_start(itask->it_idm_task, (uintptr_t)itask->it_itt);
2128 2127
2129 2128 /*
2130 2129 * If we have any immediate data then setup the immediate buffer
2131 2130 * context that comes with the task
2132 2131 */
2133 2132 if (rx_pdu->isp_datalen) {
2134 2133 ibuf = itask->it_immed_data;
2135 2134 ibuf->ibuf_immed_data_pdu = rx_pdu;
2136 2135 ibuf->ibuf_stmf_buf->db_data_size = rx_pdu->isp_datalen;
2137 2136 ibuf->ibuf_stmf_buf->db_buf_size = rx_pdu->isp_datalen;
2138 2137 ibuf->ibuf_stmf_buf->db_relative_offset = 0;
2139 2138 ibuf->ibuf_stmf_buf->db_sglist[0].seg_length =
2140 2139 rx_pdu->isp_datalen;
2141 2140 ibuf->ibuf_stmf_buf->db_sglist[0].seg_addr = rx_pdu->isp_data;
2142 2141
2143 2142 DTRACE_ISCSI_8(xfer__start, idm_conn_t *, ic,
2144 2143 uintptr_t, ibuf->ibuf_stmf_buf->db_sglist[0].seg_addr,
2145 2144 uint32_t, ibuf->ibuf_stmf_buf->db_relative_offset,
2146 2145 uint64_t, 0, uint32_t, 0, uint32_t, 0, /* no raddr */
2147 2146 uint32_t, rx_pdu->isp_datalen, int, XFER_BUF_TX_TO_INI);
2148 2147
2149 2148 /*
2150 2149 * For immediate data transfer, there is no callback from
2151 2150 * stmf to indicate that the initial burst of data is
2152 2151 * transferred successfully. In some cases, the task can
2153 2152 * get freed before execution returns from stmf_post_task.
2154 2153 * Although this xfer-start/done probe accurately tracks
2155 2154 * the size of the transfer, it does only provide a best
2156 2155 * effort on the timing of the transfer.
2157 2156 */
2158 2157 DTRACE_ISCSI_8(xfer__done, idm_conn_t *, ic,
2159 2158 uintptr_t, ibuf->ibuf_stmf_buf->db_sglist[0].seg_addr,
2160 2159 uint32_t, ibuf->ibuf_stmf_buf->db_relative_offset,
2161 2160 uint64_t, 0, uint32_t, 0, uint32_t, 0, /* no raddr */
2162 2161 uint32_t, rx_pdu->isp_datalen, int, XFER_BUF_TX_TO_INI);
2163 2162 stmf_post_task(task, ibuf->ibuf_stmf_buf);
2164 2163 } else {
2165 2164
2166 2165 stmf_post_task(task, NULL);
2167 2166 idm_pdu_complete(rx_pdu, IDM_STATUS_SUCCESS);
2168 2167 }
2169 2168 }
2170 2169
2171 2170 void
2172 2171 iscsit_deferred_dispatch(idm_pdu_t *rx_pdu)
2173 2172 {
2174 2173 iscsit_conn_t *ict = rx_pdu->isp_ic->ic_handle;
2175 2174
2176 2175 /*
2177 2176 * If the connection has been lost then ignore new PDU's
2178 2177 */
2179 2178 mutex_enter(&ict->ict_mutex);
2180 2179 if (ict->ict_lost) {
2181 2180 mutex_exit(&ict->ict_mutex);
2182 2181 idm_pdu_complete(rx_pdu, IDM_STATUS_FAIL);
2183 2182 return;
2184 2183 }
2185 2184
2186 2185 /*
2187 2186 * Grab a hold on the connection to prevent it from going away
2188 2187 * between now and when the taskq function is called.
2189 2188 */
2190 2189 iscsit_conn_dispatch_hold(ict);
2191 2190 mutex_exit(&ict->ict_mutex);
2192 2191
2193 2192 taskq_dispatch_ent(iscsit_global.global_dispatch_taskq,
2194 2193 iscsit_deferred, rx_pdu, 0, &rx_pdu->isp_tqent);
2195 2194 }
2196 2195
2197 2196 static void
2198 2197 iscsit_deferred(void *rx_pdu_void)
2199 2198 {
2200 2199 idm_pdu_t *rx_pdu = rx_pdu_void;
2201 2200 idm_conn_t *ic = rx_pdu->isp_ic;
2202 2201 iscsit_conn_t *ict = ic->ic_handle;
2203 2202
2204 2203 /*
2205 2204 * NOP and Task Management Commands can be marked for immediate
2206 2205 * delivery. Commands marked as 'Immediate' are to be considered
2207 2206 * for execution as soon as they arrive on the target. So these
2208 2207 * should not be checked for sequence order and put in a queue.
2209 2208 * The CmdSN is not advanced for Immediate Commands.
2210 2209 */
2211 2210 switch (IDM_PDU_OPCODE(rx_pdu)) {
2212 2211 case ISCSI_OP_NOOP_OUT:
2213 2212 if (iscsit_check_cmdsn_and_queue(rx_pdu)) {
2214 2213 iscsit_set_cmdsn(ict, rx_pdu);
2215 2214 iscsit_pdu_op_noop(ict, rx_pdu);
2216 2215 }
2217 2216 break;
2218 2217 case ISCSI_OP_LOGIN_CMD:
2219 2218 iscsit_pdu_op_login_cmd(ict, rx_pdu);
2220 2219 iscsit_conn_dispatch_rele(ict);
2221 2220 return;
2222 2221 case ISCSI_OP_TEXT_CMD:
2223 2222 if (iscsit_check_cmdsn_and_queue(rx_pdu)) {
2224 2223 iscsit_set_cmdsn(ict, rx_pdu);
2225 2224 iscsit_pdu_op_text_cmd(ict, rx_pdu);
2226 2225 }
2227 2226 break;
2228 2227 case ISCSI_OP_LOGOUT_CMD:
2229 2228 if (iscsit_check_cmdsn_and_queue(rx_pdu)) {
2230 2229 iscsit_set_cmdsn(ict, rx_pdu);
2231 2230 iscsit_pdu_op_logout_cmd(ict, rx_pdu);
2232 2231 }
2233 2232 break;
2234 2233 default:
2235 2234 /* Protocol error. IDM should have caught this */
2236 2235 idm_pdu_complete(rx_pdu, IDM_STATUS_FAIL);
2237 2236 ASSERT(0);
2238 2237 break;
2239 2238 }
2240 2239 /*
2241 2240 * Check if there are other PDUs in the session staging queue
2242 2241 * waiting to be posted to SCSI layer.
2243 2242 */
2244 2243 iscsit_process_pdu_in_queue(ict->ict_sess);
2245 2244
2246 2245 iscsit_conn_dispatch_rele(ict);
2247 2246 }
2248 2247
2249 2248 static void
2250 2249 iscsit_send_direct_scsi_resp(iscsit_conn_t *ict, idm_pdu_t *rx_pdu,
2251 2250 uint8_t response, uint8_t cmd_status)
2252 2251 {
2253 2252 idm_pdu_t *rsp_pdu;
2254 2253 idm_conn_t *ic;
2255 2254 iscsi_scsi_rsp_hdr_t *resp;
2256 2255 iscsi_scsi_cmd_hdr_t *req =
2257 2256 (iscsi_scsi_cmd_hdr_t *)rx_pdu->isp_hdr;
2258 2257
2259 2258 ic = ict->ict_ic;
2260 2259
2261 2260 rsp_pdu = idm_pdu_alloc(sizeof (iscsi_scsi_rsp_hdr_t), 0);
2262 2261 idm_pdu_init(rsp_pdu, ic, NULL, NULL);
2263 2262 /*
2264 2263 * StatSN is incremented by 1 for every response sent on
2265 2264 * a connection except for responses sent as a result of
2266 2265 * a retry or SNACK
2267 2266 */
2268 2267 rsp_pdu->isp_flags |= IDM_PDU_SET_STATSN | IDM_PDU_ADVANCE_STATSN;
2269 2268
2270 2269 resp = (iscsi_scsi_rsp_hdr_t *)rsp_pdu->isp_hdr;
2271 2270
2272 2271 resp->opcode = ISCSI_OP_SCSI_RSP;
2273 2272 resp->flags = ISCSI_FLAG_FINAL;
2274 2273 resp->response = response;
2275 2274 resp->cmd_status = cmd_status;
2276 2275 resp->itt = req->itt;
2277 2276 if ((response == ISCSI_STATUS_CMD_COMPLETED) &&
2278 2277 (req->data_length != 0) &&
2279 2278 ((req->flags & ISCSI_FLAG_CMD_READ) ||
2280 2279 (req->flags & ISCSI_FLAG_CMD_WRITE))) {
2281 2280 resp->flags |= ISCSI_FLAG_CMD_UNDERFLOW;
2282 2281 resp->residual_count = req->data_length;
2283 2282 }
2284 2283
2285 2284 DTRACE_PROBE4(iscsi__scsi__direct__response,
2286 2285 iscsit_conn_t *, ict,
2287 2286 uint8_t, resp->response,
2288 2287 uint8_t, resp->cmd_status,
2289 2288 idm_pdu_t *, rsp_pdu);
2290 2289
2291 2290 iscsit_pdu_tx(rsp_pdu);
2292 2291 }
2293 2292
2294 2293 void
2295 2294 iscsit_send_task_mgmt_resp(idm_pdu_t *tm_resp_pdu, uint8_t tm_status)
2296 2295 {
2297 2296 iscsi_scsi_task_mgt_rsp_hdr_t *tm_resp;
2298 2297
2299 2298 /*
2300 2299 * The target must take note of the last-sent StatSN.
2301 2300 * The StatSN is to be incremented after sending a
2302 2301 * task management response. Digest recovery can only
2303 2302 * work if StatSN is incremented.
2304 2303 */
2305 2304 tm_resp_pdu->isp_flags |= IDM_PDU_SET_STATSN | IDM_PDU_ADVANCE_STATSN;
2306 2305 tm_resp = (iscsi_scsi_task_mgt_rsp_hdr_t *)tm_resp_pdu->isp_hdr;
2307 2306 tm_resp->response = tm_status;
2308 2307
2309 2308 DTRACE_PROBE3(iscsi__scsi__tm__response,
2310 2309 iscsit_conn_t *, tm_resp_pdu->isp_ic->ic_handle,
2311 2310 uint8_t, tm_resp->response,
2312 2311 idm_pdu_t *, tm_resp_pdu);
2313 2312 iscsit_pdu_tx(tm_resp_pdu);
2314 2313 }
2315 2314
2316 2315 void
2317 2316 iscsit_op_scsi_task_mgmt(iscsit_conn_t *ict, idm_pdu_t *rx_pdu)
2318 2317 {
2319 2318 idm_pdu_t *tm_resp_pdu;
2320 2319 iscsit_task_t *itask;
2321 2320 iscsit_task_t *tm_itask;
2322 2321 scsi_task_t *task;
2323 2322 iscsi_scsi_task_mgt_hdr_t *iscsi_tm =
2324 2323 (iscsi_scsi_task_mgt_hdr_t *)rx_pdu->isp_hdr;
2325 2324 iscsi_scsi_task_mgt_rsp_hdr_t *iscsi_tm_rsp =
2326 2325 (iscsi_scsi_task_mgt_rsp_hdr_t *)rx_pdu->isp_hdr;
2327 2326 uint32_t rtt, cmdsn, refcmdsn;
2328 2327 uint8_t tm_func;
2329 2328
2330 2329 /*
2331 2330 * Setup response PDU (response field will get filled in later)
2332 2331 */
2333 2332 tm_resp_pdu = idm_pdu_alloc(sizeof (iscsi_scsi_task_mgt_rsp_hdr_t), 0);
2334 2333 if (tm_resp_pdu == NULL) {
2335 2334 /* Can't respond, just drop it */
2336 2335 idm_pdu_complete(rx_pdu, IDM_STATUS_SUCCESS);
2337 2336 return;
2338 2337 }
2339 2338 idm_pdu_init(tm_resp_pdu, ict->ict_ic, NULL, NULL);
2340 2339 iscsi_tm_rsp = (iscsi_scsi_task_mgt_rsp_hdr_t *)tm_resp_pdu->isp_hdr;
2341 2340 bzero(iscsi_tm_rsp, sizeof (iscsi_scsi_task_mgt_rsp_hdr_t));
2342 2341 iscsi_tm_rsp->opcode = ISCSI_OP_SCSI_TASK_MGT_RSP;
2343 2342 iscsi_tm_rsp->flags = ISCSI_FLAG_FINAL;
2344 2343 iscsi_tm_rsp->itt = rx_pdu->isp_hdr->itt;
2345 2344
2346 2345 /*
2347 2346 * Figure out what we're being asked to do.
2348 2347 */
2349 2348 DTRACE_PROBE4(iscsi__scsi__tm__request,
2350 2349 iscsit_conn_t *, ict,
2351 2350 uint8_t, (iscsi_tm->function & ISCSI_FLAG_TASK_MGMT_FUNCTION_MASK),
2352 2351 uint32_t, iscsi_tm->rtt,
2353 2352 idm_pdu_t *, rx_pdu);
2354 2353 switch (iscsi_tm->function & ISCSI_FLAG_TASK_MGMT_FUNCTION_MASK) {
2355 2354 case ISCSI_TM_FUNC_ABORT_TASK:
2356 2355 /*
2357 2356 * STMF doesn't currently support the "abort task" task
2358 2357 * management command although it does support aborting
2359 2358 * an individual task. We'll get STMF to abort the task
2360 2359 * for us but handle the details of the task management
2361 2360 * command ourselves.
2362 2361 *
2363 2362 * Find the task associated with the referenced task tag.
2364 2363 */
2365 2364 rtt = iscsi_tm->rtt;
2366 2365 itask = (iscsit_task_t *)idm_task_find_by_handle(ict->ict_ic,
2367 2366 (uintptr_t)rtt);
2368 2367
2369 2368 if (itask == NULL) {
2370 2369 cmdsn = ntohl(iscsi_tm->cmdsn);
2371 2370 refcmdsn = ntohl(iscsi_tm->refcmdsn);
2372 2371
2373 2372 /*
2374 2373 * Task was not found. But the SCSI command could be
2375 2374 * on the rxpdu wait queue. If RefCmdSN is within
2376 2375 * the CmdSN window and less than CmdSN of the TM
2377 2376 * function, return "Function Complete". Otherwise,
2378 2377 * return "Task Does Not Exist".
2379 2378 */
2380 2379
2381 2380 if (iscsit_cmdsn_in_window(ict, refcmdsn) &&
2382 2381 iscsit_sna_lt(refcmdsn, cmdsn)) {
2383 2382 mutex_enter(&ict->ict_sess->ist_sn_mutex);
2384 2383 (void) iscsit_remove_pdu_from_queue(
2385 2384 ict->ict_sess, refcmdsn);
2386 2385 iscsit_conn_dispatch_rele(ict);
2387 2386 mutex_exit(&ict->ict_sess->ist_sn_mutex);
2388 2387 iscsit_send_task_mgmt_resp(tm_resp_pdu,
2389 2388 SCSI_TCP_TM_RESP_COMPLETE);
2390 2389 } else {
2391 2390 iscsit_send_task_mgmt_resp(tm_resp_pdu,
2392 2391 SCSI_TCP_TM_RESP_NO_TASK);
2393 2392 }
2394 2393 } else {
2395 2394
2396 2395 /*
2397 2396 * Tell STMF to abort the task. This will do no harm
2398 2397 * if the task is already complete.
2399 2398 */
2400 2399 stmf_abort(STMF_QUEUE_TASK_ABORT, itask->it_stmf_task,
2401 2400 STMF_ABORTED, NULL);
2402 2401
2403 2402 /*
2404 2403 * Make sure the task hasn't already completed
2405 2404 */
2406 2405 mutex_enter(&itask->it_idm_task->idt_mutex);
2407 2406 if ((itask->it_idm_task->idt_state == TASK_COMPLETE) ||
2408 2407 (itask->it_idm_task->idt_state == TASK_IDLE)) {
2409 2408 /*
2410 2409 * Task is complete, return "Task Does Not
2411 2410 * Exist"
2412 2411 */
2413 2412 mutex_exit(&itask->it_idm_task->idt_mutex);
2414 2413 iscsit_send_task_mgmt_resp(tm_resp_pdu,
2415 2414 SCSI_TCP_TM_RESP_NO_TASK);
2416 2415 } else {
2417 2416 /*
2418 2417 * STMF is now aborting the task, return
2419 2418 * "Function Complete"
2420 2419 */
2421 2420 mutex_exit(&itask->it_idm_task->idt_mutex);
2422 2421 iscsit_send_task_mgmt_resp(tm_resp_pdu,
2423 2422 SCSI_TCP_TM_RESP_COMPLETE);
2424 2423 }
2425 2424 idm_task_rele(itask->it_idm_task);
2426 2425 }
2427 2426 idm_pdu_complete(rx_pdu, IDM_STATUS_SUCCESS);
2428 2427 return;
2429 2428
2430 2429 case ISCSI_TM_FUNC_ABORT_TASK_SET:
2431 2430 tm_func = TM_ABORT_TASK_SET;
2432 2431 break;
2433 2432
2434 2433 case ISCSI_TM_FUNC_CLEAR_ACA:
2435 2434 tm_func = TM_CLEAR_ACA;
2436 2435 break;
2437 2436
2438 2437 case ISCSI_TM_FUNC_CLEAR_TASK_SET:
2439 2438 tm_func = TM_CLEAR_TASK_SET;
2440 2439 break;
2441 2440
2442 2441 case ISCSI_TM_FUNC_LOGICAL_UNIT_RESET:
2443 2442 tm_func = TM_LUN_RESET;
2444 2443 break;
2445 2444
2446 2445 case ISCSI_TM_FUNC_TARGET_WARM_RESET:
2447 2446 tm_func = TM_TARGET_WARM_RESET;
2448 2447 break;
2449 2448
2450 2449 case ISCSI_TM_FUNC_TARGET_COLD_RESET:
2451 2450 tm_func = TM_TARGET_COLD_RESET;
2452 2451 break;
2453 2452
2454 2453 case ISCSI_TM_FUNC_TASK_REASSIGN:
2455 2454 /*
2456 2455 * We do not currently support allegiance reassignment. When
2457 2456 * we start supporting ERL1+, we will need to.
2458 2457 */
2459 2458 iscsit_send_task_mgmt_resp(tm_resp_pdu,
2460 2459 SCSI_TCP_TM_RESP_NO_ALLG_REASSN);
2461 2460 idm_pdu_complete(rx_pdu, IDM_STATUS_SUCCESS);
2462 2461 return;
2463 2462
2464 2463 default:
2465 2464 iscsit_send_task_mgmt_resp(tm_resp_pdu,
2466 2465 SCSI_TCP_TM_RESP_REJECTED);
2467 2466 idm_pdu_complete(rx_pdu, IDM_STATUS_SUCCESS);
2468 2467 return;
2469 2468 }
2470 2469
2471 2470 tm_itask = iscsit_tm_task_alloc(ict);
2472 2471 if (tm_itask == NULL) {
2473 2472 iscsit_send_task_mgmt_resp(tm_resp_pdu,
2474 2473 SCSI_TCP_TM_RESP_REJECTED);
2475 2474 idm_pdu_complete(rx_pdu, IDM_STATUS_SUCCESS);
2476 2475 return;
2477 2476 }
2478 2477
2479 2478
2480 2479 task = stmf_task_alloc(ict->ict_sess->ist_lport,
2481 2480 ict->ict_sess->ist_stmf_sess, iscsi_tm->lun,
2482 2481 0, STMF_TASK_EXT_NONE);
2483 2482 if (task == NULL) {
2484 2483 /*
2485 2484 * If this happens, either the LU is in reset, couldn't
2486 2485 * get memory, or some other condition in which we simply
2487 2486 * can't complete this request. It would be nice to return
2488 2487 * an error code like "busy" but the closest we have is
2489 2488 * "rejected".
2490 2489 */
2491 2490 iscsit_send_task_mgmt_resp(tm_resp_pdu,
2492 2491 SCSI_TCP_TM_RESP_REJECTED);
2493 2492 iscsit_tm_task_free(tm_itask);
2494 2493 idm_pdu_complete(rx_pdu, IDM_STATUS_SUCCESS);
2495 2494 return;
2496 2495 }
2497 2496
2498 2497 tm_itask->it_tm_pdu = tm_resp_pdu;
2499 2498 tm_itask->it_stmf_task = task;
2500 2499 task->task_port_private = tm_itask;
2501 2500 task->task_mgmt_function = tm_func;
2502 2501 task->task_additional_flags = TASK_AF_NO_EXPECTED_XFER_LENGTH;
2503 2502 task->task_priority = 0;
2504 2503 task->task_max_nbufs = STMF_BUFS_MAX;
2505 2504 task->task_cmd_seq_no = iscsi_tm->itt;
2506 2505 task->task_expected_xfer_length = 0;
2507 2506
2508 2507 stmf_post_task(task, NULL);
2509 2508 idm_pdu_complete(rx_pdu, IDM_STATUS_SUCCESS);
2510 2509 }
2511 2510
2512 2511 static void
2513 2512 iscsit_pdu_op_noop(iscsit_conn_t *ict, idm_pdu_t *rx_pdu)
2514 2513 {
2515 2514 iscsi_nop_out_hdr_t *out = (iscsi_nop_out_hdr_t *)rx_pdu->isp_hdr;
2516 2515 iscsi_nop_in_hdr_t *in;
2517 2516 int resp_datalen;
2518 2517 idm_pdu_t *resp;
2519 2518
2520 2519 /* Ignore the response from initiator */
2521 2520 if ((out->itt == ISCSI_RSVD_TASK_TAG) ||
2522 2521 (out->ttt != ISCSI_RSVD_TASK_TAG)) {
2523 2522 idm_pdu_complete(rx_pdu, IDM_STATUS_SUCCESS);
2524 2523 return;
2525 2524 }
2526 2525
2527 2526 /* Allocate a PDU to respond */
2528 2527 resp_datalen = ntoh24(out->dlength);
2529 2528 resp = idm_pdu_alloc(sizeof (iscsi_hdr_t), resp_datalen);
2530 2529 idm_pdu_init(resp, ict->ict_ic, NULL, NULL);
2531 2530 if (resp_datalen > 0) {
2532 2531 bcopy(rx_pdu->isp_data, resp->isp_data, resp_datalen);
2533 2532 }
2534 2533
2535 2534 /*
2536 2535 * When sending a NOP-In as a response to a NOP-Out from the initiator,
2537 2536 * the target must respond with the same initiator task tag that was
2538 2537 * provided in the NOP-Out request, the target transfer tag must be
2539 2538 * ISCSI_RSVD_TASK_TAG (0xffffffff) and StatSN will contain the next
2540 2539 * status sequence number. The StatSN for the connection is advanced
2541 2540 * after this PDU is sent.
2542 2541 */
2543 2542 in = (iscsi_nop_in_hdr_t *)resp->isp_hdr;
2544 2543 bzero(in, sizeof (*in));
2545 2544 in->opcode = ISCSI_OP_NOOP_IN;
2546 2545 in->flags = ISCSI_FLAG_FINAL;
2547 2546 bcopy(out->lun, in->lun, 8);
2548 2547 in->itt = out->itt;
2549 2548 in->ttt = ISCSI_RSVD_TASK_TAG;
2550 2549 hton24(in->dlength, resp_datalen);
2551 2550 resp->isp_flags |= IDM_PDU_SET_STATSN | IDM_PDU_ADVANCE_STATSN;
2552 2551 /* Any other field in resp to be set? */
2553 2552 iscsit_pdu_tx(resp);
2554 2553 idm_pdu_complete(rx_pdu, IDM_STATUS_SUCCESS);
2555 2554 }
2556 2555
2557 2556 static void
2558 2557 iscsit_pdu_op_login_cmd(iscsit_conn_t *ict, idm_pdu_t *rx_pdu)
2559 2558 {
2560 2559
2561 2560 /*
2562 2561 * Submit PDU to login state machine. State machine will free the
2563 2562 * PDU.
2564 2563 */
2565 2564 iscsit_login_sm_event(ict, ILE_LOGIN_RCV, rx_pdu);
2566 2565 }
2567 2566
2568 2567 void
2569 2568 iscsit_pdu_op_logout_cmd(iscsit_conn_t *ict, idm_pdu_t *rx_pdu)
2570 2569 {
2571 2570 iscsi_logout_hdr_t *logout_req =
2572 2571 (iscsi_logout_hdr_t *)rx_pdu->isp_hdr;
2573 2572 iscsi_logout_rsp_hdr_t *logout_rsp;
2574 2573 idm_pdu_t *resp;
2575 2574
2576 2575 /* Allocate a PDU to respond */
2577 2576 resp = idm_pdu_alloc(sizeof (iscsi_hdr_t), 0);
2578 2577 idm_pdu_init(resp, ict->ict_ic, NULL, NULL);
2579 2578 /*
2580 2579 * The StatSN is to be sent to the initiator,
2581 2580 * it is not required to increment the number
2582 2581 * as the connection is terminating.
2583 2582 */
2584 2583 resp->isp_flags |= IDM_PDU_SET_STATSN;
2585 2584 /*
2586 2585 * Logout results in the immediate termination of all tasks except
2587 2586 * if the logout reason is ISCSI_LOGOUT_REASON_RECOVERY. The
2588 2587 * connection state machine will drive this task cleanup automatically
2589 2588 * so we don't need to handle that here.
2590 2589 */
2591 2590 logout_rsp = (iscsi_logout_rsp_hdr_t *)resp->isp_hdr;
2592 2591 bzero(logout_rsp, sizeof (*logout_rsp));
2593 2592 logout_rsp->opcode = ISCSI_OP_LOGOUT_RSP;
2594 2593 logout_rsp->flags = ISCSI_FLAG_FINAL;
2595 2594 logout_rsp->itt = logout_req->itt;
2596 2595 if ((logout_req->flags & ISCSI_FLAG_LOGOUT_REASON_MASK) >
2597 2596 ISCSI_LOGOUT_REASON_RECOVERY) {
2598 2597 logout_rsp->response = ISCSI_LOGOUT_RECOVERY_UNSUPPORTED;
2599 2598 } else {
2600 2599 logout_rsp->response = ISCSI_LOGOUT_SUCCESS;
2601 2600 }
2602 2601
2603 2602 iscsit_pdu_tx(resp);
2604 2603 idm_pdu_complete(rx_pdu, IDM_STATUS_SUCCESS);
2605 2604 }
2606 2605
2607 2606 /*
2608 2607 * Calculate the number of outstanding commands we can process
2609 2608 */
2610 2609 int
2611 2610 iscsit_cmd_window()
2612 2611 {
2613 2612 /*
2614 2613 * Instead of using a pre-defined constant for the command window,
2615 2614 * it should be made confiurable and dynamic. With MC/S, sequence
2616 2615 * numbers will be used up at a much faster rate than with SC/S.
2617 2616 */
2618 2617 return (ISCSIT_MAX_WINDOW);
2619 2618 }
2620 2619
2621 2620 /*
2622 2621 * Set local registers based on incoming PDU
2623 2622 */
2624 2623 void
2625 2624 iscsit_set_cmdsn(iscsit_conn_t *ict, idm_pdu_t *rx_pdu)
2626 2625 {
2627 2626 iscsit_sess_t *ist;
2628 2627 iscsi_scsi_cmd_hdr_t *req;
2629 2628
2630 2629 ist = ict->ict_sess;
2631 2630
2632 2631 req = (iscsi_scsi_cmd_hdr_t *)rx_pdu->isp_hdr;
2633 2632 if (req->opcode & ISCSI_OP_IMMEDIATE) {
2634 2633 /* no cmdsn increment for immediate PDUs */
2635 2634 return;
2636 2635 }
2637 2636
2638 2637 /* Ensure that the ExpCmdSN advances in an orderly manner */
2639 2638 mutex_enter(&ist->ist_sn_mutex);
2640 2639 ist->ist_expcmdsn = ntohl(req->cmdsn) + 1;
2641 2640 ist->ist_maxcmdsn = ntohl(req->cmdsn) + iscsit_cmd_window();
2642 2641 mutex_exit(&ist->ist_sn_mutex);
2643 2642 }
2644 2643
2645 2644 /*
2646 2645 * Wrapper funtion, calls iscsi_calc_rspsn and idm_pdu_tx
2647 2646 */
2648 2647 void
2649 2648 iscsit_pdu_tx(idm_pdu_t *pdu)
2650 2649 {
2651 2650 iscsit_conn_t *ict = pdu->isp_ic->ic_handle;
2652 2651 iscsi_scsi_rsp_hdr_t *rsp = (iscsi_scsi_rsp_hdr_t *)pdu->isp_hdr;
2653 2652 iscsit_sess_t *ist = ict->ict_sess;
2654 2653
2655 2654 /*
2656 2655 * The command sequence numbers are session-wide and must stay
2657 2656 * consistent across the transfer, so protect the cmdsn with a
2658 2657 * mutex lock on the session. The status sequence number will
2659 2658 * be updated just before the transport layer transmits the PDU.
2660 2659 */
2661 2660
2662 2661 mutex_enter(&ict->ict_sess->ist_sn_mutex);
2663 2662 /* Set ExpCmdSN and MaxCmdSN */
2664 2663 rsp->maxcmdsn = htonl(ist->ist_maxcmdsn);
2665 2664 rsp->expcmdsn = htonl(ist->ist_expcmdsn);
2666 2665 idm_pdu_tx(pdu);
2667 2666 mutex_exit(&ict->ict_sess->ist_sn_mutex);
2668 2667 }
2669 2668
2670 2669 /*
2671 2670 * Internal functions
2672 2671 */
2673 2672
2674 2673 void
2675 2674 iscsit_send_async_event(iscsit_conn_t *ict, uint8_t event)
2676 2675 {
2677 2676 idm_pdu_t *abt;
2678 2677 iscsi_async_evt_hdr_t *async_abt;
2679 2678
2680 2679 /*
2681 2680 * Get a PDU to build the abort request.
2682 2681 */
2683 2682 abt = idm_pdu_alloc(sizeof (iscsi_hdr_t), 0);
2684 2683 if (abt == NULL) {
2685 2684 idm_conn_event(ict->ict_ic, CE_TRANSPORT_FAIL, NULL);
2686 2685 return;
2687 2686 }
2688 2687
2689 2688 /*
2690 2689 * A asynchronous message is sent by the target to request a logout.
2691 2690 * The StatSN for the connection is advanced after the PDU is sent
2692 2691 * to allow for initiator and target state synchronization.
2693 2692 */
2694 2693 idm_pdu_init(abt, ict->ict_ic, NULL, NULL);
2695 2694 abt->isp_datalen = 0;
2696 2695 abt->isp_flags |= IDM_PDU_SET_STATSN | IDM_PDU_ADVANCE_STATSN;
2697 2696
2698 2697 async_abt = (iscsi_async_evt_hdr_t *)abt->isp_hdr;
2699 2698 bzero(async_abt, sizeof (*async_abt));
2700 2699 async_abt->opcode = ISCSI_OP_ASYNC_EVENT;
2701 2700 async_abt->async_event = event;
2702 2701 async_abt->flags = ISCSI_FLAG_FINAL;
2703 2702 async_abt->rsvd4[0] = 0xff;
2704 2703 async_abt->rsvd4[1] = 0xff;
2705 2704 async_abt->rsvd4[2] = 0xff;
2706 2705 async_abt->rsvd4[3] = 0xff;
2707 2706
2708 2707 switch (event) {
2709 2708 case ISCSI_ASYNC_EVENT_REQUEST_LOGOUT:
2710 2709 async_abt->param3 = htons(IDM_LOGOUT_SECONDS);
2711 2710 break;
2712 2711 case ISCSI_ASYNC_EVENT_SCSI_EVENT:
2713 2712 case ISCSI_ASYNC_EVENT_DROPPING_CONNECTION:
2714 2713 case ISCSI_ASYNC_EVENT_DROPPING_ALL_CONNECTIONS:
2715 2714 case ISCSI_ASYNC_EVENT_PARAM_NEGOTIATION:
2716 2715 default:
2717 2716 ASSERT(0);
2718 2717 }
2719 2718
2720 2719 iscsit_pdu_tx(abt);
2721 2720 }
2722 2721
2723 2722 void
2724 2723 iscsit_send_reject(iscsit_conn_t *ict, idm_pdu_t *rejected_pdu, uint8_t reason)
2725 2724 {
2726 2725 idm_pdu_t *reject_pdu;
2727 2726 iscsi_reject_rsp_hdr_t *reject;
2728 2727
2729 2728 /*
2730 2729 * Get a PDU to build the abort request.
2731 2730 */
2732 2731 reject_pdu = idm_pdu_alloc(sizeof (iscsi_hdr_t),
2733 2732 rejected_pdu->isp_hdrlen);
2734 2733 if (reject_pdu == NULL) {
2735 2734 idm_conn_event(ict->ict_ic, CE_TRANSPORT_FAIL, NULL);
2736 2735 return;
2737 2736 }
2738 2737 idm_pdu_init(reject_pdu, ict->ict_ic, NULL, NULL);
2739 2738 /* StatSN is advanced after a Reject PDU */
2740 2739 reject_pdu->isp_flags |= IDM_PDU_SET_STATSN | IDM_PDU_ADVANCE_STATSN;
2741 2740 reject_pdu->isp_datalen = rejected_pdu->isp_hdrlen;
2742 2741 bcopy(rejected_pdu->isp_hdr, reject_pdu->isp_data,
2743 2742 rejected_pdu->isp_hdrlen);
2744 2743
2745 2744 reject = (iscsi_reject_rsp_hdr_t *)reject_pdu->isp_hdr;
2746 2745 bzero(reject, sizeof (*reject));
2747 2746 reject->opcode = ISCSI_OP_REJECT_MSG;
2748 2747 reject->reason = reason;
2749 2748 reject->flags = ISCSI_FLAG_FINAL;
2750 2749 hton24(reject->dlength, rejected_pdu->isp_hdrlen);
2751 2750 reject->must_be_ff[0] = 0xff;
2752 2751 reject->must_be_ff[1] = 0xff;
2753 2752 reject->must_be_ff[2] = 0xff;
2754 2753 reject->must_be_ff[3] = 0xff;
2755 2754
2756 2755 iscsit_pdu_tx(reject_pdu);
2757 2756 }
2758 2757
2759 2758
2760 2759 static iscsit_task_t *
2761 2760 iscsit_task_alloc(iscsit_conn_t *ict)
2762 2761 {
2763 2762 iscsit_task_t *itask;
2764 2763 iscsit_buf_t *immed_ibuf;
2765 2764
2766 2765 /*
2767 2766 * Possible items to pre-alloc if we cache iscsit_task_t's:
2768 2767 *
2769 2768 * Status PDU w/ sense buffer
2770 2769 * stmf_data_buf_t for immediate data
2771 2770 */
2772 2771 itask = kmem_alloc(sizeof (iscsit_task_t) + sizeof (iscsit_buf_t) +
2773 2772 sizeof (stmf_data_buf_t), KM_NOSLEEP);
2774 2773 if (itask != NULL) {
2775 2774 mutex_init(&itask->it_mutex, NULL, MUTEX_DRIVER, NULL);
2776 2775 itask->it_aborted = itask->it_stmf_abort =
2777 2776 itask->it_tm_task = 0;
2778 2777
2779 2778 immed_ibuf = (iscsit_buf_t *)(itask + 1);
2780 2779 bzero(immed_ibuf, sizeof (*immed_ibuf));
2781 2780 immed_ibuf->ibuf_is_immed = B_TRUE;
2782 2781 immed_ibuf->ibuf_stmf_buf = (stmf_data_buf_t *)(immed_ibuf + 1);
2783 2782
2784 2783 bzero(immed_ibuf->ibuf_stmf_buf, sizeof (stmf_data_buf_t));
2785 2784 immed_ibuf->ibuf_stmf_buf->db_port_private = immed_ibuf;
2786 2785 immed_ibuf->ibuf_stmf_buf->db_sglist_length = 1;
2787 2786 immed_ibuf->ibuf_stmf_buf->db_flags = DB_DIRECTION_FROM_RPORT |
2788 2787 DB_DONT_CACHE;
2789 2788 itask->it_immed_data = immed_ibuf;
2790 2789 itask->it_idm_task = idm_task_alloc(ict->ict_ic);
2791 2790 if (itask->it_idm_task != NULL) {
2792 2791 itask->it_idm_task->idt_private = itask;
2793 2792 itask->it_ict = ict;
2794 2793 itask->it_ttt = itask->it_idm_task->idt_tt;
2795 2794 return (itask);
2796 2795 } else {
2797 2796 kmem_free(itask, sizeof (iscsit_task_t) +
2798 2797 sizeof (iscsit_buf_t) + sizeof (stmf_data_buf_t));
2799 2798 }
2800 2799 }
2801 2800
2802 2801 return (NULL);
2803 2802 }
2804 2803
2805 2804 static void
2806 2805 iscsit_task_free(iscsit_task_t *itask)
2807 2806 {
2808 2807 idm_task_free(itask->it_idm_task);
2809 2808 mutex_destroy(&itask->it_mutex);
2810 2809 kmem_free(itask, sizeof (iscsit_task_t) +
2811 2810 sizeof (iscsit_buf_t) + sizeof (stmf_data_buf_t));
2812 2811 }
2813 2812
2814 2813 static iscsit_task_t *
2815 2814 iscsit_tm_task_alloc(iscsit_conn_t *ict)
2816 2815 {
2817 2816 iscsit_task_t *itask;
2818 2817
2819 2818 itask = kmem_zalloc(sizeof (iscsit_task_t), KM_NOSLEEP);
2820 2819 if (itask != NULL) {
2821 2820 idm_conn_hold(ict->ict_ic);
2822 2821 mutex_init(&itask->it_mutex, NULL, MUTEX_DRIVER, NULL);
2823 2822 itask->it_aborted = itask->it_stmf_abort =
2824 2823 itask->it_tm_responded = 0;
2825 2824 itask->it_tm_pdu = NULL;
2826 2825 itask->it_tm_task = 1;
2827 2826 itask->it_ict = ict;
2828 2827 }
2829 2828
2830 2829 return (itask);
2831 2830 }
2832 2831
2833 2832 static void
2834 2833 iscsit_tm_task_free(iscsit_task_t *itask)
2835 2834 {
2836 2835 /*
2837 2836 * If we responded then the call to idm_pdu_complete will free the
2838 2837 * PDU. Otherwise we got aborted before the TM function could
2839 2838 * complete and we need to free the PDU explicitly.
2840 2839 */
2841 2840 if (itask->it_tm_pdu != NULL && !itask->it_tm_responded)
2842 2841 idm_pdu_free(itask->it_tm_pdu);
2843 2842 idm_conn_rele(itask->it_ict->ict_ic);
2844 2843 mutex_destroy(&itask->it_mutex);
2845 2844 kmem_free(itask, sizeof (iscsit_task_t));
2846 2845 }
2847 2846
2848 2847 static idm_status_t
2849 2848 iscsit_task_start(iscsit_task_t *itask)
2850 2849 {
2851 2850 iscsit_sess_t *ist = itask->it_ict->ict_sess;
2852 2851 avl_index_t where;
2853 2852
2854 2853 /*
2855 2854 * Sanity check the ITT and ensure that this task does not already
2856 2855 * exist. If not then add the task to the session task list.
2857 2856 */
2858 2857 mutex_enter(&ist->ist_mutex);
2859 2858 mutex_enter(&itask->it_mutex);
2860 2859 itask->it_active = 1;
2861 2860 if (avl_find(&ist->ist_task_list, itask, &where) == NULL) {
2862 2861 /* New task, add to AVL */
2863 2862 avl_insert(&ist->ist_task_list, itask, where);
2864 2863 mutex_exit(&itask->it_mutex);
2865 2864 mutex_exit(&ist->ist_mutex);
2866 2865 return (IDM_STATUS_SUCCESS);
2867 2866 }
2868 2867 mutex_exit(&itask->it_mutex);
2869 2868 mutex_exit(&ist->ist_mutex);
2870 2869
2871 2870 return (IDM_STATUS_REJECT);
2872 2871 }
2873 2872
2874 2873 static void
2875 2874 iscsit_task_done(iscsit_task_t *itask)
2876 2875 {
2877 2876 iscsit_sess_t *ist = itask->it_ict->ict_sess;
2878 2877
2879 2878 mutex_enter(&ist->ist_mutex);
2880 2879 mutex_enter(&itask->it_mutex);
2881 2880 if (itask->it_active) {
2882 2881 avl_remove(&ist->ist_task_list, itask);
2883 2882 itask->it_active = 0;
2884 2883 }
2885 2884 mutex_exit(&itask->it_mutex);
2886 2885 mutex_exit(&ist->ist_mutex);
2887 2886 }
2888 2887
2889 2888 /*
2890 2889 * iscsit status PDU cache
2891 2890 */
2892 2891
2893 2892 /*ARGSUSED*/
2894 2893 static int
2895 2894 iscsit_status_pdu_constructor(void *pdu_void, void *arg, int flags)
2896 2895 {
2897 2896 idm_pdu_t *pdu = pdu_void;
2898 2897 iscsi_scsi_rsp_hdr_t *rsp;
2899 2898
2900 2899 bzero(pdu, sizeof (idm_pdu_t));
2901 2900 pdu->isp_callback = iscsit_send_good_status_done;
2902 2901 pdu->isp_magic = IDM_PDU_MAGIC;
2903 2902 pdu->isp_hdr = (iscsi_hdr_t *)(pdu + 1); /* Ptr arithmetic */
2904 2903 pdu->isp_hdrlen = sizeof (iscsi_hdr_t);
2905 2904
2906 2905 /* Setup status response */
2907 2906 rsp = (iscsi_scsi_rsp_hdr_t *)pdu->isp_hdr;
2908 2907 bzero(rsp, sizeof (*rsp));
2909 2908 rsp->opcode = ISCSI_OP_SCSI_RSP;
2910 2909 rsp->flags = ISCSI_FLAG_FINAL;
2911 2910 rsp->response = ISCSI_STATUS_CMD_COMPLETED;
2912 2911
2913 2912 return (0);
2914 2913 }
2915 2914
2916 2915 /*
2917 2916 * iscsit private data handler
2918 2917 */
2919 2918
2920 2919 /*ARGSUSED*/
2921 2920 static void
2922 2921 iscsit_pp_cb(struct stmf_port_provider *pp, int cmd, void *arg, uint32_t flags)
2923 2922 {
2924 2923 it_config_t *cfg;
2925 2924 nvlist_t *nvl;
2926 2925 iscsit_service_enabled_t old_state;
2927 2926
2928 2927 if ((cmd != STMF_PROVIDER_DATA_UPDATED) || (arg == NULL)) {
2929 2928 return;
2930 2929 }
2931 2930
2932 2931 nvl = (nvlist_t *)arg;
2933 2932
2934 2933 /* Translate nvlist */
2935 2934 if (it_nv_to_config(nvl, &cfg) != 0) {
2936 2935 cmn_err(CE_WARN, "Configuration is invalid");
2937 2936 return;
2938 2937 }
2939 2938
2940 2939 /* Check that no iSCSI ioctl is currently running */
2941 2940 mutex_enter(&iscsit_global.global_state_mutex);
2942 2941 old_state = iscsit_global.global_svc_state;
2943 2942 switch (iscsit_global.global_svc_state) {
2944 2943 case ISE_ENABLED:
2945 2944 case ISE_DISABLED:
2946 2945 iscsit_global.global_svc_state = ISE_BUSY;
2947 2946 break;
2948 2947 case ISE_ENABLING:
2949 2948 /*
2950 2949 * It is OK for the iscsit_pp_cb to be called from inside of
2951 2950 * an iSCSI ioctl only if we are currently executing inside
2952 2951 * of stmf_register_port_provider.
2953 2952 */
2954 2953 ASSERT((flags & STMF_PCB_PREG_COMPLETE) != 0);
2955 2954 break;
2956 2955 default:
2957 2956 cmn_err(CE_WARN, "iscsit_pp_cb called when global_svc_state"
2958 2957 " is not ENABLED(0x%x) -- ignoring",
2959 2958 iscsit_global.global_svc_state);
2960 2959 mutex_exit(&iscsit_global.global_state_mutex);
2961 2960 it_config_free_cmn(cfg);
2962 2961 return;
2963 2962 }
2964 2963 mutex_exit(&iscsit_global.global_state_mutex);
2965 2964
2966 2965 /* Update config */
2967 2966 (void) iscsit_config_merge(cfg);
2968 2967
2969 2968 it_config_free_cmn(cfg);
2970 2969
2971 2970 /* Restore old iSCSI driver global state */
2972 2971 mutex_enter(&iscsit_global.global_state_mutex);
2973 2972 ASSERT(iscsit_global.global_svc_state == ISE_BUSY ||
2974 2973 iscsit_global.global_svc_state == ISE_ENABLING);
2975 2974 iscsit_global.global_svc_state = old_state;
2976 2975 mutex_exit(&iscsit_global.global_state_mutex);
2977 2976 }
2978 2977
2979 2978
2980 2979 static it_cfg_status_t
2981 2980 iscsit_config_merge(it_config_t *in_cfg)
2982 2981 {
2983 2982 it_cfg_status_t status;
2984 2983 it_config_t *cfg;
2985 2984 it_config_t tmp_cfg;
2986 2985 list_t tpg_del_list;
2987 2986
2988 2987 if (in_cfg) {
2989 2988 cfg = in_cfg;
2990 2989 } else {
2991 2990 /* Make empty config */
2992 2991 bzero(&tmp_cfg, sizeof (tmp_cfg));
2993 2992 cfg = &tmp_cfg;
2994 2993 }
2995 2994
2996 2995 list_create(&tpg_del_list, sizeof (iscsit_tpg_t),
2997 2996 offsetof(iscsit_tpg_t, tpg_delete_ln));
2998 2997
2999 2998 /*
3000 2999 * Update targets, initiator contexts, target portal groups,
3001 3000 * and iSNS client
3002 3001 */
3003 3002 ISCSIT_GLOBAL_LOCK(RW_WRITER);
3004 3003 if (((status = iscsit_config_merge_tpg(cfg, &tpg_del_list))
3005 3004 != 0) ||
3006 3005 ((status = iscsit_config_merge_tgt(cfg)) != 0) ||
3007 3006 ((status = iscsit_config_merge_ini(cfg)) != 0) ||
3008 3007 ((status = isnst_config_merge(cfg)) != 0)) {
3009 3008 ISCSIT_GLOBAL_UNLOCK();
3010 3009 return (status);
3011 3010 }
3012 3011
3013 3012 /* Update other global config parameters */
3014 3013 if (iscsit_global.global_props) {
3015 3014 nvlist_free(iscsit_global.global_props);
3016 3015 iscsit_global.global_props = NULL;
3017 3016 }
3018 3017 if (in_cfg) {
3019 3018 (void) nvlist_dup(cfg->config_global_properties,
3020 3019 &iscsit_global.global_props, KM_SLEEP);
3021 3020 }
3022 3021 ISCSIT_GLOBAL_UNLOCK();
3023 3022
3024 3023 iscsit_config_destroy_tpgs(&tpg_del_list);
3025 3024
3026 3025 list_destroy(&tpg_del_list);
3027 3026
3028 3027 return (ITCFG_SUCCESS);
3029 3028 }
3030 3029
3031 3030 /*
3032 3031 * iscsit_sna_lt[e]
3033 3032 *
3034 3033 * Compare serial numbers using serial number arithmetic as defined in
3035 3034 * RFC 1982.
3036 3035 *
3037 3036 * NOTE: This code is duplicated in the isns server. It ought to be common.
3038 3037 */
3039 3038
3040 3039 static int
3041 3040 iscsit_sna_lt(uint32_t sn1, uint32_t sn2)
3042 3041 {
3043 3042 return ((sn1 != sn2) &&
3044 3043 (((sn1 < sn2) && ((sn2 - sn1) < ISCSIT_SNA32_CHECK)) ||
3045 3044 ((sn1 > sn2) && ((sn1 - sn2) > ISCSIT_SNA32_CHECK))));
3046 3045 }
3047 3046
3048 3047 static int
3049 3048 iscsit_sna_lte(uint32_t sn1, uint32_t sn2)
3050 3049 {
3051 3050 return ((sn1 == sn2) ||
3052 3051 (((sn1 < sn2) && ((sn2 - sn1) < ISCSIT_SNA32_CHECK)) ||
3053 3052 ((sn1 > sn2) && ((sn1 - sn2) > ISCSIT_SNA32_CHECK))));
3054 3053 }
3055 3054
3056 3055
3057 3056 static boolean_t
3058 3057 iscsit_cmdsn_in_window(iscsit_conn_t *ict, uint32_t cmdsn)
3059 3058 {
3060 3059 iscsit_sess_t *ist = ict->ict_sess;
3061 3060 int rval = B_TRUE;
3062 3061
3063 3062 ist = ict->ict_sess;
3064 3063
3065 3064 mutex_enter(&ist->ist_sn_mutex);
3066 3065
3067 3066 /*
3068 3067 * If cmdsn is less than ist_expcmdsn - iscsit_cmd_window() or
3069 3068 * greater than ist_expcmdsn, it's not in the window.
3070 3069 */
3071 3070
3072 3071 if (iscsit_sna_lt(cmdsn, (ist->ist_expcmdsn - iscsit_cmd_window())) ||
3073 3072 !iscsit_sna_lte(cmdsn, ist->ist_expcmdsn)) {
3074 3073 rval = B_FALSE;
3075 3074 }
3076 3075
3077 3076 mutex_exit(&ist->ist_sn_mutex);
3078 3077
3079 3078 return (rval);
3080 3079 }
3081 3080
3082 3081 /*
3083 3082 * iscsit_check_cmdsn_and_queue
3084 3083 *
3085 3084 * Independent of the order in which the iSCSI target receives non-immediate
3086 3085 * command PDU across the entire session and any multiple connections within
3087 3086 * the session, the target must deliver the commands to the SCSI layer in
3088 3087 * CmdSN order. So out-of-order non-immediate commands are queued up on a
3089 3088 * session-wide wait queue. Duplicate commands are ignored.
3090 3089 *
3091 3090 */
3092 3091 static int
3093 3092 iscsit_check_cmdsn_and_queue(idm_pdu_t *rx_pdu)
3094 3093 {
3095 3094 idm_conn_t *ic = rx_pdu->isp_ic;
3096 3095 iscsit_conn_t *ict = ic->ic_handle;
3097 3096 iscsit_sess_t *ist = ict->ict_sess;
3098 3097 iscsi_scsi_cmd_hdr_t *hdr = (iscsi_scsi_cmd_hdr_t *)rx_pdu->isp_hdr;
3099 3098
3100 3099 mutex_enter(&ist->ist_sn_mutex);
3101 3100 if (hdr->opcode & ISCSI_OP_IMMEDIATE) {
3102 3101 /* do not queue, handle it immediately */
3103 3102 DTRACE_PROBE2(immediate__cmd, iscsit_sess_t *, ist,
3104 3103 idm_pdu_t *, rx_pdu);
3105 3104 mutex_exit(&ist->ist_sn_mutex);
3106 3105 return (ISCSIT_CMDSN_EQ_EXPCMDSN);
3107 3106 }
3108 3107 if (iscsit_sna_lt(ist->ist_expcmdsn, ntohl(hdr->cmdsn))) {
3109 3108 /*
3110 3109 * Out-of-order commands (cmdSN higher than ExpCmdSN)
3111 3110 * are staged on a fixed-size circular buffer until
3112 3111 * the missing command is delivered to the SCSI layer.
3113 3112 * Irrespective of the order of insertion into the
3114 3113 * staging queue, the commands are processed out of the
3115 3114 * queue in cmdSN order only.
3116 3115 */
3117 3116 rx_pdu->isp_queue_time = ddi_get_time();
3118 3117 iscsit_add_pdu_to_queue(ist, rx_pdu);
3119 3118 mutex_exit(&ist->ist_sn_mutex);
3120 3119 return (ISCSIT_CMDSN_GT_EXPCMDSN);
3121 3120 } else if (iscsit_sna_lt(ntohl(hdr->cmdsn), ist->ist_expcmdsn)) {
3122 3121 DTRACE_PROBE3(cmdsn__lt__expcmdsn, iscsit_sess_t *, ist,
3123 3122 iscsit_conn_t *, ict, idm_pdu_t *, rx_pdu);
3124 3123 mutex_exit(&ist->ist_sn_mutex);
3125 3124 return (ISCSIT_CMDSN_LT_EXPCMDSN);
3126 3125 } else {
3127 3126 mutex_exit(&ist->ist_sn_mutex);
3128 3127 return (ISCSIT_CMDSN_EQ_EXPCMDSN);
3129 3128 }
3130 3129 }
3131 3130
3132 3131 /*
3133 3132 * iscsit_add_pdu_to_queue() adds PDUs into the array indexed by
3134 3133 * their cmdsn value. The length of the array is kept above the
3135 3134 * maximum window size. The window keeps the cmdsn within a range
3136 3135 * such that there are no collisons. e.g. the assumption is that
3137 3136 * the windowing checks make it impossible to receive PDUs that
3138 3137 * index into the same location in the array.
3139 3138 */
3140 3139 static void
3141 3140 iscsit_add_pdu_to_queue(iscsit_sess_t *ist, idm_pdu_t *rx_pdu)
3142 3141 {
3143 3142 iscsit_cbuf_t *cbuf = ist->ist_rxpdu_queue;
3144 3143 iscsit_conn_t *ict = rx_pdu->isp_ic->ic_handle;
3145 3144 uint32_t cmdsn =
3146 3145 ((iscsi_scsi_cmd_hdr_t *)rx_pdu->isp_hdr)->cmdsn;
3147 3146 uint32_t index;
3148 3147
3149 3148 ASSERT(MUTEX_HELD(&ist->ist_sn_mutex));
3150 3149 /*
3151 3150 * If the connection is being torn down, then
3152 3151 * don't add the PDU to the staging queue
3153 3152 */
|
↓ open down ↓ |
3117 lines elided |
↑ open up ↑ |
3154 3153 mutex_enter(&ict->ict_mutex);
3155 3154 if (ict->ict_lost) {
3156 3155 mutex_exit(&ict->ict_mutex);
3157 3156 idm_pdu_complete(rx_pdu, IDM_STATUS_FAIL);
3158 3157 return;
3159 3158 }
3160 3159 iscsit_conn_dispatch_hold(ict);
3161 3160 mutex_exit(&ict->ict_mutex);
3162 3161
3163 3162 index = ntohl(cmdsn) % ISCSIT_RXPDU_QUEUE_LEN;
3164 - ASSERT(cbuf->cb_buffer[index] == NULL);
3165 - cbuf->cb_buffer[index] = rx_pdu;
3166 - cbuf->cb_num_elems++;
3163 + /*
3164 + * In the normal case, assuming that the Initiator is not
3165 + * buggy and that we don't have packet duplication occuring,
3166 + * the entry in the array will be NULL. However, we may have
3167 + * received a duplicate PDU with cmdsn > expsn , and in that
3168 + * case we just ignore this PDU -- the previously received one
3169 + * remains queued for processing. We need to be careful not
3170 + * to leak this one however.
3171 + */
3172 + if (cbuf->cb_buffer[index] != NULL) {
3173 + idm_pdu_complete(rx_pdu, IDM_STATUS_FAIL);
3174 + } else {
3175 + cbuf->cb_buffer[index] = rx_pdu;
3176 + cbuf->cb_num_elems++;
3177 + }
3167 3178 }
3168 3179
3169 3180 static idm_pdu_t *
3170 3181 iscsit_remove_pdu_from_queue(iscsit_sess_t *ist, uint32_t cmdsn)
3171 3182 {
3172 3183 iscsit_cbuf_t *cbuf = ist->ist_rxpdu_queue;
3173 3184 idm_pdu_t *pdu = NULL;
3174 3185 uint32_t index;
3175 3186
3176 3187 ASSERT(MUTEX_HELD(&ist->ist_sn_mutex));
3177 3188 index = cmdsn % ISCSIT_RXPDU_QUEUE_LEN;
3178 3189 if ((pdu = cbuf->cb_buffer[index]) != NULL) {
3179 3190 ASSERT(cmdsn ==
3180 3191 ntohl(((iscsi_scsi_cmd_hdr_t *)pdu->isp_hdr)->cmdsn));
3181 3192 cbuf->cb_buffer[index] = NULL;
3182 3193 cbuf->cb_num_elems--;
3183 3194 return (pdu);
3184 3195 }
3185 3196 return (NULL);
3186 3197 }
3187 3198
3188 3199 /*
3189 3200 * iscsit_process_pdu_in_queue() finds the next pdu in sequence
3190 3201 * and posts it to the SCSI layer
3191 3202 */
3192 3203 static void
3193 3204 iscsit_process_pdu_in_queue(iscsit_sess_t *ist)
3194 3205 {
3195 3206 iscsit_cbuf_t *cbuf = ist->ist_rxpdu_queue;
3196 3207 idm_pdu_t *pdu = NULL;
3197 3208 uint32_t expcmdsn;
3198 3209
3199 3210 for (;;) {
3200 3211 mutex_enter(&ist->ist_sn_mutex);
3201 3212 if (cbuf->cb_num_elems == 0) {
3202 3213 mutex_exit(&ist->ist_sn_mutex);
3203 3214 break;
3204 3215 }
3205 3216 expcmdsn = ist->ist_expcmdsn;
3206 3217 if ((pdu = iscsit_remove_pdu_from_queue(ist, expcmdsn))
3207 3218 == NULL) {
3208 3219 mutex_exit(&ist->ist_sn_mutex);
3209 3220 break;
3210 3221 }
3211 3222 mutex_exit(&ist->ist_sn_mutex);
3212 3223 iscsit_post_staged_pdu(pdu);
3213 3224 }
3214 3225 }
3215 3226
3216 3227 static void
3217 3228 iscsit_post_staged_pdu(idm_pdu_t *rx_pdu)
3218 3229 {
3219 3230 iscsit_conn_t *ict = rx_pdu->isp_ic->ic_handle;
3220 3231
3221 3232 /* Post the PDU to the SCSI layer */
3222 3233 switch (IDM_PDU_OPCODE(rx_pdu)) {
3223 3234 case ISCSI_OP_NOOP_OUT:
3224 3235 iscsit_set_cmdsn(ict, rx_pdu);
3225 3236 iscsit_pdu_op_noop(ict, rx_pdu);
3226 3237 break;
3227 3238 case ISCSI_OP_TEXT_CMD:
3228 3239 iscsit_set_cmdsn(ict, rx_pdu);
3229 3240 iscsit_pdu_op_text_cmd(ict, rx_pdu);
3230 3241 break;
3231 3242 case ISCSI_OP_SCSI_TASK_MGT_MSG:
3232 3243 iscsit_set_cmdsn(ict, rx_pdu);
3233 3244 iscsit_op_scsi_task_mgmt(ict, rx_pdu);
3234 3245 break;
3235 3246 case ISCSI_OP_SCSI_CMD:
3236 3247 /* cmdSN will be incremented after creating itask */
3237 3248 iscsit_post_scsi_cmd(rx_pdu->isp_ic, rx_pdu);
3238 3249 break;
3239 3250 case ISCSI_OP_LOGOUT_CMD:
3240 3251 iscsit_set_cmdsn(ict, rx_pdu);
3241 3252 iscsit_pdu_op_logout_cmd(ict, rx_pdu);
3242 3253 break;
3243 3254 default:
3244 3255 /* No other PDUs should be placed on the queue */
3245 3256 ASSERT(0);
3246 3257 }
3247 3258 iscsit_conn_dispatch_rele(ict); /* release hold on the conn */
3248 3259 }
3249 3260
3250 3261 /* ARGSUSED */
3251 3262 void
3252 3263 iscsit_rxpdu_queue_monitor_start(void)
3253 3264 {
3254 3265 mutex_enter(&iscsit_rxpdu_queue_monitor_mutex);
3255 3266 if (iscsit_rxpdu_queue_monitor_thr_running) {
3256 3267 mutex_exit(&iscsit_rxpdu_queue_monitor_mutex);
3257 3268 return;
3258 3269 }
3259 3270 iscsit_rxpdu_queue_monitor_thr_id =
3260 3271 thread_create(NULL, 0, iscsit_rxpdu_queue_monitor, NULL,
3261 3272 0, &p0, TS_RUN, minclsyspri);
3262 3273 while (!iscsit_rxpdu_queue_monitor_thr_running) {
3263 3274 cv_wait(&iscsit_rxpdu_queue_monitor_cv,
3264 3275 &iscsit_rxpdu_queue_monitor_mutex);
3265 3276 }
3266 3277 mutex_exit(&iscsit_rxpdu_queue_monitor_mutex);
3267 3278
3268 3279 }
3269 3280
3270 3281 /* ARGSUSED */
3271 3282 void
3272 3283 iscsit_rxpdu_queue_monitor_stop(void)
3273 3284 {
3274 3285 mutex_enter(&iscsit_rxpdu_queue_monitor_mutex);
3275 3286 if (iscsit_rxpdu_queue_monitor_thr_running) {
3276 3287 iscsit_rxpdu_queue_monitor_thr_running = B_FALSE;
3277 3288 cv_signal(&iscsit_rxpdu_queue_monitor_cv);
3278 3289 mutex_exit(&iscsit_rxpdu_queue_monitor_mutex);
3279 3290
3280 3291 thread_join(iscsit_rxpdu_queue_monitor_thr_did);
3281 3292 return;
3282 3293 }
3283 3294 mutex_exit(&iscsit_rxpdu_queue_monitor_mutex);
3284 3295 }
3285 3296
3286 3297 /*
3287 3298 * A separate thread is used to scan the staging queue on all the
3288 3299 * sessions, If a delayed PDU does not arrive within a timeout, the
3289 3300 * target will advance to the staged PDU that is next in sequence
3290 3301 * and exceeded the threshold wait time. It is up to the initiator
3291 3302 * to note that the target has not acknowledged a particular cmdsn
3292 3303 * and take appropriate action.
3293 3304 */
3294 3305 /* ARGSUSED */
3295 3306 static void
3296 3307 iscsit_rxpdu_queue_monitor(void *arg)
3297 3308 {
3298 3309 iscsit_tgt_t *tgt;
3299 3310 iscsit_sess_t *ist;
3300 3311
3301 3312 mutex_enter(&iscsit_rxpdu_queue_monitor_mutex);
3302 3313 iscsit_rxpdu_queue_monitor_thr_did = curthread->t_did;
3303 3314 iscsit_rxpdu_queue_monitor_thr_running = B_TRUE;
3304 3315 cv_signal(&iscsit_rxpdu_queue_monitor_cv);
3305 3316
3306 3317 while (iscsit_rxpdu_queue_monitor_thr_running) {
3307 3318 ISCSIT_GLOBAL_LOCK(RW_READER);
3308 3319 for (tgt = avl_first(&iscsit_global.global_target_list);
3309 3320 tgt != NULL;
3310 3321 tgt = AVL_NEXT(&iscsit_global.global_target_list, tgt)) {
3311 3322 mutex_enter(&tgt->target_mutex);
3312 3323 for (ist = avl_first(&tgt->target_sess_list);
3313 3324 ist != NULL;
3314 3325 ist = AVL_NEXT(&tgt->target_sess_list, ist)) {
3315 3326
3316 3327 iscsit_rxpdu_queue_monitor_session(ist);
3317 3328 }
3318 3329 mutex_exit(&tgt->target_mutex);
3319 3330 }
3320 3331 ISCSIT_GLOBAL_UNLOCK();
3321 3332 if (iscsit_rxpdu_queue_monitor_thr_running == B_FALSE) {
3322 3333 break;
3323 3334 }
3324 3335 (void) cv_reltimedwait(&iscsit_rxpdu_queue_monitor_cv,
3325 3336 &iscsit_rxpdu_queue_monitor_mutex,
3326 3337 ISCSIT_RXPDU_QUEUE_MONITOR_INTERVAL * drv_usectohz(1000000),
3327 3338 TR_CLOCK_TICK);
3328 3339 }
3329 3340 mutex_exit(&iscsit_rxpdu_queue_monitor_mutex);
3330 3341 thread_exit();
3331 3342 }
3332 3343
3333 3344 static void
3334 3345 iscsit_rxpdu_queue_monitor_session(iscsit_sess_t *ist)
3335 3346 {
3336 3347 iscsit_cbuf_t *cbuf = ist->ist_rxpdu_queue;
3337 3348 idm_pdu_t *next_pdu = NULL;
3338 3349 uint32_t index, next_cmdsn, i;
3339 3350
3340 3351 /*
3341 3352 * Assume that all PDUs in the staging queue have a cmdsn >= expcmdsn.
3342 3353 * Starting with the expcmdsn, iterate over the staged PDUs to find
3343 3354 * the next PDU with a wait time greater than the threshold. If found
3344 3355 * advance the staged PDU to the SCSI layer, skipping over the missing
3345 3356 * PDU(s) to get past the hole in the command sequence. It is up to
3346 3357 * the initiator to note that the target has not acknowledged a cmdsn
3347 3358 * and take appropriate action.
3348 3359 *
3349 3360 * Since the PDU(s) arrive in any random order, it is possible that
3350 3361 * that the actual wait time for a particular PDU is much longer than
3351 3362 * the defined threshold. e.g. Consider a case where commands are sent
3352 3363 * over 4 different connections, and cmdsn = 1004 arrives first, then
3353 3364 * 1003, and 1002 and 1001 are lost due to a connection failure.
3354 3365 * So now 1003 is waiting for 1002 to be delivered, and although the
3355 3366 * wait time of 1004 > wait time of 1003, only 1003 will be considered
3356 3367 * by the monitor thread. 1004 will be automatically processed by
3357 3368 * iscsit_process_pdu_in_queue() once the scan is complete and the
3358 3369 * expcmdsn becomes current.
3359 3370 */
3360 3371 mutex_enter(&ist->ist_sn_mutex);
3361 3372 cbuf = ist->ist_rxpdu_queue;
3362 3373 if (cbuf->cb_num_elems == 0) {
3363 3374 mutex_exit(&ist->ist_sn_mutex);
3364 3375 return;
3365 3376 }
3366 3377 for (next_pdu = NULL, i = 0; ; i++) {
3367 3378 next_cmdsn = ist->ist_expcmdsn + i; /* start at expcmdsn */
3368 3379 index = next_cmdsn % ISCSIT_RXPDU_QUEUE_LEN;
3369 3380 if ((next_pdu = cbuf->cb_buffer[index]) != NULL) {
3370 3381 /*
3371 3382 * If the PDU wait time has not exceeded threshold
3372 3383 * stop scanning the staging queue until the timer
3373 3384 * fires again
3374 3385 */
3375 3386 if ((ddi_get_time() - next_pdu->isp_queue_time)
3376 3387 < rxpdu_queue_threshold) {
3377 3388 mutex_exit(&ist->ist_sn_mutex);
3378 3389 return;
3379 3390 }
3380 3391 /*
3381 3392 * Remove the next PDU from the queue and post it
3382 3393 * to the SCSI layer, skipping over the missing
3383 3394 * PDU. Stop scanning the staging queue until
3384 3395 * the monitor timer fires again
3385 3396 */
3386 3397 (void) iscsit_remove_pdu_from_queue(ist, next_cmdsn);
3387 3398 mutex_exit(&ist->ist_sn_mutex);
3388 3399 DTRACE_PROBE3(advanced__to__blocked__cmdsn,
3389 3400 iscsit_sess_t *, ist, idm_pdu_t *, next_pdu,
3390 3401 uint32_t, next_cmdsn);
3391 3402 iscsit_post_staged_pdu(next_pdu);
3392 3403 /* Deliver any subsequent PDUs immediately */
3393 3404 iscsit_process_pdu_in_queue(ist);
3394 3405 return;
3395 3406 }
3396 3407 /*
3397 3408 * Skipping over i PDUs, e.g. a case where commands 1001 and
3398 3409 * 1002 are lost in the network, skip over both and post 1003
3399 3410 * expcmdsn then becomes 1004 at the end of the scan.
3400 3411 */
3401 3412 DTRACE_PROBE2(skipping__over__cmdsn, iscsit_sess_t *, ist,
3402 3413 uint32_t, next_cmdsn);
3403 3414 }
3404 3415 /*
3405 3416 * following the assumption, staged cmdsn >= expcmdsn, this statement
3406 3417 * is never reached.
3407 3418 */
3408 3419 }
|
↓ open down ↓ |
232 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX