Annotation of embedaddon/istgt/src/istgt_iscsi.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2008-2011 Daisuke Aoyama <aoyama@peach.ne.jp>.
! 3: * All rights reserved.
! 4: *
! 5: * Redistribution and use in source and binary forms, with or without
! 6: * modification, are permitted provided that the following conditions
! 7: * are met:
! 8: * 1. Redistributions of source code must retain the above copyright
! 9: * notice, this list of conditions and the following disclaimer.
! 10: * 2. Redistributions in binary form must reproduce the above copyright
! 11: * notice, this list of conditions and the following disclaimer in the
! 12: * documentation and/or other materials provided with the distribution.
! 13: *
! 14: * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 15: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 16: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 17: * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
! 18: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 19: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 20: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 21: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 22: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 23: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 24: * SUCH DAMAGE.
! 25: *
! 26: */
! 27:
! 28: #ifdef HAVE_CONFIG_H
! 29: #include "config.h"
! 30: #endif
! 31:
! 32: #include <stdint.h>
! 33: #include <inttypes.h>
! 34:
! 35: #include <errno.h>
! 36: #include <signal.h>
! 37: #include <stdio.h>
! 38: #include <stdlib.h>
! 39: #include <string.h>
! 40: #include <poll.h>
! 41: #include <pthread.h>
! 42: #ifdef HAVE_PTHREAD_NP_H
! 43: #include <pthread_np.h>
! 44: #endif
! 45: #include <unistd.h>
! 46: #include <sys/types.h>
! 47: #include <sys/socket.h>
! 48: #include <time.h>
! 49:
! 50: #include "istgt.h"
! 51: #include "istgt_ver.h"
! 52: #include "istgt_log.h"
! 53: #include "istgt_conf.h"
! 54: #include "istgt_sock.h"
! 55: #include "istgt_misc.h"
! 56: #include "istgt_crc32c.h"
! 57: #include "istgt_md5.h"
! 58: #include "istgt_iscsi.h"
! 59: #include "istgt_iscsi_param.h"
! 60: #include "istgt_lu.h"
! 61: #include "istgt_proto.h"
! 62: #include "istgt_scsi.h"
! 63: #include "istgt_queue.h"
! 64:
! 65: #ifdef ISTGT_USE_KQUEUE
! 66: #include <sys/types.h>
! 67: #include <sys/event.h>
! 68: #include <sys/time.h>
! 69: #endif
! 70:
! 71: /* according to RFC1982 */
! 72: #define SN32_CMPMAX (((uint32_t)1U) << (32 - 1))
! 73: #define SN32_LT(S1,S2) \
! 74: (((uint32_t)(S1) != (uint32_t)(S2)) \
! 75: && (((uint32_t)(S1) < (uint32_t)(S2) \
! 76: && ((uint32_t)(S2) - (uint32_t)(S1) < SN32_CMPMAX)) \
! 77: || ((uint32_t)(S1) > (uint32_t)(S2) \
! 78: && ((uint32_t)(S1) - (uint32_t)(S2) > SN32_CMPMAX))))
! 79: #define SN32_GT(S1,S2) \
! 80: (((uint32_t)(S1) != (uint32_t)(S2)) \
! 81: && (((uint32_t)(S1) < (uint32_t)(S2) \
! 82: && ((uint32_t)(S2) - (uint32_t)(S1) > SN32_CMPMAX)) \
! 83: || ((uint32_t)(S1) > (uint32_t)(S2) \
! 84: && ((uint32_t)(S1) - (uint32_t)(S2) < SN32_CMPMAX))))
! 85:
! 86: #define POLLWAIT 3000
! 87: #define MAX_MCSREVWAIT (10 * 1000)
! 88: #define ISCMDQ 8
! 89:
! 90: #define ISCSI_GETVAL(PARAMS,KEY) \
! 91: istgt_iscsi_param_get_val((PARAMS),(KEY))
! 92: #define ISCSI_EQVAL(PARAMS,KEY,VAL) \
! 93: istgt_iscsi_param_eq_val((PARAMS),(KEY),(VAL))
! 94: #define ISCSI_DELVAL(PARAMS,KEY) \
! 95: istgt_iscsi_param_del((PARAMS),(KEY))
! 96: #define ISCSI_ADDVAL(PARAMS,KEY,VAL,LIST,TYPE) \
! 97: istgt_iscsi_param_add((PARAMS),(KEY),(VAL), (LIST), (TYPE))
! 98:
! 99: static int g_nconns;
! 100: static CONN_Ptr *g_conns;
! 101: static pthread_mutex_t g_conns_mutex;
! 102:
! 103: static uint16_t g_last_tsih;
! 104: static pthread_mutex_t g_last_tsih_mutex;
! 105:
! 106: static int istgt_add_transfer_task(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd);
! 107: static void istgt_clear_transfer_task(CONN_Ptr conn, uint32_t CmdSN);
! 108: static void istgt_clear_all_transfer_task(CONN_Ptr conn);
! 109: static int istgt_iscsi_send_r2t(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, int offset, int len, uint32_t transfer_tag, uint32_t *R2TSN);
! 110: static int istgt_append_sess(CONN_Ptr conn, uint64_t isid, uint16_t tsih, uint16_t cid);
! 111: static void istgt_remove_conn(CONN_Ptr conn);
! 112: static int istgt_iscsi_drop_all_conns(CONN_Ptr conn);
! 113: static int istgt_iscsi_drop_old_conns(CONN_Ptr conn);
! 114:
! 115: #if 0
! 116: #define ISTGT_USE_RECVBLOCK
! 117: #define ISTGT_USE_SENDBLOCK
! 118: #endif
! 119: #if 0
! 120: #define ISTGT_USE_RECVWAIT
! 121: #endif
! 122: static ssize_t
! 123: istgt_iscsi_read(CONN_Ptr conn, void *buf, size_t nbytes)
! 124: {
! 125: #ifndef ISTGT_USE_RECVBLOCK
! 126: uint8_t padding[ISCSI_ALIGNMENT];
! 127: #endif
! 128: uint8_t *cp;
! 129: size_t pad_bytes;
! 130: size_t total;
! 131: ssize_t r;
! 132:
! 133: total = 0;
! 134: cp = (uint8_t *) buf;
! 135: #ifdef ISTGT_USE_RECVBLOCK
! 136: pad_bytes = ISCSI_ALIGN(nbytes) - nbytes;
! 137: do {
! 138: #ifdef ISTGT_USE_RECVWAIT
! 139: r = recv(conn->sock, cp + total, (nbytes + pad_bytes - total),
! 140: MSG_WAITALL);
! 141: #else
! 142: r = recv(conn->sock, cp + total, (nbytes + pad_bytes - total),
! 143: 0);
! 144: #endif
! 145: if (r < 0) {
! 146: /* error */
! 147: ISTGT_TRACELOG(ISTGT_TRACE_NET,
! 148: "Read error (errno=%d)\n", errno);
! 149: return r;
! 150: }
! 151: if (r == 0) {
! 152: /* EOF */
! 153: ISTGT_TRACELOG(ISTGT_TRACE_NET, "Read EOF\n");
! 154: return r;
! 155: }
! 156: total += r;
! 157: } while (total < nbytes);
! 158: if (total != (nbytes + pad_bytes)) {
! 159: /* incomplete bytes */
! 160: ISTGT_TRACELOG(ISTGT_TRACE_NET, "Read %d/%d+%d bytes\n",
! 161: total, nbytes, pad_bytes);
! 162: if (total > nbytes) {
! 163: total = nbytes;
! 164: }
! 165: return total;
! 166: }
! 167:
! 168: if (pad_bytes != 0) {
! 169: /* complete padding */
! 170: ISTGT_TRACELOG(ISTGT_TRACE_NET, "Read %d bytes (padding %d)\n",
! 171: nbytes, pad_bytes);
! 172: } else {
! 173: /* just aligned */
! 174: ISTGT_TRACELOG(ISTGT_TRACE_NET, "Read %d bytes (no padding)\n",
! 175: nbytes);
! 176: }
! 177: #else /* !ISTGT_USE_RECVBLOCK */
! 178: do {
! 179: r = istgt_read_socket(conn->sock, cp + total, (nbytes - total),
! 180: conn->timeout);
! 181: if (r < 0) {
! 182: /* error */
! 183: ISTGT_TRACELOG(ISTGT_TRACE_NET,
! 184: "Read error (errno=%d)\n", errno);
! 185: return r;
! 186: }
! 187: if (r == 0) {
! 188: /* EOF */
! 189: ISTGT_TRACELOG(ISTGT_TRACE_NET, "Read EOF\n");
! 190: return r;
! 191: }
! 192: total += r;
! 193: } while (total < nbytes);
! 194: #if 0
! 195: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "RAW DATA", cp, total);
! 196: #endif
! 197:
! 198: if (total != nbytes) {
! 199: /* incomplete bytes */
! 200: ISTGT_TRACELOG(ISTGT_TRACE_NET, "Read %d/%d bytes\n",
! 201: total, nbytes);
! 202: return total;
! 203: }
! 204:
! 205: /* need padding? */
! 206: pad_bytes = ISCSI_ALIGN(nbytes) - nbytes;
! 207: if (pad_bytes != 0) {
! 208: total = 0;
! 209: cp = (uint8_t *) &padding[0];
! 210: do {
! 211: r = istgt_read_socket(conn->sock, cp + total,
! 212: (pad_bytes - total), conn->timeout);
! 213: if (r < 0) {
! 214: /* error */
! 215: ISTGT_TRACELOG(ISTGT_TRACE_NET,
! 216: "Read %d bytes (padding error) (errno=%d)\n",
! 217: nbytes, errno);
! 218: return nbytes;
! 219: }
! 220: if (r == 0) {
! 221: /* EOF */
! 222: ISTGT_TRACELOG(ISTGT_TRACE_NET,
! 223: "Read %d bytes (padding EOF)\n",
! 224: nbytes);
! 225: return nbytes;
! 226: }
! 227: total += r;
! 228: } while (total < pad_bytes);
! 229:
! 230: if (total != pad_bytes) {
! 231: /* incomplete padding */
! 232: ISTGT_TRACELOG(ISTGT_TRACE_NET,
! 233: "Read %d bytes (padding %d)\n",
! 234: nbytes, total);
! 235: return nbytes;
! 236: }
! 237: /* complete padding */
! 238: ISTGT_TRACELOG(ISTGT_TRACE_NET, "Read %d bytes (padding %d)\n",
! 239: nbytes, pad_bytes);
! 240: return nbytes;
! 241: }
! 242:
! 243: /* just aligned */
! 244: ISTGT_TRACELOG(ISTGT_TRACE_NET, "Read %d bytes (no padding)\n",
! 245: nbytes);
! 246: #endif /* ISTGT_USE_RECVBLOCK */
! 247: return nbytes;
! 248: }
! 249:
! 250: static ssize_t
! 251: istgt_iscsi_write(CONN_Ptr conn, const void *buf, size_t nbytes)
! 252: {
! 253: uint8_t padding[ISCSI_ALIGNMENT];
! 254: const uint8_t *cp;
! 255: size_t pad_bytes;
! 256: size_t total;
! 257: ssize_t r;
! 258:
! 259: total = 0;
! 260: cp = (const uint8_t *) buf;
! 261: #ifdef ISTGT_USE_SENDBLOCK
! 262: pad_bytes = ISCSI_ALIGN(nbytes) - nbytes;
! 263: do {
! 264: r = send(conn->wsock, cp, nbytes, 0);
! 265: if (r < 0) {
! 266: /* error */
! 267: ISTGT_TRACELOG(ISTGT_TRACE_NET,
! 268: "Write error (errno=%d)\n", errno);
! 269: return r;
! 270: }
! 271: total += r;
! 272: } while (total < nbytes);
! 273:
! 274: if (total != nbytes) {
! 275: /* incomplete bytes */
! 276: ISTGT_TRACELOG(ISTGT_TRACE_NET, "Write %d/%d bytes\n",
! 277: total, nbytes);
! 278: return total;
! 279: }
! 280:
! 281: if (pad_bytes != 0) {
! 282: memset(padding, 0, sizeof padding);
! 283: total = 0;
! 284: cp = (const uint8_t *) &padding[0];
! 285: do {
! 286: r = send(conn->wsock, cp, pad_bytes, 0);
! 287: if (r < 0) {
! 288: /* error */
! 289: ISTGT_TRACELOG(ISTGT_TRACE_NET,
! 290: "Write %d bytes (padding error) (errno=%d)\n",
! 291: nbytes, errno);
! 292: return nbytes;
! 293: }
! 294: total += r;
! 295: } while (total < pad_bytes);
! 296:
! 297: if (total != pad_bytes) {
! 298: /* incomplete padding */
! 299: ISTGT_TRACELOG(ISTGT_TRACE_NET,
! 300: "Write %d bytes (padding %d)\n",
! 301: nbytes, total);
! 302: return nbytes;
! 303: }
! 304:
! 305: /* complete padding */
! 306: ISTGT_TRACELOG(ISTGT_TRACE_NET,
! 307: "Write %d bytes (padding %d)\n",
! 308: nbytes, pad_bytes);
! 309: } else {
! 310: /* just aligned */
! 311: ISTGT_TRACELOG(ISTGT_TRACE_NET,
! 312: "Write %d bytes (no padding)\n",
! 313: nbytes);
! 314: }
! 315: #else /* !ISTGT_USE_SENDBLOCK */
! 316: do {
! 317: r = istgt_write_socket(conn->wsock, cp + total,
! 318: (nbytes - total), conn->timeout);
! 319: if (r < 0) {
! 320: /* error */
! 321: ISTGT_TRACELOG(ISTGT_TRACE_NET,
! 322: "Write error (errno=%d)\n", errno);
! 323: return r;
! 324: }
! 325: total += r;
! 326: } while (total < nbytes);
! 327:
! 328: if (total != nbytes) {
! 329: /* incomplete bytes */
! 330: ISTGT_TRACELOG(ISTGT_TRACE_NET, "Write %d/%d bytes\n",
! 331: total, nbytes);
! 332: return r;
! 333: }
! 334:
! 335: /* need padding? */
! 336: pad_bytes = ISCSI_ALIGN(nbytes) - nbytes;
! 337: if (pad_bytes != 0) {
! 338: memset(padding, 0, sizeof padding);
! 339: total = 0;
! 340: cp = (const uint8_t *) &padding[0];
! 341: do {
! 342: r = istgt_write_socket(conn->wsock, cp + total,
! 343: (pad_bytes - total), conn->timeout);
! 344: if (r < 0) {
! 345: /* error */
! 346: ISTGT_TRACELOG(ISTGT_TRACE_NET,
! 347: "Write %d bytes (padding error) (errno=%d)\n",
! 348: nbytes, errno);
! 349: return nbytes;
! 350: }
! 351: total += r;
! 352: } while (total < pad_bytes);
! 353:
! 354: if (total != pad_bytes) {
! 355: /* incomplete padding */
! 356: ISTGT_TRACELOG(ISTGT_TRACE_NET,
! 357: "Write %d bytes (padding %d)\n",
! 358: nbytes, total);
! 359: return nbytes;
! 360: }
! 361: /* complete padding */
! 362: ISTGT_TRACELOG(ISTGT_TRACE_NET,
! 363: "Write %d bytes (padding %d)\n",
! 364: nbytes, pad_bytes);
! 365: return nbytes;
! 366: }
! 367:
! 368: /* just aligned */
! 369: ISTGT_TRACELOG(ISTGT_TRACE_NET, "Write %d bytes (no padding)\n",
! 370: nbytes);
! 371: #endif /* ISTGT_USE_SENDBLOCK */
! 372: return nbytes;
! 373: }
! 374:
! 375: #define MATCH_DIGEST_WORD(BUF, CRC32C) \
! 376: ( ((((uint32_t) *((uint8_t *)(BUF)+0)) << 0) \
! 377: | (((uint32_t) *((uint8_t *)(BUF)+1)) << 8) \
! 378: | (((uint32_t) *((uint8_t *)(BUF)+2)) << 16) \
! 379: | (((uint32_t) *((uint8_t *)(BUF)+3)) << 24)) \
! 380: == (CRC32C))
! 381:
! 382: #define MAKE_DIGEST_WORD(BUF, CRC32C) \
! 383: ( ((*((uint8_t *)(BUF)+0)) = (uint8_t)((uint32_t)(CRC32C) >> 0)), \
! 384: ((*((uint8_t *)(BUF)+1)) = (uint8_t)((uint32_t)(CRC32C) >> 8)), \
! 385: ((*((uint8_t *)(BUF)+2)) = (uint8_t)((uint32_t)(CRC32C) >> 16)), \
! 386: ((*((uint8_t *)(BUF)+3)) = (uint8_t)((uint32_t)(CRC32C) >> 24)))
! 387:
! 388: #if 0
! 389: static int
! 390: istgt_match_digest_word(const uint8_t *buf, uint32_t crc32c)
! 391: {
! 392: uint32_t l;
! 393:
! 394: l = (buf[0] & 0xffU) << 0;
! 395: l |= (buf[1] & 0xffU) << 8;
! 396: l |= (buf[2] & 0xffU) << 16;
! 397: l |= (buf[3] & 0xffU) << 24;
! 398: return (l == crc32c);
! 399: }
! 400:
! 401: static uint8_t *
! 402: istgt_make_digest_word(uint8_t *buf, size_t len, uint32_t crc32c)
! 403: {
! 404: if (len < ISCSI_DIGEST_LEN)
! 405: return NULL;
! 406:
! 407: buf[0] = (crc32c >> 0) & 0xffU;
! 408: buf[1] = (crc32c >> 8) & 0xffU;
! 409: buf[2] = (crc32c >> 16) & 0xffU;
! 410: buf[3] = (crc32c >> 24) & 0xffU;
! 411: return buf;
! 412: }
! 413: #endif
! 414:
! 415: static int
! 416: istgt_iscsi_read_pdu(CONN_Ptr conn, ISCSI_PDU_Ptr pdu)
! 417: {
! 418: uint32_t crc32c;
! 419: int total_ahs_len;
! 420: int data_len;
! 421: int segment_len;
! 422: int total;
! 423: int rc;
! 424:
! 425: pdu->ahs = NULL;
! 426: pdu->total_ahs_len = 0;
! 427: pdu->data = NULL;
! 428: pdu->data_segment_len = 0;
! 429: total = 0;
! 430:
! 431: /* BHS */
! 432: ISTGT_TRACELOG(ISTGT_TRACE_NET, "BHS read %d\n",
! 433: ISCSI_BHS_LEN);
! 434: rc = istgt_iscsi_read(conn, &pdu->bhs, ISCSI_BHS_LEN);
! 435: if (rc < 0) {
! 436: if (errno == ECONNRESET) {
! 437: ISTGT_WARNLOG("Connection reset by peer (%s)\n",
! 438: conn->initiator_name);
! 439: conn->state = CONN_STATE_EXITING;
! 440: } else if (errno == ETIMEDOUT) {
! 441: ISTGT_WARNLOG("Operation timed out (%s)\n",
! 442: conn->initiator_name);
! 443: conn->state = CONN_STATE_EXITING;
! 444: } else {
! 445: ISTGT_ERRLOG("iscsi_read() failed (errno=%d)\n",
! 446: errno);
! 447: }
! 448: return -1;
! 449: }
! 450: if (rc == 0) {
! 451: ISTGT_TRACELOG(ISTGT_TRACE_NET, "iscsi_read() EOF\n");
! 452: conn->state = CONN_STATE_EXITING;
! 453: return -1;
! 454: }
! 455: if (rc != ISCSI_BHS_LEN) {
! 456: ISTGT_ERRLOG("invalid BHS length (%d)\n", rc);
! 457: return -1;
! 458: }
! 459: total += ISCSI_BHS_LEN;
! 460:
! 461: /* AHS */
! 462: total_ahs_len = DGET8(&pdu->bhs.total_ahs_len);
! 463: if (total_ahs_len != 0) {
! 464: pdu->ahs = xmalloc(ISCSI_ALIGN((4 * total_ahs_len)));
! 465: ISTGT_TRACELOG(ISTGT_TRACE_NET, "AHS read %d\n",
! 466: (4 * total_ahs_len));
! 467: rc = istgt_iscsi_read(conn, pdu->ahs, (4 * total_ahs_len));
! 468: if (rc < 0) {
! 469: ISTGT_ERRLOG("iscsi_read() failed\n");
! 470: return -1;
! 471: }
! 472: if (rc == 0) {
! 473: ISTGT_TRACELOG(ISTGT_TRACE_NET, "iscsi_read() EOF\n");
! 474: conn->state = CONN_STATE_EXITING;
! 475: return -1;
! 476: }
! 477: if (rc != (4 * total_ahs_len)) {
! 478: ISTGT_ERRLOG("invalid AHS length (%d)\n", rc);
! 479: return -1;
! 480: }
! 481: pdu->total_ahs_len = total_ahs_len;
! 482: total += (4 * total_ahs_len);
! 483: } else {
! 484: pdu->ahs = NULL;
! 485: pdu->total_ahs_len = 0;
! 486: }
! 487:
! 488: /* Header Digest */
! 489: if (conn->header_digest) {
! 490: ISTGT_TRACELOG(ISTGT_TRACE_NET, "HeaderDigest read %d\n",
! 491: ISCSI_DIGEST_LEN);
! 492: rc = istgt_iscsi_read(conn, pdu->header_digest,
! 493: ISCSI_DIGEST_LEN);
! 494: if (rc < 0) {
! 495: ISTGT_ERRLOG("iscsi_read() failed\n");
! 496: {
! 497: int opcode = BGET8W(&pdu->bhs.opcode, 5, 6);
! 498: ISTGT_ERRLOG("Header Digest read error (opcode = 0x%x)\n",
! 499: opcode);
! 500: }
! 501: return -1;
! 502: }
! 503: if (rc == 0) {
! 504: ISTGT_TRACELOG(ISTGT_TRACE_NET, "iscsi_read() EOF\n");
! 505: conn->state = CONN_STATE_EXITING;
! 506: return -1;
! 507: }
! 508: if (rc != ISCSI_DIGEST_LEN) {
! 509: ISTGT_ERRLOG("invalid Header Digest length (%d)\n",
! 510: rc);
! 511: return -1;
! 512: }
! 513: total += ISCSI_DIGEST_LEN;
! 514: }
! 515:
! 516: /* Data Segment */
! 517: data_len = DGET24(&pdu->bhs.data_segment_len[0]);
! 518: if (data_len != 0) {
! 519: if (conn->sess == NULL) {
! 520: segment_len = DEFAULT_FIRSTBURSTLENGTH;
! 521: } else {
! 522: segment_len = conn->MaxRecvDataSegmentLength;
! 523: }
! 524: if (data_len > segment_len) {
! 525: ISTGT_ERRLOG("Data(%d) > Segment(%d)\n",
! 526: data_len, segment_len);
! 527: return -1;
! 528: }
! 529: if (ISCSI_ALIGN(data_len) <= ISTGT_SHORTDATASIZE) {
! 530: pdu->data = pdu->shortdata;
! 531: } else {
! 532: pdu->data = xmalloc(ISCSI_ALIGN(segment_len));
! 533: }
! 534: ISTGT_TRACELOG(ISTGT_TRACE_NET, "Data read %d\n",
! 535: data_len);
! 536: rc = istgt_iscsi_read(conn, pdu->data, data_len);
! 537: if (rc < 0) {
! 538: ISTGT_ERRLOG("iscsi_read() failed (%d,errno=%d)\n",
! 539: rc, errno);
! 540: return -1;
! 541: }
! 542: if (rc == 0) {
! 543: ISTGT_TRACELOG(ISTGT_TRACE_NET, "iscsi_read() EOF\n");
! 544: conn->state = CONN_STATE_EXITING;
! 545: return -1;
! 546: }
! 547: if (rc != data_len) {
! 548: ISTGT_ERRLOG("invalid Data Segment length (%d)\n", rc);
! 549: return -1;
! 550: }
! 551: pdu->data_segment_len = data_len;
! 552: total += data_len;
! 553:
! 554: #if 0
! 555: if (data_len > 512) {
! 556: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "DataSegment",
! 557: pdu->data, 512);
! 558: } else {
! 559: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "DataSegment",
! 560: pdu->data, data_len);
! 561: }
! 562: #endif
! 563: } else {
! 564: pdu->data = NULL;
! 565: pdu->data_segment_len = 0;
! 566: }
! 567:
! 568: /* Data Digest */
! 569: if (conn->data_digest && data_len != 0) {
! 570: ISTGT_TRACELOG(ISTGT_TRACE_NET, "DataDigest read %d\n",
! 571: ISCSI_DIGEST_LEN);
! 572: rc = istgt_iscsi_read(conn, pdu->data_digest,
! 573: ISCSI_DIGEST_LEN);
! 574: if (rc < 0) {
! 575: ISTGT_ERRLOG("iscsi_read() failed\n");
! 576: return -1;
! 577: }
! 578: if (rc == 0) {
! 579: ISTGT_TRACELOG(ISTGT_TRACE_NET, "iscsi_read() EOF\n");
! 580: conn->state = CONN_STATE_EXITING;
! 581: return -1;
! 582: }
! 583: if (rc != ISCSI_DIGEST_LEN) {
! 584: ISTGT_ERRLOG("invalid Data Digest length (%d)\n", rc);
! 585: return -1;
! 586: }
! 587: total += ISCSI_DIGEST_LEN;
! 588: }
! 589:
! 590: /* check digest */
! 591: if (conn->header_digest) {
! 592: if (total_ahs_len == 0) {
! 593: crc32c = istgt_crc32c((uint8_t *) &pdu->bhs,
! 594: ISCSI_BHS_LEN);
! 595: } else {
! 596: int upd_total = 0;
! 597: crc32c = ISTGT_CRC32C_INITIAL;
! 598: crc32c = istgt_update_crc32c((uint8_t *) &pdu->bhs,
! 599: ISCSI_BHS_LEN, crc32c);
! 600: upd_total += ISCSI_BHS_LEN;
! 601: crc32c = istgt_update_crc32c((uint8_t *) pdu->ahs,
! 602: (4 * total_ahs_len), crc32c);
! 603: upd_total += (4 * total_ahs_len);
! 604: crc32c = istgt_fixup_crc32c(upd_total, crc32c);
! 605: crc32c = crc32c ^ ISTGT_CRC32C_XOR;
! 606: }
! 607: rc = MATCH_DIGEST_WORD(pdu->header_digest, crc32c);
! 608: if (rc == 0) {
! 609: ISTGT_ERRLOG("header digest error\n");
! 610: return -1;
! 611: }
! 612: }
! 613: if (conn->data_digest && data_len != 0) {
! 614: crc32c = istgt_crc32c(pdu->data, data_len);
! 615: rc = MATCH_DIGEST_WORD(pdu->data_digest, crc32c);
! 616: if (rc == 0) {
! 617: ISTGT_ERRLOG("data digest error\n");
! 618: return -1;
! 619: }
! 620: }
! 621:
! 622: return total;
! 623: }
! 624:
! 625: static int istgt_iscsi_write_pdu_internal(CONN_Ptr conn, ISCSI_PDU_Ptr pdu);
! 626:
! 627: static int
! 628: istgt_iscsi_write_pdu(CONN_Ptr conn, ISCSI_PDU_Ptr pdu)
! 629: {
! 630: int rc;
! 631:
! 632: if (conn->use_sender == 0) {
! 633: rc = istgt_iscsi_write_pdu_internal(conn, pdu);
! 634: } else {
! 635: ISTGT_LU_TASK_Ptr lu_task;
! 636: ISCSI_PDU_Ptr src_pdu, dst_pdu;
! 637: uint8_t *cp;
! 638: int total_ahs_len;
! 639: int data_len;
! 640: int alloc_len;
! 641: int total;
! 642:
! 643: cp = (uint8_t *) &pdu->bhs;
! 644: total_ahs_len = DGET8(&cp[4]);
! 645: data_len = DGET24(&cp[5]);
! 646: total = 0;
! 647:
! 648: #if 0
! 649: ISTGT_LOG("W:PDU OP=%x, tag=%x, ExpCmdSN=%u, MaxCmdSN=%u\n",
! 650: DGET8(&cp[0]), DGET32(&cp[32]), DGET32(&cp[28]), DGET32(&cp[32]));
! 651: #endif
! 652: /* allocate for queued PDU */
! 653: alloc_len = ISCSI_ALIGN(sizeof *lu_task);
! 654: alloc_len += ISCSI_ALIGN(sizeof *lu_task->lu_cmd.pdu);
! 655: alloc_len += ISCSI_ALIGN(4 * total_ahs_len);
! 656: alloc_len += ISCSI_ALIGN(data_len);
! 657: lu_task = xmalloc(alloc_len);
! 658: memset(lu_task, 0, alloc_len);
! 659: lu_task->lu_cmd.pdu = (ISCSI_PDU_Ptr) ((uint8_t *)lu_task
! 660: + ISCSI_ALIGN(sizeof *lu_task));
! 661: lu_task->lu_cmd.pdu->ahs = (ISCSI_AHS *) ((uint8_t *)lu_task->lu_cmd.pdu
! 662: + ISCSI_ALIGN(sizeof *lu_task->lu_cmd.pdu));
! 663: lu_task->lu_cmd.pdu->data = (uint8_t *)lu_task->lu_cmd.pdu->ahs
! 664: + ISCSI_ALIGN(4 * total_ahs_len);
! 665:
! 666: /* specify type and self conn */
! 667: lu_task->type = ISTGT_LU_TASK_REQPDU;
! 668: lu_task->conn = conn;
! 669:
! 670: /* copy PDU structure */
! 671: src_pdu = pdu;
! 672: dst_pdu = lu_task->lu_cmd.pdu;
! 673: memcpy(&dst_pdu->bhs, &src_pdu->bhs, ISCSI_BHS_LEN);
! 674: total += ISCSI_BHS_LEN;
! 675: if (total_ahs_len != 0) {
! 676: memcpy(dst_pdu->ahs, src_pdu->ahs, 4 * total_ahs_len);
! 677: total += (4 * total_ahs_len);
! 678: } else {
! 679: dst_pdu->ahs = NULL;
! 680: }
! 681: if (conn->header_digest) {
! 682: memcpy(dst_pdu->header_digest, src_pdu->header_digest,
! 683: ISCSI_DIGEST_LEN);
! 684: total += ISCSI_DIGEST_LEN;
! 685: }
! 686: if (data_len != 0) {
! 687: memcpy(dst_pdu->data, src_pdu->data, data_len);
! 688: total += data_len;
! 689: } else {
! 690: dst_pdu->data = NULL;
! 691: }
! 692: if (conn->data_digest && data_len != 0) {
! 693: memcpy(dst_pdu->data_digest, src_pdu->data_digest,
! 694: ISCSI_DIGEST_LEN);
! 695: total += ISCSI_DIGEST_LEN;
! 696: }
! 697:
! 698: /* insert to queue */
! 699: MTX_LOCK(&conn->result_queue_mutex);
! 700: rc = istgt_queue_enqueue(&conn->result_queue, lu_task);
! 701: if (rc != 0) {
! 702: MTX_UNLOCK(&conn->result_queue_mutex);
! 703: ISTGT_ERRLOG("queue_enqueue() failed\n");
! 704: return -1;
! 705: }
! 706: /* notify to thread */
! 707: rc = pthread_cond_broadcast(&conn->result_queue_cond);
! 708: MTX_UNLOCK(&conn->result_queue_mutex);
! 709: if (rc != 0) {
! 710: ISTGT_ERRLOG("cond_broadcast() failed\n");
! 711: return -1;
! 712: }
! 713:
! 714: /* total bytes should be sent in queue */
! 715: rc = total;
! 716: }
! 717: return rc;
! 718: }
! 719:
! 720: static int
! 721: istgt_iscsi_write_pdu_internal(CONN_Ptr conn, ISCSI_PDU_Ptr pdu)
! 722: {
! 723: uint8_t *cp;
! 724: uint32_t crc32c;
! 725: int enable_digest;
! 726: int opcode;
! 727: int total_ahs_len;
! 728: int data_len;
! 729: int total;
! 730: int rc;
! 731:
! 732: cp = (uint8_t *) &pdu->bhs;
! 733: total_ahs_len = DGET8(&cp[4]);
! 734: data_len = DGET24(&cp[5]);
! 735: total = 0;
! 736:
! 737: enable_digest = 1;
! 738: opcode = BGET8W(&cp[0], 5, 6);
! 739: if (opcode == ISCSI_OP_LOGIN_RSP) {
! 740: /* this PDU should be sent without digest */
! 741: enable_digest = 0;
! 742: }
! 743:
! 744: #define ISTGT_USE_SHORTPDU_WRITE
! 745: #ifdef ISTGT_USE_SHORTPDU_WRITE
! 746: /* if short size, BHS + AHS + HD + DATA + DD */
! 747: if (total_ahs_len == 0
! 748: && data_len <= ISTGT_SHORTDATASIZE) {
! 749: uint8_t *spp = conn->shortpdu;
! 750: int pad_len = 0;
! 751: memcpy(spp, (uint8_t *) &pdu->bhs, ISCSI_BHS_LEN);
! 752: total = ISCSI_BHS_LEN;
! 753: if (enable_digest && conn->header_digest) {
! 754: crc32c = istgt_crc32c(spp, total);
! 755: MAKE_DIGEST_WORD(spp + total, crc32c);
! 756: total += ISCSI_DIGEST_LEN;
! 757: }
! 758: memcpy(spp + total, pdu->data, data_len);
! 759: total += data_len;
! 760: if ((data_len % ISCSI_ALIGNMENT) != 0) {
! 761: memset(spp + total, 0,
! 762: ISCSI_ALIGN(data_len) - data_len);
! 763: total += ISCSI_ALIGN(data_len) - data_len;
! 764: pad_len += ISCSI_ALIGN(data_len) - data_len;
! 765: }
! 766: if (enable_digest && conn->data_digest && data_len != 0) {
! 767: crc32c = istgt_crc32c(pdu->data, data_len);
! 768: MAKE_DIGEST_WORD(spp + total, crc32c);
! 769: total += ISCSI_DIGEST_LEN;
! 770: }
! 771:
! 772: ISTGT_TRACELOG(ISTGT_TRACE_NET, "PDU write %d\n",
! 773: total);
! 774: rc = istgt_iscsi_write(conn, spp, total);
! 775: if (rc < 0) {
! 776: ISTGT_ERRLOG("iscsi_write() failed (errno=%d)\n",
! 777: errno);
! 778: return -1;
! 779: }
! 780: if (rc != total) {
! 781: ISTGT_ERRLOG("incomplete PDU length (%d)\n", rc);
! 782: return -1;
! 783: }
! 784: return total - pad_len;
! 785: }
! 786: #endif /* ISTGT_USE_SHORTPDU_WRITE */
! 787:
! 788: /* BHS */
! 789: ISTGT_TRACELOG(ISTGT_TRACE_NET, "BHS write %d\n",
! 790: ISCSI_BHS_LEN);
! 791: rc = istgt_iscsi_write(conn, &pdu->bhs, ISCSI_BHS_LEN);
! 792: if (rc < 0) {
! 793: ISTGT_ERRLOG("iscsi_write() failed (errno=%d)\n", errno);
! 794: return -1;
! 795: }
! 796: if (rc != ISCSI_BHS_LEN) {
! 797: ISTGT_ERRLOG("incomplete BHS length (%d)\n", rc);
! 798: return -1;
! 799: }
! 800: total += ISCSI_BHS_LEN;
! 801:
! 802: /* AHS */
! 803: if (total_ahs_len != 0) {
! 804: ISTGT_TRACELOG(ISTGT_TRACE_NET, "AHS write %d\n",
! 805: (4 * total_ahs_len));
! 806: rc = istgt_iscsi_write(conn, pdu->ahs, (4 * total_ahs_len));
! 807: if (rc < 0) {
! 808: ISTGT_ERRLOG("iscsi_write() failed\n");
! 809: return -1;
! 810: }
! 811: if (rc != (4 * total_ahs_len)) {
! 812: ISTGT_ERRLOG("incomplete AHS length (%d)\n", rc);
! 813: return -1;
! 814: }
! 815: total += (4 * total_ahs_len);
! 816: }
! 817:
! 818: /* Header Digest */
! 819: if (enable_digest && conn->header_digest) {
! 820: if (total_ahs_len == 0) {
! 821: crc32c = istgt_crc32c((uint8_t *) &pdu->bhs,
! 822: ISCSI_BHS_LEN);
! 823: } else {
! 824: int upd_total = 0;
! 825: crc32c = ISTGT_CRC32C_INITIAL;
! 826: crc32c = istgt_update_crc32c((uint8_t *) &pdu->bhs,
! 827: ISCSI_BHS_LEN, crc32c);
! 828: upd_total += ISCSI_BHS_LEN;
! 829: crc32c = istgt_update_crc32c((uint8_t *) pdu->ahs,
! 830: (4 * total_ahs_len), crc32c);
! 831: upd_total += (4 * total_ahs_len);
! 832: crc32c = istgt_fixup_crc32c(upd_total, crc32c);
! 833: crc32c = crc32c ^ ISTGT_CRC32C_XOR;
! 834: }
! 835: MAKE_DIGEST_WORD(pdu->header_digest, crc32c);
! 836:
! 837: ISTGT_TRACELOG(ISTGT_TRACE_NET, "HeaderDigest write %d\n",
! 838: ISCSI_DIGEST_LEN);
! 839: rc = istgt_iscsi_write(conn, pdu->header_digest,
! 840: ISCSI_DIGEST_LEN);
! 841: if (rc < 0) {
! 842: ISTGT_ERRLOG("iscsi_write() failed\n");
! 843: return -1;
! 844: }
! 845: if (rc != ISCSI_DIGEST_LEN) {
! 846: ISTGT_ERRLOG("incomplete Header Digest length (%d)\n",
! 847: rc);
! 848: return -1;
! 849: }
! 850: total += ISCSI_DIGEST_LEN;
! 851: }
! 852:
! 853: /* Data Segment */
! 854: if (data_len != 0) {
! 855: ISTGT_TRACELOG(ISTGT_TRACE_NET, "Data write %d\n",
! 856: data_len);
! 857: rc = istgt_iscsi_write(conn, pdu->data, data_len);
! 858: if (rc < 0) {
! 859: ISTGT_ERRLOG("iscsi_write() failed\n");
! 860: return -1;
! 861: }
! 862: if (rc != data_len) {
! 863: ISTGT_ERRLOG("incomplete Data Segment length (%d)\n",
! 864: rc);
! 865: return -1;
! 866: }
! 867: total += data_len;
! 868: }
! 869:
! 870: /* Data Digest */
! 871: if (enable_digest && conn->data_digest && data_len != 0) {
! 872: crc32c = istgt_crc32c(pdu->data, data_len);
! 873: MAKE_DIGEST_WORD(pdu->data_digest, crc32c);
! 874:
! 875: ISTGT_TRACELOG(ISTGT_TRACE_NET, "DataDigest write %d\n",
! 876: ISCSI_DIGEST_LEN);
! 877: ISTGT_TRACELOG(ISTGT_TRACE_NET, "DataDigest %x\n",
! 878: crc32c);
! 879: rc = istgt_iscsi_write(conn, pdu->data_digest,
! 880: ISCSI_DIGEST_LEN);
! 881: if (rc < 0) {
! 882: ISTGT_ERRLOG("iscsi_write() failed\n");
! 883: return -1;
! 884: }
! 885: if (rc != ISCSI_DIGEST_LEN) {
! 886: ISTGT_ERRLOG("incomplete Data Digest length (%d)\n",
! 887: rc);
! 888: return -1;
! 889: }
! 890: total += ISCSI_DIGEST_LEN;
! 891: }
! 892:
! 893: return total;
! 894: }
! 895:
! 896: int
! 897: istgt_iscsi_copy_pdu(ISCSI_PDU_Ptr dst_pdu, ISCSI_PDU_Ptr src_pdu)
! 898: {
! 899: memcpy(&dst_pdu->bhs, &src_pdu->bhs, ISCSI_BHS_LEN);
! 900: dst_pdu->ahs = src_pdu->ahs;
! 901: memcpy(dst_pdu->header_digest, src_pdu->header_digest,
! 902: ISCSI_DIGEST_LEN);
! 903: if (src_pdu->data == src_pdu->shortdata) {
! 904: memcpy(dst_pdu->shortdata, src_pdu->shortdata,
! 905: sizeof src_pdu->shortdata);
! 906: dst_pdu->data = dst_pdu->shortdata;
! 907: } else {
! 908: dst_pdu->data = src_pdu->data;
! 909: }
! 910: memcpy(dst_pdu->data_digest, src_pdu->data_digest, ISCSI_DIGEST_LEN);
! 911: dst_pdu->total_ahs_len = src_pdu->total_ahs_len;
! 912: dst_pdu->data_segment_len = src_pdu->data_segment_len;
! 913: dst_pdu->copy_pdu = 0;
! 914: src_pdu->copy_pdu = 1;
! 915: return 0;
! 916: }
! 917:
! 918: typedef struct iscsi_param_table_t
! 919: {
! 920: const char *key;
! 921: const char *val;
! 922: const char *list;
! 923: int type;
! 924: } ISCSI_PARAM_TABLE;
! 925:
! 926: static ISCSI_PARAM_TABLE conn_param_table[] =
! 927: {
! 928: { "HeaderDigest", "None", "CRC32C,None", ISPT_LIST },
! 929: { "DataDigest", "None", "CRC32C,None", ISPT_LIST },
! 930: { "MaxRecvDataSegmentLength", "8192", "512,16777215", ISPT_NUMERICAL },
! 931: { "OFMarker", "No", "Yes,No", ISPT_BOOLEAN_AND },
! 932: { "IFMarker", "No", "Yes,No", ISPT_BOOLEAN_AND },
! 933: { "OFMarkInt", "1", "1,65535", ISPT_NUMERICAL },
! 934: { "IFMarkInt", "1", "1,65535", ISPT_NUMERICAL },
! 935: { "AuthMethod", "None", "CHAP,None", ISPT_LIST },
! 936: { "CHAP_A", "5", "5", ISPT_LIST },
! 937: { "CHAP_N", "", "", ISPT_DECLARATIVE },
! 938: { "CHAP_R", "", "", ISPT_DECLARATIVE },
! 939: { "CHAP_I", "", "", ISPT_DECLARATIVE },
! 940: { "CHAP_C", "", "", ISPT_DECLARATIVE },
! 941: { NULL, NULL, NULL, ISPT_INVALID },
! 942: };
! 943:
! 944: static ISCSI_PARAM_TABLE sess_param_table[] =
! 945: {
! 946: { "MaxConnections", "1", "1,65535", ISPT_NUMERICAL },
! 947: #if 0
! 948: /* need special handling */
! 949: { "SendTargets", "", "", ISPT_DECLARATIVE },
! 950: #endif
! 951: { "TargetName", "", "", ISPT_DECLARATIVE },
! 952: { "InitiatorName", "", "", ISPT_DECLARATIVE },
! 953: { "TargetAlias", "", "", ISPT_DECLARATIVE },
! 954: { "InitiatorAlias", "", "", ISPT_DECLARATIVE },
! 955: { "TargetAddress", "", "", ISPT_DECLARATIVE },
! 956: { "TargetPortalGroupTag", "1", "1,65535", ISPT_NUMERICAL },
! 957: { "InitialR2T", "Yes", "Yes,No", ISPT_BOOLEAN_OR },
! 958: { "ImmediateData", "Yes", "Yes,No", ISPT_BOOLEAN_AND },
! 959: { "MaxBurstLength", "262144", "512,16777215", ISPT_NUMERICAL },
! 960: { "FirstBurstLength", "65536", "512,16777215", ISPT_NUMERICAL },
! 961: { "DefaultTime2Wait", "2", "0,3600", ISPT_NUMERICAL_MAX },
! 962: { "DefaultTime2Retain", "20", "0,3600", ISPT_NUMERICAL },
! 963: { "MaxOutstandingR2T", "1", "1,65536", ISPT_NUMERICAL },
! 964: { "DataPDUInOrder", "Yes", "Yes,No", ISPT_BOOLEAN_OR },
! 965: { "DataSequenceInOrder", "Yes", "Yes,No", ISPT_BOOLEAN_OR },
! 966: { "ErrorRecoveryLevel", "0", "0,2", ISPT_NUMERICAL },
! 967: { "SessionType", "Normal", "Normal,Discovery", ISPT_DECLARATIVE },
! 968: { NULL, NULL, NULL, ISPT_INVALID },
! 969: };
! 970:
! 971: static int
! 972: istgt_iscsi_params_init_internal(ISCSI_PARAM **params, ISCSI_PARAM_TABLE *table)
! 973: {
! 974: int rc;
! 975: int i;
! 976:
! 977: for (i = 0; table[i].key != NULL; i++) {
! 978: rc = istgt_iscsi_param_add(params, table[i].key, table[i].val,
! 979: table[i].list, table[i].type);
! 980: if (rc < 0) {
! 981: ISTGT_ERRLOG("iscsi_param_add() failed\n");
! 982: return -1;
! 983: }
! 984: }
! 985:
! 986: return 0;
! 987: }
! 988:
! 989: static int
! 990: istgt_iscsi_conn_params_init(ISCSI_PARAM **params)
! 991: {
! 992: return istgt_iscsi_params_init_internal(params, &conn_param_table[0]);
! 993: }
! 994:
! 995: static int
! 996: istgt_iscsi_sess_params_init(ISCSI_PARAM **params)
! 997: {
! 998: return istgt_iscsi_params_init_internal(params, &sess_param_table[0]);
! 999: }
! 1000:
! 1001: static char *
! 1002: istgt_iscsi_param_get_val(ISCSI_PARAM *params, const char *key)
! 1003: {
! 1004: ISCSI_PARAM *param;
! 1005:
! 1006: param = istgt_iscsi_param_find(params, key);
! 1007: if (param == NULL)
! 1008: return NULL;
! 1009: return param->val;
! 1010: }
! 1011:
! 1012: static int
! 1013: istgt_iscsi_param_eq_val(ISCSI_PARAM *params, const char *key, const char *val)
! 1014: {
! 1015: ISCSI_PARAM *param;
! 1016:
! 1017: param = istgt_iscsi_param_find(params, key);
! 1018: if (param == NULL)
! 1019: return 0;
! 1020: if (strcasecmp(param->val, val) == 0)
! 1021: return 1;
! 1022: return 0;
! 1023: }
! 1024:
! 1025: #if 0
! 1026: static int
! 1027: istgt_iscsi_print_params(ISCSI_PARAM *params)
! 1028: {
! 1029: ISCSI_PARAM *param;
! 1030:
! 1031: for (param = params; param != NULL; param = param->next) {
! 1032: printf("key=[%s] val=[%s] list=[%s] type=%d\n",
! 1033: param->key, param->val, param->list, param->type);
! 1034: }
! 1035: return 0;
! 1036: }
! 1037: #endif
! 1038:
! 1039: static int
! 1040: istgt_iscsi_negotiate_params(CONN_Ptr conn, ISCSI_PARAM *params, uint8_t *data, int alloc_len, int data_len)
! 1041: {
! 1042: ISCSI_PARAM *param;
! 1043: ISCSI_PARAM *cur_param;
! 1044: char *valid_list, *in_val;
! 1045: char *valid_next, *in_next;
! 1046: char *cur_val;
! 1047: char *new_val;
! 1048: char *valid_val;
! 1049: char *min_val, *max_val;
! 1050: int discovery;
! 1051: int cur_type;
! 1052: int val_i, cur_val_i;
! 1053: int min_i, max_i;
! 1054: int total;
! 1055: int len;
! 1056: int sw;
! 1057:
! 1058: total = data_len;
! 1059: if (alloc_len < 1) {
! 1060: return 0;
! 1061: }
! 1062: if (total > alloc_len) {
! 1063: total = alloc_len;
! 1064: data[total - 1] = '\0';
! 1065: return total;
! 1066: }
! 1067:
! 1068: if (params == NULL) {
! 1069: /* no input */
! 1070: return total;
! 1071: }
! 1072:
! 1073: /* discovery? */
! 1074: discovery = 0;
! 1075: cur_param = istgt_iscsi_param_find(params, "SessionType");
! 1076: if (cur_param == NULL) {
! 1077: SESS_MTX_LOCK(conn);
! 1078: cur_param = istgt_iscsi_param_find(conn->sess->params, "SessionType");
! 1079: if (cur_param == NULL) {
! 1080: /* no session type */
! 1081: } else {
! 1082: if (strcasecmp(cur_param->val, "Discovery") == 0) {
! 1083: discovery = 1;
! 1084: }
! 1085: }
! 1086: SESS_MTX_UNLOCK(conn);
! 1087: } else {
! 1088: if (strcasecmp(cur_param->val, "Discovery") == 0) {
! 1089: discovery = 1;
! 1090: }
! 1091: }
! 1092:
! 1093: /* for temporary store */
! 1094: valid_list = xmalloc(ISCSI_TEXT_MAX_VAL_LEN + 1);
! 1095: in_val = xmalloc(ISCSI_TEXT_MAX_VAL_LEN + 1);
! 1096: cur_val = xmalloc(ISCSI_TEXT_MAX_VAL_LEN + 1);
! 1097:
! 1098: for (param = params; param != NULL; param = param->next) {
! 1099: /* sendtargets is special */
! 1100: if (strcasecmp(param->key, "SendTargets") == 0) {
! 1101: continue;
! 1102: }
! 1103: /* CHAP keys */
! 1104: if (strcasecmp(param->key, "CHAP_A") == 0
! 1105: || strcasecmp(param->key, "CHAP_N") == 0
! 1106: || strcasecmp(param->key, "CHAP_R") == 0
! 1107: || strcasecmp(param->key, "CHAP_I") == 0
! 1108: || strcasecmp(param->key, "CHAP_C") == 0) {
! 1109: continue;
! 1110: }
! 1111:
! 1112: if (discovery) {
! 1113: /* 12.2, 12.10, 12.11, 12.13, 12.14, 12.17, 12.18, 12.19 */
! 1114: if (strcasecmp(param->key, "MaxConnections") == 0
! 1115: || strcasecmp(param->key, "InitialR2T") == 0
! 1116: || strcasecmp(param->key, "ImmediateData") == 0
! 1117: || strcasecmp(param->key, "MaxBurstLength") == 0
! 1118: || strcasecmp(param->key, "FirstBurstLength") == 0
! 1119: || strcasecmp(param->key, "MaxOutstandingR2T") == 0
! 1120: || strcasecmp(param->key, "DataPDUInOrder") == 0
! 1121: || strcasecmp(param->key, "DataSequenceInOrder") == 0) {
! 1122: strlcpy(in_val, "Irrelevant",
! 1123: ISCSI_TEXT_MAX_VAL_LEN);
! 1124: new_val = in_val;
! 1125: cur_type = -1;
! 1126: goto add_val;
! 1127: }
! 1128: }
! 1129:
! 1130: /* get current param */
! 1131: sw = 0;
! 1132: cur_param = istgt_iscsi_param_find(conn->params, param->key);
! 1133: if (cur_param == NULL) {
! 1134: sw = 1;
! 1135: SESS_MTX_LOCK(conn);
! 1136: cur_param = istgt_iscsi_param_find(conn->sess->params,
! 1137: param->key);
! 1138: if (cur_param == NULL) {
! 1139: SESS_MTX_UNLOCK(conn);
! 1140: if (strncasecmp(param->key, "X-", 2) == 0
! 1141: || strncasecmp(param->key, "X#", 2) == 0) {
! 1142: /* Extension Key */
! 1143: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 1144: "extension key %.64s\n",
! 1145: param->key);
! 1146: } else {
! 1147: ISTGT_ERRLOG("unknown key %.64s\n",
! 1148: param->key);
! 1149: }
! 1150: strlcpy(in_val, "NotUnderstood",
! 1151: ISCSI_TEXT_MAX_VAL_LEN);
! 1152: new_val = in_val;
! 1153: cur_type = -1;
! 1154: goto add_val;
! 1155: }
! 1156: strlcpy(valid_list, cur_param->list,
! 1157: ISCSI_TEXT_MAX_VAL_LEN);
! 1158: strlcpy(cur_val, cur_param->val,
! 1159: ISCSI_TEXT_MAX_VAL_LEN);
! 1160: cur_type = cur_param->type;
! 1161: SESS_MTX_UNLOCK(conn);
! 1162: } else {
! 1163: strlcpy(valid_list, cur_param->list,
! 1164: ISCSI_TEXT_MAX_VAL_LEN);
! 1165: strlcpy(cur_val, cur_param->val,
! 1166: ISCSI_TEXT_MAX_VAL_LEN);
! 1167: cur_type = cur_param->type;
! 1168: }
! 1169:
! 1170: /* negotiate value */
! 1171: switch (cur_type) {
! 1172: case ISPT_LIST:
! 1173: strlcpy(in_val, param->val, ISCSI_TEXT_MAX_VAL_LEN);
! 1174: in_next = in_val;
! 1175: while ((new_val = strsepq(&in_next, ",")) != NULL) {
! 1176: valid_next = valid_list;
! 1177: while ((valid_val = strsepq(&valid_next, ",")) != NULL) {
! 1178: if (strcasecmp(new_val, valid_val) == 0) {
! 1179: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "match %s\n",
! 1180: new_val);
! 1181: goto update_val;
! 1182: }
! 1183: }
! 1184: }
! 1185: if (new_val == NULL) {
! 1186: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 1187: "key %.64s reject\n",
! 1188: param->key);
! 1189: strlcpy(in_val, "Reject",
! 1190: ISCSI_TEXT_MAX_VAL_LEN);
! 1191: new_val = in_val;
! 1192: goto add_val;
! 1193: }
! 1194: break;
! 1195:
! 1196: case ISPT_NUMERICAL:
! 1197: val_i = (int) strtol(param->val, NULL, 10);
! 1198: cur_val_i = (int) strtol(cur_val, NULL, 10);
! 1199: valid_next = valid_list;
! 1200: min_val = strsepq(&valid_next, ",");
! 1201: max_val = strsepq(&valid_next, ",");
! 1202: if (min_val != NULL) {
! 1203: min_i = (int) strtol(min_val, NULL, 10);
! 1204: } else {
! 1205: min_i = 0;
! 1206: }
! 1207: if (max_val != NULL) {
! 1208: max_i = (int) strtol(max_val, NULL, 10);
! 1209: } else {
! 1210: max_i = 0;
! 1211: }
! 1212: if (val_i < min_i || val_i > max_i) {
! 1213: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 1214: "key %.64s reject\n",
! 1215: param->key);
! 1216: strlcpy(in_val, "Reject",
! 1217: ISCSI_TEXT_MAX_VAL_LEN);
! 1218: new_val = in_val;
! 1219: goto add_val;
! 1220: }
! 1221: if (strcasecmp(param->key, "MaxRecvDataSegmentLength") == 0) {
! 1222: /* Declarative, but set as same value */
! 1223: cur_val_i = conn->TargetMaxRecvDataSegmentLength;
! 1224: }
! 1225: if (val_i > cur_val_i) {
! 1226: val_i = cur_val_i;
! 1227: }
! 1228: snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN, "%d", val_i);
! 1229: new_val = in_val;
! 1230: break;
! 1231:
! 1232: case ISPT_NUMERICAL_MAX:
! 1233: val_i = (int) strtol(param->val, NULL, 10);
! 1234: cur_val_i = (int) strtol(cur_val, NULL, 10);
! 1235: valid_next = valid_list;
! 1236: min_val = strsepq(&valid_next, ",");
! 1237: max_val = strsepq(&valid_next, ",");
! 1238: if (min_val != NULL) {
! 1239: min_i = (int) strtol(min_val, NULL, 10);
! 1240: } else {
! 1241: min_i = 0;
! 1242: }
! 1243: if (max_val != NULL) {
! 1244: max_i = (int) strtol(max_val, NULL, 10);
! 1245: } else {
! 1246: max_i = 0;
! 1247: }
! 1248: if (val_i < min_i || val_i > max_i) {
! 1249: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 1250: "key %.64s reject\n",
! 1251: param->key);
! 1252: strlcpy(in_val, "Reject",
! 1253: ISCSI_TEXT_MAX_VAL_LEN);
! 1254: new_val = in_val;
! 1255: goto add_val;
! 1256: }
! 1257: if (val_i < cur_val_i) {
! 1258: val_i = cur_val_i;
! 1259: }
! 1260: snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN, "%d", val_i);
! 1261: new_val = in_val;
! 1262: break;
! 1263:
! 1264: case ISPT_BOOLEAN_OR:
! 1265: if (strcasecmp(cur_val, "Yes") == 0) {
! 1266: /* YES || XXX */
! 1267: strlcpy(in_val, "Yes", ISCSI_TEXT_MAX_VAL_LEN);
! 1268: new_val = in_val;
! 1269: } else {
! 1270: if (strcasecmp(param->val, "Yes") == 0
! 1271: || strcasecmp(param->val, "No") == 0) {
! 1272: new_val = param->val;
! 1273: } else {
! 1274: /* unknown value */
! 1275: strlcpy(in_val, "Reject",
! 1276: ISCSI_TEXT_MAX_VAL_LEN);
! 1277: new_val = in_val;
! 1278: goto add_val;
! 1279: }
! 1280: }
! 1281: break;
! 1282:
! 1283: case ISPT_BOOLEAN_AND:
! 1284: if (strcasecmp(cur_val, "No") == 0) {
! 1285: /* No && XXX */
! 1286: strlcpy(in_val, "No", ISCSI_TEXT_MAX_VAL_LEN);
! 1287: new_val = in_val;
! 1288: } else {
! 1289: if (strcasecmp(param->val, "Yes") == 0
! 1290: || strcasecmp(param->val, "No") == 0) {
! 1291: new_val = param->val;
! 1292: } else {
! 1293: /* unknown value */
! 1294: strlcpy(in_val, "Reject",
! 1295: ISCSI_TEXT_MAX_VAL_LEN);
! 1296: new_val = in_val;
! 1297: goto add_val;
! 1298: }
! 1299: }
! 1300: break;
! 1301:
! 1302: case ISPT_DECLARATIVE:
! 1303: strlcpy(in_val, param->val, ISCSI_TEXT_MAX_VAL_LEN);
! 1304: new_val = in_val;
! 1305: break;
! 1306:
! 1307: default:
! 1308: strlcpy(in_val, param->val, ISCSI_TEXT_MAX_VAL_LEN);
! 1309: new_val = in_val;
! 1310: break;
! 1311: }
! 1312:
! 1313: update_val:
! 1314: if (sw) {
! 1315: /* update session wide */
! 1316: SESS_MTX_LOCK(conn);
! 1317: istgt_iscsi_param_set(conn->sess->params, param->key,
! 1318: new_val);
! 1319: SESS_MTX_UNLOCK(conn);
! 1320: } else {
! 1321: /* update connection only */
! 1322: istgt_iscsi_param_set(conn->params, param->key,
! 1323: new_val);
! 1324: }
! 1325: add_val:
! 1326: if (cur_type != ISPT_DECLARATIVE) {
! 1327: if (alloc_len - total < 1) {
! 1328: ISTGT_ERRLOG("data space small %d\n",
! 1329: alloc_len);
! 1330: return total;
! 1331: }
! 1332: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, "negotiated %s=%s\n",
! 1333: param->key, new_val);
! 1334: len = snprintf((char *) data + total,
! 1335: alloc_len - total, "%s=%s",
! 1336: param->key, new_val);
! 1337: total += len + 1;
! 1338: }
! 1339: }
! 1340:
! 1341: xfree(valid_list);
! 1342: xfree(in_val);
! 1343: xfree(cur_val);
! 1344:
! 1345: return total;
! 1346: }
! 1347:
! 1348: static int
! 1349: istgt_iscsi_append_text(CONN_Ptr conn, const char *key, const char *val, uint8_t *data, int alloc_len, int data_len)
! 1350: {
! 1351: int total;
! 1352: int len;
! 1353:
! 1354: total = data_len;
! 1355: if (alloc_len < 1) {
! 1356: return 0;
! 1357: }
! 1358: if (total > alloc_len) {
! 1359: total = alloc_len;
! 1360: data[total - 1] = '\0';
! 1361: return total;
! 1362: }
! 1363:
! 1364: if (alloc_len - total < 1) {
! 1365: ISTGT_ERRLOG("data space small %d\n", alloc_len);
! 1366: return total;
! 1367: }
! 1368: len = snprintf((char *) data + total, alloc_len - total, "%s=%s",
! 1369: key, val);
! 1370: total += len + 1;
! 1371:
! 1372: return total;
! 1373: }
! 1374:
! 1375: static int
! 1376: istgt_iscsi_append_param(CONN_Ptr conn, const char *key, uint8_t *data, int alloc_len, int data_len)
! 1377: {
! 1378: ISCSI_PARAM *param;
! 1379: int rc;
! 1380:
! 1381: param = istgt_iscsi_param_find(conn->params, key);
! 1382: if (param == NULL) {
! 1383: param = istgt_iscsi_param_find(conn->sess->params, key);
! 1384: if (param == NULL) {
! 1385: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "no key %.64s\n",
! 1386: key);
! 1387: return data_len;
! 1388: }
! 1389: }
! 1390: rc = istgt_iscsi_append_text(conn, param->key, param->val, data,
! 1391: alloc_len, data_len);
! 1392: return rc;
! 1393: }
! 1394:
! 1395: int
! 1396: istgt_chap_get_authinfo(ISTGT_CHAP_AUTH *auth, const char *authfile, const char *authuser, int ag_tag)
! 1397: {
! 1398: CONFIG *config = NULL;
! 1399: CF_SECTION *sp;
! 1400: const char *val;
! 1401: const char *user, *muser;
! 1402: const char *secret, *msecret;
! 1403: int rc;
! 1404: int i;
! 1405:
! 1406: if (auth->user != NULL) {
! 1407: xfree(auth->user);
! 1408: xfree(auth->secret);
! 1409: xfree(auth->muser);
! 1410: xfree(auth->msecret);
! 1411: auth->user = auth->secret = NULL;
! 1412: auth->muser = auth->msecret = NULL;
! 1413: }
! 1414:
! 1415: /* read config files */
! 1416: config = istgt_allocate_config();
! 1417: rc = istgt_read_config(config, authfile);
! 1418: if (rc < 0) {
! 1419: ISTGT_ERRLOG("auth conf error\n");
! 1420: istgt_free_config(config);
! 1421: return -1;
! 1422: }
! 1423: //istgt_print_config(config);
! 1424:
! 1425: sp = config->section;
! 1426: while (sp != NULL) {
! 1427: if (sp->type == ST_AUTHGROUP) {
! 1428: if (sp->num == 0) {
! 1429: ISTGT_ERRLOG("Group 0 is invalid\n");
! 1430: istgt_free_config(config);
! 1431: return -1;
! 1432: }
! 1433: if (ag_tag != sp->num) {
! 1434: goto skip_ag_tag;
! 1435: }
! 1436:
! 1437: val = istgt_get_val(sp, "Comment");
! 1438: if (val != NULL) {
! 1439: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 1440: "Comment %s\n", val);
! 1441: }
! 1442: for (i = 0; ; i++) {
! 1443: val = istgt_get_nval(sp, "Auth", i);
! 1444: if (val == NULL)
! 1445: break;
! 1446: user = istgt_get_nmval(sp, "Auth", i, 0);
! 1447: secret = istgt_get_nmval(sp, "Auth", i, 1);
! 1448: muser = istgt_get_nmval(sp, "Auth", i, 2);
! 1449: msecret = istgt_get_nmval(sp, "Auth", i, 3);
! 1450: if (strcasecmp(authuser, user) == 0) {
! 1451: /* match user */
! 1452: auth->user = xstrdup(user);
! 1453: auth->secret = xstrdup(secret);
! 1454: auth->muser = xstrdup(muser);
! 1455: auth->msecret = xstrdup(msecret);
! 1456: istgt_free_config(config);
! 1457: return 0;
! 1458: }
! 1459: }
! 1460: }
! 1461: skip_ag_tag:
! 1462: sp = sp->next;
! 1463: }
! 1464:
! 1465: istgt_free_config(config);
! 1466: return 0;
! 1467: }
! 1468:
! 1469: static int
! 1470: istgt_iscsi_get_authinfo(CONN_Ptr conn, const char *authuser)
! 1471: {
! 1472: char *authfile = NULL;
! 1473: int ag_tag;
! 1474: int rc;
! 1475:
! 1476: SESS_MTX_LOCK(conn);
! 1477: if (conn->sess->lu != NULL) {
! 1478: ag_tag = conn->sess->lu->auth_group;
! 1479: } else {
! 1480: ag_tag = -1;
! 1481: }
! 1482: SESS_MTX_UNLOCK(conn);
! 1483: if (ag_tag < 0) {
! 1484: MTX_LOCK(&conn->istgt->mutex);
! 1485: ag_tag = conn->istgt->discovery_auth_group;
! 1486: MTX_UNLOCK(&conn->istgt->mutex);
! 1487: }
! 1488: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "ag_tag=%d\n", ag_tag);
! 1489:
! 1490: MTX_LOCK(&conn->istgt->mutex);
! 1491: authfile = xstrdup(conn->istgt->authfile);
! 1492: MTX_UNLOCK(&conn->istgt->mutex);
! 1493:
! 1494: rc = istgt_chap_get_authinfo(&conn->auth, authfile, authuser, ag_tag);
! 1495: if (rc < 0) {
! 1496: ISTGT_ERRLOG("chap_get_authinfo() failed\n");
! 1497: xfree(authfile);
! 1498: return -1;
! 1499: }
! 1500: xfree(authfile);
! 1501: return 0;
! 1502: }
! 1503:
! 1504: static int
! 1505: istgt_iscsi_auth_params(CONN_Ptr conn, ISCSI_PARAM *params, const char *method, uint8_t *data, int alloc_len, int data_len)
! 1506: {
! 1507: char *in_val;
! 1508: char *in_next;
! 1509: char *new_val;
! 1510: const char *val;
! 1511: const char *user;
! 1512: const char *response;
! 1513: const char *challenge;
! 1514: int total;
! 1515: int rc;
! 1516:
! 1517: if (conn == NULL || params == NULL || method == NULL) {
! 1518: return -1;
! 1519: }
! 1520: if (strcasecmp(method, "CHAP") == 0) {
! 1521: /* method OK */
! 1522: } else {
! 1523: ISTGT_ERRLOG("unsupported AuthMethod %.64s\n", method);
! 1524: return -1;
! 1525: }
! 1526:
! 1527: total = data_len;
! 1528: if (alloc_len < 1) {
! 1529: return 0;
! 1530: }
! 1531: if (total > alloc_len) {
! 1532: total = alloc_len;
! 1533: data[total - 1] = '\0';
! 1534: return total;
! 1535: }
! 1536:
! 1537: /* for temporary store */
! 1538: in_val = xmalloc(ISCSI_TEXT_MAX_VAL_LEN + 1);
! 1539:
! 1540: /* CHAP method (RFC1994) */
! 1541: if ((val = ISCSI_GETVAL(params, "CHAP_A")) != NULL) {
! 1542: if (conn->auth.chap_phase != ISTGT_CHAP_PHASE_WAIT_A) {
! 1543: ISTGT_ERRLOG("CHAP sequence error\n");
! 1544: goto error_return;
! 1545: }
! 1546:
! 1547: /* CHAP_A is LIST type */
! 1548: strlcpy(in_val, val, ISCSI_TEXT_MAX_VAL_LEN);
! 1549: in_next = in_val;
! 1550: while ((new_val = strsepq(&in_next, ",")) != NULL) {
! 1551: if (strcasecmp(new_val, "5") == 0) {
! 1552: /* CHAP with MD5 */
! 1553: break;
! 1554: }
! 1555: }
! 1556: if (new_val == NULL) {
! 1557: strlcpy(in_val, "Reject", ISCSI_TEXT_MAX_VAL_LEN);
! 1558: new_val = in_val;
! 1559: total = istgt_iscsi_append_text(conn, "CHAP_A",
! 1560: new_val, data, alloc_len, total);
! 1561: goto error_return;
! 1562: }
! 1563: /* selected algorithm is 5 (MD5) */
! 1564: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "got CHAP_A=%s\n", new_val);
! 1565: total = istgt_iscsi_append_text(conn, "CHAP_A", new_val,
! 1566: data, alloc_len, total);
! 1567:
! 1568: /* Identifier is one octet */
! 1569: istgt_gen_random(conn->auth.chap_id, 1);
! 1570: snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN, "%d",
! 1571: (int) conn->auth.chap_id[0]);
! 1572: total = istgt_iscsi_append_text(conn, "CHAP_I", in_val,
! 1573: data, alloc_len, total);
! 1574:
! 1575: /* Challenge Value is a variable stream of octets */
! 1576: /* (binary length MUST not exceed 1024 bytes) */
! 1577: conn->auth.chap_challenge_len = ISTGT_CHAP_CHALLENGE_LEN;
! 1578: istgt_gen_random(conn->auth.chap_challenge,
! 1579: conn->auth.chap_challenge_len);
! 1580: istgt_bin2hex(in_val, ISCSI_TEXT_MAX_VAL_LEN,
! 1581: conn->auth.chap_challenge,
! 1582: conn->auth.chap_challenge_len);
! 1583: total = istgt_iscsi_append_text(conn, "CHAP_C", in_val,
! 1584: data, alloc_len, total);
! 1585:
! 1586: conn->auth.chap_phase = ISTGT_CHAP_PHASE_WAIT_NR;
! 1587: } else if ((val = ISCSI_GETVAL(params, "CHAP_N")) != NULL) {
! 1588: uint8_t resmd5[ISTGT_MD5DIGEST_LEN];
! 1589: uint8_t tgtmd5[ISTGT_MD5DIGEST_LEN];
! 1590: ISTGT_MD5CTX md5ctx;
! 1591:
! 1592: user = val;
! 1593: if (conn->auth.chap_phase != ISTGT_CHAP_PHASE_WAIT_NR) {
! 1594: ISTGT_ERRLOG("CHAP sequence error\n");
! 1595: goto error_return;
! 1596: }
! 1597:
! 1598: response = ISCSI_GETVAL(params, "CHAP_R");
! 1599: if (response == NULL) {
! 1600: ISTGT_ERRLOG("no response\n");
! 1601: goto error_return;
! 1602: }
! 1603: rc = istgt_hex2bin(resmd5, ISTGT_MD5DIGEST_LEN, response);
! 1604: if (rc < 0 || rc != ISTGT_MD5DIGEST_LEN) {
! 1605: ISTGT_ERRLOG("response format error\n");
! 1606: goto error_return;
! 1607: }
! 1608: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "got CHAP_N/CHAP_R\n");
! 1609:
! 1610: rc = istgt_iscsi_get_authinfo(conn, val);
! 1611: if (rc < 0) {
! 1612: //ISTGT_ERRLOG("auth user or secret is missing\n");
! 1613: ISTGT_ERRLOG("iscsi_get_authinfo() failed\n");
! 1614: goto error_return;
! 1615: }
! 1616: if (conn->auth.user == NULL || conn->auth.secret == NULL) {
! 1617: //ISTGT_ERRLOG("auth user or secret is missing\n");
! 1618: ISTGT_ERRLOG("auth failed (user %.64s)\n", user);
! 1619: goto error_return;
! 1620: }
! 1621:
! 1622: istgt_md5init(&md5ctx);
! 1623: /* Identifier */
! 1624: istgt_md5update(&md5ctx, conn->auth.chap_id, 1);
! 1625: /* followed by secret */
! 1626: istgt_md5update(&md5ctx, conn->auth.secret,
! 1627: strlen(conn->auth.secret));
! 1628: /* followed by Challenge Value */
! 1629: istgt_md5update(&md5ctx, conn->auth.chap_challenge,
! 1630: conn->auth.chap_challenge_len);
! 1631: /* tgtmd5 is expecting Response Value */
! 1632: istgt_md5final(tgtmd5, &md5ctx);
! 1633:
! 1634: istgt_bin2hex(in_val, ISCSI_TEXT_MAX_VAL_LEN,
! 1635: tgtmd5, ISTGT_MD5DIGEST_LEN);
! 1636:
! 1637: #if 0
! 1638: printf("tgtmd5=%s, resmd5=%s\n", in_val, response);
! 1639: istgt_dump("tgtmd5", tgtmd5, ISTGT_MD5DIGEST_LEN);
! 1640: istgt_dump("resmd5", resmd5, ISTGT_MD5DIGEST_LEN);
! 1641: #endif
! 1642:
! 1643: /* compare MD5 digest */
! 1644: if (memcmp(tgtmd5, resmd5, ISTGT_MD5DIGEST_LEN) != 0) {
! 1645: /* not match */
! 1646: //ISTGT_ERRLOG("auth user or secret is missing\n");
! 1647: ISTGT_ERRLOG("auth failed (user %.64s)\n", user);
! 1648: goto error_return;
! 1649: }
! 1650: /* OK initiator's secret */
! 1651: conn->authenticated = 1;
! 1652:
! 1653: /* mutual CHAP? */
! 1654: val = ISCSI_GETVAL(params, "CHAP_I");
! 1655: if (val != NULL) {
! 1656: conn->auth.chap_mid[0] = (uint8_t) strtol(val, NULL, 10);
! 1657: challenge = ISCSI_GETVAL(params, "CHAP_C");
! 1658: if (challenge == NULL) {
! 1659: ISTGT_ERRLOG("CHAP sequence error\n");
! 1660: goto error_return;
! 1661: }
! 1662: rc = istgt_hex2bin(conn->auth.chap_mchallenge,
! 1663: ISTGT_CHAP_CHALLENGE_LEN,
! 1664: challenge);
! 1665: if (rc < 0) {
! 1666: ISTGT_ERRLOG("challenge format error\n");
! 1667: goto error_return;
! 1668: }
! 1669: conn->auth.chap_mchallenge_len = rc;
! 1670: #if 0
! 1671: istgt_dump("MChallenge", conn->auth.chap_mchallenge,
! 1672: conn->auth.chap_mchallenge_len);
! 1673: #endif
! 1674: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 1675: "got CHAP_I/CHAP_C\n");
! 1676:
! 1677: if (conn->auth.muser == NULL || conn->auth.msecret == NULL) {
! 1678: //ISTGT_ERRLOG("mutual auth user or secret is missing\n");
! 1679: ISTGT_ERRLOG("auth failed (user %.64s)\n",
! 1680: user);
! 1681: goto error_return;
! 1682: }
! 1683:
! 1684: istgt_md5init(&md5ctx);
! 1685: /* Identifier */
! 1686: istgt_md5update(&md5ctx, conn->auth.chap_mid, 1);
! 1687: /* followed by secret */
! 1688: istgt_md5update(&md5ctx, conn->auth.msecret,
! 1689: strlen(conn->auth.msecret));
! 1690: /* followed by Challenge Value */
! 1691: istgt_md5update(&md5ctx, conn->auth.chap_mchallenge,
! 1692: conn->auth.chap_mchallenge_len);
! 1693: /* tgtmd5 is Response Value */
! 1694: istgt_md5final(tgtmd5, &md5ctx);
! 1695:
! 1696: istgt_bin2hex(in_val, ISCSI_TEXT_MAX_VAL_LEN,
! 1697: tgtmd5, ISTGT_MD5DIGEST_LEN);
! 1698:
! 1699: total = istgt_iscsi_append_text(conn, "CHAP_N",
! 1700: conn->auth.muser, data, alloc_len, total);
! 1701: total = istgt_iscsi_append_text(conn, "CHAP_R",
! 1702: in_val, data, alloc_len, total);
! 1703: } else {
! 1704: /* not mutual */
! 1705: if (conn->req_mutual) {
! 1706: ISTGT_ERRLOG("required mutual CHAP\n");
! 1707: goto error_return;
! 1708: }
! 1709: }
! 1710:
! 1711: conn->auth.chap_phase = ISTGT_CHAP_PHASE_END;
! 1712: } else {
! 1713: /* not found CHAP keys */
! 1714: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "start CHAP\n");
! 1715: conn->auth.chap_phase = ISTGT_CHAP_PHASE_WAIT_A;
! 1716: }
! 1717:
! 1718: xfree(in_val);
! 1719: return total;
! 1720:
! 1721: error_return:
! 1722: conn->auth.chap_phase = ISTGT_CHAP_PHASE_WAIT_A;
! 1723: xfree(in_val);
! 1724: return -1;
! 1725: }
! 1726:
! 1727: static int
! 1728: istgt_iscsi_reject(CONN_Ptr conn, ISCSI_PDU_Ptr pdu, int reason)
! 1729: {
! 1730: ISCSI_PDU rsp_pdu;
! 1731: uint8_t *rsp;
! 1732: uint8_t *data;
! 1733: int total_ahs_len;
! 1734: int data_len;
! 1735: int alloc_len;
! 1736: int rc;
! 1737:
! 1738: total_ahs_len = DGET8(&pdu->bhs.total_ahs_len);
! 1739: data_len = 0;
! 1740: alloc_len = ISCSI_BHS_LEN + (4 * total_ahs_len);
! 1741: if (conn->header_digest) {
! 1742: alloc_len += ISCSI_DIGEST_LEN;
! 1743: }
! 1744: data = xmalloc(alloc_len);
! 1745: memset(data, 0, alloc_len);
! 1746:
! 1747: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 1748: "Reject PDU reason=%d\n",
! 1749: reason);
! 1750: if (conn->sess != NULL) {
! 1751: SESS_MTX_LOCK(conn);
! 1752: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
! 1753: "StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
! 1754: conn->StatSN, conn->sess->ExpCmdSN,
! 1755: conn->sess->MaxCmdSN);
! 1756: SESS_MTX_UNLOCK(conn);
! 1757: } else {
! 1758: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
! 1759: "StatSN=%u\n",
! 1760: conn->StatSN);
! 1761: }
! 1762:
! 1763: memcpy(data, &pdu->bhs, ISCSI_BHS_LEN);
! 1764: data_len += ISCSI_BHS_LEN;
! 1765: if (total_ahs_len != 0) {
! 1766: memcpy(data + data_len, pdu->ahs, (4 * total_ahs_len));
! 1767: data_len += (4 * total_ahs_len);
! 1768: }
! 1769: if (conn->header_digest) {
! 1770: memcpy(data + data_len, pdu->header_digest, ISCSI_DIGEST_LEN);
! 1771: data_len += ISCSI_DIGEST_LEN;
! 1772: }
! 1773:
! 1774: rsp = (uint8_t *) &rsp_pdu.bhs;
! 1775: rsp_pdu.data = data;
! 1776: memset(rsp, 0, ISCSI_BHS_LEN);
! 1777: rsp[0] = ISCSI_OP_REJECT;
! 1778: BDADD8W(&rsp[1], 1, 7, 1);
! 1779: rsp[2] = reason;
! 1780: rsp[4] = 0; // TotalAHSLength
! 1781: DSET24(&rsp[5], data_len); // DataSegmentLength
! 1782:
! 1783: DSET32(&rsp[16], 0xffffffffU);
! 1784:
! 1785: DSET32(&rsp[24], conn->StatSN);
! 1786: conn->StatSN++;
! 1787: if (conn->sess != NULL) {
! 1788: SESS_MTX_LOCK(conn);
! 1789: DSET32(&rsp[28], conn->sess->ExpCmdSN);
! 1790: DSET32(&rsp[32], conn->sess->MaxCmdSN);
! 1791: SESS_MTX_UNLOCK(conn);
! 1792: } else {
! 1793: DSET32(&rsp[28], 1);
! 1794: DSET32(&rsp[32], 1);
! 1795: }
! 1796: DSET32(&rsp[36], 0); // DataSN/R2TSN
! 1797:
! 1798: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "PDU", rsp, ISCSI_BHS_LEN);
! 1799:
! 1800: rc = istgt_iscsi_write_pdu(conn, &rsp_pdu);
! 1801: if (rc < 0) {
! 1802: ISTGT_ERRLOG("iscsi_write_pdu() failed\n");
! 1803: xfree(data);
! 1804: return -1;
! 1805: }
! 1806:
! 1807: xfree(data);
! 1808: return 0;
! 1809: }
! 1810:
! 1811: static void
! 1812: istgt_iscsi_copy_param2var(CONN_Ptr conn)
! 1813: {
! 1814: const char *val;
! 1815:
! 1816: val = ISCSI_GETVAL(conn->params, "MaxRecvDataSegmentLength");
! 1817: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 1818: "copy MaxRecvDataSegmentLength=%s\n", val);
! 1819: conn->MaxRecvDataSegmentLength = (int) strtol(val, NULL, 10);
! 1820: if (conn->sendbufsize != conn->MaxRecvDataSegmentLength) {
! 1821: xfree(conn->recvbuf);
! 1822: xfree(conn->sendbuf);
! 1823: if (conn->MaxRecvDataSegmentLength < 8192) {
! 1824: conn->recvbufsize = 8192;
! 1825: conn->sendbufsize = 8192;
! 1826: } else {
! 1827: conn->recvbufsize = conn->MaxRecvDataSegmentLength;
! 1828: conn->sendbufsize = conn->MaxRecvDataSegmentLength;
! 1829: }
! 1830: conn->recvbuf = xmalloc(conn->recvbufsize);
! 1831: conn->sendbuf = xmalloc(conn->sendbufsize);
! 1832: }
! 1833: val = ISCSI_GETVAL(conn->params, "HeaderDigest");
! 1834: if (strcasecmp(val, "CRC32C") == 0) {
! 1835: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set HeaderDigest=1\n");
! 1836: conn->header_digest = 1;
! 1837: } else {
! 1838: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set HeaderDigest=0\n");
! 1839: conn->header_digest = 0;
! 1840: }
! 1841: val = ISCSI_GETVAL(conn->params, "DataDigest");
! 1842: if (strcasecmp(val, "CRC32C") == 0) {
! 1843: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set DataDigest=1\n");
! 1844: conn->data_digest = 1;
! 1845: } else {
! 1846: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set DataDigest=0\n");
! 1847: conn->data_digest = 0;
! 1848: }
! 1849:
! 1850: SESS_MTX_LOCK(conn);
! 1851: val = ISCSI_GETVAL(conn->sess->params, "MaxConnections");
! 1852: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "copy MaxConnections=%s\n", val);
! 1853: conn->sess->MaxConnections = (int) strtol(val, NULL, 10);
! 1854: val = ISCSI_GETVAL(conn->sess->params, "MaxOutstandingR2T");
! 1855: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "copy MaxOutstandingR2T=%s\n", val);
! 1856: conn->sess->MaxOutstandingR2T = (int) strtol(val, NULL, 10);
! 1857: conn->MaxOutstandingR2T = conn->sess->MaxOutstandingR2T;
! 1858: val = ISCSI_GETVAL(conn->sess->params, "FirstBurstLength");
! 1859: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "copy FirstBurstLength=%s\n", val);
! 1860: conn->sess->FirstBurstLength = (int) strtol(val, NULL, 10);
! 1861: conn->FirstBurstLength = conn->sess->FirstBurstLength;
! 1862: val = ISCSI_GETVAL(conn->sess->params, "MaxBurstLength");
! 1863: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "copy MaxBurstLength=%s\n", val);
! 1864: conn->sess->MaxBurstLength = (int) strtol(val, NULL, 10);
! 1865: conn->MaxBurstLength = conn->sess->MaxBurstLength;
! 1866: val = ISCSI_GETVAL(conn->sess->params, "InitialR2T");
! 1867: if (strcasecmp(val, "Yes") == 0) {
! 1868: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set InitialR2T=1\n");
! 1869: conn->sess->initial_r2t = 1;
! 1870: } else{
! 1871: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set InitialR2T=0\n");
! 1872: conn->sess->initial_r2t = 0;
! 1873: }
! 1874: val = ISCSI_GETVAL(conn->sess->params, "ImmediateData");
! 1875: if (strcasecmp(val, "Yes") == 0) {
! 1876: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set ImmediateData=1\n");
! 1877: conn->sess->immediate_data = 1;
! 1878: } else {
! 1879: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "set ImmediateData=0\n");
! 1880: conn->sess->immediate_data = 0;
! 1881: }
! 1882: SESS_MTX_UNLOCK(conn);
! 1883: }
! 1884:
! 1885: static int
! 1886: istgt_iscsi_check_values(CONN_Ptr conn)
! 1887: {
! 1888: SESS_MTX_LOCK(conn);
! 1889: if (conn->sess->FirstBurstLength > conn->sess->MaxBurstLength) {
! 1890: ISTGT_ERRLOG("FirstBurstLength(%d) > MaxBurstLength(%d)\n",
! 1891: conn->sess->FirstBurstLength,
! 1892: conn->sess->MaxBurstLength);
! 1893: SESS_MTX_UNLOCK(conn);
! 1894: return -1;
! 1895: }
! 1896: if (conn->sess->MaxBurstLength > 0x00ffffff) {
! 1897: ISTGT_ERRLOG("MaxBurstLength(%d) > 0x00ffffff\n",
! 1898: conn->sess->MaxBurstLength);
! 1899: SESS_MTX_UNLOCK(conn);
! 1900: return -1;
! 1901: }
! 1902: if (conn->TargetMaxRecvDataSegmentLength < 512) {
! 1903: ISTGT_ERRLOG("MaxRecvDataSegmentLength(%d) < 512\n",
! 1904: conn->TargetMaxRecvDataSegmentLength);
! 1905: return -1;
! 1906: }
! 1907: if (conn->TargetMaxRecvDataSegmentLength > 0x00ffffff) {
! 1908: ISTGT_ERRLOG("MaxRecvDataSegmentLength(%d) > 0x00ffffff\n",
! 1909: conn->TargetMaxRecvDataSegmentLength);
! 1910: SESS_MTX_UNLOCK(conn);
! 1911: return -1;
! 1912: }
! 1913: if (conn->MaxRecvDataSegmentLength < 512) {
! 1914: ISTGT_ERRLOG("MaxRecvDataSegmentLength(%d) < 512\n",
! 1915: conn->MaxRecvDataSegmentLength);
! 1916: return -1;
! 1917: }
! 1918: if (conn->MaxRecvDataSegmentLength > 0x00ffffff) {
! 1919: ISTGT_ERRLOG("MaxRecvDataSegmentLength(%d) > 0x00ffffff\n",
! 1920: conn->MaxRecvDataSegmentLength);
! 1921: SESS_MTX_UNLOCK(conn);
! 1922: return -1;
! 1923: }
! 1924: SESS_MTX_UNLOCK(conn);
! 1925: return 0;
! 1926: }
! 1927:
! 1928: static int
! 1929: istgt_iscsi_op_login(CONN_Ptr conn, ISCSI_PDU_Ptr pdu)
! 1930: {
! 1931: char buf[MAX_TMPBUF];
! 1932: ISTGT_LU_Ptr lu = NULL;
! 1933: ISCSI_PARAM *params = NULL;
! 1934: ISCSI_PDU rsp_pdu;
! 1935: uint8_t *rsp;
! 1936: uint8_t *cp;
! 1937: uint8_t *data;
! 1938: const char *session_type;
! 1939: const char *auth_method;
! 1940: const char *val;
! 1941: uint64_t isid;
! 1942: uint16_t tsih;
! 1943: uint16_t cid;
! 1944: uint32_t task_tag;
! 1945: uint32_t CmdSN;
! 1946: uint32_t ExpStatSN;
! 1947: int T_bit, C_bit;
! 1948: int CSG, NSG;
! 1949: int VersionMin, VersionMax;
! 1950: int StatusClass, StatusDetail;
! 1951: int data_len;
! 1952: int alloc_len;
! 1953: int rc;
! 1954:
! 1955: /* Login is proceeding OK */
! 1956: StatusClass = 0x00;
! 1957: StatusDetail = 0x00;
! 1958:
! 1959: data_len = 0;
! 1960:
! 1961: if (conn->MaxRecvDataSegmentLength < 8192) {
! 1962: // Default MaxRecvDataSegmentLength - RFC3720(12.12)
! 1963: alloc_len = 8192;
! 1964: } else {
! 1965: alloc_len = conn->MaxRecvDataSegmentLength;
! 1966: }
! 1967: data = xmalloc(alloc_len);
! 1968: memset(data, 0, alloc_len);
! 1969:
! 1970: cp = (uint8_t *) &pdu->bhs;
! 1971: T_bit = BGET8(&cp[1], 7);
! 1972: C_bit = BGET8(&cp[1], 6);
! 1973: CSG = BGET8W(&cp[1], 3, 2);
! 1974: NSG = BGET8W(&cp[1], 1, 2);
! 1975: VersionMin = cp[2];
! 1976: VersionMax = cp[3];
! 1977:
! 1978: isid = DGET48(&cp[8]);
! 1979: tsih = DGET16(&cp[14]);
! 1980: cid = DGET16(&cp[20]);
! 1981: task_tag = DGET32(&cp[16]);
! 1982: CmdSN = DGET32(&cp[24]);
! 1983: ExpStatSN = DGET32(&cp[28]);
! 1984:
! 1985: #if 1
! 1986: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "PDU", cp, ISCSI_BHS_LEN);
! 1987: #endif
! 1988:
! 1989: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 1990: "T=%d, C=%d, CSG=%d, NSG=%d, Min=%d, Max=%d, ITT=%x\n",
! 1991: T_bit, C_bit, CSG, NSG, VersionMin, VersionMax, task_tag);
! 1992: if (conn->sess != NULL) {
! 1993: SESS_MTX_LOCK(conn);
! 1994: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
! 1995: "CmdSN=%u, ExpStatSN=%u, StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
! 1996: CmdSN, ExpStatSN, conn->StatSN, conn->sess->ExpCmdSN,
! 1997: conn->sess->MaxCmdSN);
! 1998: SESS_MTX_UNLOCK(conn);
! 1999: } else {
! 2000: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
! 2001: "CmdSN=%u, ExpStatSN=%u, StatSN=%u\n",
! 2002: CmdSN, ExpStatSN, conn->StatSN);
! 2003: }
! 2004:
! 2005: if (T_bit && C_bit) {
! 2006: ISTGT_ERRLOG("transit error\n");
! 2007: xfree(data);
! 2008: return -1;
! 2009: }
! 2010: if (VersionMin > ISCSI_VERSION || VersionMax < ISCSI_VERSION) {
! 2011: ISTGT_ERRLOG("unsupported version %d/%d\n", VersionMin, VersionMax);
! 2012: /* Unsupported version */
! 2013: StatusClass = 0x02;
! 2014: StatusDetail = 0x05;
! 2015: goto response;
! 2016: }
! 2017:
! 2018: /* store incoming parameters */
! 2019: rc = istgt_iscsi_parse_params(¶ms, pdu->data, pdu->data_segment_len);
! 2020: if (rc < 0) {
! 2021: ISTGT_ERRLOG("iscsi_parse_params() failed\n");
! 2022: error_return:
! 2023: istgt_iscsi_param_free(params);
! 2024: xfree(data);
! 2025: return -1;
! 2026: }
! 2027:
! 2028: /* set port identifiers and parameters */
! 2029: if (conn->login_phase == ISCSI_LOGIN_PHASE_NONE) {
! 2030: /* Initiator Name and Port */
! 2031: val = ISCSI_GETVAL(params, "InitiatorName");
! 2032: if (val == NULL) {
! 2033: ISTGT_ERRLOG("InitiatorName is empty\n");
! 2034: /* Missing parameter */
! 2035: StatusClass = 0x02;
! 2036: StatusDetail = 0x07;
! 2037: goto response;
! 2038: }
! 2039: snprintf(conn->initiator_name, sizeof conn->initiator_name,
! 2040: "%s", val);
! 2041: snprintf(conn->initiator_port, sizeof conn->initiator_port,
! 2042: "%s" ",i,0x" "%12.12" PRIx64, val, isid);
! 2043: strlwr(conn->initiator_name);
! 2044: strlwr(conn->initiator_port);
! 2045: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Initiator name: %s\n",
! 2046: conn->initiator_name);
! 2047: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Initiator port: %s\n",
! 2048: conn->initiator_port);
! 2049:
! 2050: /* Session Type */
! 2051: session_type = ISCSI_GETVAL(params, "SessionType");
! 2052: if (session_type == NULL) {
! 2053: if (tsih != 0) {
! 2054: session_type = "Normal";
! 2055: } else {
! 2056: ISTGT_ERRLOG("SessionType is empty\n");
! 2057: /* Missing parameter */
! 2058: StatusClass = 0x02;
! 2059: StatusDetail = 0x07;
! 2060: goto response;
! 2061: }
! 2062: }
! 2063: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Session Type: %s\n",
! 2064: session_type);
! 2065:
! 2066: /* Target Name and Port */
! 2067: if (strcasecmp(session_type, "Normal") == 0) {
! 2068: val = ISCSI_GETVAL(params, "TargetName");
! 2069: if (val == NULL) {
! 2070: ISTGT_ERRLOG("TargetName is empty\n");
! 2071: /* Missing parameter */
! 2072: StatusClass = 0x02;
! 2073: StatusDetail = 0x07;
! 2074: goto response;
! 2075: }
! 2076: snprintf(conn->target_name, sizeof conn->target_name,
! 2077: "%s", val);
! 2078: snprintf(conn->target_port, sizeof conn->target_port,
! 2079: "%s" ",t,0x" "%4.4x", val, conn->portal.tag);
! 2080: strlwr(conn->target_name);
! 2081: strlwr(conn->target_port);
! 2082:
! 2083: MTX_LOCK(&conn->istgt->mutex);
! 2084: lu = istgt_lu_find_target(conn->istgt,
! 2085: conn->target_name);
! 2086: if (lu == NULL) {
! 2087: MTX_UNLOCK(&conn->istgt->mutex);
! 2088: ISTGT_ERRLOG("lu_find_target() failed\n");
! 2089: /* Not found */
! 2090: StatusClass = 0x02;
! 2091: StatusDetail = 0x03;
! 2092: goto response;
! 2093: }
! 2094: rc = istgt_lu_access(conn, lu, conn->initiator_name,
! 2095: conn->initiator_addr);
! 2096: if (rc < 0) {
! 2097: MTX_UNLOCK(&conn->istgt->mutex);
! 2098: ISTGT_ERRLOG("lu_access() failed\n");
! 2099: /* Not found */
! 2100: StatusClass = 0x02;
! 2101: StatusDetail = 0x03;
! 2102: goto response;
! 2103: }
! 2104: if (rc == 0) {
! 2105: MTX_UNLOCK(&conn->istgt->mutex);
! 2106: ISTGT_ERRLOG("access denied\n");
! 2107: /* Not found */
! 2108: StatusClass = 0x02;
! 2109: StatusDetail = 0x03;
! 2110: goto response;
! 2111: }
! 2112: MTX_UNLOCK(&conn->istgt->mutex);
! 2113:
! 2114: /* check existing session */
! 2115: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
! 2116: "isid=%"PRIx64", tsih=%u, cid=%u\n",
! 2117: isid, tsih, cid);
! 2118: if (tsih != 0) {
! 2119: /* multiple connections */
! 2120: rc = istgt_append_sess(conn, isid, tsih, cid);
! 2121: if (rc < 0) {
! 2122: ISTGT_ERRLOG("isid=%"PRIx64", tsih=%u, cid=%u: "
! 2123: "append_sess() failed\n",
! 2124: isid, tsih, cid);
! 2125: /* Can't include in session */
! 2126: StatusClass = 0x02;
! 2127: StatusDetail = 0x08;
! 2128: goto response;
! 2129: }
! 2130: } else {
! 2131: /* new session, drop old sess by the initiator */
! 2132: istgt_iscsi_drop_old_conns(conn);
! 2133: }
! 2134:
! 2135: /* force target flags */
! 2136: MTX_LOCK(&lu->mutex);
! 2137: if (lu->no_auth_chap) {
! 2138: conn->req_auth = 0;
! 2139: rc = istgt_iscsi_param_del(&conn->params,
! 2140: "AuthMethod");
! 2141: if (rc < 0) {
! 2142: MTX_UNLOCK(&lu->mutex);
! 2143: ISTGT_ERRLOG("iscsi_param_del() failed\n");
! 2144: goto error_return;
! 2145: }
! 2146: rc = istgt_iscsi_param_add(&conn->params,
! 2147: "AuthMethod", "None", "None", ISPT_LIST);
! 2148: if (rc < 0) {
! 2149: MTX_UNLOCK(&lu->mutex);
! 2150: ISTGT_ERRLOG("iscsi_param_add() failed\n");
! 2151: goto error_return;
! 2152: }
! 2153: } else if (lu->auth_chap) {
! 2154: conn->req_auth = 1;
! 2155: rc = istgt_iscsi_param_del(&conn->params,
! 2156: "AuthMethod");
! 2157: if (rc < 0) {
! 2158: MTX_UNLOCK(&lu->mutex);
! 2159: ISTGT_ERRLOG("iscsi_param_del() failed\n");
! 2160: goto error_return;
! 2161: }
! 2162: rc = istgt_iscsi_param_add(&conn->params,
! 2163: "AuthMethod", "CHAP", "CHAP", ISPT_LIST);
! 2164: if (rc < 0) {
! 2165: MTX_UNLOCK(&lu->mutex);
! 2166: ISTGT_ERRLOG("iscsi_param_add() failed\n");
! 2167: goto error_return;
! 2168: }
! 2169: }
! 2170: if (lu->auth_chap_mutual) {
! 2171: conn->req_mutual = 1;
! 2172: }
! 2173: if (lu->header_digest) {
! 2174: rc = istgt_iscsi_param_del(&conn->params,
! 2175: "HeaderDigest");
! 2176: if (rc < 0) {
! 2177: MTX_UNLOCK(&lu->mutex);
! 2178: ISTGT_ERRLOG("iscsi_param_del() failed\n");
! 2179: goto error_return;
! 2180: }
! 2181: rc = istgt_iscsi_param_add(&conn->params,
! 2182: "HeaderDigest", "CRC32C", "CRC32C",
! 2183: ISPT_LIST);
! 2184: if (rc < 0) {
! 2185: MTX_UNLOCK(&lu->mutex);
! 2186: ISTGT_ERRLOG("iscsi_param_add() failed\n");
! 2187: goto error_return;
! 2188: }
! 2189: }
! 2190: if (lu->data_digest) {
! 2191: rc = istgt_iscsi_param_del(&conn->params,
! 2192: "DataDigest");
! 2193: if (rc < 0) {
! 2194: MTX_UNLOCK(&lu->mutex);
! 2195: ISTGT_ERRLOG("iscsi_param_del() failed\n");
! 2196: goto error_return;
! 2197: }
! 2198: rc = istgt_iscsi_param_add(&conn->params,
! 2199: "DataDigest", "CRC32C", "CRC32C",
! 2200: ISPT_LIST);
! 2201: if (rc < 0) {
! 2202: MTX_UNLOCK(&lu->mutex);
! 2203: ISTGT_ERRLOG("iscsi_param_add() failed\n");
! 2204: goto error_return;
! 2205: }
! 2206: }
! 2207: MTX_UNLOCK(&lu->mutex);
! 2208: } else if (strcasecmp(session_type, "Discovery") == 0) {
! 2209: snprintf(conn->target_name, sizeof conn->target_name,
! 2210: "%s", "dummy");
! 2211: snprintf(conn->target_port, sizeof conn->target_port,
! 2212: "%s" ",t,0x" "%4.4x", "dummy", conn->portal.tag);
! 2213: lu = NULL;
! 2214: tsih = 0;
! 2215:
! 2216: /* force target flags */
! 2217: MTX_LOCK(&conn->istgt->mutex);
! 2218: if (conn->istgt->no_discovery_auth) {
! 2219: conn->req_auth = 0;
! 2220: rc = istgt_iscsi_param_del(&conn->params,
! 2221: "AuthMethod");
! 2222: if (rc < 0) {
! 2223: MTX_UNLOCK(&conn->istgt->mutex);
! 2224: ISTGT_ERRLOG("iscsi_param_del() failed\n");
! 2225: goto error_return;
! 2226: }
! 2227: rc = istgt_iscsi_param_add(&conn->params,
! 2228: "AuthMethod", "None", "None", ISPT_LIST);
! 2229: if (rc < 0) {
! 2230: MTX_UNLOCK(&conn->istgt->mutex);
! 2231: ISTGT_ERRLOG("iscsi_param_add() failed\n");
! 2232: goto error_return;
! 2233: }
! 2234: } else if (conn->istgt->req_discovery_auth) {
! 2235: conn->req_auth = 1;
! 2236: rc = istgt_iscsi_param_del(&conn->params,
! 2237: "AuthMethod");
! 2238: if (rc < 0) {
! 2239: MTX_UNLOCK(&conn->istgt->mutex);
! 2240: ISTGT_ERRLOG("iscsi_param_del() failed\n");
! 2241: goto error_return;
! 2242: }
! 2243: rc = istgt_iscsi_param_add(&conn->params,
! 2244: "AuthMethod", "CHAP", "CHAP", ISPT_LIST);
! 2245: if (rc < 0) {
! 2246: MTX_UNLOCK(&conn->istgt->mutex);
! 2247: ISTGT_ERRLOG("iscsi_param_add() failed\n");
! 2248: goto error_return;
! 2249: }
! 2250: }
! 2251: if (conn->istgt->req_discovery_auth_mutual) {
! 2252: conn->req_mutual = 1;
! 2253: }
! 2254: MTX_UNLOCK(&conn->istgt->mutex);
! 2255: } else {
! 2256: ISTGT_ERRLOG("unknown session type\n");
! 2257: /* Missing parameter */
! 2258: StatusClass = 0x02;
! 2259: StatusDetail = 0x07;
! 2260: goto response;
! 2261: }
! 2262: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Target name: %s\n",
! 2263: conn->target_name);
! 2264: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Target port: %s\n",
! 2265: conn->target_port);
! 2266:
! 2267: conn->authenticated = 0;
! 2268: conn->auth.chap_phase = ISTGT_CHAP_PHASE_WAIT_A;
! 2269: conn->cid = cid;
! 2270: if (lu == NULL || lu->queue_depth == 0) {
! 2271: conn->queue_depth = ISCMDQ;
! 2272: } else {
! 2273: conn->queue_depth = lu->queue_depth;
! 2274: }
! 2275: conn->max_pending = (conn->queue_depth + 1) * 2;
! 2276: #if 0
! 2277: /* override config setting */
! 2278: MTX_LOCK(&conn->r2t_mutex);
! 2279: if ((conn->max_r2t > 0)
! 2280: && (conn->max_r2t < conn->max_pending)) {
! 2281: int i;
! 2282: xfree(conn->r2t_tasks);
! 2283: conn->max_r2t = conn->max_pending;
! 2284: conn->r2t_tasks = xmalloc (sizeof *conn->r2t_tasks
! 2285: * (conn->max_r2t + 1));
! 2286: for (i = 0; i < (conn->max_r2t + 1); i++) {
! 2287: conn->r2t_tasks[i] = NULL;
! 2288: }
! 2289: }
! 2290: MTX_UNLOCK(&conn->r2t_mutex);
! 2291: #endif
! 2292: if (conn->sess == NULL) {
! 2293: /* new session */
! 2294: rc = istgt_create_sess(conn->istgt, conn, lu);
! 2295: if (rc < 0) {
! 2296: ISTGT_ERRLOG("create_sess() failed\n");
! 2297: goto error_return;
! 2298: }
! 2299:
! 2300: /* initialize parameters */
! 2301: conn->StatSN = ExpStatSN;
! 2302: SESS_MTX_LOCK(conn);
! 2303: conn->MaxOutstandingR2T
! 2304: = conn->sess->MaxOutstandingR2T;
! 2305: conn->sess->isid = isid;
! 2306: conn->sess->tsih = tsih;
! 2307: conn->sess->lu = lu;
! 2308: conn->sess->ExpCmdSN = CmdSN;
! 2309: conn->sess->MaxCmdSN = CmdSN + conn->queue_depth - 1;
! 2310: SESS_MTX_UNLOCK(conn);
! 2311: }
! 2312:
! 2313: /* limit conns on discovery session */
! 2314: if (strcasecmp(session_type, "Discovery") == 0) {
! 2315: SESS_MTX_LOCK(conn);
! 2316: conn->sess->MaxConnections = 1;
! 2317: rc = istgt_iscsi_param_set_int(conn->sess->params,
! 2318: "MaxConnections", conn->sess->MaxConnections);
! 2319: SESS_MTX_UNLOCK(conn);
! 2320: if (rc < 0) {
! 2321: ISTGT_ERRLOG("iscsi_param_set_int() failed\n");
! 2322: goto error_return;
! 2323: }
! 2324: }
! 2325:
! 2326: /* declarative parameters */
! 2327: if (lu != NULL) {
! 2328: MTX_LOCK(&lu->mutex);
! 2329: if (lu->alias != NULL) {
! 2330: snprintf(buf, sizeof buf, "%s", lu->alias);
! 2331: } else {
! 2332: snprintf(buf, sizeof buf, "%s", "");
! 2333: }
! 2334: MTX_UNLOCK(&lu->mutex);
! 2335: SESS_MTX_LOCK(conn);
! 2336: rc = istgt_iscsi_param_set(conn->sess->params,
! 2337: "TargetAlias", buf);
! 2338: SESS_MTX_UNLOCK(conn);
! 2339: if (rc < 0) {
! 2340: ISTGT_ERRLOG("iscsi_param_set() failed\n");
! 2341: goto error_return;
! 2342: }
! 2343: }
! 2344: snprintf(buf, sizeof buf, "%s:%s,%d",
! 2345: conn->portal.host, conn->portal.port, conn->portal.tag);
! 2346: SESS_MTX_LOCK(conn);
! 2347: rc = istgt_iscsi_param_set(conn->sess->params,
! 2348: "TargetAddress", buf);
! 2349: SESS_MTX_UNLOCK(conn);
! 2350: if (rc < 0) {
! 2351: ISTGT_ERRLOG("iscsi_param_set() failed\n");
! 2352: goto error_return;
! 2353: }
! 2354: snprintf(buf, sizeof buf, "%d", conn->portal.tag);
! 2355: SESS_MTX_LOCK(conn);
! 2356: rc = istgt_iscsi_param_set(conn->sess->params,
! 2357: "TargetPortalGroupTag", buf);
! 2358: SESS_MTX_UNLOCK(conn);
! 2359: if (rc < 0) {
! 2360: ISTGT_ERRLOG("iscsi_param_set() failed\n");
! 2361: goto error_return;
! 2362: }
! 2363:
! 2364: /* write in response */
! 2365: if (lu != NULL) {
! 2366: SESS_MTX_LOCK(conn);
! 2367: val = ISCSI_GETVAL(conn->sess->params, "TargetAlias");
! 2368: if (val != NULL && strlen(val) != 0) {
! 2369: data_len = istgt_iscsi_append_param(conn,
! 2370: "TargetAlias", data, alloc_len, data_len);
! 2371: }
! 2372: if (strcasecmp(session_type, "Discovery") == 0) {
! 2373: data_len = istgt_iscsi_append_param(conn,
! 2374: "TargetAddress", data, alloc_len, data_len);
! 2375: }
! 2376: data_len = istgt_iscsi_append_param(conn,
! 2377: "TargetPortalGroupTag", data, alloc_len, data_len);
! 2378: SESS_MTX_UNLOCK(conn);
! 2379: }
! 2380:
! 2381: /* start login phase */
! 2382: conn->login_phase = ISCSI_LOGIN_PHASE_START;
! 2383: }
! 2384:
! 2385: /* negotiate parameters */
! 2386: data_len = istgt_iscsi_negotiate_params(conn, params,
! 2387: data, alloc_len, data_len);
! 2388: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "Negotiated Params",
! 2389: data, data_len);
! 2390:
! 2391: switch (CSG) {
! 2392: case 0:
! 2393: /* SecurityNegotiation */
! 2394: auth_method = ISCSI_GETVAL(conn->params, "AuthMethod");
! 2395: if (auth_method == NULL) {
! 2396: ISTGT_ERRLOG("AuthMethod is empty\n");
! 2397: /* Missing parameter */
! 2398: StatusClass = 0x02;
! 2399: StatusDetail = 0x07;
! 2400: goto response;
! 2401: }
! 2402: if (strcasecmp(auth_method, "None") == 0) {
! 2403: conn->authenticated = 1;
! 2404: } else {
! 2405: rc = istgt_iscsi_auth_params(conn, params, auth_method,
! 2406: data, alloc_len, data_len);
! 2407: if (rc < 0) {
! 2408: ISTGT_ERRLOG("iscsi_auth_params() failed\n");
! 2409: /* Authentication failure */
! 2410: StatusClass = 0x02;
! 2411: StatusDetail = 0x01;
! 2412: goto response;
! 2413: }
! 2414: data_len = rc;
! 2415: if (conn->authenticated == 0) {
! 2416: /* not complete */
! 2417: T_bit = 0;
! 2418: } else {
! 2419: if (conn->auth.chap_phase != ISTGT_CHAP_PHASE_END) {
! 2420: ISTGT_WARNLOG("CHAP phase not complete");
! 2421: }
! 2422: }
! 2423: #if 0
! 2424: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG,
! 2425: "Negotiated Auth Params", data, data_len);
! 2426: #endif
! 2427: }
! 2428: break;
! 2429: case 1:
! 2430: /* LoginOperationalNegotiation */
! 2431: if (conn->login_phase == ISCSI_LOGIN_PHASE_START) {
! 2432: if (conn->req_auth) {
! 2433: /* Authentication failure */
! 2434: StatusClass = 0x02;
! 2435: StatusDetail = 0x01;
! 2436: goto response;
! 2437: } else {
! 2438: /* AuthMethod=None */
! 2439: conn->authenticated = 1;
! 2440: }
! 2441: }
! 2442: if (conn->authenticated == 0) {
! 2443: ISTGT_ERRLOG("authentication error\n");
! 2444: /* Authentication failure */
! 2445: StatusClass = 0x02;
! 2446: StatusDetail = 0x01;
! 2447: goto response;
! 2448: }
! 2449: break;
! 2450: case 3:
! 2451: /* FullFeaturePhase */
! 2452: ISTGT_ERRLOG("XXX Login in FullFeaturePhase\n");
! 2453: /* Initiator error */
! 2454: StatusClass = 0x02;
! 2455: StatusDetail = 0x00;
! 2456: goto response;
! 2457: default:
! 2458: ISTGT_ERRLOG("unknown stage\n");
! 2459: /* Initiator error */
! 2460: StatusClass = 0x02;
! 2461: StatusDetail = 0x00;
! 2462: goto response;
! 2463: }
! 2464:
! 2465: if (T_bit) {
! 2466: switch (NSG) {
! 2467: case 0:
! 2468: /* SecurityNegotiation */
! 2469: conn->login_phase = ISCSI_LOGIN_PHASE_SECURITY;
! 2470: break;
! 2471: case 1:
! 2472: /* LoginOperationalNegotiation */
! 2473: conn->login_phase = ISCSI_LOGIN_PHASE_OPERATIONAL;
! 2474: break;
! 2475: case 3:
! 2476: /* FullFeaturePhase */
! 2477: conn->login_phase = ISCSI_LOGIN_PHASE_FULLFEATURE;
! 2478:
! 2479: SESS_MTX_LOCK(conn);
! 2480: if (ISCSI_EQVAL(conn->sess->params, "SessionType", "Normal")) {
! 2481: /* normal session */
! 2482: tsih = conn->sess->tsih;
! 2483: /* new tsih? */
! 2484: if (tsih == 0) {
! 2485: tsih = istgt_lu_allocate_tsih(conn->sess->lu,
! 2486: conn->initiator_port,
! 2487: conn->portal.tag);
! 2488: if (tsih == 0) {
! 2489: SESS_MTX_UNLOCK(conn);
! 2490: ISTGT_ERRLOG("lu_allocate_tsih() failed\n");
! 2491: goto error_return;
! 2492: }
! 2493: conn->sess->tsih = tsih;
! 2494: } else {
! 2495: /* multiple connection */
! 2496: }
! 2497:
! 2498: snprintf(buf, sizeof buf, "Login from %s (%s) on %s LU%d"
! 2499: " (%s:%s,%d), ISID=%"PRIx64", TSIH=%u,"
! 2500: " CID=%u, HeaderDigest=%s, DataDigest=%s\n",
! 2501: conn->initiator_name, conn->initiator_addr,
! 2502: conn->target_name, conn->sess->lu->num,
! 2503: conn->portal.host, conn->portal.port,
! 2504: conn->portal.tag,
! 2505: conn->sess->isid, conn->sess->tsih, conn->cid,
! 2506: (ISCSI_EQVAL(conn->params, "HeaderDigest", "CRC32C")
! 2507: ? "on" : "off"),
! 2508: (ISCSI_EQVAL(conn->params, "DataDigest", "CRC32C")
! 2509: ? "on" : "off"));
! 2510: ISTGT_NOTICELOG("%s", buf);
! 2511: } else if (ISCSI_EQVAL(conn->sess->params, "SessionType", "Discovery")) {
! 2512: /* discovery session */
! 2513: /* new tsih */
! 2514: MTX_LOCK(&g_last_tsih_mutex);
! 2515: tsih = conn->sess->tsih;
! 2516: g_last_tsih++;
! 2517: tsih = g_last_tsih;
! 2518: if (tsih == 0) {
! 2519: g_last_tsih++;
! 2520: tsih = g_last_tsih;
! 2521: }
! 2522: conn->sess->tsih = tsih;
! 2523: MTX_UNLOCK(&g_last_tsih_mutex);
! 2524:
! 2525: snprintf(buf, sizeof buf, "Login(discovery) from %s (%s) on"
! 2526: " (%s:%s,%d), ISID=%"PRIx64", TSIH=%u,"
! 2527: " CID=%u, HeaderDigest=%s, DataDigest=%s\n",
! 2528: conn->initiator_name, conn->initiator_addr,
! 2529: conn->portal.host, conn->portal.port,
! 2530: conn->portal.tag,
! 2531: conn->sess->isid, conn->sess->tsih, conn->cid,
! 2532: (ISCSI_EQVAL(conn->params, "HeaderDigest", "CRC32C")
! 2533: ? "on" : "off"),
! 2534: (ISCSI_EQVAL(conn->params, "DataDigest", "CRC32C")
! 2535: ? "on" : "off"));
! 2536: ISTGT_NOTICELOG("%s", buf);
! 2537: } else {
! 2538: ISTGT_ERRLOG("unknown session type\n");
! 2539: SESS_MTX_UNLOCK(conn);
! 2540: /* Initiator error */
! 2541: StatusClass = 0x02;
! 2542: StatusDetail = 0x00;
! 2543: goto response;
! 2544: }
! 2545: SESS_MTX_UNLOCK(conn);
! 2546:
! 2547: conn->full_feature = 1;
! 2548: break;
! 2549: default:
! 2550: ISTGT_ERRLOG("unknown stage\n");
! 2551: /* Initiator error */
! 2552: StatusClass = 0x02;
! 2553: StatusDetail = 0x00;
! 2554: goto response;
! 2555: }
! 2556: }
! 2557:
! 2558: response:
! 2559: /* response PDU */
! 2560: rsp = (uint8_t *) &rsp_pdu.bhs;
! 2561: rsp_pdu.data = data;
! 2562: memset(rsp, 0, ISCSI_BHS_LEN);
! 2563: rsp[0] = ISCSI_OP_LOGIN_RSP;
! 2564: BDADD8(&rsp[1], T_bit, 7);
! 2565: BDADD8(&rsp[1], C_bit, 6);
! 2566: BDADD8W(&rsp[1], CSG, 3, 2);
! 2567: BDADD8W(&rsp[1], NSG, 1, 2);
! 2568: rsp[2] = ISCSI_VERSION; // Version-max
! 2569: rsp[3] = ISCSI_VERSION; // Version-active
! 2570: rsp[4] = 0; // TotalAHSLength
! 2571: DSET24(&rsp[5], data_len); // DataSegmentLength
! 2572:
! 2573: DSET48(&rsp[8], isid);
! 2574: DSET16(&rsp[14], tsih);
! 2575: DSET32(&rsp[16], task_tag);
! 2576:
! 2577: DSET32(&rsp[24], conn->StatSN);
! 2578: conn->StatSN++;
! 2579: if (conn->sess != NULL) {
! 2580: SESS_MTX_LOCK(conn);
! 2581: DSET32(&rsp[28], conn->sess->ExpCmdSN);
! 2582: DSET32(&rsp[32], conn->sess->MaxCmdSN);
! 2583: SESS_MTX_UNLOCK(conn);
! 2584: } else {
! 2585: DSET32(&rsp[28], CmdSN);
! 2586: DSET32(&rsp[32], CmdSN);
! 2587: }
! 2588:
! 2589: rsp[36] = StatusClass;
! 2590: rsp[37] = StatusDetail;
! 2591:
! 2592: #if 1
! 2593: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "PDU", rsp, ISCSI_BHS_LEN);
! 2594: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "DATA", data, data_len);
! 2595: #endif
! 2596: rc = istgt_iscsi_write_pdu(conn, &rsp_pdu);
! 2597: if (rc < 0) {
! 2598: ISTGT_ERRLOG("iscsi_write_pdu() failed\n");
! 2599: istgt_iscsi_param_free(params);
! 2600: xfree(data);
! 2601: return -1;
! 2602: }
! 2603:
! 2604: /* after send PDU digest on/off */
! 2605: if (conn->full_feature) {
! 2606: /* update internal variables */
! 2607: istgt_iscsi_copy_param2var(conn);
! 2608: /* check value */
! 2609: rc = istgt_iscsi_check_values(conn);
! 2610: if (rc < 0) {
! 2611: ISTGT_ERRLOG("iscsi_check_values() failed\n");
! 2612: istgt_iscsi_param_free(params);
! 2613: xfree(data);
! 2614: return -1;
! 2615: }
! 2616: }
! 2617:
! 2618: istgt_iscsi_param_free(params);
! 2619: xfree(data);
! 2620: return 0;
! 2621: }
! 2622:
! 2623: static int
! 2624: istgt_iscsi_op_text(CONN_Ptr conn, ISCSI_PDU_Ptr pdu)
! 2625: {
! 2626: ISCSI_PARAM *params = NULL;
! 2627: ISCSI_PDU rsp_pdu;
! 2628: uint8_t *rsp;
! 2629: uint8_t *cp;
! 2630: uint8_t *data;
! 2631: uint64_t lun;
! 2632: uint32_t task_tag;
! 2633: uint32_t transfer_tag;
! 2634: uint32_t CmdSN;
! 2635: uint32_t ExpStatSN;
! 2636: const char *iiqn;
! 2637: const char *val;
! 2638: int I_bit, F_bit, C_bit;
! 2639: int data_len;
! 2640: int alloc_len;
! 2641: int rc;
! 2642:
! 2643: if (!conn->full_feature) {
! 2644: ISTGT_ERRLOG("before Full Feature\n");
! 2645: return -1;
! 2646: }
! 2647:
! 2648: data_len = 0;
! 2649: alloc_len = conn->sendbufsize;
! 2650: data = (uint8_t *) conn->sendbuf;
! 2651: memset(data, 0, alloc_len);
! 2652:
! 2653: cp = (uint8_t *) &pdu->bhs;
! 2654: I_bit = BGET8(&cp[0], 7);
! 2655: F_bit = BGET8(&cp[1], 7);
! 2656: C_bit = BGET8(&cp[1], 6);
! 2657:
! 2658: lun = DGET64(&cp[8]);
! 2659: task_tag = DGET32(&cp[16]);
! 2660: transfer_tag = DGET32(&cp[20]);
! 2661: CmdSN = DGET32(&cp[24]);
! 2662: ExpStatSN = DGET32(&cp[28]);
! 2663:
! 2664: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 2665: "I=%d, F=%d, C=%d, ITT=%x, TTT=%x\n",
! 2666: I_bit, F_bit, C_bit, task_tag, transfer_tag);
! 2667: SESS_MTX_LOCK(conn);
! 2668: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
! 2669: "CmdSN=%u, ExpStatSN=%u, StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
! 2670: CmdSN, ExpStatSN, conn->StatSN, conn->sess->ExpCmdSN,
! 2671: conn->sess->MaxCmdSN);
! 2672: if (I_bit == 0) {
! 2673: if (SN32_LT(CmdSN, conn->sess->ExpCmdSN)
! 2674: || SN32_GT(CmdSN, conn->sess->MaxCmdSN)) {
! 2675: ISTGT_ERRLOG("CmdSN(%u) ignore (ExpCmdSN=%u, MaxCmdSN=%u)\n",
! 2676: CmdSN, conn->sess->ExpCmdSN,
! 2677: conn->sess->MaxCmdSN);
! 2678: SESS_MTX_UNLOCK(conn);
! 2679: return -1;
! 2680: }
! 2681: } else if (CmdSN != conn->sess->ExpCmdSN) {
! 2682: SESS_MTX_UNLOCK(conn);
! 2683: ISTGT_ERRLOG("CmdSN(%u) error\n", CmdSN);
! 2684: return -1;
! 2685: }
! 2686: SESS_MTX_UNLOCK(conn);
! 2687: if (SN32_GT(ExpStatSN, conn->StatSN)) {
! 2688: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "StatSN(%u) advanced\n",
! 2689: ExpStatSN);
! 2690: conn->StatSN = ExpStatSN;
! 2691: }
! 2692: if (ExpStatSN != conn->StatSN) {
! 2693: #if 0
! 2694: ISTGT_ERRLOG("StatSN(%u) error\n", ExpStatSN);
! 2695: return -1;
! 2696: #else
! 2697: /* StarPort have a bug */
! 2698: ISTGT_WARNLOG("StatSN(%u) rewound\n", ExpStatSN);
! 2699: conn->StatSN = ExpStatSN;
! 2700: #endif
! 2701: }
! 2702:
! 2703: if (F_bit && C_bit) {
! 2704: ISTGT_ERRLOG("final and continue\n");
! 2705: return -1;
! 2706: }
! 2707:
! 2708: /* store incoming parameters */
! 2709: rc = istgt_iscsi_parse_params(¶ms, pdu->data,
! 2710: pdu->data_segment_len);
! 2711: if (rc < 0) {
! 2712: ISTGT_ERRLOG("iscsi_parse_params() failed\n");
! 2713: istgt_iscsi_param_free(params);
! 2714: return -1;
! 2715: }
! 2716:
! 2717: /* negotiate parameters */
! 2718: data_len = istgt_iscsi_negotiate_params(conn, params,
! 2719: data, alloc_len, data_len);
! 2720: /* sendtargets is special case */
! 2721: val = ISCSI_GETVAL(params, "SendTargets");
! 2722: if (val != NULL) {
! 2723: if (strcasecmp(val, "") == 0) {
! 2724: val = conn->target_name;
! 2725: }
! 2726: SESS_MTX_LOCK(conn);
! 2727: iiqn = ISCSI_GETVAL(conn->sess->params,
! 2728: "InitiatorName");
! 2729: if (ISCSI_EQVAL(conn->sess->params,
! 2730: "SessionType", "Discovery")) {
! 2731: data_len = istgt_lu_sendtargets(conn,
! 2732: conn->initiator_name,
! 2733: conn->initiator_addr,
! 2734: val, data, alloc_len, data_len);
! 2735: } else {
! 2736: if (strcasecmp(val, "ALL") == 0) {
! 2737: /* not in discovery session */
! 2738: data_len = istgt_iscsi_append_text(conn, "SendTargets",
! 2739: "Reject", data, alloc_len, data_len);
! 2740: } else {
! 2741: data_len = istgt_lu_sendtargets(conn,
! 2742: conn->initiator_name,
! 2743: conn->initiator_addr,
! 2744: val, data, alloc_len, data_len);
! 2745: }
! 2746: }
! 2747: SESS_MTX_UNLOCK(conn);
! 2748: }
! 2749: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "Negotiated Params",
! 2750: data, data_len);
! 2751:
! 2752: /* response PDU */
! 2753: rsp = (uint8_t *) &rsp_pdu.bhs;
! 2754: rsp_pdu.data = data;
! 2755: memset(rsp, 0, ISCSI_BHS_LEN);
! 2756: rsp[0] = ISCSI_OP_TEXT_RSP;
! 2757: BDADD8(&rsp[1], F_bit, 7);
! 2758: BDADD8(&rsp[1], C_bit, 6);
! 2759: rsp[4] = 0; // TotalAHSLength
! 2760: DSET24(&rsp[5], data_len); // DataSegmentLength
! 2761:
! 2762: DSET64(&rsp[8], lun);
! 2763: DSET32(&rsp[16], task_tag);
! 2764: if (F_bit) {
! 2765: DSET32(&rsp[20], 0xffffffffU);
! 2766: } else {
! 2767: transfer_tag = 1 + conn->id;
! 2768: DSET32(&rsp[20], transfer_tag);
! 2769: }
! 2770:
! 2771: DSET32(&rsp[24], conn->StatSN);
! 2772: conn->StatSN++;
! 2773: SESS_MTX_LOCK(conn);
! 2774: if (I_bit == 0) {
! 2775: conn->sess->ExpCmdSN++;
! 2776: conn->sess->MaxCmdSN++;
! 2777: }
! 2778: DSET32(&rsp[28], conn->sess->ExpCmdSN);
! 2779: DSET32(&rsp[32], conn->sess->MaxCmdSN);
! 2780: SESS_MTX_UNLOCK(conn);
! 2781:
! 2782: rc = istgt_iscsi_write_pdu(conn, &rsp_pdu);
! 2783: if (rc < 0) {
! 2784: ISTGT_ERRLOG("iscsi_write_pdu() failed\n");
! 2785: istgt_iscsi_param_free(params);
! 2786: return -1;
! 2787: }
! 2788:
! 2789: /* update internal variables */
! 2790: istgt_iscsi_copy_param2var(conn);
! 2791: /* check value */
! 2792: rc = istgt_iscsi_check_values(conn);
! 2793: if (rc < 0) {
! 2794: ISTGT_ERRLOG("iscsi_check_values() failed\n");
! 2795: istgt_iscsi_param_free(params);
! 2796: return -1;
! 2797: }
! 2798:
! 2799: istgt_iscsi_param_free(params);
! 2800: return 0;
! 2801: }
! 2802:
! 2803: static int
! 2804: istgt_iscsi_op_logout(CONN_Ptr conn, ISCSI_PDU_Ptr pdu)
! 2805: {
! 2806: char buf[MAX_TMPBUF];
! 2807: ISCSI_PDU rsp_pdu;
! 2808: uint8_t *rsp;
! 2809: uint8_t *cp;
! 2810: uint8_t *data;
! 2811: uint32_t task_tag;
! 2812: uint16_t cid;
! 2813: uint32_t CmdSN;
! 2814: uint32_t ExpStatSN;
! 2815: int reason;
! 2816: int response;
! 2817: int data_len;
! 2818: int alloc_len;
! 2819: int rc;
! 2820:
! 2821: data_len = 0;
! 2822: alloc_len = conn->sendbufsize;
! 2823: data = (uint8_t *) conn->sendbuf;
! 2824: memset(data, 0, alloc_len);
! 2825:
! 2826: cp = (uint8_t *) &pdu->bhs;
! 2827: reason = BGET8W(&cp[1], 6, 7);
! 2828:
! 2829: task_tag = DGET32(&cp[16]);
! 2830: cid = DGET16(&cp[20]);
! 2831: CmdSN = DGET32(&cp[24]);
! 2832: ExpStatSN = DGET32(&cp[28]);
! 2833:
! 2834: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 2835: "reason=%d, ITT=%x, cid=%d\n",
! 2836: reason, task_tag, cid);
! 2837: if (conn->sess != NULL) {
! 2838: SESS_MTX_LOCK(conn);
! 2839: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
! 2840: "CmdSN=%u, ExpStatSN=%u, StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
! 2841: CmdSN, ExpStatSN, conn->StatSN, conn->sess->ExpCmdSN,
! 2842: conn->sess->MaxCmdSN);
! 2843: if (CmdSN != conn->sess->ExpCmdSN) {
! 2844: ISTGT_WARNLOG("CmdSN(%u) might have dropped\n", CmdSN);
! 2845: /* ignore error */
! 2846: }
! 2847: SESS_MTX_UNLOCK(conn);
! 2848: } else {
! 2849: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
! 2850: "CmdSN=%u, ExpStatSN=%u, StatSN=%u\n",
! 2851: CmdSN, ExpStatSN, conn->StatSN);
! 2852: }
! 2853: if (SN32_GT(ExpStatSN, conn->StatSN)) {
! 2854: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "StatSN(%u) advanced\n",
! 2855: ExpStatSN);
! 2856: conn->StatSN = ExpStatSN;
! 2857: }
! 2858: if (ExpStatSN != conn->StatSN) {
! 2859: ISTGT_WARNLOG("StatSN(%u/%u) might have dropped\n",
! 2860: ExpStatSN, conn->StatSN);
! 2861: /* ignore error */
! 2862: }
! 2863:
! 2864: response = 0; // connection or session closed successfully
! 2865:
! 2866: /* response PDU */
! 2867: rsp = (uint8_t *) &rsp_pdu.bhs;
! 2868: rsp_pdu.data = data;
! 2869: memset(rsp, 0, ISCSI_BHS_LEN);
! 2870: rsp[0] = ISCSI_OP_LOGOUT_RSP;
! 2871: BDADD8W(&rsp[1], 1, 7, 1);
! 2872: rsp[2] = response;
! 2873: rsp[4] = 0; // TotalAHSLength
! 2874: DSET24(&rsp[5], data_len); // DataSegmentLength
! 2875:
! 2876: DSET32(&rsp[16], task_tag);
! 2877:
! 2878: DSET32(&rsp[24], conn->StatSN);
! 2879: conn->StatSN++;
! 2880: if (conn->sess != NULL) {
! 2881: SESS_MTX_LOCK(conn);
! 2882: if (conn->sess->connections == 1) {
! 2883: conn->sess->ExpCmdSN++;
! 2884: conn->sess->MaxCmdSN++;
! 2885: }
! 2886: DSET32(&rsp[28], conn->sess->ExpCmdSN);
! 2887: DSET32(&rsp[32], conn->sess->MaxCmdSN);
! 2888: SESS_MTX_UNLOCK(conn);
! 2889: } else {
! 2890: DSET32(&rsp[28], CmdSN);
! 2891: DSET32(&rsp[32], CmdSN);
! 2892: }
! 2893:
! 2894: DSET16(&rsp[40], 0); // Time2Wait
! 2895: DSET16(&rsp[42], 0); // Time2Retain
! 2896:
! 2897: rc = istgt_iscsi_write_pdu(conn, &rsp_pdu);
! 2898: if (rc < 0) {
! 2899: ISTGT_ERRLOG("iscsi_write_pdu() failed\n");
! 2900: return -1;
! 2901: }
! 2902:
! 2903: SESS_MTX_LOCK(conn);
! 2904: if (ISCSI_EQVAL(conn->sess->params, "SessionType", "Normal")) {
! 2905: snprintf(buf, sizeof buf, "Logout from %s (%s) on %s LU%d"
! 2906: " (%s:%s,%d), ISID=%"PRIx64", TSIH=%u,"
! 2907: " CID=%u, HeaderDigest=%s, DataDigest=%s\n",
! 2908: conn->initiator_name, conn->initiator_addr,
! 2909: conn->target_name, conn->sess->lu->num,
! 2910: conn->portal.host, conn->portal.port, conn->portal.tag,
! 2911: conn->sess->isid, conn->sess->tsih, conn->cid,
! 2912: (ISCSI_EQVAL(conn->params, "HeaderDigest", "CRC32C")
! 2913: ? "on" : "off"),
! 2914: (ISCSI_EQVAL(conn->params, "DataDigest", "CRC32C")
! 2915: ? "on" : "off"));
! 2916: ISTGT_NOTICELOG("%s", buf);
! 2917: } else {
! 2918: /* discovery session */
! 2919: snprintf(buf, sizeof buf, "Logout(discovery) from %s (%s) on"
! 2920: " (%s:%s,%d), ISID=%"PRIx64", TSIH=%u,"
! 2921: " CID=%u, HeaderDigest=%s, DataDigest=%s\n",
! 2922: conn->initiator_name, conn->initiator_addr,
! 2923: conn->portal.host, conn->portal.port, conn->portal.tag,
! 2924: conn->sess->isid, conn->sess->tsih, conn->cid,
! 2925: (ISCSI_EQVAL(conn->params, "HeaderDigest", "CRC32C")
! 2926: ? "on" : "off"),
! 2927: (ISCSI_EQVAL(conn->params, "DataDigest", "CRC32C")
! 2928: ? "on" : "off"));
! 2929: ISTGT_NOTICELOG("%s", buf);
! 2930: }
! 2931: SESS_MTX_UNLOCK(conn);
! 2932:
! 2933: conn->exec_logout = 1;
! 2934: return 0;
! 2935: }
! 2936:
! 2937: static int istgt_iscsi_transfer_in_internal(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd);
! 2938:
! 2939: static int
! 2940: istgt_iscsi_transfer_in(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
! 2941: {
! 2942: int rc;
! 2943:
! 2944: //MTX_LOCK(&conn->wpdu_mutex);
! 2945: rc = istgt_iscsi_transfer_in_internal(conn, lu_cmd);
! 2946: //MTX_UNLOCK(&conn->wpdu_mutex);
! 2947: return rc;
! 2948: }
! 2949:
! 2950: static int
! 2951: istgt_iscsi_transfer_in_internal(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
! 2952: {
! 2953: ISCSI_PDU rsp_pdu;
! 2954: uint8_t *rsp;
! 2955: uint8_t *data;
! 2956: uint32_t task_tag;
! 2957: uint32_t transfer_tag;
! 2958: uint32_t DataSN;
! 2959: int transfer_len;
! 2960: int data_len;
! 2961: int segment_len;
! 2962: int offset;
! 2963: int F_bit, O_bit, U_bit, S_bit;
! 2964: int residual_len;
! 2965: int sent_status;
! 2966: int len;
! 2967: int rc;
! 2968:
! 2969: data = lu_cmd->data;
! 2970: transfer_len = lu_cmd->transfer_len;
! 2971: data_len = lu_cmd->data_len;
! 2972: segment_len = conn->MaxRecvDataSegmentLength;
! 2973:
! 2974: F_bit = O_bit = U_bit = S_bit = 0;
! 2975: if (data_len < transfer_len) {
! 2976: /* underflow */
! 2977: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Underflow %u/%u\n",
! 2978: data_len, transfer_len);
! 2979: residual_len = transfer_len - data_len;
! 2980: transfer_len = data_len;
! 2981: U_bit = 1;
! 2982: } else if (data_len > transfer_len) {
! 2983: /* overflow */
! 2984: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Overflow %u/%u\n",
! 2985: data_len, transfer_len);
! 2986: residual_len = data_len - transfer_len;
! 2987: O_bit = 1;
! 2988: } else {
! 2989: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Transfer %u\n",
! 2990: transfer_len);
! 2991: residual_len = 0;
! 2992: }
! 2993:
! 2994: task_tag = lu_cmd->task_tag;
! 2995: transfer_tag = 0xffffffffU;
! 2996: DataSN = 0;
! 2997: sent_status = 0;
! 2998:
! 2999: /* send data splitted by segment_len */
! 3000: for (offset = 0; offset < transfer_len; offset += segment_len) {
! 3001: len = DMIN32(segment_len, (transfer_len - offset));
! 3002:
! 3003: if (offset + len > transfer_len) {
! 3004: ISTGT_ERRLOG("transfer missing\n");
! 3005: return -1;
! 3006: } else if (offset + len == transfer_len) {
! 3007: /* final PDU */
! 3008: F_bit = 1;
! 3009: S_bit = 0;
! 3010: if (lu_cmd->sense_data_len == 0
! 3011: && (lu_cmd->status == ISTGT_SCSI_STATUS_GOOD
! 3012: || lu_cmd->status == ISTGT_SCSI_STATUS_CONDITION_MET
! 3013: || lu_cmd->status == ISTGT_SCSI_STATUS_INTERMEDIATE
! 3014: || lu_cmd->status == ISTGT_SCSI_STATUS_INTERMEDIATE_CONDITION_MET)) {
! 3015: S_bit = 1;
! 3016: sent_status = 1;
! 3017: }
! 3018: } else {
! 3019: F_bit = 0;
! 3020: S_bit = 0;
! 3021: }
! 3022:
! 3023: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 3024: "Transfer=%d, Offset=%d, Len=%d\n",
! 3025: transfer_len, offset, len);
! 3026: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
! 3027: "StatSN=%u, DataSN=%u, Offset=%u, Len=%d\n",
! 3028: conn->StatSN, DataSN, offset, len);
! 3029:
! 3030: /* DATA PDU */
! 3031: rsp = (uint8_t *) &rsp_pdu.bhs;
! 3032: rsp_pdu.data = data + offset;
! 3033: memset(rsp, 0, ISCSI_BHS_LEN);
! 3034: rsp[0] = ISCSI_OP_SCSI_DATAIN;
! 3035: BDADD8(&rsp[1], F_bit, 7);
! 3036: BDADD8(&rsp[1], 0, 6); // A_bit Acknowledge
! 3037: if (F_bit && S_bit) {
! 3038: BDADD8(&rsp[1], O_bit, 2);
! 3039: BDADD8(&rsp[1], U_bit, 1);
! 3040: } else {
! 3041: BDADD8(&rsp[1], 0, 2);
! 3042: BDADD8(&rsp[1], 0, 1);
! 3043: }
! 3044: BDADD8(&rsp[1], S_bit, 0);
! 3045: if (S_bit) {
! 3046: rsp[3] = lu_cmd->status;
! 3047: } else {
! 3048: rsp[3] = 0; // Status or Rsvd
! 3049: }
! 3050: rsp[4] = 0; // TotalAHSLength
! 3051: DSET24(&rsp[5], len); // DataSegmentLength
! 3052:
! 3053: DSET32(&rsp[16], task_tag);
! 3054: DSET32(&rsp[20], transfer_tag);
! 3055:
! 3056: if (S_bit) {
! 3057: DSET32(&rsp[24], conn->StatSN);
! 3058: conn->StatSN++;
! 3059: } else {
! 3060: DSET32(&rsp[24], 0); // StatSN or Reserved
! 3061: }
! 3062: SESS_MTX_LOCK(conn);
! 3063: if (F_bit && S_bit && lu_cmd->I_bit == 0) {
! 3064: conn->sess->MaxCmdSN++;
! 3065: }
! 3066: DSET32(&rsp[28], conn->sess->ExpCmdSN);
! 3067: DSET32(&rsp[32], conn->sess->MaxCmdSN);
! 3068: SESS_MTX_UNLOCK(conn);
! 3069:
! 3070: DSET32(&rsp[36], DataSN);
! 3071: DataSN++;
! 3072:
! 3073: DSET32(&rsp[40], (uint32_t) offset);
! 3074: if (F_bit && S_bit) {
! 3075: DSET32(&rsp[44], residual_len);
! 3076: } else {
! 3077: DSET32(&rsp[44], 0);
! 3078: }
! 3079:
! 3080: rc = istgt_iscsi_write_pdu_internal(conn, &rsp_pdu);
! 3081: if (rc < 0) {
! 3082: ISTGT_ERRLOG("iscsi_write_pdu() failed\n");
! 3083: return -1;
! 3084: }
! 3085: }
! 3086:
! 3087: if (sent_status) {
! 3088: return 1;
! 3089: }
! 3090: return 0;
! 3091: }
! 3092:
! 3093: static int
! 3094: istgt_iscsi_op_scsi(CONN_Ptr conn, ISCSI_PDU_Ptr pdu)
! 3095: {
! 3096: ISTGT_LU_CMD lu_cmd;
! 3097: ISCSI_PDU rsp_pdu;
! 3098: uint8_t *rsp;
! 3099: uint8_t *cp;
! 3100: uint8_t *data;
! 3101: uint8_t *cdb;
! 3102: uint64_t lun;
! 3103: uint32_t task_tag;
! 3104: uint32_t transfer_len;
! 3105: uint32_t CmdSN;
! 3106: uint32_t ExpStatSN;
! 3107: int I_bit, F_bit, R_bit, W_bit, Attr_bit;
! 3108: int o_bit, u_bit, O_bit, U_bit;
! 3109: int bidi_residual_len;
! 3110: int residual_len;
! 3111: int data_len;
! 3112: int alloc_len;
! 3113: int rc;
! 3114:
! 3115: if (!conn->full_feature) {
! 3116: ISTGT_ERRLOG("before Full Feature\n");
! 3117: return -1;
! 3118: }
! 3119:
! 3120: data_len = 0;
! 3121: alloc_len = conn->sendbufsize;
! 3122: data = (uint8_t *) conn->sendbuf;
! 3123: memset(data, 0, alloc_len);
! 3124: memset(&lu_cmd, 0, sizeof lu_cmd);
! 3125:
! 3126: cp = (uint8_t *) &pdu->bhs;
! 3127: I_bit = BGET8(&cp[0], 6);
! 3128: F_bit = BGET8(&cp[1], 7);
! 3129: R_bit = BGET8(&cp[1], 6);
! 3130: W_bit = BGET8(&cp[1], 5);
! 3131: Attr_bit = BGET8W(&cp[1], 2, 3);
! 3132:
! 3133: lun = DGET64(&cp[8]);
! 3134: task_tag = DGET32(&cp[16]);
! 3135: transfer_len = DGET32(&cp[20]);
! 3136: CmdSN = DGET32(&cp[24]);
! 3137: ExpStatSN = DGET32(&cp[28]);
! 3138:
! 3139: cdb = &cp[32];
! 3140: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "CDB", cdb, 16);
! 3141: #if 0
! 3142: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "PDU", cp, ISCSI_BHS_LEN);
! 3143: #endif
! 3144:
! 3145: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 3146: "I=%d, F=%d, R=%d, W=%d, Attr=%d, ITT=%x, TL=%u\n",
! 3147: I_bit, F_bit, R_bit, W_bit, Attr_bit,
! 3148: task_tag, transfer_len);
! 3149: SESS_MTX_LOCK(conn);
! 3150: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
! 3151: "CmdSN=%u, ExpStatSN=%u, StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
! 3152: CmdSN, ExpStatSN, conn->StatSN, conn->sess->ExpCmdSN,
! 3153: conn->sess->MaxCmdSN);
! 3154: if (I_bit == 0) {
! 3155: /* XXX MCS reverse order? */
! 3156: if (SN32_GT(CmdSN, conn->sess->ExpCmdSN)) {
! 3157: if (conn->sess->connections > 1) {
! 3158: struct timespec abstime;
! 3159: time_t now;
! 3160:
! 3161: SESS_MTX_UNLOCK(conn);
! 3162: now = time(NULL);
! 3163: memset(&abstime, 0, sizeof abstime);
! 3164: abstime.tv_sec = now + (MAX_MCSREVWAIT / 1000);
! 3165: abstime.tv_nsec = (MAX_MCSREVWAIT % 1000) * 1000000;
! 3166:
! 3167: rc = 0;
! 3168: SESS_MTX_LOCK(conn);
! 3169: while (SN32_GT(CmdSN, conn->sess->ExpCmdSN)) {
! 3170: conn->sess->req_mcs_cond++;
! 3171: rc = pthread_cond_timedwait(&conn->sess->mcs_cond,
! 3172: &conn->sess->mutex,
! 3173: &abstime);
! 3174: if (rc == ETIMEDOUT) {
! 3175: if (SN32_GT(CmdSN, conn->sess->ExpCmdSN)) {
! 3176: rc = -1;
! 3177: /* timeout */
! 3178: break;
! 3179: }
! 3180: /* OK cond */
! 3181: rc = 0;
! 3182: break;
! 3183: }
! 3184: if (rc != 0) {
! 3185: break;
! 3186: }
! 3187: }
! 3188: if (rc < 0) {
! 3189: ISTGT_ERRLOG("MCS: CmdSN(%u) error ExpCmdSN=%u\n",
! 3190: CmdSN, conn->sess->ExpCmdSN);
! 3191: SESS_MTX_UNLOCK(conn);
! 3192: return -1;
! 3193: }
! 3194: #if 0
! 3195: ISTGT_WARNLOG("MCS: reverse CmdSN=%u(retry=%d, yields=%d)\n",
! 3196: CmdSN, retry, try_yields);
! 3197: #endif
! 3198: }
! 3199: }
! 3200: }
! 3201:
! 3202: if (I_bit == 0) {
! 3203: if (SN32_LT(CmdSN, conn->sess->ExpCmdSN)
! 3204: || SN32_GT(CmdSN, conn->sess->MaxCmdSN)) {
! 3205: ISTGT_ERRLOG("CmdSN(%u) ignore (ExpCmdSN=%u, MaxCmdSN=%u)\n",
! 3206: CmdSN, conn->sess->ExpCmdSN,
! 3207: conn->sess->MaxCmdSN);
! 3208: SESS_MTX_UNLOCK(conn);
! 3209: return -1;
! 3210: }
! 3211: if (SN32_GT(CmdSN, conn->sess->ExpCmdSN)) {
! 3212: ISTGT_WARNLOG("CmdSN(%u) > ExpCmdSN(%u)\n",
! 3213: CmdSN, conn->sess->ExpCmdSN);
! 3214: conn->sess->ExpCmdSN = CmdSN;
! 3215: }
! 3216: } else if (CmdSN != conn->sess->ExpCmdSN) {
! 3217: SESS_MTX_UNLOCK(conn);
! 3218: ISTGT_ERRLOG("CmdSN(%u) error ExpCmdSN=%u\n",
! 3219: CmdSN, conn->sess->ExpCmdSN);
! 3220: return -1;
! 3221: }
! 3222: SESS_MTX_UNLOCK(conn);
! 3223: if (SN32_GT(ExpStatSN, conn->StatSN)) {
! 3224: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "StatSN(%u) advanced\n",
! 3225: ExpStatSN);
! 3226: conn->StatSN = ExpStatSN;
! 3227: }
! 3228: {
! 3229: uint32_t QCmdSN;
! 3230: SESS_MTX_LOCK(conn);
! 3231: QCmdSN = conn->sess->MaxCmdSN - conn->sess->ExpCmdSN + 1;
! 3232: SESS_MTX_UNLOCK(conn);
! 3233: QCmdSN += conn->queue_depth;
! 3234: if (SN32_LT(ExpStatSN + QCmdSN, conn->StatSN)) {
! 3235: ISTGT_ERRLOG("StatSN(%u/%u) QCmdSN(%u) error\n",
! 3236: ExpStatSN, conn->StatSN, QCmdSN);
! 3237: return -1;
! 3238: }
! 3239: }
! 3240:
! 3241: lu_cmd.pdu = pdu;
! 3242: SESS_MTX_LOCK(conn);
! 3243: lu_cmd.lu = conn->sess->lu;
! 3244: if (I_bit == 0) {
! 3245: conn->sess->ExpCmdSN++;
! 3246: if (conn->sess->req_mcs_cond > 0) {
! 3247: conn->sess->req_mcs_cond--;
! 3248: rc = pthread_cond_broadcast(&conn->sess->mcs_cond);
! 3249: if (rc != 0) {
! 3250: SESS_MTX_UNLOCK(conn);
! 3251: ISTGT_ERRLOG("cond_broadcast() failed\n");
! 3252: return -1;
! 3253: }
! 3254: }
! 3255: }
! 3256: SESS_MTX_UNLOCK(conn);
! 3257:
! 3258: if (R_bit != 0 && W_bit != 0) {
! 3259: ISTGT_ERRLOG("Bidirectional CDB is not supported\n");
! 3260: return -1;
! 3261: }
! 3262:
! 3263: lu_cmd.I_bit = I_bit;
! 3264: lu_cmd.F_bit = F_bit;
! 3265: lu_cmd.R_bit = R_bit;
! 3266: lu_cmd.W_bit = W_bit;
! 3267: lu_cmd.Attr_bit = Attr_bit;
! 3268: lu_cmd.lun = lun;
! 3269: lu_cmd.task_tag = task_tag;
! 3270: lu_cmd.transfer_len = transfer_len;
! 3271: lu_cmd.CmdSN = CmdSN;
! 3272: lu_cmd.cdb = cdb;
! 3273:
! 3274: lu_cmd.iobuf = conn->iobuf;
! 3275: lu_cmd.iobufsize = conn->iobufsize;
! 3276: lu_cmd.data = data;
! 3277: lu_cmd.data_len = 0;
! 3278: lu_cmd.alloc_len = alloc_len;
! 3279: lu_cmd.sense_data = conn->snsbuf;
! 3280: lu_cmd.sense_data_len = 0;
! 3281: lu_cmd.sense_alloc_len = conn->snsbufsize;
! 3282:
! 3283: /* need R2T? */
! 3284: if ((W_bit && F_bit) && (conn->max_r2t > 0)) {
! 3285: if (lu_cmd.pdu->data_segment_len < transfer_len) {
! 3286: rc = istgt_add_transfer_task(conn, &lu_cmd);
! 3287: if (rc < 0) {
! 3288: ISTGT_ERRLOG("add_transfer_task() failed\n");
! 3289: return -1;
! 3290: }
! 3291: }
! 3292: }
! 3293:
! 3294: /* execute SCSI command */
! 3295: rc = istgt_lu_execute(conn, &lu_cmd);
! 3296: if (rc < 0) {
! 3297: ISTGT_ERRLOG("lu_execute() failed\n");
! 3298: return -1;
! 3299: }
! 3300: switch (rc) {
! 3301: case ISTGT_LU_TASK_RESULT_QUEUE_OK:
! 3302: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Queue OK\n");
! 3303: return 0;
! 3304: case ISTGT_LU_TASK_RESULT_QUEUE_FULL:
! 3305: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Queue Full\n");
! 3306: ISTGT_WARNLOG("Queue Full\n");
! 3307: break;
! 3308: case ISTGT_LU_TASK_RESULT_IMMEDIATE:
! 3309: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Immediate\n");
! 3310: break;
! 3311: default:
! 3312: ISTGT_ERRLOG("lu_execute() unknown rc=%d\n", rc);
! 3313: return -1;
! 3314: }
! 3315:
! 3316: /* transfer data from logical unit */
! 3317: /* (direction is view of initiator side) */
! 3318: if (lu_cmd.R_bit
! 3319: && (lu_cmd.status == ISTGT_SCSI_STATUS_GOOD
! 3320: || lu_cmd.sense_data_len != 0)) {
! 3321: rc = istgt_iscsi_transfer_in(conn, &lu_cmd);
! 3322: if (rc < 0) {
! 3323: ISTGT_ERRLOG("iscsi_transfer_in() failed\n");
! 3324: return -1;
! 3325: }
! 3326: if (rc > 0) {
! 3327: /* sent status by last DATAIN PDU */
! 3328: return 0;
! 3329: }
! 3330: }
! 3331:
! 3332: o_bit = u_bit = O_bit = U_bit = 0;
! 3333: bidi_residual_len = residual_len = 0;
! 3334: data_len = lu_cmd.data_len;
! 3335: if (transfer_len != 0
! 3336: && lu_cmd.status == ISTGT_SCSI_STATUS_GOOD) {
! 3337: if (data_len < transfer_len) {
! 3338: /* underflow */
! 3339: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Underflow %u/%u\n",
! 3340: data_len, transfer_len);
! 3341: residual_len = transfer_len - data_len;
! 3342: U_bit = 1;
! 3343: } else if (data_len > transfer_len) {
! 3344: /* overflow */
! 3345: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Overflow %u/%u\n",
! 3346: data_len, transfer_len);
! 3347: residual_len = data_len - transfer_len;
! 3348: O_bit = 1;
! 3349: } else {
! 3350: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Transfer %u\n",
! 3351: transfer_len);
! 3352: }
! 3353: }
! 3354:
! 3355: /* response PDU */
! 3356: rsp = (uint8_t *) &rsp_pdu.bhs;
! 3357: rsp_pdu.data = lu_cmd.sense_data;
! 3358: memset(rsp, 0, ISCSI_BHS_LEN);
! 3359: rsp[0] = ISCSI_OP_SCSI_RSP;
! 3360: BDADD8(&rsp[1], 1, 7);
! 3361: BDADD8(&rsp[1], o_bit, 4);
! 3362: BDADD8(&rsp[1], u_bit, 3);
! 3363: BDADD8(&rsp[1], O_bit, 2);
! 3364: BDADD8(&rsp[1], U_bit, 1);
! 3365: rsp[2] = 0x00; // Command Completed at Target
! 3366: //rsp[2] = 0x01; // Target Failure
! 3367: rsp[3] = lu_cmd.status;
! 3368: rsp[4] = 0; // TotalAHSLength
! 3369: DSET24(&rsp[5], lu_cmd.sense_data_len); // DataSegmentLength
! 3370:
! 3371: DSET32(&rsp[16], task_tag);
! 3372: DSET32(&rsp[20], 0); // SNACK Tag
! 3373:
! 3374: DSET32(&rsp[24], conn->StatSN);
! 3375: conn->StatSN++;
! 3376: SESS_MTX_LOCK(conn);
! 3377: if (I_bit == 0) {
! 3378: conn->sess->MaxCmdSN++;
! 3379: }
! 3380: DSET32(&rsp[28], conn->sess->ExpCmdSN);
! 3381: DSET32(&rsp[32], conn->sess->MaxCmdSN);
! 3382: SESS_MTX_UNLOCK(conn);
! 3383:
! 3384: DSET32(&rsp[36], 0); // ExpDataSN
! 3385: DSET32(&rsp[40], bidi_residual_len);
! 3386: DSET32(&rsp[44], residual_len);
! 3387:
! 3388: rc = istgt_iscsi_write_pdu(conn, &rsp_pdu);
! 3389: if (rc < 0) {
! 3390: ISTGT_ERRLOG("iscsi_write_pdu() failed\n");
! 3391: return -1;
! 3392: }
! 3393:
! 3394: return 0;
! 3395: }
! 3396:
! 3397: static int
! 3398: istgt_iscsi_task_transfer_out(CONN_Ptr conn, ISTGT_LU_TASK_Ptr lu_task)
! 3399: {
! 3400: ISTGT_LU_CMD_Ptr lu_cmd;
! 3401: uint32_t transfer_len;
! 3402: int rc;
! 3403:
! 3404: lu_cmd = &lu_task->lu_cmd;
! 3405: transfer_len = lu_cmd->transfer_len;
! 3406:
! 3407: rc = istgt_iscsi_transfer_out(conn, lu_cmd, lu_cmd->iobuf,
! 3408: lu_cmd->iobufsize, transfer_len);
! 3409: return rc;
! 3410: }
! 3411:
! 3412: static int
! 3413: istgt_iscsi_task_response(CONN_Ptr conn, ISTGT_LU_TASK_Ptr lu_task)
! 3414: {
! 3415: ISTGT_LU_CMD_Ptr lu_cmd;
! 3416: ISCSI_PDU rsp_pdu;
! 3417: uint8_t *rsp;
! 3418: uint32_t task_tag;
! 3419: uint32_t transfer_len;
! 3420: uint32_t CmdSN;
! 3421: int I_bit;
! 3422: int o_bit, u_bit, O_bit, U_bit;
! 3423: int bidi_residual_len;
! 3424: int residual_len;
! 3425: int data_len;
! 3426: int rc;
! 3427:
! 3428: lu_cmd = &lu_task->lu_cmd;
! 3429: transfer_len = lu_cmd->transfer_len;
! 3430: task_tag = lu_cmd->task_tag;
! 3431: I_bit = lu_cmd->I_bit;
! 3432: CmdSN = lu_cmd->CmdSN;
! 3433:
! 3434: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "SCSI response CmdSN=%u\n", CmdSN);
! 3435:
! 3436: /* transfer data from logical unit */
! 3437: /* (direction is view of initiator side) */
! 3438: if (lu_cmd->R_bit
! 3439: && (lu_cmd->status == ISTGT_SCSI_STATUS_GOOD
! 3440: || lu_cmd->sense_data_len != 0)) {
! 3441: if (lu_task->lock) {
! 3442: rc = istgt_iscsi_transfer_in_internal(conn, lu_cmd);
! 3443: } else {
! 3444: rc = istgt_iscsi_transfer_in(conn, lu_cmd);
! 3445: }
! 3446: if (rc < 0) {
! 3447: ISTGT_ERRLOG("iscsi_transfer_in() failed\n");
! 3448: return -1;
! 3449: }
! 3450: if (rc > 0) {
! 3451: /* sent status by last DATAIN PDU */
! 3452: return 0;
! 3453: }
! 3454: }
! 3455:
! 3456: o_bit = u_bit = O_bit = U_bit = 0;
! 3457: bidi_residual_len = residual_len = 0;
! 3458: data_len = lu_cmd->data_len;
! 3459: if (transfer_len != 0
! 3460: && lu_cmd->status == ISTGT_SCSI_STATUS_GOOD) {
! 3461: if (data_len < transfer_len) {
! 3462: /* underflow */
! 3463: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Underflow %u/%u\n",
! 3464: data_len, transfer_len);
! 3465: residual_len = transfer_len - data_len;
! 3466: U_bit = 1;
! 3467: } else if (data_len > transfer_len) {
! 3468: /* overflow */
! 3469: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Overflow %u/%u\n",
! 3470: data_len, transfer_len);
! 3471: residual_len = data_len - transfer_len;
! 3472: O_bit = 1;
! 3473: } else {
! 3474: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Transfer %u\n",
! 3475: transfer_len);
! 3476: }
! 3477: }
! 3478:
! 3479: /* response PDU */
! 3480: rsp = (uint8_t *) &rsp_pdu.bhs;
! 3481: rsp_pdu.data = lu_cmd->sense_data;
! 3482: memset(rsp, 0, ISCSI_BHS_LEN);
! 3483: rsp[0] = ISCSI_OP_SCSI_RSP;
! 3484: BDADD8(&rsp[1], 1, 7);
! 3485: BDADD8(&rsp[1], o_bit, 4);
! 3486: BDADD8(&rsp[1], u_bit, 3);
! 3487: BDADD8(&rsp[1], O_bit, 2);
! 3488: BDADD8(&rsp[1], U_bit, 1);
! 3489: rsp[2] = 0x00; // Command Completed at Target
! 3490: //rsp[2] = 0x01; // Target Failure
! 3491: rsp[3] = lu_cmd->status;
! 3492: rsp[4] = 0; // TotalAHSLength
! 3493: DSET24(&rsp[5], lu_cmd->sense_data_len); // DataSegmentLength
! 3494:
! 3495: DSET32(&rsp[16], task_tag);
! 3496: DSET32(&rsp[20], 0); // SNACK Tag
! 3497:
! 3498: DSET32(&rsp[24], conn->StatSN);
! 3499: conn->StatSN++;
! 3500: SESS_MTX_LOCK(conn);
! 3501: if (I_bit == 0) {
! 3502: conn->sess->MaxCmdSN++;
! 3503: }
! 3504: DSET32(&rsp[28], conn->sess->ExpCmdSN);
! 3505: DSET32(&rsp[32], conn->sess->MaxCmdSN);
! 3506: SESS_MTX_UNLOCK(conn);
! 3507:
! 3508: DSET32(&rsp[36], 0); // ExpDataSN
! 3509: DSET32(&rsp[40], bidi_residual_len);
! 3510: DSET32(&rsp[44], residual_len);
! 3511:
! 3512: if (lu_task->lock) {
! 3513: rc = istgt_iscsi_write_pdu_internal(conn, &rsp_pdu);
! 3514: } else {
! 3515: rc = istgt_iscsi_write_pdu(conn, &rsp_pdu);
! 3516: }
! 3517: if (rc < 0) {
! 3518: ISTGT_ERRLOG("iscsi_write_pdu() failed\n");
! 3519: return -1;
! 3520: }
! 3521:
! 3522: return 0;
! 3523: }
! 3524:
! 3525: static int
! 3526: istgt_iscsi_op_task(CONN_Ptr conn, ISCSI_PDU_Ptr pdu)
! 3527: {
! 3528: ISCSI_PDU rsp_pdu;
! 3529: uint8_t *rsp;
! 3530: uint8_t *cp;
! 3531: uint64_t lun;
! 3532: uint32_t task_tag;
! 3533: uint32_t ref_task_tag;
! 3534: uint32_t CmdSN;
! 3535: uint32_t ExpStatSN;
! 3536: uint32_t ref_CmdSN;
! 3537: uint32_t ExpDataSN;
! 3538: int I_bit;
! 3539: int function;
! 3540: int response;
! 3541: int rc;
! 3542:
! 3543: if (!conn->full_feature) {
! 3544: ISTGT_ERRLOG("before Full Feature\n");
! 3545: return -1;
! 3546: }
! 3547:
! 3548: cp = (uint8_t *) &pdu->bhs;
! 3549: I_bit = BGET8(&cp[0], 6);
! 3550: function = BGET8W(&cp[1], 6, 7);
! 3551:
! 3552: lun = DGET64(&cp[8]);
! 3553: task_tag = DGET32(&cp[16]);
! 3554: ref_task_tag = DGET32(&cp[20]);
! 3555: CmdSN = DGET32(&cp[24]);
! 3556: ExpStatSN = DGET32(&cp[28]);
! 3557: ref_CmdSN = DGET32(&cp[32]);
! 3558: ExpDataSN = DGET32(&cp[36]);
! 3559:
! 3560: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 3561: "I=%d, func=%d, ITT=%x, ref TT=%x, LUN=0x%16.16"PRIx64"\n",
! 3562: I_bit, function, task_tag, ref_task_tag, lun);
! 3563: SESS_MTX_LOCK(conn);
! 3564: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
! 3565: "CmdSN=%u, ExpStatSN=%u, StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
! 3566: CmdSN, ExpStatSN, conn->StatSN, conn->sess->ExpCmdSN,
! 3567: conn->sess->MaxCmdSN);
! 3568: if (CmdSN != conn->sess->ExpCmdSN) {
! 3569: ISTGT_WARNLOG("CmdSN(%u) might have dropped\n",
! 3570: conn->sess->ExpCmdSN);
! 3571: conn->sess->ExpCmdSN = CmdSN;
! 3572: }
! 3573: SESS_MTX_UNLOCK(conn);
! 3574: if (SN32_GT(ExpStatSN, conn->StatSN)) {
! 3575: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "StatSN(%u) advanced\n",
! 3576: ExpStatSN);
! 3577: conn->StatSN = ExpStatSN;
! 3578: }
! 3579: #if 0
! 3580: /* not need */
! 3581: if (ExpStatSN != conn->StatSN) {
! 3582: ISTGT_WARNLOG("StatSN(%u/%u) might have dropped\n",
! 3583: ExpStatSN, conn->StatSN);
! 3584: conn->StatSN = ExpStatSN;
! 3585: }
! 3586: #endif
! 3587:
! 3588: response = 0; // Function complete.
! 3589: switch (function) {
! 3590: case ISCSI_TASK_FUNC_ABORT_TASK:
! 3591: ISTGT_LOG("ABORT_TASK\n");
! 3592: SESS_MTX_LOCK(conn);
! 3593: rc = istgt_lu_clear_task_ITLQ(conn, conn->sess->lu, lun,
! 3594: ref_CmdSN);
! 3595: SESS_MTX_UNLOCK(conn);
! 3596: if (rc < 0) {
! 3597: ISTGT_ERRLOG("LU reset failed\n");
! 3598: }
! 3599: istgt_clear_transfer_task(conn, ref_CmdSN);
! 3600: break;
! 3601: case ISCSI_TASK_FUNC_ABORT_TASK_SET:
! 3602: ISTGT_LOG("ABORT_TASK_SET\n");
! 3603: SESS_MTX_LOCK(conn);
! 3604: rc = istgt_lu_clear_task_ITL(conn, conn->sess->lu, lun);
! 3605: SESS_MTX_UNLOCK(conn);
! 3606: if (rc < 0) {
! 3607: ISTGT_ERRLOG("LU reset failed\n");
! 3608: }
! 3609: istgt_clear_all_transfer_task(conn);
! 3610: break;
! 3611: case ISCSI_TASK_FUNC_CLEAR_ACA:
! 3612: ISTGT_LOG("CLEAR_ACA\n");
! 3613: break;
! 3614: case ISCSI_TASK_FUNC_CLEAR_TASK_SET:
! 3615: ISTGT_LOG("CLEAR_TASK_SET\n");
! 3616: SESS_MTX_LOCK(conn);
! 3617: rc = istgt_lu_clear_task_ITL(conn, conn->sess->lu, lun);
! 3618: SESS_MTX_UNLOCK(conn);
! 3619: if (rc < 0) {
! 3620: ISTGT_ERRLOG("LU reset failed\n");
! 3621: }
! 3622: istgt_clear_all_transfer_task(conn);
! 3623: break;
! 3624: case ISCSI_TASK_FUNC_LOGICAL_UNIT_RESET:
! 3625: ISTGT_LOG("LOGICAL_UNIT_RESET\n");
! 3626: istgt_iscsi_drop_all_conns(conn);
! 3627: SESS_MTX_LOCK(conn);
! 3628: rc = istgt_lu_reset(conn->sess->lu, lun);
! 3629: SESS_MTX_UNLOCK(conn);
! 3630: if (rc < 0) {
! 3631: ISTGT_ERRLOG("LU reset failed\n");
! 3632: }
! 3633: //conn->state = CONN_STATE_EXITING;
! 3634: break;
! 3635: case ISCSI_TASK_FUNC_TARGET_WARM_RESET:
! 3636: ISTGT_LOG("TARGET_WARM_RESET\n");
! 3637: istgt_iscsi_drop_all_conns(conn);
! 3638: SESS_MTX_LOCK(conn);
! 3639: rc = istgt_lu_reset(conn->sess->lu, lun);
! 3640: SESS_MTX_UNLOCK(conn);
! 3641: if (rc < 0) {
! 3642: ISTGT_ERRLOG("LU reset failed\n");
! 3643: }
! 3644: //conn->state = CONN_STATE_EXITING;
! 3645: break;
! 3646: case ISCSI_TASK_FUNC_TARGET_COLD_RESET:
! 3647: ISTGT_LOG("TARGET_COLD_RESET\n");
! 3648: istgt_iscsi_drop_all_conns(conn);
! 3649: SESS_MTX_LOCK(conn);
! 3650: rc = istgt_lu_reset(conn->sess->lu, lun);
! 3651: SESS_MTX_UNLOCK(conn);
! 3652: if (rc < 0) {
! 3653: ISTGT_ERRLOG("LU reset failed\n");
! 3654: }
! 3655: conn->state = CONN_STATE_EXITING;
! 3656: break;
! 3657: case ISCSI_TASK_FUNC_TASK_REASSIGN:
! 3658: ISTGT_LOG("TASK_REASSIGN\n");
! 3659: break;
! 3660: default:
! 3661: ISTGT_ERRLOG("unsupported function %d\n", function);
! 3662: response = 255; // Function rejected.
! 3663: break;
! 3664: }
! 3665:
! 3666: /* response PDU */
! 3667: rsp = (uint8_t *) &rsp_pdu.bhs;
! 3668: rsp_pdu.data = NULL;
! 3669: memset(rsp, 0, ISCSI_BHS_LEN);
! 3670: rsp[0] = ISCSI_OP_TASK_RSP;
! 3671: BDADD8(&rsp[1], 1, 7);
! 3672: rsp[2] = response;
! 3673: rsp[4] = 0; // TotalAHSLength
! 3674: DSET24(&rsp[5], 0); // DataSegmentLength
! 3675:
! 3676: DSET32(&rsp[16], task_tag);
! 3677:
! 3678: DSET32(&rsp[24], conn->StatSN);
! 3679: conn->StatSN++;
! 3680: SESS_MTX_LOCK(conn);
! 3681: if (I_bit == 0) {
! 3682: conn->sess->ExpCmdSN++;
! 3683: conn->sess->MaxCmdSN++;
! 3684: }
! 3685: DSET32(&rsp[28], conn->sess->ExpCmdSN);
! 3686: DSET32(&rsp[32], conn->sess->MaxCmdSN);
! 3687: SESS_MTX_UNLOCK(conn);
! 3688:
! 3689: rc = istgt_iscsi_write_pdu(conn, &rsp_pdu);
! 3690: if (rc < 0) {
! 3691: ISTGT_ERRLOG("iscsi_write_pdu() failed\n");
! 3692: return -1;
! 3693: }
! 3694:
! 3695: return 0;
! 3696: }
! 3697:
! 3698: static int
! 3699: istgt_iscsi_op_nopout(CONN_Ptr conn, ISCSI_PDU_Ptr pdu)
! 3700: {
! 3701: ISCSI_PDU rsp_pdu;
! 3702: uint8_t *rsp;
! 3703: uint8_t *cp;
! 3704: uint8_t *data;
! 3705: uint64_t lun;
! 3706: uint32_t task_tag;
! 3707: uint32_t transfer_tag;
! 3708: uint32_t CmdSN;
! 3709: uint32_t ExpStatSN;
! 3710: int I_bit;
! 3711: int ping_len;
! 3712: int data_len;
! 3713: int alloc_len;
! 3714: int rc;
! 3715:
! 3716: if (!conn->full_feature) {
! 3717: ISTGT_ERRLOG("before Full Feature\n");
! 3718: return -1;
! 3719: }
! 3720:
! 3721: data_len = 0;
! 3722: alloc_len = conn->sendbufsize;
! 3723: data = (uint8_t *) conn->sendbuf;
! 3724: memset(data, 0, alloc_len);
! 3725:
! 3726: cp = (uint8_t *) &pdu->bhs;
! 3727: I_bit = BGET8(&cp[0], 6);
! 3728: ping_len = DGET24(&cp[5]);
! 3729:
! 3730: lun = DGET64(&cp[8]);
! 3731: task_tag = DGET32(&cp[16]);
! 3732: transfer_tag = DGET32(&cp[20]);
! 3733: CmdSN = DGET32(&cp[24]);
! 3734: ExpStatSN = DGET32(&cp[28]);
! 3735:
! 3736: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 3737: "I=%d, ITT=%x, TTT=%x\n",
! 3738: I_bit, task_tag, transfer_tag);
! 3739: SESS_MTX_LOCK(conn);
! 3740: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
! 3741: "CmdSN=%u, ExpStatSN=%u, StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
! 3742: CmdSN, ExpStatSN, conn->StatSN, conn->sess->ExpCmdSN,
! 3743: conn->sess->MaxCmdSN);
! 3744: if (I_bit == 0) {
! 3745: if (SN32_LT(CmdSN, conn->sess->ExpCmdSN)
! 3746: || SN32_GT(CmdSN, conn->sess->MaxCmdSN)) {
! 3747: ISTGT_ERRLOG("CmdSN(%u) ignore (ExpCmdSN=%u, MaxCmdSN=%u)\n",
! 3748: CmdSN, conn->sess->ExpCmdSN,
! 3749: conn->sess->MaxCmdSN);
! 3750: SESS_MTX_UNLOCK(conn);
! 3751: return -1;
! 3752: }
! 3753: } else if (CmdSN != conn->sess->ExpCmdSN) {
! 3754: SESS_MTX_UNLOCK(conn);
! 3755: ISTGT_ERRLOG("CmdSN(%u) error\n", CmdSN);
! 3756: return -1;
! 3757: }
! 3758: SESS_MTX_UNLOCK(conn);
! 3759: if (SN32_GT(ExpStatSN, conn->StatSN)) {
! 3760: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "StatSN(%u) advanced\n",
! 3761: ExpStatSN);
! 3762: conn->StatSN = ExpStatSN;
! 3763: }
! 3764: {
! 3765: uint32_t QCmdSN;
! 3766: SESS_MTX_LOCK(conn);
! 3767: QCmdSN = conn->sess->MaxCmdSN - conn->sess->ExpCmdSN + 1;
! 3768: SESS_MTX_UNLOCK(conn);
! 3769: QCmdSN += conn->queue_depth;
! 3770: if (SN32_LT(ExpStatSN + QCmdSN, conn->StatSN)) {
! 3771: ISTGT_ERRLOG("StatSN(%u/%u) QCmdSN(%u) error\n",
! 3772: ExpStatSN, conn->StatSN, QCmdSN);
! 3773: return -1;
! 3774: }
! 3775: }
! 3776:
! 3777: if (task_tag == 0xffffffffU) {
! 3778: if (I_bit == 1) {
! 3779: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 3780: "got NOPOUT ITT=0xffffffff\n");
! 3781: return 0;
! 3782: } else {
! 3783: ISTGT_ERRLOG("got NOPOUT ITT=0xffffffff, I=0\n");
! 3784: return -1;
! 3785: }
! 3786: }
! 3787:
! 3788: /* response of NOPOUT */
! 3789: if (ping_len != 0) {
! 3790: if (ping_len > alloc_len) {
! 3791: data_len = DMIN32(alloc_len,
! 3792: conn->MaxRecvDataSegmentLength);
! 3793: } else {
! 3794: data_len = DMIN32(ping_len,
! 3795: conn->MaxRecvDataSegmentLength);
! 3796: }
! 3797: /* ping data */
! 3798: memcpy(data, pdu->data, data_len);
! 3799: }
! 3800: transfer_tag = 0xffffffffU;
! 3801:
! 3802: /* response PDU */
! 3803: rsp = (uint8_t *) &rsp_pdu.bhs;
! 3804: rsp_pdu.data = data;
! 3805: memset(rsp, 0, ISCSI_BHS_LEN);
! 3806: rsp[0] = ISCSI_OP_NOPIN;
! 3807: BDADD8(&rsp[1], 1, 7);
! 3808: rsp[4] = 0; // TotalAHSLength
! 3809: DSET24(&rsp[5], data_len); // DataSegmentLength
! 3810:
! 3811: DSET64(&rsp[8], lun);
! 3812: DSET32(&rsp[16], task_tag);
! 3813: DSET32(&rsp[20], transfer_tag);
! 3814:
! 3815: DSET32(&rsp[24], conn->StatSN);
! 3816: conn->StatSN++;
! 3817: SESS_MTX_LOCK(conn);
! 3818: if (I_bit == 0) {
! 3819: conn->sess->ExpCmdSN++;
! 3820: conn->sess->MaxCmdSN++;
! 3821: }
! 3822: DSET32(&rsp[28], conn->sess->ExpCmdSN);
! 3823: DSET32(&rsp[32], conn->sess->MaxCmdSN);
! 3824: SESS_MTX_UNLOCK(conn);
! 3825:
! 3826: rc = istgt_iscsi_write_pdu(conn, &rsp_pdu);
! 3827: if (rc < 0) {
! 3828: ISTGT_ERRLOG("iscsi_write_pdu() failed\n");
! 3829: return -1;
! 3830: }
! 3831:
! 3832: return 0;
! 3833: }
! 3834:
! 3835: static ISTGT_R2T_TASK_Ptr
! 3836: istgt_allocate_transfer_task(void)
! 3837: {
! 3838: ISTGT_R2T_TASK_Ptr r2t_task;
! 3839:
! 3840: r2t_task = xmalloc(sizeof *r2t_task);
! 3841: memset(r2t_task, 0, sizeof *r2t_task);
! 3842: r2t_task->conn = NULL;
! 3843: r2t_task->lu = NULL;
! 3844: r2t_task->iobuf = NULL;
! 3845: return r2t_task;
! 3846: }
! 3847:
! 3848: static void
! 3849: istgt_free_transfer_task(ISTGT_R2T_TASK_Ptr r2t_task)
! 3850: {
! 3851: if (r2t_task == NULL)
! 3852: return;
! 3853: xfree(r2t_task->iobuf);
! 3854: xfree(r2t_task);
! 3855: }
! 3856:
! 3857: static ISTGT_R2T_TASK_Ptr
! 3858: istgt_get_transfer_task(CONN_Ptr conn, uint32_t transfer_tag)
! 3859: {
! 3860: ISTGT_R2T_TASK_Ptr r2t_task;
! 3861: int i;
! 3862:
! 3863: MTX_LOCK(&conn->r2t_mutex);
! 3864: if (conn->pending_r2t == 0) {
! 3865: MTX_UNLOCK(&conn->r2t_mutex);
! 3866: return NULL;
! 3867: }
! 3868: for (i = 0; i < conn->pending_r2t; i++) {
! 3869: r2t_task = conn->r2t_tasks[i];
! 3870: #if 0
! 3871: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 3872: "CmdSN=%d, TransferTag=%x/%x\n",
! 3873: r2t_task->CmdSN, r2t_task->transfer_tag, transfer_tag);
! 3874: #endif
! 3875: if (r2t_task->transfer_tag == transfer_tag) {
! 3876: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 3877: "Match index=%d, CmdSN=%d, TransferTag=%x\n",
! 3878: i, r2t_task->CmdSN, r2t_task->transfer_tag);
! 3879: MTX_UNLOCK(&conn->r2t_mutex);
! 3880: return r2t_task;
! 3881: }
! 3882: }
! 3883: MTX_UNLOCK(&conn->r2t_mutex);
! 3884: return NULL;
! 3885: }
! 3886:
! 3887: static int
! 3888: istgt_add_transfer_task(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
! 3889: {
! 3890: ISTGT_R2T_TASK_Ptr r2t_task;
! 3891: uint32_t transfer_len;
! 3892: uint32_t transfer_tag;
! 3893: int first_burst_len;
! 3894: int max_burst_len;
! 3895: int data_len;
! 3896: int offset = 0;
! 3897: int len;
! 3898: int idx;
! 3899: int rc;
! 3900:
! 3901: MTX_LOCK(&conn->r2t_mutex);
! 3902: if (conn->pending_r2t >= conn->max_r2t) {
! 3903: // no slot available, skip now...
! 3904: //ISTGT_WARNLOG("No R2T space available (%d/%d)\n",
! 3905: // conn->pending_r2t, conn->max_r2t);
! 3906: MTX_UNLOCK(&conn->r2t_mutex);
! 3907: return 0;
! 3908: }
! 3909: MTX_UNLOCK(&conn->r2t_mutex);
! 3910:
! 3911: transfer_len = lu_cmd->transfer_len;
! 3912: transfer_tag = lu_cmd->task_tag;
! 3913: data_len = lu_cmd->pdu->data_segment_len;
! 3914: first_burst_len = conn->FirstBurstLength;
! 3915: max_burst_len = conn->MaxBurstLength;
! 3916: offset += data_len;
! 3917: if (offset >= first_burst_len) {
! 3918: len = DMIN32(max_burst_len, (transfer_len - offset));
! 3919:
! 3920: r2t_task = istgt_allocate_transfer_task();
! 3921: r2t_task->conn = conn;
! 3922: r2t_task->lu = lu_cmd->lu;
! 3923: r2t_task->lun = lu_cmd->lun;
! 3924: r2t_task->CmdSN = lu_cmd->CmdSN;
! 3925: r2t_task->task_tag = lu_cmd->task_tag;
! 3926: r2t_task->transfer_len = transfer_len;
! 3927: r2t_task->transfer_tag = transfer_tag;
! 3928:
! 3929: r2t_task->iobufsize = lu_cmd->transfer_len + 65536;
! 3930: r2t_task->iobuf = xmalloc(r2t_task->iobufsize);
! 3931: memcpy(r2t_task->iobuf, lu_cmd->pdu->data, data_len);
! 3932: r2t_task->offset = offset;
! 3933: r2t_task->R2TSN = 0;
! 3934: r2t_task->DataSN = 0;
! 3935: r2t_task->F_bit = lu_cmd->F_bit;
! 3936:
! 3937: MTX_LOCK(&conn->r2t_mutex);
! 3938: idx = conn->pending_r2t++;
! 3939: conn->r2t_tasks[idx] = r2t_task;
! 3940: MTX_UNLOCK(&conn->r2t_mutex);
! 3941:
! 3942: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 3943: "Send R2T(Offset=%d, Tag=%x)\n",
! 3944: r2t_task->offset, r2t_task->transfer_tag);
! 3945: rc = istgt_iscsi_send_r2t(conn, lu_cmd,
! 3946: r2t_task->offset, len, r2t_task->transfer_tag,
! 3947: &r2t_task->R2TSN);
! 3948: if (rc < 0) {
! 3949: ISTGT_ERRLOG("iscsi_send_r2t() failed\n");
! 3950: return -1;
! 3951: }
! 3952: }
! 3953: return 0;
! 3954: }
! 3955:
! 3956: static void
! 3957: istgt_del_transfer_task(CONN_Ptr conn, ISTGT_R2T_TASK_Ptr r2t_task)
! 3958: {
! 3959: int found = 0;
! 3960: int i;
! 3961:
! 3962: if (r2t_task == NULL)
! 3963: return;
! 3964:
! 3965: MTX_LOCK(&conn->r2t_mutex);
! 3966: if (conn->pending_r2t == 0) {
! 3967: MTX_UNLOCK(&conn->r2t_mutex);
! 3968: return;
! 3969: }
! 3970: for (i = 0; i < conn->pending_r2t; i++) {
! 3971: if (conn->r2t_tasks[i] == r2t_task) {
! 3972: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 3973: "Remove R2T task conn id=%d, index=%d\n",
! 3974: conn->id, i);
! 3975: found = 1;
! 3976: break;
! 3977: }
! 3978: }
! 3979: if (found) {
! 3980: for ( ; i < conn->pending_r2t; i++) {
! 3981: conn->r2t_tasks[i] = conn->r2t_tasks[i + 1];
! 3982: }
! 3983: conn->pending_r2t--;
! 3984: conn->r2t_tasks[conn->pending_r2t] = NULL;
! 3985: }
! 3986: MTX_UNLOCK(&conn->r2t_mutex);
! 3987: }
! 3988:
! 3989: static void
! 3990: istgt_clear_transfer_task(CONN_Ptr conn, uint32_t CmdSN)
! 3991: {
! 3992: int found = 0;
! 3993: int i;
! 3994:
! 3995: MTX_LOCK(&conn->r2t_mutex);
! 3996: if (conn->pending_r2t == 0) {
! 3997: MTX_UNLOCK(&conn->r2t_mutex);
! 3998: return;
! 3999: }
! 4000: for (i = 0; i < conn->pending_r2t; i++) {
! 4001: if (conn->r2t_tasks[i]->CmdSN == CmdSN) {
! 4002: istgt_free_transfer_task(conn->r2t_tasks[i]);
! 4003: conn->r2t_tasks[i] = NULL;
! 4004: found = 1;
! 4005: break;
! 4006: }
! 4007: }
! 4008: if (found) {
! 4009: for ( ; i < conn->pending_r2t; i++) {
! 4010: conn->r2t_tasks[i] = conn->r2t_tasks[i + 1];
! 4011: }
! 4012: conn->pending_r2t--;
! 4013: conn->r2t_tasks[conn->pending_r2t] = NULL;
! 4014: }
! 4015: MTX_UNLOCK(&conn->r2t_mutex);
! 4016: }
! 4017:
! 4018: static void
! 4019: istgt_clear_all_transfer_task(CONN_Ptr conn)
! 4020: {
! 4021: int i;
! 4022:
! 4023: MTX_LOCK(&conn->r2t_mutex);
! 4024: if (conn->pending_r2t == 0) {
! 4025: MTX_UNLOCK(&conn->r2t_mutex);
! 4026: return;
! 4027: }
! 4028: for (i = 0; i < conn->pending_r2t; i++) {
! 4029: istgt_free_transfer_task(conn->r2t_tasks[i]);
! 4030: conn->r2t_tasks[i] = NULL;
! 4031: }
! 4032: conn->pending_r2t = 0;
! 4033: MTX_UNLOCK(&conn->r2t_mutex);
! 4034: }
! 4035:
! 4036: static int
! 4037: istgt_iscsi_op_data(CONN_Ptr conn, ISCSI_PDU_Ptr pdu)
! 4038: {
! 4039: ISTGT_R2T_TASK_Ptr r2t_task;
! 4040: uint8_t *cp;
! 4041: uint8_t *data;
! 4042: uint64_t lun;
! 4043: uint64_t current_lun;
! 4044: uint32_t current_task_tag;
! 4045: uint32_t current_transfer_tag;
! 4046: uint32_t ExpStatSN;
! 4047: uint32_t task_tag;
! 4048: uint32_t transfer_tag;
! 4049: uint32_t ExpDataSN;
! 4050: uint32_t DataSN;
! 4051: uint32_t buffer_offset;
! 4052: int F_bit;
! 4053: int data_len;
! 4054: int alloc_len;
! 4055: int offset;
! 4056: int rc;
! 4057:
! 4058: if (!conn->full_feature) {
! 4059: ISTGT_ERRLOG("before Full Feature\n");
! 4060: return -1;
! 4061: }
! 4062: MTX_LOCK(&conn->r2t_mutex);
! 4063: if (conn->pending_r2t == 0) {
! 4064: ISTGT_ERRLOG("No R2T task\n");
! 4065: MTX_UNLOCK(&conn->r2t_mutex);
! 4066: reject_return:
! 4067: rc = istgt_iscsi_reject(conn, pdu, 0x09);
! 4068: if (rc < 0) {
! 4069: ISTGT_ERRLOG("iscsi_reject() failed\n");
! 4070: return -1;
! 4071: }
! 4072: return 0;
! 4073: }
! 4074: MTX_UNLOCK(&conn->r2t_mutex);
! 4075:
! 4076: cp = (uint8_t *) &pdu->bhs;
! 4077: F_bit = BGET8(&cp[1], 7);
! 4078: data_len = DGET24(&cp[5]);
! 4079:
! 4080: lun = DGET64(&cp[8]);
! 4081: task_tag = DGET32(&cp[16]);
! 4082: transfer_tag = DGET32(&cp[20]);
! 4083: ExpStatSN = DGET32(&cp[28]);
! 4084: DataSN = DGET32(&cp[36]);
! 4085: buffer_offset = DGET32(&cp[40]);
! 4086:
! 4087: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 4088: "pending R2T = %d\n", conn->pending_r2t);
! 4089:
! 4090: r2t_task = istgt_get_transfer_task(conn, transfer_tag);
! 4091: if (r2t_task == NULL) {
! 4092: ISTGT_ERRLOG("Not found R2T task for transfer_tag=%x\n",
! 4093: transfer_tag);
! 4094: goto reject_return;
! 4095: }
! 4096:
! 4097: current_lun = r2t_task->lun;
! 4098: current_task_tag = r2t_task->task_tag;
! 4099: current_transfer_tag = r2t_task->transfer_tag;
! 4100: offset = r2t_task->offset;
! 4101: data = r2t_task->iobuf;
! 4102: alloc_len = r2t_task->iobufsize;
! 4103: ExpDataSN = r2t_task->DataSN;
! 4104:
! 4105: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
! 4106: "StatSN=%u, ExpStatSN=%u, DataSN=%u, Offset=%u, Data=%d\n",
! 4107: conn->StatSN, ExpStatSN, DataSN, buffer_offset, data_len);
! 4108: if (DataSN != ExpDataSN) {
! 4109: ISTGT_ERRLOG("DataSN(%u) error\n", DataSN);
! 4110: return -1;
! 4111: }
! 4112: if (task_tag != current_task_tag) {
! 4113: ISTGT_ERRLOG("task_tag(%x/%x) error\n",
! 4114: task_tag, current_task_tag);
! 4115: return -1;
! 4116: }
! 4117: if (transfer_tag != current_transfer_tag) {
! 4118: ISTGT_ERRLOG("transfer_tag(%x/%x) error\n",
! 4119: transfer_tag, current_transfer_tag);
! 4120: return -1;
! 4121: }
! 4122: if (buffer_offset != offset) {
! 4123: ISTGT_ERRLOG("offset(%u) error\n", buffer_offset);
! 4124: return -1;
! 4125: }
! 4126: if (buffer_offset + data_len > alloc_len) {
! 4127: ISTGT_ERRLOG("offset error\n");
! 4128: return -1;
! 4129: }
! 4130:
! 4131: memcpy(data + buffer_offset, pdu->data, data_len);
! 4132: offset += data_len;
! 4133: ExpDataSN++;
! 4134:
! 4135: r2t_task->offset = offset;
! 4136: r2t_task->DataSN = ExpDataSN;
! 4137: r2t_task->F_bit = F_bit;
! 4138: return 0;
! 4139: }
! 4140:
! 4141: static int
! 4142: istgt_iscsi_send_r2t(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, int offset, int len, uint32_t transfer_tag, uint32_t *R2TSN)
! 4143: {
! 4144: ISCSI_PDU rsp_pdu;
! 4145: uint8_t *rsp;
! 4146: int rc;
! 4147:
! 4148: /* R2T PDU */
! 4149: rsp = (uint8_t *) &rsp_pdu.bhs;
! 4150: rsp_pdu.data = NULL;
! 4151: memset(rsp, 0, ISCSI_BHS_LEN);
! 4152: rsp[0] = ISCSI_OP_R2T;
! 4153: BDADD8(&rsp[1], 1, 7);
! 4154: rsp[4] = 0; // TotalAHSLength
! 4155: DSET24(&rsp[5], 0); // DataSegmentLength
! 4156:
! 4157: DSET64(&rsp[8], lu_cmd->lun);
! 4158: DSET32(&rsp[16], lu_cmd->task_tag);
! 4159: DSET32(&rsp[20], transfer_tag);
! 4160:
! 4161: DSET32(&rsp[24], conn->StatSN);
! 4162: SESS_MTX_LOCK(conn);
! 4163: DSET32(&rsp[28], conn->sess->ExpCmdSN);
! 4164: DSET32(&rsp[32], conn->sess->MaxCmdSN);
! 4165: SESS_MTX_UNLOCK(conn);
! 4166:
! 4167: DSET32(&rsp[36], *R2TSN);
! 4168: *R2TSN += 1;
! 4169: DSET32(&rsp[40], (uint32_t) offset);
! 4170: DSET32(&rsp[44], (uint32_t) len);
! 4171:
! 4172: rc = istgt_iscsi_write_pdu(conn, &rsp_pdu);
! 4173: if (rc < 0) {
! 4174: ISTGT_ERRLOG("iscsi_write_pdu() failed\n");
! 4175: return -1;
! 4176: }
! 4177:
! 4178: return 0;
! 4179: }
! 4180:
! 4181: int
! 4182: istgt_iscsi_transfer_out(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint8_t *data, int alloc_len, int transfer_len)
! 4183: {
! 4184: ISTGT_R2T_TASK_Ptr r2t_task;
! 4185: ISCSI_PDU data_pdu;
! 4186: uint8_t *cp;
! 4187: uint64_t current_lun;
! 4188: uint64_t lun;
! 4189: uint32_t current_task_tag;
! 4190: uint32_t current_transfer_tag;
! 4191: uint32_t ExpDataSN;
! 4192: uint32_t task_tag;
! 4193: uint32_t transfer_tag;
! 4194: uint32_t ExpStatSN;
! 4195: uint32_t DataSN;
! 4196: uint32_t buffer_offset;
! 4197: uint32_t R2TSN;
! 4198: int immediate, opcode;
! 4199: int F_bit;
! 4200: int data_len;
! 4201: int segment_len;
! 4202: int first_burst_len;
! 4203: int max_burst_len;
! 4204: int offset;
! 4205: int len;
! 4206: int r2t_flag;
! 4207: int r2t_offset;
! 4208: int r2t_sent;
! 4209: int rc;
! 4210:
! 4211: current_lun = lu_cmd->lun;
! 4212: current_task_tag = lu_cmd->task_tag;
! 4213: current_transfer_tag = lu_cmd->task_tag;
! 4214: ExpDataSN = 0;
! 4215: segment_len = conn->MaxRecvDataSegmentLength;
! 4216: first_burst_len = conn->FirstBurstLength;
! 4217: max_burst_len = conn->MaxBurstLength;
! 4218: offset = 0;
! 4219: r2t_flag = 0;
! 4220: r2t_offset = 0;
! 4221: r2t_sent = 0;
! 4222: R2TSN = 0;
! 4223:
! 4224: cp = (uint8_t *) &lu_cmd->pdu->bhs;
! 4225: data_len = DGET24(&cp[5]);
! 4226:
! 4227: if (transfer_len > alloc_len) {
! 4228: ISTGT_ERRLOG("transfer_len > alloc_len\n");
! 4229: return -1;
! 4230: }
! 4231:
! 4232: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 4233: "Transfer=%d, First=%d, Max=%d, Segment=%d\n",
! 4234: transfer_len, data_len, max_burst_len, segment_len);
! 4235:
! 4236: r2t_task = istgt_get_transfer_task(conn, current_transfer_tag);
! 4237: if (r2t_task != NULL) {
! 4238: current_lun = r2t_task->lun;
! 4239: current_task_tag = r2t_task->task_tag;
! 4240: current_transfer_tag = r2t_task->transfer_tag;
! 4241: offset = r2t_task->offset;
! 4242: R2TSN = r2t_task->R2TSN;
! 4243: ExpDataSN = r2t_task->DataSN;
! 4244: F_bit = r2t_task->F_bit;
! 4245: r2t_flag = 1;
! 4246: data_len = 0;
! 4247:
! 4248: memcpy(data, r2t_task->iobuf, offset);
! 4249: istgt_del_transfer_task(conn, r2t_task);
! 4250: istgt_free_transfer_task(r2t_task);
! 4251:
! 4252: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 4253: "Using R2T(%d) offset=%d, DataSN=%d\n",
! 4254: conn->pending_r2t, offset, ExpDataSN);
! 4255:
! 4256: rc = istgt_queue_count(&conn->pending_pdus);
! 4257: if (rc > 0) {
! 4258: if (g_trace_flag) {
! 4259: ISTGT_WARNLOG("pending_pdus > 0\n");
! 4260: }
! 4261: }
! 4262: if (offset < transfer_len) {
! 4263: if (offset >= (first_burst_len + max_burst_len)) {
! 4264: /* need more data */
! 4265: r2t_flag = 0;
! 4266: }
! 4267: len = DMIN32(max_burst_len,
! 4268: (transfer_len - offset));
! 4269: memset(&data_pdu.bhs, 0, ISCSI_BHS_LEN);
! 4270: data_pdu.ahs = NULL;
! 4271: data_pdu.data = NULL;
! 4272: data_pdu.copy_pdu = 0;
! 4273: goto r2t_retry;
! 4274: } else if (offset == transfer_len) {
! 4275: if (F_bit == 0) {
! 4276: ISTGT_ERRLOG("F_bit not set on the last PDU\n");
! 4277: return -1;
! 4278: }
! 4279: }
! 4280: goto r2t_return;
! 4281: }
! 4282:
! 4283: if (data_len != 0) {
! 4284: if (data_len > first_burst_len) {
! 4285: ISTGT_ERRLOG("data_len > first_burst_len\n");
! 4286: return -1;
! 4287: }
! 4288: if (offset + data_len > alloc_len) {
! 4289: ISTGT_ERRLOG("offset + data_len > alloc_len\n");
! 4290: return -1;
! 4291: }
! 4292: memcpy(data + offset, lu_cmd->pdu->data, data_len);
! 4293: offset += data_len;
! 4294: r2t_offset = offset;
! 4295: }
! 4296:
! 4297: if (offset < transfer_len) {
! 4298: len = DMIN32(first_burst_len, (transfer_len - offset));
! 4299: memset(&data_pdu.bhs, 0, ISCSI_BHS_LEN);
! 4300: data_pdu.ahs = NULL;
! 4301: data_pdu.data = NULL;
! 4302: data_pdu.copy_pdu = 0;
! 4303: do {
! 4304: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 4305: "Transfer=%d, Offset=%d, Len=%d\n",
! 4306: transfer_len, offset, len);
! 4307: /* send R2T if required */
! 4308: if (r2t_flag == 0
! 4309: && (conn->sess->initial_r2t || offset >= first_burst_len)) {
! 4310: len = DMIN32(max_burst_len,
! 4311: (transfer_len - offset));
! 4312: rc = istgt_iscsi_send_r2t(conn, lu_cmd,
! 4313: offset, len, current_transfer_tag, &R2TSN);
! 4314: if (rc < 0) {
! 4315: ISTGT_ERRLOG("iscsi_send_r2t() failed\n");
! 4316: error_return:
! 4317: if (data_pdu.copy_pdu == 0) {
! 4318: xfree(data_pdu.ahs);
! 4319: data_pdu.ahs = NULL;
! 4320: if (data_pdu.data
! 4321: != data_pdu.shortdata) {
! 4322: xfree(data_pdu.data);
! 4323: }
! 4324: data_pdu.data = NULL;
! 4325: }
! 4326: return -1;
! 4327: }
! 4328: r2t_flag = 1;
! 4329: r2t_offset = offset;
! 4330: r2t_sent = 1;
! 4331: ExpDataSN = 0;
! 4332: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 4333: "R2T, Transfer=%d, Offset=%d, Len=%d\n",
! 4334: transfer_len, offset, len);
! 4335: } else {
! 4336: r2t_sent = 0;
! 4337: }
! 4338:
! 4339: /* transfer by segment_len */
! 4340: rc = istgt_iscsi_read_pdu(conn, &data_pdu);
! 4341: if (rc < 0) {
! 4342: //ISTGT_ERRLOG("iscsi_read_pdu() failed\n");
! 4343: ISTGT_ERRLOG("iscsi_read_pdu() failed, r2t_sent=%d\n",
! 4344: r2t_sent);
! 4345: goto error_return;
! 4346: }
! 4347: immediate = BGET8W(&data_pdu.bhs.opcode, 6, 1);
! 4348: opcode = BGET8W(&data_pdu.bhs.opcode, 5, 6);
! 4349:
! 4350: cp = (uint8_t *) &data_pdu.bhs;
! 4351: F_bit = BGET8(&cp[1], 7);
! 4352: data_len = DGET24(&cp[5]);
! 4353:
! 4354: lun = DGET64(&cp[8]);
! 4355: task_tag = DGET32(&cp[16]);
! 4356: transfer_tag = DGET32(&cp[20]);
! 4357: ExpStatSN = DGET32(&cp[28]);
! 4358: DataSN = DGET32(&cp[36]);
! 4359: buffer_offset = DGET32(&cp[40]);
! 4360:
! 4361: /* current tag DATA? */
! 4362: if (opcode == ISCSI_OP_SCSI_DATAOUT) {
! 4363: if (task_tag != current_task_tag) {
! 4364: not_current_tag:
! 4365: //ISTGT_LOG("not task_tag received\n");
! 4366: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 4367: "not task_tag received\n");
! 4368: rc = istgt_iscsi_op_data(conn,
! 4369: &data_pdu);
! 4370: if (rc < 0) {
! 4371: ISTGT_ERRLOG("iscsi_op_data() failed\n");
! 4372: goto error_return;
! 4373: }
! 4374: if (data_pdu.data != data_pdu.shortdata) {
! 4375: xfree(data_pdu.data);
! 4376: }
! 4377: data_pdu.ahs = NULL;
! 4378: data_pdu.data = NULL;
! 4379: data_pdu.copy_pdu = 0;
! 4380: continue;
! 4381: }
! 4382: if (transfer_tag != current_transfer_tag) {
! 4383: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 4384: "not transfer_tag received\n");
! 4385: goto not_current_tag;
! 4386: }
! 4387: }
! 4388:
! 4389: if (opcode != ISCSI_OP_SCSI_DATAOUT) {
! 4390: ISCSI_PDU_Ptr save_pdu;
! 4391:
! 4392: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 4393: "non DATAOUT PDU received and pending"
! 4394: " (OP=0x%x)\n",
! 4395: opcode);
! 4396:
! 4397: rc = istgt_queue_count(&conn->pending_pdus);
! 4398: if (rc > conn->max_pending) {
! 4399: ISTGT_ERRLOG("pending queue(%d) is full\n",
! 4400: conn->max_pending);
! 4401: goto error_return;
! 4402: }
! 4403: save_pdu = xmalloc(sizeof *save_pdu);
! 4404: memset(save_pdu, 0, sizeof *save_pdu);
! 4405: rc = istgt_iscsi_copy_pdu(save_pdu, &data_pdu);
! 4406: if (rc < 0) {
! 4407: ISTGT_ERRLOG("iscsi_copy_pdu() failed\n");
! 4408: xfree(save_pdu);
! 4409: save_pdu = NULL;
! 4410: goto error_return;
! 4411: }
! 4412: rc = istgt_queue_enqueue(&conn->pending_pdus,
! 4413: save_pdu);
! 4414: if (rc < 0) {
! 4415: ISTGT_ERRLOG("queue_enqueue() failed\n");
! 4416: xfree(save_pdu->ahs);
! 4417: save_pdu->ahs = NULL;
! 4418: if (save_pdu->data
! 4419: != save_pdu->shortdata) {
! 4420: xfree(save_pdu->data);
! 4421: }
! 4422: save_pdu->data = NULL;
! 4423: xfree(save_pdu);
! 4424: save_pdu = NULL;
! 4425: goto error_return;
! 4426: }
! 4427: data_pdu.ahs = NULL;
! 4428: data_pdu.data = NULL;
! 4429: data_pdu.copy_pdu = 0;
! 4430: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 4431: "non DATAOUT PDU pending\n");
! 4432: continue;
! 4433: }
! 4434:
! 4435: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
! 4436: "StatSN=%u, "
! 4437: "ExpStatSN=%u, DataSN=%u, Offset=%u, Data=%d\n",
! 4438: conn->StatSN,
! 4439: ExpStatSN, DataSN, buffer_offset, data_len);
! 4440: if (DataSN != ExpDataSN) {
! 4441: ISTGT_ERRLOG("DataSN(%u) error\n", DataSN);
! 4442: goto error_return;
! 4443: }
! 4444: #if 0
! 4445: /* not check in DATAOUT */
! 4446: if (ExpStatSN != conn->StatSN) {
! 4447: ISTGT_ERRLOG("StatSN(%u) error\n",
! 4448: conn->StatSN);
! 4449: goto error_return;
! 4450: }
! 4451: #endif
! 4452:
! 4453: #if 0
! 4454: /* not check in DATAOUT */
! 4455: if (lun != current_lun) {
! 4456: #if 0
! 4457: ISTGT_ERRLOG("lun(0x%16.16"PRIx64") error\n",
! 4458: lun);
! 4459: goto error_return;
! 4460: #else
! 4461: ISTGT_WARNLOG("lun(0x%16.16"PRIx64")\n", lun);
! 4462: #endif
! 4463: }
! 4464: #endif
! 4465: if (task_tag != current_task_tag) {
! 4466: ISTGT_ERRLOG("task_tag(%x/%x) error\n",
! 4467: task_tag, current_task_tag);
! 4468: goto error_return;
! 4469: }
! 4470: if (transfer_tag != current_transfer_tag) {
! 4471: ISTGT_ERRLOG("transfer_tag(%x/%x) error\n",
! 4472: transfer_tag, current_transfer_tag);
! 4473: goto error_return;
! 4474: }
! 4475: if (buffer_offset != offset) {
! 4476: ISTGT_ERRLOG("offset(%u) error\n",
! 4477: buffer_offset);
! 4478: goto error_return;
! 4479: }
! 4480: if (buffer_offset + data_len > alloc_len) {
! 4481: ISTGT_ERRLOG("offset error\n");
! 4482: goto error_return;
! 4483: }
! 4484:
! 4485: memcpy(data + buffer_offset, data_pdu.data, data_len);
! 4486: offset += data_len;
! 4487: len -= data_len;
! 4488: ExpDataSN++;
! 4489:
! 4490: if (r2t_flag == 0 && (offset > first_burst_len)) {
! 4491: ISTGT_ERRLOG("data_len(%d) > first_burst_length(%d)",
! 4492: offset, first_burst_len);
! 4493: goto error_return;
! 4494: }
! 4495: if (F_bit != 0 && len != 0) {
! 4496: if (offset < transfer_len) {
! 4497: r2t_flag = 0;
! 4498: goto r2t_retry;
! 4499: }
! 4500: ISTGT_ERRLOG("Expecting more data %d\n", len);
! 4501: goto error_return;
! 4502: }
! 4503: if (F_bit == 0 && len == 0) {
! 4504: ISTGT_ERRLOG("F_bit not set on the last PDU\n");
! 4505: goto error_return;
! 4506: }
! 4507: if (len == 0) {
! 4508: r2t_flag = 0;
! 4509: }
! 4510: r2t_retry:
! 4511: if (data_pdu.copy_pdu == 0) {
! 4512: xfree(data_pdu.ahs);
! 4513: data_pdu.ahs = NULL;
! 4514: if (data_pdu.data != data_pdu.shortdata) {
! 4515: xfree(data_pdu.data);
! 4516: }
! 4517: data_pdu.data = NULL;
! 4518: }
! 4519: } while (offset < transfer_len);
! 4520:
! 4521: cp = (uint8_t *) &data_pdu.bhs;
! 4522: F_bit = BGET8(&cp[1], 7);
! 4523: if (F_bit == 0) {
! 4524: ISTGT_ERRLOG("F_bit not set on the last PDU\n");
! 4525: return -1;
! 4526: }
! 4527: } else {
! 4528: cp = (uint8_t *) &lu_cmd->pdu->bhs;
! 4529: F_bit = BGET8(&cp[1], 7);
! 4530: if (F_bit == 0) {
! 4531: ISTGT_ERRLOG("F_bit not set on the last PDU\n");
! 4532: return -1;
! 4533: }
! 4534: }
! 4535:
! 4536: r2t_return:
! 4537: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Transfered=%d, Offset=%d\n",
! 4538: transfer_len, offset);
! 4539:
! 4540: return 0;
! 4541: }
! 4542:
! 4543: static int
! 4544: istgt_iscsi_send_nopin(CONN_Ptr conn)
! 4545: {
! 4546: ISCSI_PDU rsp_pdu;
! 4547: uint8_t *rsp;
! 4548: uint64_t lun;
! 4549: uint32_t task_tag;
! 4550: uint32_t transfer_tag;
! 4551: int rc;
! 4552:
! 4553: if (conn->sess == NULL) {
! 4554: return 0;
! 4555: }
! 4556: if (!conn->full_feature) {
! 4557: ISTGT_ERRLOG("before Full Feature\n");
! 4558: return -1;
! 4559: }
! 4560:
! 4561: SESS_MTX_LOCK(conn);
! 4562: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 4563: "send NOPIN isid=%"PRIx64", tsih=%u, cid=%u\n",
! 4564: conn->sess->isid, conn->sess->tsih, conn->cid);
! 4565: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
! 4566: "StatSN=%u, ExpCmdSN=%u, MaxCmdSN=%u\n",
! 4567: conn->StatSN, conn->sess->ExpCmdSN,
! 4568: conn->sess->MaxCmdSN);
! 4569: SESS_MTX_UNLOCK(conn);
! 4570:
! 4571: /* without wanting NOPOUT */
! 4572: lun = 0;
! 4573: task_tag = 0xffffffffU;
! 4574: transfer_tag = 0xffffffffU;
! 4575:
! 4576: /* response PDU */
! 4577: rsp = (uint8_t *) &rsp_pdu.bhs;
! 4578: rsp_pdu.data = NULL;
! 4579: memset(rsp, 0, ISCSI_BHS_LEN);
! 4580: rsp[0] = ISCSI_OP_NOPIN;
! 4581: BDADD8(&rsp[1], 1, 7);
! 4582: rsp[4] = 0; // TotalAHSLength
! 4583: DSET24(&rsp[5], 0); // DataSegmentLength
! 4584:
! 4585: DSET64(&rsp[8], lun);
! 4586: DSET32(&rsp[16], task_tag);
! 4587: DSET32(&rsp[20], transfer_tag);
! 4588:
! 4589: DSET32(&rsp[24], conn->StatSN);
! 4590: SESS_MTX_LOCK(conn);
! 4591: DSET32(&rsp[28], conn->sess->ExpCmdSN);
! 4592: DSET32(&rsp[32], conn->sess->MaxCmdSN);
! 4593: SESS_MTX_UNLOCK(conn);
! 4594:
! 4595: rc = istgt_iscsi_write_pdu(conn, &rsp_pdu);
! 4596: if (rc < 0) {
! 4597: ISTGT_ERRLOG("iscsi_write_pdu() failed\n");
! 4598: return -1;
! 4599: }
! 4600:
! 4601: return 0;
! 4602: }
! 4603:
! 4604: static int
! 4605: istgt_iscsi_execute(CONN_Ptr conn, ISCSI_PDU_Ptr pdu)
! 4606: {
! 4607: int immediate, opcode;
! 4608: int rc;
! 4609:
! 4610: if (pdu == NULL)
! 4611: return -1;
! 4612:
! 4613: immediate = BGET8W(&conn->pdu.bhs.opcode, 6, 1);
! 4614: opcode = BGET8W(&conn->pdu.bhs.opcode, 5, 6);
! 4615:
! 4616: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, "opcode %x\n", opcode);
! 4617: switch(opcode) {
! 4618: case ISCSI_OP_NOPOUT:
! 4619: rc = istgt_iscsi_op_nopout(conn, pdu);
! 4620: if (rc < 0) {
! 4621: ISTGT_ERRLOG("iscsi_op_nopout() failed\n");
! 4622: return -1;
! 4623: }
! 4624: break;
! 4625:
! 4626: case ISCSI_OP_SCSI:
! 4627: rc = istgt_iscsi_op_scsi(conn, pdu);
! 4628: if (rc < 0) {
! 4629: ISTGT_ERRLOG("iscsi_op_scsi() failed\n");
! 4630: return -1;
! 4631: }
! 4632: break;
! 4633:
! 4634: case ISCSI_OP_TASK:
! 4635: rc = istgt_iscsi_op_task(conn, pdu);
! 4636: if (rc < 0) {
! 4637: ISTGT_ERRLOG("iscsi_op_task() failed\n");
! 4638: return -1;
! 4639: }
! 4640: break;
! 4641:
! 4642: case ISCSI_OP_LOGIN:
! 4643: rc = istgt_iscsi_op_login(conn, pdu);
! 4644: if (rc < 0) {
! 4645: ISTGT_ERRLOG("iscsi_op_login() failed\n");
! 4646: return -1;
! 4647: }
! 4648: break;
! 4649:
! 4650: case ISCSI_OP_TEXT:
! 4651: rc = istgt_iscsi_op_text(conn, pdu);
! 4652: if (rc < 0) {
! 4653: ISTGT_ERRLOG("iscsi_op_text() failed\n");
! 4654: return -1;
! 4655: }
! 4656: break;
! 4657:
! 4658: case ISCSI_OP_LOGOUT:
! 4659: rc = istgt_iscsi_op_logout(conn, pdu);
! 4660: if (rc < 0) {
! 4661: ISTGT_ERRLOG("iscsi_op_logout() failed\n");
! 4662: return -1;
! 4663: }
! 4664: break;
! 4665:
! 4666: case ISCSI_OP_SCSI_DATAOUT:
! 4667: rc = istgt_iscsi_op_data(conn, pdu);
! 4668: if (rc < 0) {
! 4669: ISTGT_ERRLOG("iscsi_op_data() failed\n");
! 4670: return -1;
! 4671: }
! 4672: break;
! 4673:
! 4674: case ISCSI_OP_SNACK:
! 4675: ISTGT_ERRLOG("got SNACK\n");
! 4676: goto error_out;
! 4677: default:
! 4678: error_out:
! 4679: ISTGT_ERRLOG("unsupported opcode %x\n", opcode);
! 4680: rc = istgt_iscsi_reject(conn, pdu, 0x04);
! 4681: if (rc < 0) {
! 4682: ISTGT_ERRLOG("iscsi_reject() failed\n");
! 4683: return -1;
! 4684: }
! 4685: break;
! 4686: }
! 4687:
! 4688: return 0;
! 4689: }
! 4690:
! 4691: static void
! 4692: wait_all_task(CONN_Ptr conn)
! 4693: {
! 4694: ISTGT_LU_TASK_Ptr lu_task;
! 4695: #ifdef ISTGT_USE_KQUEUE
! 4696: int kq;
! 4697: struct kevent kev;
! 4698: struct timespec kev_timeout;
! 4699: #else
! 4700: struct pollfd fds[1];
! 4701: #endif /* ISTGT_USE_KQUEUE */
! 4702: int msec = 30 * 1000;
! 4703: int rc;
! 4704:
! 4705: if (conn->running_tasks == 0)
! 4706: return;
! 4707:
! 4708: #ifdef ISTGT_USE_KQUEUE
! 4709: kq = kqueue();
! 4710: if (kq == -1) {
! 4711: ISTGT_ERRLOG("kqueue() failed\n");
! 4712: return;
! 4713: }
! 4714: EV_SET(&kev, conn->task_pipe[0], EVFILT_READ, EV_ADD, 0, 0, NULL);
! 4715: rc = kevent(kq, &kev, 1, NULL, 0, NULL);
! 4716: if (rc == -1) {
! 4717: ISTGT_ERRLOG("kevent() failed\n");
! 4718: close(kq);
! 4719: return;
! 4720: }
! 4721: #else
! 4722: fds[0].fd = conn->task_pipe[0];
! 4723: fds[0].events = POLLIN;
! 4724: #endif /* ISTGT_USE_KQUEUE */
! 4725:
! 4726: /* wait all running tasks */
! 4727: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 4728: "waiting task start (%d) (left %d tasks)\n",
! 4729: conn->id, conn->running_tasks);
! 4730: while (1) {
! 4731: #ifdef ISTGT_USE_KQUEUE
! 4732: kev_timeout.tv_sec = msec / 1000;
! 4733: kev_timeout.tv_nsec = (msec % 1000) * 1000000;
! 4734: rc = kevent(kq, NULL, 0, &kev, 1, &kev_timeout);
! 4735: if (rc == -1 && errno == EINTR) {
! 4736: continue;
! 4737: }
! 4738: if (rc == -1) {
! 4739: ISTGT_ERRLOG("kevent() failed\n");
! 4740: break;
! 4741: }
! 4742: if (rc == 0) {
! 4743: ISTGT_ERRLOG("waiting task timeout (left %d tasks)\n",
! 4744: conn->running_tasks);
! 4745: break;
! 4746: }
! 4747: #else
! 4748: rc = poll(fds, 1, msec);
! 4749: if (rc == -1 && errno == EINTR) {
! 4750: continue;
! 4751: }
! 4752: if (rc == -1) {
! 4753: ISTGT_ERRLOG("poll() failed\n");
! 4754: break;
! 4755: }
! 4756: if (rc == 0) {
! 4757: ISTGT_ERRLOG("waiting task timeout (left %d tasks)\n",
! 4758: conn->running_tasks);
! 4759: break;
! 4760: }
! 4761: #endif /* ISTGT_USE_KQUEUE */
! 4762:
! 4763: #ifdef ISTGT_USE_KQUEUE
! 4764: if (kev.ident == conn->task_pipe[0]) {
! 4765: if (kev.flags & (EV_EOF|EV_ERROR)) {
! 4766: break;
! 4767: }
! 4768: #else
! 4769: if (fds[0].revents & POLLHUP) {
! 4770: break;
! 4771: }
! 4772: if (fds[0].revents & POLLIN) {
! 4773: #endif /* ISTGT_USE_KQUEUE */
! 4774: char tmp[1];
! 4775:
! 4776: rc = read(conn->task_pipe[0], tmp, 1);
! 4777: if (rc < 0 || rc == 0 || rc != 1) {
! 4778: ISTGT_ERRLOG("read() failed\n");
! 4779: break;
! 4780: }
! 4781:
! 4782: MTX_LOCK(&conn->task_queue_mutex);
! 4783: lu_task = istgt_queue_dequeue(&conn->task_queue);
! 4784: MTX_UNLOCK(&conn->task_queue_mutex);
! 4785: if (lu_task != NULL) {
! 4786: if (lu_task->lu_cmd.W_bit) {
! 4787: /* write */
! 4788: if (lu_task->req_transfer_out != 0) {
! 4789: /* error transfer */
! 4790: lu_task->error = 1;
! 4791: lu_task->abort = 1;
! 4792: rc = pthread_cond_broadcast(&lu_task->trans_cond);
! 4793: if (rc != 0) {
! 4794: ISTGT_ERRLOG("cond_broadcast() failed\n");
! 4795: /* ignore error */
! 4796: }
! 4797: } else {
! 4798: if (lu_task->req_execute) {
! 4799: conn->running_tasks--;
! 4800: if (conn->running_tasks == 0) {
! 4801: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 4802: "task cleanup finished\n");
! 4803: break;
! 4804: }
! 4805: }
! 4806: /* ignore response */
! 4807: rc = istgt_lu_destroy_task(lu_task);
! 4808: if (rc < 0) {
! 4809: ISTGT_ERRLOG("lu_destroy_task() failed\n");
! 4810: /* ignore error */
! 4811: }
! 4812: }
! 4813: } else {
! 4814: /* read or no data */
! 4815: /* ignore response */
! 4816: rc = istgt_lu_destroy_task(lu_task);
! 4817: if (rc < 0) {
! 4818: ISTGT_ERRLOG("lu_destroy_task() failed\n");
! 4819: /* ignore error */
! 4820: }
! 4821: }
! 4822: } else {
! 4823: ISTGT_ERRLOG("lu_task is NULL\n");
! 4824: break;
! 4825: }
! 4826: }
! 4827: }
! 4828:
! 4829: istgt_clear_all_transfer_task(conn);
! 4830: #ifdef ISTGT_USE_KQUEUE
! 4831: close(kq);
! 4832: #endif /* ISTGT_USE_KQUEUE */
! 4833: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 4834: "waiting task end (%d) (left %d tasks)\n",
! 4835: conn->id, conn->running_tasks);
! 4836: }
! 4837:
! 4838: static void
! 4839: worker_cleanup(void *arg)
! 4840: {
! 4841: CONN_Ptr conn = (CONN_Ptr) arg;
! 4842: ISTGT_LU_Ptr lu;
! 4843: int rc;
! 4844:
! 4845: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "worker_cleanup\n");
! 4846: ISTGT_WARNLOG("force cleanup execute\n");
! 4847:
! 4848: /* cleanup */
! 4849: pthread_mutex_unlock(&conn->task_queue_mutex);
! 4850: pthread_mutex_unlock(&conn->result_queue_mutex);
! 4851: if (conn->sess != NULL) {
! 4852: if (conn->sess->lu != NULL) {
! 4853: pthread_mutex_unlock(&conn->sess->lu->mutex);
! 4854: }
! 4855: pthread_mutex_unlock(&conn->sess->mutex);
! 4856: }
! 4857: if (conn->exec_lu_task != NULL) {
! 4858: conn->exec_lu_task->error = 1;
! 4859: pthread_cond_broadcast(&conn->exec_lu_task->trans_cond);
! 4860: pthread_mutex_unlock(&conn->exec_lu_task->trans_mutex);
! 4861: }
! 4862: pthread_mutex_unlock(&conn->wpdu_mutex);
! 4863: pthread_mutex_unlock(&conn->r2t_mutex);
! 4864: pthread_mutex_unlock(&conn->istgt->mutex);
! 4865: pthread_mutex_unlock(&g_conns_mutex);
! 4866: pthread_mutex_unlock(&g_last_tsih_mutex);
! 4867:
! 4868: conn->state = CONN_STATE_EXITING;
! 4869: if (conn->sess != NULL) {
! 4870: SESS_MTX_LOCK(conn);
! 4871: lu = conn->sess->lu;
! 4872: if (lu != NULL && lu->queue_depth != 0) {
! 4873: rc = istgt_lu_clear_task_IT(conn, lu);
! 4874: if (rc < 0) {
! 4875: ISTGT_ERRLOG("lu_clear_task_IT() failed\n");
! 4876: }
! 4877: istgt_clear_all_transfer_task(conn);
! 4878: }
! 4879: SESS_MTX_UNLOCK(conn);
! 4880: }
! 4881: if (conn->pdu.copy_pdu == 0) {
! 4882: xfree(conn->pdu.ahs);
! 4883: conn->pdu.ahs = NULL;
! 4884: if (conn->pdu.data != conn->pdu.shortdata) {
! 4885: xfree(conn->pdu.data);
! 4886: }
! 4887: conn->pdu.data = NULL;
! 4888: }
! 4889: wait_all_task(conn);
! 4890: if (conn->use_sender) {
! 4891: pthread_cond_broadcast(&conn->result_queue_cond);
! 4892: pthread_join(conn->sender_thread, NULL);
! 4893: }
! 4894: close(conn->sock);
! 4895: #ifdef ISTGT_USE_KQUEUE
! 4896: close(conn->kq);
! 4897: conn->kq = -1;
! 4898: #endif /* ISTGT_USE_KQUEUE */
! 4899: sleep(1);
! 4900:
! 4901: /* cleanup conn & sess */
! 4902: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "cancel cleanup LOCK\n");
! 4903: MTX_LOCK(&g_conns_mutex);
! 4904: g_conns[conn->id] = NULL;
! 4905: istgt_remove_conn(conn);
! 4906: MTX_UNLOCK(&g_conns_mutex);
! 4907: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "cancel cleanup UNLOCK\n");
! 4908:
! 4909: return;
! 4910: }
! 4911:
! 4912: static void *
! 4913: sender(void *arg)
! 4914: {
! 4915: CONN_Ptr conn = (CONN_Ptr) arg;
! 4916: ISTGT_LU_TASK_Ptr lu_task;
! 4917: struct timespec abstime;
! 4918: time_t now;
! 4919: int rc;
! 4920:
! 4921: #ifdef HAVE_PTHREAD_SET_NAME_NP
! 4922: {
! 4923: char buf[MAX_TMPBUF];
! 4924: snprintf(buf, sizeof buf, "sendthread #%d", conn->id);
! 4925: pthread_set_name_np(conn->sender_thread, buf);
! 4926: }
! 4927: #endif
! 4928: memset(&abstime, 0, sizeof abstime);
! 4929: /* handle DATA-IN/SCSI status */
! 4930: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "sender loop start (%d)\n", conn->id);
! 4931: //MTX_LOCK(&conn->sender_mutex);
! 4932: while (1) {
! 4933: if (conn->state != CONN_STATE_RUNNING) {
! 4934: break;
! 4935: }
! 4936: MTX_LOCK(&conn->result_queue_mutex);
! 4937: lu_task = istgt_queue_dequeue(&conn->result_queue);
! 4938: if (lu_task == NULL) {
! 4939: now = time(NULL);
! 4940: abstime.tv_sec = now + conn->timeout;
! 4941: abstime.tv_nsec = 0;
! 4942: rc = pthread_cond_timedwait(&conn->result_queue_cond,
! 4943: &conn->result_queue_mutex, &abstime);
! 4944: if (rc == ETIMEDOUT) {
! 4945: /* nothing */
! 4946: }
! 4947: lu_task = istgt_queue_dequeue(&conn->result_queue);
! 4948: if (lu_task == NULL) {
! 4949: MTX_UNLOCK(&conn->result_queue_mutex);
! 4950: continue;
! 4951: }
! 4952: }
! 4953: MTX_UNLOCK(&conn->result_queue_mutex);
! 4954: /* send all responses */
! 4955: // MTX_LOCK(&conn->wpdu_mutex);
! 4956: do {
! 4957: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 4958: "task response CmdSN=%u\n", lu_task->lu_cmd.CmdSN);
! 4959: lu_task->lock = 1;
! 4960: if (lu_task->type == ISTGT_LU_TASK_RESPONSE) {
! 4961: /* send DATA-IN, SCSI status */
! 4962: rc = istgt_iscsi_task_response(conn, lu_task);
! 4963: if (rc < 0) {
! 4964: lu_task->error = 1;
! 4965: ISTGT_ERRLOG(
! 4966: "iscsi_task_response() failed on %s(%s)\n",
! 4967: conn->target_port, conn->initiator_port);
! 4968: break;
! 4969: }
! 4970: rc = istgt_lu_destroy_task(lu_task);
! 4971: if (rc < 0) {
! 4972: ISTGT_ERRLOG("lu_destroy_task() failed\n");
! 4973: break;
! 4974: }
! 4975: } else if (lu_task->type == ISTGT_LU_TASK_REQPDU) {
! 4976: /* send PDU */
! 4977: rc = istgt_iscsi_write_pdu_internal(lu_task->conn,
! 4978: lu_task->lu_cmd.pdu);
! 4979: if (rc < 0) {
! 4980: lu_task->error = 1;
! 4981: ISTGT_ERRLOG(
! 4982: "iscsi_write_pdu() failed on %s(%s)\n",
! 4983: lu_task->conn->target_port,
! 4984: lu_task->conn->initiator_port);
! 4985: break;
! 4986: }
! 4987: /* free allocated memory by caller */
! 4988: xfree(lu_task);
! 4989: } else {
! 4990: ISTGT_ERRLOG("Unknown task type %x\n", lu_task->type);
! 4991: rc = -1;
! 4992: }
! 4993: // conn is running?
! 4994: if (conn->state != CONN_STATE_RUNNING) {
! 4995: //ISTGT_WARNLOG("exit thread\n");
! 4996: break;
! 4997: }
! 4998: MTX_LOCK(&conn->result_queue_mutex);
! 4999: lu_task = istgt_queue_dequeue(&conn->result_queue);
! 5000: MTX_UNLOCK(&conn->result_queue_mutex);
! 5001: } while (lu_task != NULL);
! 5002: // MTX_UNLOCK(&conn->wpdu_mutex);
! 5003: }
! 5004: //MTX_UNLOCK(&conn->sender_mutex);
! 5005: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "sender loop ended (%d)\n", conn->id);
! 5006: return NULL;
! 5007: }
! 5008:
! 5009: static void *
! 5010: worker(void *arg)
! 5011: {
! 5012: CONN_Ptr conn = (CONN_Ptr) arg;
! 5013: ISTGT_LU_TASK_Ptr lu_task;
! 5014: ISTGT_LU_Ptr lu;
! 5015: ISCSI_PDU_Ptr pdu;
! 5016: sigset_t signew, sigold;
! 5017: #ifdef ISTGT_USE_KQUEUE
! 5018: int kq;
! 5019: struct kevent kev;
! 5020: struct timespec kev_timeout;
! 5021: #else
! 5022: struct pollfd fds[2];
! 5023: int nopin_timer;
! 5024: #endif /* ISTGT_USE_KQUEUE */
! 5025: int opcode;
! 5026: int rc;
! 5027:
! 5028: ISTGT_TRACELOG(ISTGT_TRACE_NET, "connect to %s:%s,%d\n",
! 5029: conn->portal.host, conn->portal.port, conn->portal.tag);
! 5030:
! 5031: #ifdef ISTGT_USE_KQUEUE
! 5032: kq = kqueue();
! 5033: if (kq == -1) {
! 5034: ISTGT_ERRLOG("kqueue() failed\n");
! 5035: return NULL;
! 5036: }
! 5037: conn->kq = kq;
! 5038: EV_SET(&kev, conn->sock, EVFILT_READ, EV_ADD, 0, 0, NULL);
! 5039: rc = kevent(kq, &kev, 1, NULL, 0, NULL);
! 5040: if (rc == -1) {
! 5041: ISTGT_ERRLOG("kevent() failed\n");
! 5042: close(kq);
! 5043: return NULL;
! 5044: }
! 5045: EV_SET(&kev, conn->task_pipe[0], EVFILT_READ, EV_ADD, 0, 0, NULL);
! 5046: rc = kevent(kq, &kev, 1, NULL, 0, NULL);
! 5047: if (rc == -1) {
! 5048: ISTGT_ERRLOG("kevent() failed\n");
! 5049: close(kq);
! 5050: return NULL;
! 5051: }
! 5052:
! 5053: EV_SET(&kev, SIGINT, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
! 5054: rc = kevent(kq, &kev, 1, NULL, 0, NULL);
! 5055: if (rc == -1) {
! 5056: ISTGT_ERRLOG("kevent() failed\n");
! 5057: close(kq);
! 5058: return NULL;
! 5059: }
! 5060: EV_SET(&kev, SIGTERM, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
! 5061: rc = kevent(kq, &kev, 1, NULL, 0, NULL);
! 5062: if (rc == -1) {
! 5063: ISTGT_ERRLOG("kevent() failed\n");
! 5064: close(kq);
! 5065: return NULL;
! 5066: }
! 5067: #else
! 5068: memset(&fds, 0, sizeof fds);
! 5069: fds[0].fd = conn->sock;
! 5070: fds[0].events = POLLIN;
! 5071: fds[1].fd = conn->task_pipe[0];
! 5072: fds[1].events = POLLIN;
! 5073:
! 5074: nopin_timer = conn->nopininterval;
! 5075: #endif /* ISTGT_USE_KQUEUE */
! 5076:
! 5077: conn->pdu.ahs = NULL;
! 5078: conn->pdu.data = NULL;
! 5079: conn->pdu.copy_pdu = 0;
! 5080: conn->state = CONN_STATE_RUNNING;
! 5081: conn->exec_lu_task = NULL;
! 5082: lu_task = NULL;
! 5083:
! 5084: pthread_cleanup_push(worker_cleanup, conn);
! 5085: pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
! 5086:
! 5087: conn->use_sender = 0;
! 5088: if (conn->istgt->swmode >= ISTGT_SWMODE_NORMAL) {
! 5089: /* create sender thread */
! 5090: #ifdef ISTGT_STACKSIZE
! 5091: rc = pthread_create(&conn->sender_thread, &conn->istgt->attr,
! 5092: &sender, (void *)conn);
! 5093: #else
! 5094: rc = pthread_create(&conn->sender_thread, NULL, &sender,
! 5095: (void *)conn);
! 5096: #endif
! 5097: if (rc != 0) {
! 5098: ISTGT_ERRLOG("pthread_create() failed\n");
! 5099: goto cleanup_exit;
! 5100: }
! 5101: conn->use_sender = 1;
! 5102: }
! 5103: conn->wsock = conn->sock;
! 5104:
! 5105: sigemptyset(&signew);
! 5106: sigemptyset(&sigold);
! 5107: sigaddset(&signew, ISTGT_SIGWAKEUP);
! 5108: pthread_sigmask(SIG_UNBLOCK, &signew, &sigold);
! 5109:
! 5110: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "loop start (%d)\n", conn->id);
! 5111: while (1) {
! 5112: /* check exit request */
! 5113: if (conn->sess != NULL) {
! 5114: SESS_MTX_LOCK(conn);
! 5115: lu = conn->sess->lu;
! 5116: SESS_MTX_UNLOCK(conn);
! 5117: } else {
! 5118: lu = NULL;
! 5119: }
! 5120: if (lu != NULL) {
! 5121: if (istgt_lu_get_state(lu) != ISTGT_STATE_RUNNING) {
! 5122: conn->state = CONN_STATE_EXITING;
! 5123: break;
! 5124: }
! 5125: } else {
! 5126: if (istgt_get_state(conn->istgt) != ISTGT_STATE_RUNNING) {
! 5127: conn->state = CONN_STATE_EXITING;
! 5128: break;
! 5129: }
! 5130: }
! 5131:
! 5132: pthread_testcancel();
! 5133: if (conn->state != CONN_STATE_RUNNING) {
! 5134: break;
! 5135: }
! 5136:
! 5137: #ifdef ISTGT_USE_KQUEUE
! 5138: ISTGT_TRACELOG(ISTGT_TRACE_NET,
! 5139: "kevent sock %d (timeout %dms)\n",
! 5140: conn->sock, conn->nopininterval);
! 5141: if (conn->nopininterval != 0) {
! 5142: kev_timeout.tv_sec = conn->nopininterval / 1000;
! 5143: kev_timeout.tv_nsec = (conn->nopininterval % 1000) * 1000000;
! 5144: } else {
! 5145: kev_timeout.tv_sec = DEFAULT_NOPININTERVAL;
! 5146: kev_timeout.tv_nsec = 0;
! 5147: }
! 5148: rc = kevent(kq, NULL, 0, &kev, 1, &kev_timeout);
! 5149: if (rc == -1 && errno == EINTR) {
! 5150: //ISTGT_ERRLOG("EINTR kevent\n");
! 5151: continue;
! 5152: }
! 5153: if (rc == -1) {
! 5154: ISTGT_ERRLOG("kevent() failed\n");
! 5155: break;
! 5156: }
! 5157: if (rc == 0) {
! 5158: /* idle timeout, send diagnosis packet */
! 5159: if (conn->nopininterval != 0) {
! 5160: rc = istgt_iscsi_send_nopin(conn);
! 5161: if (rc < 0) {
! 5162: ISTGT_ERRLOG("iscsi_send_nopin() failed\n");
! 5163: break;
! 5164: }
! 5165: }
! 5166: continue;
! 5167: }
! 5168: if (kev.filter == EVFILT_SIGNAL) {
! 5169: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "kevent SIGNAL\n");
! 5170: if (kev.ident == SIGINT || kev.ident == SIGTERM) {
! 5171: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 5172: "kevent SIGNAL SIGINT/SIGTERM\n");
! 5173: break;
! 5174: }
! 5175: continue;
! 5176: }
! 5177: #else
! 5178: //ISTGT_TRACELOG(ISTGT_TRACE_NET, "poll sock %d\n", conn->sock);
! 5179: rc = poll(fds, 2, POLLWAIT);
! 5180: if (rc == -1 && errno == EINTR) {
! 5181: //ISTGT_ERRLOG("EINTR poll\n");
! 5182: continue;
! 5183: }
! 5184: if (rc == -1) {
! 5185: ISTGT_ERRLOG("poll() failed\n");
! 5186: break;
! 5187: }
! 5188: if (rc == 0) {
! 5189: /* no fds */
! 5190: if (nopin_timer > 0) {
! 5191: nopin_timer -= POLLWAIT;
! 5192: if (nopin_timer <= 0) {
! 5193: nopin_timer = conn->nopininterval;
! 5194: rc = istgt_iscsi_send_nopin(conn);
! 5195: if (rc < 0) {
! 5196: ISTGT_ERRLOG("iscsi_send_nopin() failed\n");
! 5197: break;
! 5198: }
! 5199: }
! 5200: }
! 5201: continue;
! 5202: }
! 5203: nopin_timer = conn->nopininterval;
! 5204: #endif /* ISTGT_USE_KQUEUE */
! 5205:
! 5206: /* on socket */
! 5207: #ifdef ISTGT_USE_KQUEUE
! 5208: if (kev.ident == conn->sock) {
! 5209: if (kev.flags & (EV_EOF|EV_ERROR)) {
! 5210: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 5211: "kevent EOF/ERROR\n");
! 5212: break;
! 5213: }
! 5214: #else
! 5215: if (fds[0].revents & POLLHUP) {
! 5216: break;
! 5217: }
! 5218: if (fds[0].revents & POLLIN) {
! 5219: #endif /* ISTGT_USE_KQUEUE */
! 5220: conn->pdu.copy_pdu = 0;
! 5221: rc = istgt_iscsi_read_pdu(conn, &conn->pdu);
! 5222: if (rc < 0) {
! 5223: ISTGT_ERRLOG("conn->state = %d\n", conn->state);
! 5224: if (conn->state != CONN_STATE_RUNNING) {
! 5225: if (errno == EINPROGRESS) {
! 5226: sleep(1);
! 5227: continue;
! 5228: }
! 5229: if (errno == ECONNRESET
! 5230: || errno == ETIMEDOUT) {
! 5231: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 5232: "iscsi_read_pdu() RESET/TIMEOUT\n");
! 5233: } else {
! 5234: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 5235: "iscsi_read_pdu() EOF\n");
! 5236: }
! 5237: break;
! 5238: }
! 5239: ISTGT_ERRLOG("iscsi_read_pdu() failed\n");
! 5240: break;
! 5241: }
! 5242: execute_pdu:
! 5243: opcode = BGET8W(&conn->pdu.bhs.opcode, 5, 6);
! 5244:
! 5245: #if 0
! 5246: pthread_testcancel();
! 5247: #endif
! 5248: if (conn->state != CONN_STATE_RUNNING) {
! 5249: break;
! 5250: }
! 5251:
! 5252: if (g_trace_flag) {
! 5253: if (conn->sess != NULL) {
! 5254: SESS_MTX_LOCK(conn);
! 5255: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
! 5256: "isid=%"PRIx64", tsih=%u, cid=%u, op=%x\n",
! 5257: conn->sess->isid, conn->sess->tsih,
! 5258: conn->cid, opcode);
! 5259: SESS_MTX_UNLOCK(conn);
! 5260: } else {
! 5261: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
! 5262: "isid=xxx, tsih=xxx, cid=%u, op=%x\n",
! 5263: conn->cid, opcode);
! 5264: }
! 5265: }
! 5266: rc = istgt_iscsi_execute(conn, &conn->pdu);
! 5267: if (rc < 0) {
! 5268: ISTGT_ERRLOG("iscsi_execute() failed on %s(%s)\n",
! 5269: conn->target_port, conn->initiator_port);
! 5270: break;
! 5271: }
! 5272: if (g_trace_flag) {
! 5273: if (conn->sess != NULL) {
! 5274: SESS_MTX_LOCK(conn);
! 5275: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
! 5276: "isid=%"PRIx64", tsih=%u, cid=%u, op=%x complete\n",
! 5277: conn->sess->isid, conn->sess->tsih,
! 5278: conn->cid, opcode);
! 5279: SESS_MTX_UNLOCK(conn);
! 5280: } else {
! 5281: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
! 5282: "isid=xxx, tsih=xxx, cid=%u, op=%x complete\n",
! 5283: conn->cid, opcode);
! 5284: }
! 5285: }
! 5286:
! 5287: if (opcode == ISCSI_OP_LOGOUT) {
! 5288: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI, "logout received\n");
! 5289: break;
! 5290: }
! 5291:
! 5292: if (conn->pdu.copy_pdu == 0) {
! 5293: xfree(conn->pdu.ahs);
! 5294: conn->pdu.ahs = NULL;
! 5295: if (conn->pdu.data != conn->pdu.shortdata) {
! 5296: xfree(conn->pdu.data);
! 5297: }
! 5298: conn->pdu.data = NULL;
! 5299: }
! 5300:
! 5301: /* execute pending PDUs */
! 5302: pdu = istgt_queue_dequeue(&conn->pending_pdus);
! 5303: if (pdu != NULL) {
! 5304: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 5305: "execute pending PDU\n");
! 5306: rc = istgt_iscsi_copy_pdu(&conn->pdu, pdu);
! 5307: conn->pdu.copy_pdu = 0;
! 5308: xfree(pdu);
! 5309: goto execute_pdu;
! 5310: }
! 5311:
! 5312: #if 0
! 5313: /* retry read/PDUs */
! 5314: continue;
! 5315: #endif
! 5316: }
! 5317:
! 5318: /* execute on task queue */
! 5319: #ifdef ISTGT_USE_KQUEUE
! 5320: if (kev.ident == conn->task_pipe[0]) {
! 5321: if (kev.flags & (EV_EOF|EV_ERROR)) {
! 5322: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 5323: "kevent EOF/ERROR\n");
! 5324: break;
! 5325: }
! 5326: #else
! 5327: if (fds[1].revents & POLLHUP) {
! 5328: break;
! 5329: }
! 5330: if (fds[1].revents & POLLIN) {
! 5331: #endif /* ISTGT_USE_KQUEUE */
! 5332: char tmp[1];
! 5333:
! 5334: //ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "Queue Task START\n");
! 5335:
! 5336: rc = read(conn->task_pipe[0], tmp, 1);
! 5337: if (rc < 0 || rc == 0 || rc != 1) {
! 5338: ISTGT_ERRLOG("read() failed\n");
! 5339: break;
! 5340: }
! 5341:
! 5342: /* DATA-IN/OUT */
! 5343: MTX_LOCK(&conn->task_queue_mutex);
! 5344: rc = istgt_queue_count(&conn->task_queue);
! 5345: lu_task = istgt_queue_dequeue(&conn->task_queue);
! 5346: MTX_UNLOCK(&conn->task_queue_mutex);
! 5347: if (lu_task != NULL) {
! 5348: if (conn->exec_lu_task != NULL) {
! 5349: ISTGT_ERRLOG("task is overlapped (CmdSN=%u, %u)\n",
! 5350: conn->exec_lu_task->lu_cmd.CmdSN,
! 5351: lu_task->lu_cmd.CmdSN);
! 5352: break;
! 5353: }
! 5354: conn->exec_lu_task = lu_task;
! 5355: if (lu_task->lu_cmd.W_bit) {
! 5356: /* write */
! 5357: if (lu_task->req_transfer_out == 0) {
! 5358: if (lu_task->req_execute) {
! 5359: if (conn->running_tasks > 0) {
! 5360: conn->running_tasks--;
! 5361: } else {
! 5362: ISTGT_ERRLOG("running no task\n");
! 5363: }
! 5364: }
! 5365: rc = istgt_iscsi_task_response(conn, lu_task);
! 5366: if (rc < 0) {
! 5367: lu_task->error = 1;
! 5368: ISTGT_ERRLOG("iscsi_task_response() failed on %s(%s)\n",
! 5369: conn->target_port,
! 5370: conn->initiator_port);
! 5371: break;
! 5372: }
! 5373: rc = istgt_lu_destroy_task(lu_task);
! 5374: if (rc < 0) {
! 5375: ISTGT_ERRLOG("lu_destroy_task() failed\n");
! 5376: break;
! 5377: }
! 5378: lu_task = NULL;
! 5379: conn->exec_lu_task = NULL;
! 5380: } else {
! 5381: MTX_LOCK(&lu_task->trans_mutex);
! 5382: //ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 5383: // "Task Write Trans START\n");
! 5384: rc = istgt_iscsi_task_transfer_out(conn, lu_task);
! 5385: if (rc < 0) {
! 5386: lu_task->error = 1;
! 5387: MTX_UNLOCK(&lu_task->trans_mutex);
! 5388: ISTGT_ERRLOG("iscsi_task_transfer_out() failed on %s(%s)\n",
! 5389: conn->target_port,
! 5390: conn->initiator_port);
! 5391: break;
! 5392: }
! 5393: //ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 5394: // "Task Write Trans END\n");
! 5395:
! 5396: lu_task->req_transfer_out = 0;
! 5397:
! 5398: /* need response after execution */
! 5399: lu_task->req_execute = 1;
! 5400: if (conn->use_sender == 0) {
! 5401: conn->running_tasks++;
! 5402: }
! 5403: MTX_UNLOCK(&lu_task->trans_mutex);
! 5404:
! 5405: rc = pthread_cond_broadcast(&lu_task->trans_cond);
! 5406: if (rc != 0) {
! 5407: //MTX_UNLOCK(&lu_task->trans_mutex);
! 5408: ISTGT_ERRLOG("cond_broadcast() failed\n");
! 5409: break;
! 5410: }
! 5411: lu_task = NULL;
! 5412: conn->exec_lu_task = NULL;
! 5413: }
! 5414: } else {
! 5415: /* read or no data */
! 5416: rc = istgt_iscsi_task_response(conn, lu_task);
! 5417: if (rc < 0) {
! 5418: lu_task->error = 1;
! 5419: ISTGT_ERRLOG("iscsi_task_response() failed on %s(%s)\n",
! 5420: conn->target_port,
! 5421: conn->initiator_port);
! 5422: break;
! 5423: }
! 5424: rc = istgt_lu_destroy_task(lu_task);
! 5425: if (rc < 0) {
! 5426: ISTGT_ERRLOG("lu_destroy_task() failed\n");
! 5427: break;
! 5428: }
! 5429: lu_task = NULL;
! 5430: conn->exec_lu_task = NULL;
! 5431: }
! 5432: }
! 5433: /* XXX PDUs in DATA-OUT? */
! 5434: pdu = istgt_queue_dequeue(&conn->pending_pdus);
! 5435: if (pdu != NULL) {
! 5436: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 5437: "pending in task\n");
! 5438: rc = istgt_iscsi_copy_pdu(&conn->pdu, pdu);
! 5439: conn->pdu.copy_pdu = 0;
! 5440: xfree(pdu);
! 5441: #ifdef ISTGT_USE_KQUEUE
! 5442: kev.ident = -1;
! 5443: #else
! 5444: fds[1].revents &= ~POLLIN;
! 5445: #endif /* ISTGT_USE_KQUEUE */
! 5446: goto execute_pdu;
! 5447: }
! 5448: }
! 5449: }
! 5450: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "loop ended (%d)\n", conn->id);
! 5451:
! 5452: cleanup_exit:
! 5453: ;
! 5454: pthread_cleanup_pop(0);
! 5455: conn->state = CONN_STATE_EXITING;
! 5456: if (conn->sess != NULL) {
! 5457: SESS_MTX_LOCK(conn);
! 5458: lu = conn->sess->lu;
! 5459: if (lu != NULL && lu->queue_depth != 0) {
! 5460: rc = istgt_lu_clear_task_IT(conn, lu);
! 5461: if (rc < 0) {
! 5462: ISTGT_ERRLOG("lu_clear_task_IT() failed\n");
! 5463: }
! 5464: istgt_clear_all_transfer_task(conn);
! 5465: }
! 5466: SESS_MTX_UNLOCK(conn);
! 5467: }
! 5468: if (conn->pdu.copy_pdu == 0) {
! 5469: xfree(conn->pdu.ahs);
! 5470: conn->pdu.ahs = NULL;
! 5471: if (conn->pdu.data != conn->pdu.shortdata) {
! 5472: xfree(conn->pdu.data);
! 5473: }
! 5474: conn->pdu.data = NULL;
! 5475: }
! 5476: wait_all_task(conn);
! 5477:
! 5478: if (conn->use_sender) {
! 5479: /* stop sender thread */
! 5480: rc = pthread_cond_broadcast(&conn->result_queue_cond);
! 5481: if (rc != 0) {
! 5482: ISTGT_ERRLOG("cond_broadcast() failed\n");
! 5483: /* ignore errors */
! 5484: }
! 5485: rc = pthread_join(conn->sender_thread, NULL);
! 5486: if (rc != 0) {
! 5487: ISTGT_ERRLOG("pthread_join() failed\n");
! 5488: /* ignore errors */
! 5489: }
! 5490: }
! 5491:
! 5492: close(conn->sock);
! 5493: #ifdef ISTGT_USE_KQUEUE
! 5494: close(kq);
! 5495: conn->kq = -1;
! 5496: #endif /* ISTGT_USE_KQUEUE */
! 5497: sleep(1);
! 5498: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "worker %d end\n", conn->id);
! 5499:
! 5500: /* cleanup conn & sess */
! 5501: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "cleanup LOCK\n");
! 5502: MTX_LOCK(&g_conns_mutex);
! 5503: g_conns[conn->id] = NULL;
! 5504: istgt_remove_conn(conn);
! 5505: MTX_UNLOCK(&g_conns_mutex);
! 5506: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "cleanup UNLOCK\n");
! 5507:
! 5508: return NULL;
! 5509: }
! 5510:
! 5511: int
! 5512: istgt_create_conn(ISTGT_Ptr istgt, PORTAL_Ptr portal, int sock, struct sockaddr *sa, socklen_t salen)
! 5513: {
! 5514: char buf[MAX_TMPBUF];
! 5515: CONN_Ptr conn;
! 5516: int rc;
! 5517: int i;
! 5518:
! 5519: conn = xmalloc(sizeof *conn);
! 5520: memset(conn, 0, sizeof *conn);
! 5521:
! 5522: conn->istgt = istgt;
! 5523: MTX_LOCK(&istgt->mutex);
! 5524: conn->timeout = istgt->timeout;
! 5525: conn->nopininterval = istgt->nopininterval;
! 5526: conn->nopininterval *= 1000; /* sec. to msec. */
! 5527: conn->max_r2t = istgt->maxr2t;
! 5528: conn->TargetMaxRecvDataSegmentLength = istgt->MaxRecvDataSegmentLength;
! 5529: MTX_UNLOCK(&istgt->mutex);
! 5530: conn->MaxRecvDataSegmentLength = 8192; // RFC3720(12.12)
! 5531: if (conn->TargetMaxRecvDataSegmentLength
! 5532: < conn->MaxRecvDataSegmentLength) {
! 5533: conn->TargetMaxRecvDataSegmentLength
! 5534: = conn->MaxRecvDataSegmentLength;
! 5535: }
! 5536: conn->MaxOutstandingR2T = 1;
! 5537: conn->FirstBurstLength = DEFAULT_FIRSTBURSTLENGTH;
! 5538: conn->MaxBurstLength = DEFAULT_MAXBURSTLENGTH;
! 5539:
! 5540: conn->portal.label = xstrdup(portal->label);
! 5541: conn->portal.host = xstrdup(portal->host);
! 5542: conn->portal.port = xstrdup(portal->port);
! 5543: conn->portal.idx = portal->idx;
! 5544: conn->portal.tag = portal->tag;
! 5545: conn->portal.sock = -1;
! 5546: conn->sock = sock;
! 5547: conn->wsock = -1;
! 5548: #ifdef ISTGT_USE_KQUEUE
! 5549: conn->kq = -1;
! 5550: #endif /* ISTGT_USE_KQUEUE */
! 5551: conn->use_sender = 0;
! 5552:
! 5553: conn->sess = NULL;
! 5554: conn->params = NULL;
! 5555: conn->state = CONN_STATE_INVALID;
! 5556: conn->exec_logout = 0;
! 5557: conn->max_pending = 0;
! 5558: conn->queue_depth = 0;
! 5559: conn->pending_r2t = 0;
! 5560: conn->header_digest = 0;
! 5561: conn->data_digest = 0;
! 5562: conn->full_feature = 0;
! 5563: conn->login_phase = ISCSI_LOGIN_PHASE_NONE;
! 5564: conn->auth.user = NULL;
! 5565: conn->auth.secret = NULL;
! 5566: conn->auth.muser = NULL;
! 5567: conn->auth.msecret = NULL;
! 5568: conn->authenticated = 0;
! 5569: conn->req_auth = 0;
! 5570: conn->req_mutual = 0;
! 5571: istgt_queue_init(&conn->pending_pdus);
! 5572: conn->r2t_tasks = xmalloc (sizeof *conn->r2t_tasks
! 5573: * (conn->max_r2t + 1));
! 5574: for (i = 0; i < (conn->max_r2t + 1); i++) {
! 5575: conn->r2t_tasks[i] = NULL;
! 5576: }
! 5577: conn->task_pipe[0] = -1;
! 5578: conn->task_pipe[1] = -1;
! 5579: conn->max_task_queue = MAX_LU_QUEUE_DEPTH;
! 5580: istgt_queue_init(&conn->task_queue);
! 5581: istgt_queue_init(&conn->result_queue);
! 5582: conn->exec_lu_task = NULL;
! 5583: conn->running_tasks = 0;
! 5584:
! 5585: memset(conn->initiator_addr, 0, sizeof conn->initiator_addr);
! 5586: memset(conn->target_addr, 0, sizeof conn->target_addr);
! 5587:
! 5588: switch (sa->sa_family) {
! 5589: case AF_INET6:
! 5590: conn->initiator_family = AF_INET6;
! 5591: rc = istgt_getaddr(sock, conn->target_addr,
! 5592: sizeof conn->target_addr,
! 5593: conn->initiator_addr, sizeof conn->initiator_addr);
! 5594: if (rc < 0) {
! 5595: ISTGT_ERRLOG("istgt_getaddr() failed\n");
! 5596: goto error_return;
! 5597: }
! 5598: break;
! 5599: case AF_INET:
! 5600: conn->initiator_family = AF_INET;
! 5601: rc = istgt_getaddr(sock, conn->target_addr,
! 5602: sizeof conn->target_addr,
! 5603: conn->initiator_addr, sizeof conn->initiator_addr);
! 5604: if (rc < 0) {
! 5605: ISTGT_ERRLOG("istgt_getaddr() failed\n");
! 5606: goto error_return;
! 5607: }
! 5608: break;
! 5609: default:
! 5610: ISTGT_ERRLOG("unsupported family\n");
! 5611: goto error_return;
! 5612: }
! 5613: printf("sock=%d, addr=%s, peer=%s\n",
! 5614: sock, conn->target_addr,
! 5615: conn->initiator_addr);
! 5616:
! 5617: /* wildcard? */
! 5618: if (strcasecmp(conn->portal.host, "[::]") == 0
! 5619: || strcasecmp(conn->portal.host, "[*]") == 0) {
! 5620: if (conn->initiator_family != AF_INET6) {
! 5621: ISTGT_ERRLOG("address family error\n");
! 5622: goto error_return;
! 5623: }
! 5624: snprintf(buf, sizeof buf, "[%s]", conn->target_addr);
! 5625: xfree(conn->portal.host);
! 5626: conn->portal.host = xstrdup(buf);
! 5627: } else if (strcasecmp(conn->portal.host, "0.0.0.0") == 0
! 5628: || strcasecmp(conn->portal.host, "*") == 0) {
! 5629: if (conn->initiator_family != AF_INET) {
! 5630: ISTGT_ERRLOG("address family error\n");
! 5631: goto error_return;
! 5632: }
! 5633: snprintf(buf, sizeof buf, "%s", conn->target_addr);
! 5634: xfree(conn->portal.host);
! 5635: conn->portal.host = xstrdup(buf);
! 5636: }
! 5637:
! 5638: memset(conn->initiator_name, 0, sizeof conn->initiator_name);
! 5639: memset(conn->target_name, 0, sizeof conn->target_name);
! 5640: memset(conn->initiator_port, 0, sizeof conn->initiator_port);
! 5641: memset(conn->target_port, 0, sizeof conn->target_port);
! 5642:
! 5643: /* set timeout msec. */
! 5644: rc = istgt_set_recvtimeout(conn->sock, conn->timeout * 1000);
! 5645: if (rc != 0) {
! 5646: ISTGT_ERRLOG("istgt_set_recvtimeo() failed\n");
! 5647: goto error_return;
! 5648: }
! 5649: rc = istgt_set_sendtimeout(conn->sock, conn->timeout * 1000);
! 5650: if (rc != 0) {
! 5651: ISTGT_ERRLOG("istgt_set_sendtimeo() failed\n");
! 5652: goto error_return;
! 5653: }
! 5654:
! 5655: rc = pipe(conn->task_pipe);
! 5656: if (rc != 0) {
! 5657: ISTGT_ERRLOG("pipe() failed\n");
! 5658: conn->task_pipe[0] = -1;
! 5659: conn->task_pipe[1] = -1;
! 5660: goto error_return;
! 5661: }
! 5662: rc = pthread_mutex_init(&conn->task_queue_mutex, NULL);
! 5663: if (rc != 0) {
! 5664: ISTGT_ERRLOG("mutex_init() failed\n");
! 5665: goto error_return;
! 5666: }
! 5667: rc = pthread_mutex_init(&conn->result_queue_mutex, NULL);
! 5668: if (rc != 0) {
! 5669: ISTGT_ERRLOG("mutex_init() failed\n");
! 5670: goto error_return;
! 5671: }
! 5672: rc = pthread_cond_init(&conn->result_queue_cond, NULL);
! 5673: if (rc != 0) {
! 5674: ISTGT_ERRLOG("cond_init() failed\n");
! 5675: goto error_return;
! 5676: }
! 5677: rc = pthread_mutex_init(&conn->wpdu_mutex, NULL);
! 5678: if (rc != 0) {
! 5679: ISTGT_ERRLOG("mutex_init() failed\n");
! 5680: goto error_return;
! 5681: }
! 5682: rc = pthread_cond_init(&conn->wpdu_cond, NULL);
! 5683: if (rc != 0) {
! 5684: ISTGT_ERRLOG("cond_init() failed\n");
! 5685: goto error_return;
! 5686: }
! 5687: rc = pthread_mutex_init(&conn->r2t_mutex, NULL);
! 5688: if (rc != 0) {
! 5689: ISTGT_ERRLOG("mutex_init() failed\n");
! 5690: goto error_return;
! 5691: }
! 5692: rc = pthread_mutex_init(&conn->sender_mutex, NULL);
! 5693: if (rc != 0) {
! 5694: ISTGT_ERRLOG("mutex_init() failed\n");
! 5695: goto error_return;
! 5696: }
! 5697: rc = pthread_cond_init(&conn->sender_cond, NULL);
! 5698: if (rc != 0) {
! 5699: ISTGT_ERRLOG("cond_init() failed\n");
! 5700: goto error_return;
! 5701: }
! 5702:
! 5703: /* set default params */
! 5704: rc = istgt_iscsi_conn_params_init(&conn->params);
! 5705: if (rc < 0) {
! 5706: ISTGT_ERRLOG("iscsi_conn_params_init() failed\n");
! 5707: goto error_return;
! 5708: }
! 5709: /* replace with config value */
! 5710: rc = istgt_iscsi_param_set_int(conn->params,
! 5711: "MaxRecvDataSegmentLength",
! 5712: conn->MaxRecvDataSegmentLength);
! 5713: if (rc < 0) {
! 5714: ISTGT_ERRLOG("iscsi_param_set_int() failed\n");
! 5715: goto error_return;
! 5716: }
! 5717:
! 5718: conn->shortpdusize = ISTGT_SHORTPDUSIZE;
! 5719: conn->shortpdu = xmalloc(conn->shortpdusize);
! 5720:
! 5721: conn->iobufsize = ISTGT_IOBUFSIZE;
! 5722: conn->iobuf = xmalloc(conn->iobufsize);
! 5723: conn->snsbufsize = ISTGT_SNSBUFSIZE;
! 5724: conn->snsbuf = xmalloc(conn->snsbufsize);
! 5725:
! 5726: if (conn->MaxRecvDataSegmentLength < 8192) {
! 5727: conn->recvbufsize = 8192;
! 5728: conn->sendbufsize = 8192;
! 5729: } else {
! 5730: conn->recvbufsize = conn->MaxRecvDataSegmentLength;
! 5731: conn->sendbufsize = conn->MaxRecvDataSegmentLength;
! 5732: }
! 5733: conn->recvbuf = xmalloc(conn->recvbufsize);
! 5734: conn->sendbuf = xmalloc(conn->sendbufsize);
! 5735:
! 5736: conn->worksize = 0;
! 5737: conn->workbuf = NULL;
! 5738:
! 5739: /* register global */
! 5740: rc = -1;
! 5741: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "register global LOCK\n");
! 5742: MTX_LOCK(&g_conns_mutex);
! 5743: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "register global LOCKED\n");
! 5744: for (i = 0; i < g_nconns; i++) {
! 5745: if (g_conns[i] == NULL) {
! 5746: g_conns[i] = conn;
! 5747: conn->id = i;
! 5748: rc = 0;
! 5749: break;
! 5750: }
! 5751: }
! 5752: MTX_UNLOCK(&g_conns_mutex);
! 5753: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "register global UNLOCK\n");
! 5754: if (rc < 0) {
! 5755: ISTGT_ERRLOG("no free conn slot available\n");
! 5756: error_return:
! 5757: if (conn->task_pipe[0] != -1)
! 5758: close(conn->task_pipe[0]);
! 5759: if (conn->task_pipe[1] != -1)
! 5760: close(conn->task_pipe[1]);
! 5761: istgt_iscsi_param_free(conn->params);
! 5762: istgt_queue_destroy(&conn->pending_pdus);
! 5763: istgt_queue_destroy(&conn->task_queue);
! 5764: xfree(conn->portal.label);
! 5765: xfree(conn->portal.host);
! 5766: xfree(conn->portal.port);
! 5767: xfree(conn->iobuf);
! 5768: xfree(conn->snsbuf);
! 5769: xfree(conn->recvbuf);
! 5770: xfree(conn->sendbuf);
! 5771: xfree(conn);
! 5772: return -1;
! 5773: }
! 5774:
! 5775: /* create new thread */
! 5776: #ifdef ISTGT_STACKSIZE
! 5777: rc = pthread_create(&conn->thread, &istgt->attr, &worker, (void *)conn);
! 5778: #else
! 5779: rc = pthread_create(&conn->thread, NULL, &worker, (void *)conn);
! 5780: #endif /* ISTGT_STACKSIZE */
! 5781: if (rc != 0) {
! 5782: ISTGT_ERRLOG("pthread_create() failed\n");
! 5783: goto error_return;
! 5784: }
! 5785: rc = pthread_detach(conn->thread);
! 5786: if (rc != 0) {
! 5787: ISTGT_ERRLOG("pthread_detach() failed\n");
! 5788: goto error_return;
! 5789: }
! 5790: #ifdef HAVE_PTHREAD_SET_NAME_NP
! 5791: snprintf(buf, sizeof buf, "connthread #%d", conn->id);
! 5792: pthread_set_name_np(conn->thread, buf);
! 5793: #endif
! 5794:
! 5795: return 0;
! 5796: }
! 5797:
! 5798: int
! 5799: istgt_create_sess(ISTGT_Ptr istgt, CONN_Ptr conn, ISTGT_LU_Ptr lu)
! 5800: {
! 5801: SESS_Ptr sess;
! 5802: int rc;
! 5803:
! 5804: sess = xmalloc(sizeof *sess);
! 5805: memset(sess, 0, sizeof *sess);
! 5806:
! 5807: /* configuration values */
! 5808: MTX_LOCK(&istgt->mutex);
! 5809: if (lu != NULL) {
! 5810: MTX_LOCK(&lu->mutex);
! 5811: }
! 5812: sess->MaxConnections = istgt->MaxConnections;
! 5813: if (lu != NULL) {
! 5814: sess->MaxOutstandingR2T = lu->MaxOutstandingR2T;
! 5815: } else {
! 5816: sess->MaxOutstandingR2T = istgt->MaxOutstandingR2T;
! 5817: }
! 5818: #if 0
! 5819: if (sess->MaxOutstandingR2T > conn->max_r2t) {
! 5820: if (conn->max_r2t > 0) {
! 5821: sess->MaxOutstandingR2T = conn->max_r2t;
! 5822: } else {
! 5823: sess->MaxOutstandingR2T = 1;
! 5824: }
! 5825: }
! 5826: #else
! 5827: if (sess->MaxOutstandingR2T < 1) {
! 5828: sess->MaxOutstandingR2T = 1;
! 5829: }
! 5830: /* limit up to MaxOutstandingR2T */
! 5831: if (sess->MaxOutstandingR2T < conn->max_r2t) {
! 5832: conn->max_r2t = sess->MaxOutstandingR2T;
! 5833: }
! 5834: #endif
! 5835: if (lu != NULL) {
! 5836: sess->DefaultTime2Wait = lu->DefaultTime2Wait;
! 5837: sess->DefaultTime2Retain = lu->DefaultTime2Retain;
! 5838: sess->FirstBurstLength = lu->FirstBurstLength;
! 5839: sess->MaxBurstLength = lu->MaxBurstLength;
! 5840: conn->MaxRecvDataSegmentLength
! 5841: = lu->MaxRecvDataSegmentLength;
! 5842: sess->InitialR2T = lu->InitialR2T;
! 5843: sess->ImmediateData = lu->ImmediateData;
! 5844: sess->DataPDUInOrder = lu->DataPDUInOrder;
! 5845: sess->DataSequenceInOrder = lu->DataSequenceInOrder;
! 5846: sess->ErrorRecoveryLevel = lu->ErrorRecoveryLevel;
! 5847: } else {
! 5848: sess->DefaultTime2Wait = istgt->DefaultTime2Wait;
! 5849: sess->DefaultTime2Retain = istgt->DefaultTime2Retain;
! 5850: sess->FirstBurstLength = istgt->FirstBurstLength;
! 5851: sess->MaxBurstLength = istgt->MaxBurstLength;
! 5852: conn->MaxRecvDataSegmentLength
! 5853: = istgt->MaxRecvDataSegmentLength;
! 5854: sess->InitialR2T = istgt->InitialR2T;
! 5855: sess->ImmediateData = istgt->ImmediateData;
! 5856: sess->DataPDUInOrder = istgt->DataPDUInOrder;
! 5857: sess->DataSequenceInOrder = istgt->DataSequenceInOrder;
! 5858: sess->ErrorRecoveryLevel = istgt->ErrorRecoveryLevel;
! 5859: }
! 5860: if (lu != NULL) {
! 5861: MTX_UNLOCK(&lu->mutex);
! 5862: }
! 5863: MTX_UNLOCK(&istgt->mutex);
! 5864:
! 5865: sess->initiator_port = xstrdup(conn->initiator_port);
! 5866: sess->target_name = xstrdup(conn->target_name);
! 5867: sess->tag = conn->portal.tag;
! 5868:
! 5869: sess->max_conns = sess->MaxConnections;
! 5870: sess->conns = xmalloc(sizeof *sess->conns * sess->max_conns);
! 5871: memset(sess->conns, 0, sizeof *sess->conns * sess->max_conns);
! 5872: sess->connections = 0;
! 5873:
! 5874: sess->conns[sess->connections] = conn;
! 5875: sess->connections++;
! 5876:
! 5877: sess->req_mcs_cond = 0;
! 5878: sess->params = NULL;
! 5879: sess->lu = NULL;
! 5880: sess->isid = 0;
! 5881: sess->tsih = 0;
! 5882:
! 5883: sess->initial_r2t = 0;
! 5884: sess->immediate_data = 0;
! 5885:
! 5886: rc = pthread_mutex_init(&sess->mutex, NULL);
! 5887: if (rc != 0) {
! 5888: ISTGT_ERRLOG("mutex_init() failed\n");
! 5889: error_return:
! 5890: istgt_iscsi_param_free(sess->params);
! 5891: xfree(sess->initiator_port);
! 5892: xfree(sess->target_name);
! 5893: xfree(sess->conns);
! 5894: xfree(sess);
! 5895: conn->sess = NULL;
! 5896: return -1;
! 5897: }
! 5898: rc = pthread_cond_init(&sess->mcs_cond, NULL);
! 5899: if (rc != 0) {
! 5900: ISTGT_ERRLOG("cond_init() failed\n");
! 5901: goto error_return;
! 5902: }
! 5903:
! 5904: /* set default params */
! 5905: rc = istgt_iscsi_sess_params_init(&sess->params);
! 5906: if (rc < 0) {
! 5907: ISTGT_ERRLOG("iscsi_sess_params_init() failed\n");
! 5908: goto error_return;
! 5909: }
! 5910: /* replace with config value */
! 5911: rc = istgt_iscsi_param_set_int(sess->params,
! 5912: "MaxConnections",
! 5913: sess->MaxConnections);
! 5914: if (rc < 0) {
! 5915: ISTGT_ERRLOG("iscsi_param_set_int() failed\n");
! 5916: goto error_return;
! 5917: }
! 5918: rc = istgt_iscsi_param_set_int(sess->params,
! 5919: "MaxOutstandingR2T",
! 5920: sess->MaxOutstandingR2T);
! 5921: if (rc < 0) {
! 5922: ISTGT_ERRLOG("iscsi_param_set_int() failed\n");
! 5923: goto error_return;
! 5924: }
! 5925: rc = istgt_iscsi_param_set_int(sess->params,
! 5926: "DefaultTime2Wait",
! 5927: sess->DefaultTime2Wait);
! 5928: if (rc < 0) {
! 5929: ISTGT_ERRLOG("iscsi_param_set_int() failed\n");
! 5930: goto error_return;
! 5931: }
! 5932: rc = istgt_iscsi_param_set_int(sess->params,
! 5933: "DefaultTime2Retain",
! 5934: sess->DefaultTime2Retain);
! 5935: if (rc < 0) {
! 5936: ISTGT_ERRLOG("iscsi_param_set_int() failed\n");
! 5937: goto error_return;
! 5938: }
! 5939: rc = istgt_iscsi_param_set_int(sess->params,
! 5940: "FirstBurstLength",
! 5941: sess->FirstBurstLength);
! 5942: if (rc < 0) {
! 5943: ISTGT_ERRLOG("iscsi_param_set_int() failed\n");
! 5944: goto error_return;
! 5945: }
! 5946: rc = istgt_iscsi_param_set_int(sess->params,
! 5947: "MaxBurstLength",
! 5948: sess->MaxBurstLength);
! 5949: if (rc < 0) {
! 5950: ISTGT_ERRLOG("iscsi_param_set_int() failed\n");
! 5951: goto error_return;
! 5952: }
! 5953: rc = istgt_iscsi_param_set(sess->params,
! 5954: "InitialR2T",
! 5955: sess->InitialR2T ? "Yes" : "No");
! 5956: if (rc < 0) {
! 5957: ISTGT_ERRLOG("iscsi_param_set() failed\n");
! 5958: goto error_return;
! 5959: }
! 5960: rc = istgt_iscsi_param_set(sess->params,
! 5961: "ImmediateData",
! 5962: sess->ImmediateData ? "Yes" : "No");
! 5963: if (rc < 0) {
! 5964: ISTGT_ERRLOG("iscsi_param_set() failed\n");
! 5965: goto error_return;
! 5966: }
! 5967: rc = istgt_iscsi_param_set(sess->params,
! 5968: "DataPDUInOrder",
! 5969: sess->DataPDUInOrder ? "Yes" : "No");
! 5970: if (rc < 0) {
! 5971: ISTGT_ERRLOG("iscsi_param_set() failed\n");
! 5972: goto error_return;
! 5973: }
! 5974: rc = istgt_iscsi_param_set(sess->params,
! 5975: "DataSequenceInOrder",
! 5976: sess->DataSequenceInOrder ? "Yes" : "No");
! 5977: if (rc < 0) {
! 5978: ISTGT_ERRLOG("iscsi_param_set() failed\n");
! 5979: goto error_return;
! 5980: }
! 5981: rc = istgt_iscsi_param_set_int(sess->params,
! 5982: "ErrorRecoveryLevel",
! 5983: sess->ErrorRecoveryLevel);
! 5984: if (rc < 0) {
! 5985: ISTGT_ERRLOG("iscsi_param_set_int() failed\n");
! 5986: goto error_return;
! 5987: }
! 5988:
! 5989: /* realloc buffer */
! 5990: rc = istgt_iscsi_param_set_int(conn->params,
! 5991: "MaxRecvDataSegmentLength",
! 5992: conn->MaxRecvDataSegmentLength);
! 5993: if (rc < 0) {
! 5994: ISTGT_ERRLOG("iscsi_param_set_int() failed\n");
! 5995: goto error_return;
! 5996: }
! 5997: if (conn->MaxRecvDataSegmentLength != conn->recvbufsize) {
! 5998: xfree(conn->recvbuf);
! 5999: xfree(conn->sendbuf);
! 6000: if (conn->MaxRecvDataSegmentLength < 8192) {
! 6001: conn->recvbufsize = 8192;
! 6002: conn->sendbufsize = 8192;
! 6003: } else {
! 6004: conn->recvbufsize = conn->MaxRecvDataSegmentLength;
! 6005: conn->sendbufsize = conn->MaxRecvDataSegmentLength;
! 6006: }
! 6007: conn->recvbuf = xmalloc(conn->recvbufsize);
! 6008: conn->sendbuf = xmalloc(conn->sendbufsize);
! 6009: }
! 6010:
! 6011: /* sess for first connection of session */
! 6012: conn->sess = sess;
! 6013: return 0;
! 6014: }
! 6015:
! 6016: static int
! 6017: istgt_append_sess(CONN_Ptr conn, uint64_t isid, uint16_t tsih, uint16_t cid)
! 6018: {
! 6019: SESS_Ptr sess;
! 6020: int rc;
! 6021: int i;
! 6022:
! 6023: ISTGT_TRACELOG(ISTGT_TRACE_ISCSI,
! 6024: "append session: isid=%"PRIx64", tsih=%u, cid=%u\n",
! 6025: isid, tsih, cid);
! 6026:
! 6027: sess = NULL;
! 6028: rc = -1;
! 6029: MTX_LOCK(&g_conns_mutex);
! 6030: for (i = 0; i < g_nconns; i++) {
! 6031: if (g_conns[i] == NULL || g_conns[i]->sess == NULL)
! 6032: continue;
! 6033: sess = g_conns[i]->sess;
! 6034: MTX_LOCK(&sess->mutex);
! 6035: if (conn->portal.tag == sess->tag
! 6036: && strcasecmp(conn->initiator_port, sess->initiator_port) == 0
! 6037: && strcasecmp(conn->target_name, sess->target_name) == 0
! 6038: && (isid == sess->isid && tsih == sess->tsih)) {
! 6039: /* match tag and initiator port and target */
! 6040: rc = 0;
! 6041: break;
! 6042: }
! 6043: MTX_UNLOCK(&sess->mutex);
! 6044: }
! 6045: if (rc < 0) {
! 6046: /* no match */
! 6047: MTX_UNLOCK(&g_conns_mutex);
! 6048: ISTGT_ERRLOG("no MCS session for isid=%"PRIx64", tsih=%d, cid=%d\n",
! 6049: isid, tsih, cid);
! 6050: return -1;
! 6051: }
! 6052: /* sess is LOCK by loop */
! 6053: if (sess->connections >= sess->max_conns
! 6054: || sess->connections >= sess->MaxConnections) {
! 6055: /* no slot for connection */
! 6056: MTX_UNLOCK(&sess->mutex);
! 6057: MTX_UNLOCK(&g_conns_mutex);
! 6058: ISTGT_ERRLOG("too many connections for isid=%"PRIx64
! 6059: ", tsih=%d, cid=%d\n",
! 6060: isid, tsih, cid);
! 6061: return -1;
! 6062: }
! 6063: printf("Connections(tsih %d): %d\n", sess->tsih, sess->connections);
! 6064: conn->sess = sess;
! 6065: sess->conns[sess->connections] = conn;
! 6066: sess->connections++;
! 6067: MTX_UNLOCK(&sess->mutex);
! 6068: MTX_UNLOCK(&g_conns_mutex);
! 6069:
! 6070: return 0;
! 6071: }
! 6072:
! 6073: static void
! 6074: istgt_free_sess(SESS_Ptr sess)
! 6075: {
! 6076: if (sess == NULL)
! 6077: return;
! 6078: (void) pthread_mutex_destroy(&sess->mutex);
! 6079: (void) pthread_cond_destroy(&sess->mcs_cond);
! 6080: istgt_iscsi_param_free(sess->params);
! 6081: xfree(sess->initiator_port);
! 6082: xfree(sess->target_name);
! 6083: xfree(sess->conns);
! 6084: xfree(sess);
! 6085: }
! 6086:
! 6087: static void
! 6088: istgt_free_conn(CONN_Ptr conn)
! 6089: {
! 6090: if (conn == NULL)
! 6091: return;
! 6092: if (conn->task_pipe[0] != -1)
! 6093: close(conn->task_pipe[0]);
! 6094: if (conn->task_pipe[1] != -1)
! 6095: close(conn->task_pipe[1]);
! 6096: (void) pthread_mutex_destroy(&conn->task_queue_mutex);
! 6097: (void) pthread_mutex_destroy(&conn->result_queue_mutex);
! 6098: (void) pthread_cond_destroy(&conn->result_queue_cond);
! 6099: (void) pthread_mutex_destroy(&conn->wpdu_mutex);
! 6100: (void) pthread_cond_destroy(&conn->wpdu_cond);
! 6101: (void) pthread_mutex_destroy(&conn->r2t_mutex);
! 6102: (void) pthread_mutex_destroy(&conn->sender_mutex);
! 6103: (void) pthread_cond_destroy(&conn->sender_cond);
! 6104: istgt_iscsi_param_free(conn->params);
! 6105: istgt_queue_destroy(&conn->pending_pdus);
! 6106: istgt_queue_destroy(&conn->task_queue);
! 6107: istgt_queue_destroy(&conn->result_queue);
! 6108: xfree(conn->r2t_tasks);
! 6109: xfree(conn->portal.label);
! 6110: xfree(conn->portal.host);
! 6111: xfree(conn->portal.port);
! 6112: xfree(conn->auth.user);
! 6113: xfree(conn->auth.secret);
! 6114: xfree(conn->auth.muser);
! 6115: xfree(conn->auth.msecret);
! 6116: xfree(conn->shortpdu);
! 6117: xfree(conn->iobuf);
! 6118: xfree(conn->snsbuf);
! 6119: xfree(conn->recvbuf);
! 6120: xfree(conn->sendbuf);
! 6121: xfree(conn->workbuf);
! 6122: xfree(conn);
! 6123: }
! 6124:
! 6125: static void
! 6126: istgt_remove_conn(CONN_Ptr conn)
! 6127: {
! 6128: SESS_Ptr sess;
! 6129: int idx;
! 6130: int i, j;
! 6131:
! 6132: idx = -1;
! 6133: sess = conn->sess;
! 6134: conn->sess = NULL;
! 6135: if (sess == NULL) {
! 6136: istgt_free_conn(conn);
! 6137: return;
! 6138: }
! 6139:
! 6140: MTX_LOCK(&sess->mutex);
! 6141: for (i = 0; i < sess->connections; i++) {
! 6142: if (sess->conns[i] == conn) {
! 6143: idx = i;
! 6144: break;
! 6145: }
! 6146: }
! 6147: if (sess->connections < 1) {
! 6148: ISTGT_ERRLOG("zero connection\n");
! 6149: sess->connections = 0;
! 6150: } else {
! 6151: if (idx < 0) {
! 6152: ISTGT_ERRLOG("remove conn not found\n");
! 6153: } else {
! 6154: for (j = idx; j < sess->connections - 1; j++) {
! 6155: sess->conns[j] = sess->conns[j + 1];
! 6156: }
! 6157: sess->conns[sess->connections - 1] = NULL;
! 6158: }
! 6159: sess->connections--;
! 6160: }
! 6161: printf("Connections(tsih %d): %d\n", sess->tsih, sess->connections);
! 6162: if (sess->connections == 1) {
! 6163: /* cleanup for multiple connecsions */
! 6164: MTX_UNLOCK(&sess->mutex);
! 6165: } else if (sess->connections == 0) {
! 6166: /* cleanup last connection */
! 6167: MTX_UNLOCK(&sess->mutex);
! 6168: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "cleanup last conn free tsih\n");
! 6169: istgt_lu_free_tsih(sess->lu, sess->tsih, conn->initiator_port);
! 6170: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "cleanup last conn free sess\n");
! 6171: istgt_free_sess(sess);
! 6172: } else {
! 6173: MTX_UNLOCK(&sess->mutex);
! 6174: }
! 6175: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "cleanup free conn\n");
! 6176: istgt_free_conn(conn);
! 6177: }
! 6178:
! 6179: static int
! 6180: istgt_iscsi_drop_all_conns(CONN_Ptr conn)
! 6181: {
! 6182: CONN_Ptr xconn;
! 6183: int max_conns;
! 6184: int num;
! 6185: int rc;
! 6186: int i;
! 6187:
! 6188: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_iscsi_drop_all_conns\n");
! 6189:
! 6190: printf("drop all connections %s by %s\n",
! 6191: conn->target_name, conn->initiator_name);
! 6192:
! 6193: MTX_LOCK(&conn->istgt->mutex);
! 6194: max_conns = conn->istgt->MaxConnections;
! 6195: MTX_UNLOCK(&conn->istgt->mutex);
! 6196: num = 0;
! 6197: MTX_LOCK(&g_conns_mutex);
! 6198: for (i = 0; i < g_nconns; i++) {
! 6199: xconn = g_conns[i];
! 6200: if (xconn == NULL)
! 6201: continue;
! 6202: if (xconn == conn)
! 6203: continue;
! 6204: if (strcasecmp(conn->initiator_name, xconn->initiator_name) != 0) {
! 6205: continue;
! 6206: }
! 6207: if (strcasecmp(conn->target_name, xconn->target_name) == 0) {
! 6208: if (xconn->sess != NULL) {
! 6209: printf("exiting conn by %s(%s), TSIH=%u, CID=%u\n",
! 6210: xconn->initiator_name,
! 6211: xconn->initiator_addr,
! 6212: xconn->sess->tsih, xconn->cid);
! 6213: } else {
! 6214: printf("exiting conn by %s(%s), TSIH=xx, CID=%u\n",
! 6215: xconn->initiator_name,
! 6216: xconn->initiator_addr,
! 6217: xconn->cid);
! 6218: }
! 6219: xconn->state = CONN_STATE_EXITING;
! 6220: num++;
! 6221: }
! 6222: }
! 6223: istgt_yield();
! 6224: sleep(1);
! 6225: if (num > max_conns + 1) {
! 6226: printf("try pthread_cancel\n");
! 6227: for (i = 0; i < g_nconns; i++) {
! 6228: xconn = g_conns[i];
! 6229: if (xconn == NULL)
! 6230: continue;
! 6231: if (xconn == conn)
! 6232: continue;
! 6233: if (strcasecmp(conn->initiator_port, xconn->initiator_port) != 0) {
! 6234: continue;
! 6235: }
! 6236: if (strcasecmp(conn->target_name, xconn->target_name) == 0) {
! 6237: if (xconn->sess != NULL) {
! 6238: printf("exiting conn by %s(%s), TSIH=%u, CID=%u\n",
! 6239: xconn->initiator_port,
! 6240: xconn->initiator_addr,
! 6241: xconn->sess->tsih, xconn->cid);
! 6242: } else {
! 6243: printf("exiting conn by %s(%s), TSIH=xx, CID=%u\n",
! 6244: xconn->initiator_port,
! 6245: xconn->initiator_addr,
! 6246: xconn->cid);
! 6247: }
! 6248: rc = pthread_cancel(xconn->thread);
! 6249: if (rc != 0) {
! 6250: ISTGT_ERRLOG("pthread_cancel() failed rc=%d\n", rc);
! 6251: }
! 6252: }
! 6253: }
! 6254: }
! 6255: MTX_UNLOCK(&g_conns_mutex);
! 6256:
! 6257: if (num != 0) {
! 6258: printf("exiting %d conns\n", num);
! 6259: }
! 6260: return 0;
! 6261: }
! 6262:
! 6263: static int
! 6264: istgt_iscsi_drop_old_conns(CONN_Ptr conn)
! 6265: {
! 6266: CONN_Ptr xconn;
! 6267: int max_conns;
! 6268: int num;
! 6269: int rc;
! 6270: int i;
! 6271:
! 6272: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_iscsi_drop_old_conns\n");
! 6273:
! 6274: printf("drop old connections %s by %s\n",
! 6275: conn->target_name, conn->initiator_port);
! 6276:
! 6277: MTX_LOCK(&conn->istgt->mutex);
! 6278: max_conns = conn->istgt->MaxConnections;
! 6279: MTX_UNLOCK(&conn->istgt->mutex);
! 6280: num = 0;
! 6281: MTX_LOCK(&g_conns_mutex);
! 6282: for (i = 0; i < g_nconns; i++) {
! 6283: xconn = g_conns[i];
! 6284: if (xconn == NULL)
! 6285: continue;
! 6286: if (xconn == conn)
! 6287: continue;
! 6288: if (strcasecmp(conn->initiator_port, xconn->initiator_port) != 0) {
! 6289: continue;
! 6290: }
! 6291: if (strcasecmp(conn->target_name, xconn->target_name) == 0) {
! 6292: if (xconn->sess != NULL) {
! 6293: printf("exiting conn by %s(%s), TSIH=%u, CID=%u\n",
! 6294: xconn->initiator_port,
! 6295: xconn->initiator_addr,
! 6296: xconn->sess->tsih, xconn->cid);
! 6297: } else {
! 6298: printf("exiting conn by %s(%s), TSIH=xx, CID=%u\n",
! 6299: xconn->initiator_port,
! 6300: xconn->initiator_addr,
! 6301: xconn->cid);
! 6302: }
! 6303: xconn->state = CONN_STATE_EXITING;
! 6304: num++;
! 6305: }
! 6306: }
! 6307: istgt_yield();
! 6308: sleep(1);
! 6309: if (num > max_conns + 1) {
! 6310: printf("try pthread_cancel\n");
! 6311: for (i = 0; i < g_nconns; i++) {
! 6312: xconn = g_conns[i];
! 6313: if (xconn == NULL)
! 6314: continue;
! 6315: if (xconn == conn)
! 6316: continue;
! 6317: if (strcasecmp(conn->initiator_port, xconn->initiator_port) != 0) {
! 6318: continue;
! 6319: }
! 6320: if (strcasecmp(conn->target_name, xconn->target_name) == 0) {
! 6321: if (xconn->sess != NULL) {
! 6322: printf("exiting conn by %s(%s), TSIH=%u, CID=%u\n",
! 6323: xconn->initiator_port,
! 6324: xconn->initiator_addr,
! 6325: xconn->sess->tsih, xconn->cid);
! 6326: } else {
! 6327: printf("exiting conn by %s(%s), TSIH=xx, CID=%u\n",
! 6328: xconn->initiator_port,
! 6329: xconn->initiator_addr,
! 6330: xconn->cid);
! 6331: }
! 6332: rc = pthread_cancel(xconn->thread);
! 6333: if (rc != 0) {
! 6334: ISTGT_ERRLOG("pthread_cancel() failed rc=%d\n", rc);
! 6335: }
! 6336: }
! 6337: }
! 6338: }
! 6339: MTX_UNLOCK(&g_conns_mutex);
! 6340:
! 6341: if (num != 0) {
! 6342: printf("exiting %d conns\n", num);
! 6343: }
! 6344: return 0;
! 6345: }
! 6346:
! 6347: void
! 6348: istgt_lock_gconns(void)
! 6349: {
! 6350: MTX_LOCK(&g_conns_mutex);
! 6351: }
! 6352:
! 6353: void
! 6354: istgt_unlock_gconns(void)
! 6355: {
! 6356: MTX_UNLOCK(&g_conns_mutex);
! 6357: }
! 6358:
! 6359: int
! 6360: istgt_get_gnconns(void)
! 6361: {
! 6362: return g_nconns;
! 6363: }
! 6364:
! 6365: CONN_Ptr
! 6366: istgt_get_gconn(int idx)
! 6367: {
! 6368: if (idx >= g_nconns)
! 6369: return NULL;
! 6370: return g_conns[idx];
! 6371: }
! 6372:
! 6373: int
! 6374: istgt_get_active_conns(void)
! 6375: {
! 6376: CONN_Ptr conn;
! 6377: int num = 0;
! 6378: int i;
! 6379:
! 6380: MTX_LOCK(&g_conns_mutex);
! 6381: for (i = 0; i < g_nconns; i++) {
! 6382: conn = g_conns[i];
! 6383: if (conn == NULL)
! 6384: continue;
! 6385: num++;
! 6386: }
! 6387: MTX_UNLOCK(&g_conns_mutex);
! 6388: return num;
! 6389: }
! 6390:
! 6391: CONN_Ptr
! 6392: istgt_find_conn(const char *initiator_port, const char *target_name, uint16_t tsih)
! 6393: {
! 6394: CONN_Ptr conn;
! 6395: SESS_Ptr sess;
! 6396: int rc;
! 6397: int i;
! 6398:
! 6399: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 6400: "initiator_port=%s, target=%s, TSIH=%u",
! 6401: initiator_port, target_name, tsih);
! 6402: sess = NULL;
! 6403: rc = -1;
! 6404: //MTX_LOCK(&g_conns_mutex);
! 6405: for (i = 0; i < g_nconns; i++) {
! 6406: conn = g_conns[i];
! 6407: if (conn == NULL || conn->sess == NULL)
! 6408: continue;
! 6409: sess = conn->sess;
! 6410: MTX_LOCK(&sess->mutex);
! 6411: if (strcasecmp(initiator_port, sess->initiator_port) == 0
! 6412: && strcasecmp(target_name, sess->target_name) == 0
! 6413: && (tsih == sess->tsih)) {
! 6414: /* match initiator port and target */
! 6415: rc = 0;
! 6416: break;
! 6417: }
! 6418: MTX_UNLOCK(&sess->mutex);
! 6419: }
! 6420: if (rc < 0) {
! 6421: //MTX_UNLOCK(&g_conns_mutex);
! 6422: return NULL;
! 6423: }
! 6424: MTX_UNLOCK(&sess->mutex);
! 6425: //MTX_UNLOCK(&g_conns_mutex);
! 6426: return conn;
! 6427: }
! 6428:
! 6429: int
! 6430: istgt_iscsi_init(ISTGT_Ptr istgt)
! 6431: {
! 6432: CF_SECTION *sp;
! 6433: int rc;
! 6434: int i;
! 6435:
! 6436: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_iscsi_init\n");
! 6437: sp = istgt_find_cf_section(istgt->config, "Global");
! 6438: if (sp == NULL) {
! 6439: ISTGT_ERRLOG("find_cf_section failed()\n");
! 6440: return -1;
! 6441: }
! 6442:
! 6443: rc = pthread_mutex_init(&g_conns_mutex, NULL);
! 6444: if (rc != 0) {
! 6445: ISTGT_ERRLOG("mutex_init() failed\n");
! 6446: return -1;
! 6447: }
! 6448: rc = pthread_mutex_init(&g_last_tsih_mutex, NULL);
! 6449: if (rc != 0) {
! 6450: ISTGT_ERRLOG("mutex_init() failed\n");
! 6451: return -1;
! 6452: }
! 6453:
! 6454: g_nconns = MAX_LOGICAL_UNIT * istgt->MaxSessions * istgt->MaxConnections;
! 6455: g_nconns += MAX_LOGICAL_UNIT * istgt->MaxConnections;
! 6456: g_conns = xmalloc(sizeof *g_conns * g_nconns);
! 6457: for (i = 0; i < g_nconns; i++) {
! 6458: g_conns[i] = NULL;
! 6459: }
! 6460: g_last_tsih = 0;
! 6461:
! 6462: return 0;
! 6463: }
! 6464:
! 6465: int
! 6466: istgt_iscsi_shutdown(ISTGT_Ptr istgt)
! 6467: {
! 6468: CONN_Ptr conn;
! 6469: int retry = 10;
! 6470: int num;
! 6471: int rc;
! 6472: int i;
! 6473:
! 6474: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_iscsi_shutdown\n");
! 6475:
! 6476: num = 0;
! 6477: MTX_LOCK(&g_conns_mutex);
! 6478: for (i = 0; i < g_nconns; i++) {
! 6479: conn = g_conns[i];
! 6480: if (conn == NULL)
! 6481: continue;
! 6482: conn->state = CONN_STATE_EXITING;
! 6483: num++;
! 6484: }
! 6485: MTX_UNLOCK(&g_conns_mutex);
! 6486:
! 6487: if (num != 0) {
! 6488: /* check threads */
! 6489: while (retry > 0) {
! 6490: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
! 6491: "check thread retry=%d\n",
! 6492: retry);
! 6493: sleep(1);
! 6494: num = 0;
! 6495: MTX_LOCK(&g_conns_mutex);
! 6496: for (i = 0; i < g_nconns; i++) {
! 6497: conn = g_conns[i];
! 6498: if (conn == NULL)
! 6499: continue;
! 6500: num++;
! 6501: }
! 6502: MTX_UNLOCK(&g_conns_mutex);
! 6503: if (num == 0)
! 6504: break;
! 6505: retry--;
! 6506: }
! 6507: }
! 6508:
! 6509: rc = pthread_mutex_destroy(&g_last_tsih_mutex);
! 6510: if (rc != 0) {
! 6511: ISTGT_ERRLOG("mutex_destroy() failed\n");
! 6512: return -1;
! 6513: }
! 6514: rc = pthread_mutex_destroy(&g_conns_mutex);
! 6515: if (rc != 0) {
! 6516: ISTGT_ERRLOG("mutex_destroy() failed\n");
! 6517: return -1;
! 6518: }
! 6519:
! 6520: return 0;
! 6521: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>