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(&params, 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(&params, 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>