Annotation of embedaddon/istgt/src/istgt_iscsi.c, revision 1.1.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>