Annotation of embedaddon/istgt/src/istgt_iscsi.c, revision 1.1.1.3

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>