Annotation of embedaddon/istgt/src/istgt_lu.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2008-2011 Daisuke Aoyama <aoyama@peach.ne.jp>.
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * Redistribution and use in source and binary forms, with or without
        !             6:  * modification, are permitted provided that the following conditions
        !             7:  * are met:
        !             8:  * 1. Redistributions of source code must retain the above copyright
        !             9:  *    notice, this list of conditions and the following disclaimer.
        !            10:  * 2. Redistributions in binary form must reproduce the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer in the
        !            12:  *    documentation and/or other materials provided with the distribution.
        !            13:  *
        !            14:  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
        !            15:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            16:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            17:  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
        !            18:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            19:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            20:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            21:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            22:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            23:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            24:  * SUCH DAMAGE.
        !            25:  *
        !            26:  */
        !            27: 
        !            28: #ifdef HAVE_CONFIG_H
        !            29: #include "config.h"
        !            30: #endif
        !            31: 
        !            32: #include <inttypes.h>
        !            33: #include <stdint.h>
        !            34: 
        !            35: #include <ctype.h>
        !            36: #include <errno.h>
        !            37: #include <signal.h>
        !            38: #include <stdio.h>
        !            39: #include <stdlib.h>
        !            40: #include <string.h>
        !            41: #include <limits.h>
        !            42: #include <pthread.h>
        !            43: #ifdef HAVE_PTHREAD_NP_H
        !            44: #include <pthread_np.h>
        !            45: #endif
        !            46: #include <time.h>
        !            47: #include <sys/types.h>
        !            48: #include <sys/stat.h>
        !            49: #include <netinet/in.h>
        !            50: #include <arpa/inet.h>
        !            51: 
        !            52: #include <fcntl.h>
        !            53: #include <unistd.h>
        !            54: #include <sys/ioctl.h>
        !            55: #ifdef HAVE_SYS_DISK_H
        !            56: #include <sys/disk.h>
        !            57: #endif
        !            58: #ifdef HAVE_SYS_DISKLABEL_H
        !            59: #include <sys/disklabel.h>
        !            60: #endif
        !            61: #ifdef __linux__
        !            62: #include <linux/fs.h>
        !            63: #endif
        !            64: 
        !            65: #include "istgt.h"
        !            66: #include "istgt_ver.h"
        !            67: #include "istgt_log.h"
        !            68: #include "istgt_conf.h"
        !            69: #include "istgt_sock.h"
        !            70: #include "istgt_misc.h"
        !            71: #include "istgt_md5.h"
        !            72: #include "istgt_iscsi.h"
        !            73: #include "istgt_lu.h"
        !            74: #include "istgt_proto.h"
        !            75: #include "istgt_scsi.h"
        !            76: 
        !            77: #define MAX_MASKBUF 128
        !            78: static int
        !            79: istgt_lu_allow_ipv6(const char *netmask, const char *addr)
        !            80: {
        !            81:        struct in6_addr in6_mask;
        !            82:        struct in6_addr in6_addr;
        !            83:        char mask[MAX_MASKBUF];
        !            84:        const char *p;
        !            85:        int bits, bmask;
        !            86:        int n;
        !            87:        int i;
        !            88: 
        !            89:        if (netmask[0] != '[')
        !            90:                return 0;
        !            91:        p = strchr(netmask, ']');
        !            92:        if (p == NULL)
        !            93:                return 0;
        !            94:        n = p - (netmask + 1);
        !            95:        if (n + 1 > sizeof mask)
        !            96:                return 0;
        !            97: 
        !            98:        memcpy(mask, netmask + 1, n);
        !            99:        mask[n] = '\0';
        !           100:        p++;
        !           101: 
        !           102:        if (p[0] == '/') {
        !           103:                bits = (int) strtol(p + 1, NULL, 10);
        !           104:                if (bits < 0 || bits > 128)
        !           105:                        return 0;
        !           106:        } else {
        !           107:                bits = 128;
        !           108:        }
        !           109: 
        !           110: #if 0
        !           111:        printf("input %s\n", addr);
        !           112:        printf("mask  %s / %d\n", mask, bits);
        !           113: #endif
        !           114: 
        !           115:        /* presentation to network order binary */
        !           116:        if (inet_pton(AF_INET6, mask, &in6_mask) <= 0
        !           117:                || inet_pton(AF_INET6, addr, &in6_addr) <= 0) {
        !           118:                return 0;
        !           119:        }
        !           120: 
        !           121:        /* check 128bits */
        !           122:        for (i = 0; i < (bits / 8); i++) {
        !           123:                if (in6_mask.s6_addr[i] != in6_addr.s6_addr[i])
        !           124:                        return 0;
        !           125:        }
        !           126:        if (bits % 8) {
        !           127:                bmask = (0xffU << (8 - (bits % 8))) & 0xffU;
        !           128:                if ((in6_mask.s6_addr[i] & bmask) != (in6_addr.s6_addr[i] & bmask))
        !           129:                        return 0;
        !           130:        }
        !           131: 
        !           132:        /* match */
        !           133:        return 1;
        !           134: }
        !           135: 
        !           136: static int
        !           137: istgt_lu_allow_ipv4(const char *netmask, const char *addr)
        !           138: {
        !           139:        struct in_addr in4_mask;
        !           140:        struct in_addr in4_addr;
        !           141:        char mask[MAX_MASKBUF];
        !           142:        const char *p;
        !           143:        uint32_t bmask;
        !           144:        int bits;
        !           145:        int n;
        !           146: 
        !           147:        p = strchr(netmask, '/');
        !           148:        if (p == NULL) {
        !           149:                p = netmask + strlen(netmask);
        !           150:        }
        !           151:        n = p - netmask;
        !           152:        if (n + 1 > sizeof mask)
        !           153:                return 0;
        !           154: 
        !           155:        memcpy(mask, netmask, n);
        !           156:        mask[n] = '\0';
        !           157: 
        !           158:        if (p[0] == '/') {
        !           159:                bits = (int) strtol(p + 1, NULL, 10);
        !           160:                if (bits < 0 || bits > 32)
        !           161:                        return 0;
        !           162:        } else {
        !           163:                bits = 32;
        !           164:        }
        !           165: 
        !           166: #if 0
        !           167:        printf("input %s\n", addr);
        !           168:        printf("mask  %s / %d\n", mask, bits);
        !           169: #endif
        !           170: 
        !           171:        /* presentation to network order binary */
        !           172:        if (inet_pton(AF_INET, mask, &in4_mask) <= 0
        !           173:                || inet_pton(AF_INET, addr, &in4_addr) <= 0) {
        !           174:                return 0;
        !           175:        }
        !           176: 
        !           177:        /* check 32bits */
        !           178:        bmask = (0xffffffffU << (32 - bits)) & 0xffffffffU;
        !           179:        if ((ntohl(in4_mask.s_addr) & bmask) != (ntohl(in4_addr.s_addr) & bmask))
        !           180:                return 0;
        !           181: 
        !           182:        /* match */
        !           183:        return 1;
        !           184: }
        !           185: 
        !           186: int
        !           187: istgt_lu_allow_netmask(const char *netmask, const char *addr)
        !           188: {
        !           189:        if (netmask == NULL || addr == NULL)
        !           190:                return 0;
        !           191:        if (strcasecmp(netmask, "ALL") == 0)
        !           192:                return 1;
        !           193:        if (netmask[0] == '[') {
        !           194:                /* IPv6 */
        !           195:                if (istgt_lu_allow_ipv6(netmask, addr))
        !           196:                        return 1;
        !           197:        } else {
        !           198:                /* IPv4 */
        !           199:                if (istgt_lu_allow_ipv4(netmask, addr))
        !           200:                        return 1;
        !           201:        }
        !           202:        return 0;
        !           203: }
        !           204: 
        !           205: int
        !           206: istgt_lu_access(CONN_Ptr conn, ISTGT_LU_Ptr lu, const char *iqn, const char *addr)
        !           207: {
        !           208:        ISTGT_Ptr istgt;
        !           209:        INITIATOR_GROUP *igp;
        !           210:        int pg_tag;
        !           211:        int ig_tag;
        !           212:        int rc;
        !           213:        int i, j, k;
        !           214: 
        !           215:        if (conn == NULL || lu == NULL || iqn == NULL || addr == NULL)
        !           216:                return 0;
        !           217:        istgt = conn->istgt;
        !           218:        pg_tag = conn->portal.tag;
        !           219: 
        !           220:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "pg=%d, iqn=%s, addr=%s\n",
        !           221:                                  pg_tag, iqn, addr);
        !           222:        for (i = 0; i < lu->maxmap; i++) {
        !           223:                /* skip excluding self portal group tag */
        !           224:                if (pg_tag != lu->map[i].pg_tag)
        !           225:                        continue;
        !           226:                /* iqn is initiator group? */
        !           227:                ig_tag = lu->map[i].ig_tag;
        !           228:                igp = istgt_lu_find_initiatorgroup(istgt, ig_tag);
        !           229:                if (igp == NULL) {
        !           230:                        ISTGT_ERRLOG("LU%d: ig_tag not found\n", lu->num);
        !           231:                        continue;
        !           232:                }
        !           233:                for (j = 0; j < igp->ninitiators; j++) {
        !           234:                        /* deny initiators */
        !           235:                        if (igp->initiators[j][0] == '!'
        !           236:                            && (strcasecmp(&igp->initiators[j][1], "ALL") == 0
        !           237:                                || strcasecmp(&igp->initiators[j][1], iqn) == 0)) {
        !           238:                                /* NG */
        !           239:                                ISTGT_WARNLOG("access denied from %s (%s) to %s (%s:%s,%d)\n",
        !           240:                                    iqn, addr, conn->target_name, conn->portal.host,
        !           241:                                    conn->portal.port, conn->portal.tag);
        !           242:                                return 0;
        !           243:                        }
        !           244:                        /* allow initiators */
        !           245:                        if (strcasecmp(igp->initiators[j], "ALL") == 0
        !           246:                            || strcasecmp(igp->initiators[j], iqn) == 0) {
        !           247:                                /* OK iqn, check netmask */
        !           248:                                if (igp->nnetmasks == 0) {
        !           249:                                        /* OK, empty netmask as ALL */
        !           250:                                        return 1;
        !           251:                                }
        !           252:                                for (k = 0; k < igp->nnetmasks; k++) {
        !           253:                                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !           254:                                            "netmask=%s, addr=%s\n",
        !           255:                                            igp->netmasks[k], addr);
        !           256:                                        rc = istgt_lu_allow_netmask(igp->netmasks[k], addr);
        !           257:                                        if (rc > 0) {
        !           258:                                                /* OK netmask */
        !           259:                                                return 1;
        !           260:                                        }
        !           261:                                }
        !           262:                                /* NG netmask in this group */
        !           263:                        }
        !           264:                }
        !           265:        }
        !           266: 
        !           267:        /* NG */
        !           268:        ISTGT_WARNLOG("access denied from %s (%s) to %s (%s:%s,%d)\n",
        !           269:            iqn, addr, conn->target_name, conn->portal.host,
        !           270:            conn->portal.port, conn->portal.tag);
        !           271:        return 0;
        !           272: }
        !           273: 
        !           274: int
        !           275: istgt_lu_visible(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu, const char *iqn, int pg_tag)
        !           276: {
        !           277:        INITIATOR_GROUP *igp;
        !           278:        int match_pg_tag;
        !           279:        int ig_tag;
        !           280:        int i, j;
        !           281: 
        !           282:        if (istgt == NULL || lu == NULL || iqn == NULL)
        !           283:                return 0;
        !           284:        /* pg_tag exist map? */
        !           285:        match_pg_tag = 0;
        !           286:        for (i = 0; i < lu->maxmap; i++) {
        !           287:                if (lu->map[i].pg_tag == pg_tag) {
        !           288:                        match_pg_tag = 1;
        !           289:                        break;
        !           290:                }
        !           291:        }
        !           292:        if (match_pg_tag == 0) {
        !           293:                /* cat't access from pg_tag */
        !           294:                return 0;
        !           295:        }
        !           296:        for (i = 0; i < lu->maxmap; i++) {
        !           297:                /* iqn is initiator group? */
        !           298:                ig_tag = lu->map[i].ig_tag;
        !           299:                igp = istgt_lu_find_initiatorgroup(istgt, ig_tag);
        !           300:                if (igp == NULL) {
        !           301:                        ISTGT_ERRLOG("LU%d: ig_tag not found\n", lu->num);
        !           302:                        continue;
        !           303:                }
        !           304:                for (j = 0; j < igp->ninitiators; j++) {
        !           305:                        if (igp->initiators[j][0] == '!'
        !           306:                            && (strcasecmp(&igp->initiators[j][1], "ALL") == 0
        !           307:                                || strcasecmp(&igp->initiators[j][1], iqn) == 0)) {
        !           308:                                /* NG */
        !           309:                                return 0;
        !           310:                        }
        !           311:                        if (strcasecmp(igp->initiators[j], "ALL") == 0
        !           312:                            || strcasecmp(igp->initiators[j], iqn) == 0) {
        !           313:                                /* OK iqn, no check addr */
        !           314:                                return 1;
        !           315:                        }
        !           316:                }
        !           317:        }
        !           318: 
        !           319:        /* NG */
        !           320:        return 0;
        !           321: }
        !           322: 
        !           323: int
        !           324: istgt_lu_sendtargets(CONN_Ptr conn, const char *iiqn, const char *iaddr, const char *tiqn, uint8_t *data, int alloc_len, int data_len)
        !           325: {
        !           326:        char buf[MAX_TMPBUF];
        !           327:        ISTGT_Ptr istgt;
        !           328:        ISTGT_LU_Ptr lu;
        !           329:        char *host;
        !           330:        int total;
        !           331:        int len;
        !           332:        int rc;
        !           333:        int pg_tag;
        !           334:        int i, j, k;
        !           335: 
        !           336:        if (conn == NULL)
        !           337:                return 0;
        !           338:        istgt = conn->istgt;
        !           339: 
        !           340:        total = data_len;
        !           341:        if (alloc_len < 1) {
        !           342:                return 0;
        !           343:        }
        !           344:        if (total > alloc_len) {
        !           345:                total = alloc_len;
        !           346:                data[total - 1] = '\0';
        !           347:                return total;
        !           348:        }
        !           349: 
        !           350:        if (alloc_len - total < 1) {
        !           351:                ISTGT_ERRLOG("data space small %d\n", alloc_len);
        !           352:                return total;
        !           353:        }
        !           354: 
        !           355:        MTX_LOCK(&istgt->mutex);
        !           356:        for (i = 0; i < MAX_LOGICAL_UNIT; i++) {
        !           357:                lu = istgt->logical_unit[i];
        !           358:                if (lu == NULL)
        !           359:                        continue;
        !           360:                if (strcasecmp(tiqn, "ALL") != 0
        !           361:                        && strcasecmp(tiqn, lu->name) != 0) {
        !           362:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !           363:                            "SKIP iqn=%s for %s from %s (%s)\n",
        !           364:                            tiqn, lu->name, iiqn, iaddr);
        !           365:                        continue;
        !           366:                }
        !           367:                rc = istgt_lu_visible(istgt, lu, iiqn, conn->portal.tag);
        !           368:                if (rc == 0) {
        !           369:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !           370:                            "SKIP iqn=%s for %s from %s (%s)\n",
        !           371:                            tiqn, lu->name, iiqn, iaddr);
        !           372:                        continue;
        !           373:                }
        !           374: 
        !           375:                /* DO SENDTARGETS */
        !           376:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !           377:                    "OK iqn=%s for %s from %s (%s)\n",
        !           378:                    tiqn, lu->name, iiqn, iaddr);
        !           379: 
        !           380:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !           381:                    "TargetName=%s\n", lu->name);
        !           382:                len = snprintf((char *) data + total, alloc_len - total,
        !           383:                    "TargetName=%s", lu->name);
        !           384:                total += len + 1;
        !           385: 
        !           386:                for (j = 0; j < lu->maxmap; j++) {
        !           387:                        pg_tag = lu->map[j].pg_tag;
        !           388:                        /* skip same pg_tag */
        !           389:                        for (k = 0; k < j; k++) {
        !           390:                                if (lu->map[k].pg_tag == pg_tag) {
        !           391:                                        goto skip_pg_tag;
        !           392:                                }
        !           393:                        }
        !           394:                        /* write to data */
        !           395:                        for (k = 0; k < istgt->nportal; k++) {
        !           396:                                if (istgt->portal[k].tag == pg_tag) {
        !           397:                                        if (alloc_len - total < 1) {
        !           398:                                                MTX_UNLOCK(&istgt->mutex);
        !           399:                                                ISTGT_ERRLOG("data space small %d\n", alloc_len);
        !           400:                                                return total;
        !           401:                                        }
        !           402:                                        host = istgt->portal[k].host;
        !           403:                                        /* wildcard? */
        !           404:                                        if (strcasecmp(host, "[::]") == 0
        !           405:                                            || strcasecmp(host, "[*]") == 0
        !           406:                                            || strcasecmp(host, "0.0.0.0") == 0
        !           407:                                            || strcasecmp(host, "*") == 0) {
        !           408:                                                if ((strcasecmp(host, "[::]") == 0
        !           409:                                                        || strcasecmp(host, "[*]") == 0)
        !           410:                                                    && conn->initiator_family == AF_INET6) {
        !           411:                                                        snprintf(buf, sizeof buf, "[%s]",
        !           412:                                                            conn->target_addr);
        !           413:                                                        host = buf;
        !           414:                                                } else if ((strcasecmp(host, "0.0.0.0") == 0
        !           415:                                                        || strcasecmp(host, "*") == 0)
        !           416:                                                    && conn->initiator_family == AF_INET) {
        !           417:                                                        snprintf(buf, sizeof buf, "%s",
        !           418:                                                            conn->target_addr);
        !           419:                                                        host = buf;
        !           420:                                                } else {
        !           421:                                                        /* skip portal for the family */
        !           422:                                                        continue;
        !           423:                                                }
        !           424:                                        }
        !           425:                                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !           426:                                            "TargetAddress=%s:%s,%d\n",
        !           427:                                            host,
        !           428:                                            istgt->portal[k].port,
        !           429:                                            istgt->portal[k].tag);
        !           430:                                        len = snprintf((char *) data + total,
        !           431:                                            alloc_len - total,
        !           432:                                            "TargetAddress=%s:%s,%d",
        !           433:                                            host,
        !           434:                                            istgt->portal[k].port,
        !           435:                                            istgt->portal[k].tag);
        !           436:                                        total += len + 1;
        !           437:                                }
        !           438:                        }
        !           439:                skip_pg_tag:
        !           440:                        ;
        !           441:                }
        !           442:        }
        !           443:        MTX_UNLOCK(&istgt->mutex);
        !           444: 
        !           445:        return total;
        !           446: }
        !           447: 
        !           448: ISTGT_LU_Ptr
        !           449: istgt_lu_find_target(ISTGT_Ptr istgt, const char *target_name)
        !           450: {
        !           451:        ISTGT_LU_Ptr lu;
        !           452:        int i;
        !           453: 
        !           454:        if (istgt == NULL || target_name == NULL)
        !           455:                return NULL;
        !           456:        for (i = 0; i < MAX_LOGICAL_UNIT; i++) {
        !           457:                lu = istgt->logical_unit[i];
        !           458:                if (lu == NULL)
        !           459:                        continue;
        !           460:                if (strcasecmp(target_name, lu->name) == 0) {
        !           461:                        return lu;
        !           462:                }
        !           463:        }
        !           464:        ISTGT_WARNLOG("can't find target %s\n",
        !           465:            target_name);
        !           466:        return NULL;
        !           467: }
        !           468: 
        !           469: uint16_t
        !           470: istgt_lu_allocate_tsih(ISTGT_LU_Ptr lu, const char *initiator_port, int tag)
        !           471: {
        !           472:        uint16_t tsih;
        !           473:        int retry = 10;
        !           474:        int i;
        !           475: 
        !           476:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_allocate_tsih\n");
        !           477:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "initiator_port=%s, tag=%d\n",
        !           478:            initiator_port, tag);
        !           479:        if (lu == NULL || initiator_port == NULL || tag == 0)
        !           480:                return 0;
        !           481:        /* tsih 0 is reserved */
        !           482:        tsih = 0;
        !           483:        MTX_LOCK(&lu->mutex);
        !           484: #if 0
        !           485:        for (i = 1; i < MAX_LU_TSIH; i++) {
        !           486:                if (lu->tsih[i].initiator_port == NULL)
        !           487:                        continue;
        !           488:                if (tag != lu->tsih[i].tag)
        !           489:                        continue;
        !           490:                if (strcasecmp(initiator_port, lu->tsih[i].initiator_port) == 0) {
        !           491:                        tsih = lu->tsih[i].tsih;
        !           492:                        break;
        !           493:                }
        !           494:        }
        !           495: #endif
        !           496:        if (tsih == 0) {
        !           497:                if (lu->maxtsih >= MAX_LU_TSIH) {
        !           498:                        ISTGT_ERRLOG("LU%d: tsih is maximum\n", lu->num);
        !           499:                        MTX_UNLOCK(&lu->mutex);
        !           500:                        return 0;
        !           501:                }
        !           502:        retry:
        !           503:                lu->last_tsih++;
        !           504:                tsih = lu->last_tsih;
        !           505:                if (tsih == 0) {
        !           506:                        if (retry > 0) {
        !           507:                                retry--;
        !           508:                                goto retry;
        !           509:                        }
        !           510:                        ISTGT_ERRLOG("LU%d: retry error\n", lu->num);
        !           511:                        MTX_UNLOCK(&lu->mutex);
        !           512:                        return 0;
        !           513:                }
        !           514:                for (i = 1; i < MAX_LU_TSIH; i++) {
        !           515:                        if (lu->tsih[i].initiator_port != NULL
        !           516:                                && lu->tsih[i].tsih == tsih) {
        !           517:                                ISTGT_ERRLOG("tsih is found in list\n");
        !           518:                                if (retry > 0) {
        !           519:                                        retry--;
        !           520:                                        goto retry;
        !           521:                                }
        !           522:                                ISTGT_ERRLOG("LU%d: retry error\n", lu->num);
        !           523:                                MTX_UNLOCK(&lu->mutex);
        !           524:                                return 0;
        !           525:                        }
        !           526:                }
        !           527:                for (i = 1; i < MAX_LU_TSIH; i++) {
        !           528:                        if (lu->tsih[i].initiator_port == NULL) {
        !           529:                                lu->tsih[i].tag = tag;
        !           530:                                lu->tsih[i].tsih = tsih;
        !           531:                                lu->tsih[i].initiator_port = xstrdup(initiator_port);
        !           532:                                lu->maxtsih++;
        !           533:                                break;
        !           534:                        }
        !           535:                }
        !           536:        }
        !           537:        MTX_UNLOCK(&lu->mutex);
        !           538:        return tsih;
        !           539: }
        !           540: 
        !           541: void
        !           542: istgt_lu_free_tsih(ISTGT_LU_Ptr lu, uint16_t tsih, char *initiator_port)
        !           543: {
        !           544:        int i;
        !           545: 
        !           546:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_free_tsih\n");
        !           547:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "tsih=%u, initiator_port=%s\n",
        !           548:            tsih, initiator_port);
        !           549:        if (lu == NULL || initiator_port == NULL)
        !           550:                return;
        !           551:        if (tsih == 0)
        !           552:                return;
        !           553: 
        !           554:        MTX_LOCK(&lu->mutex);
        !           555:        for (i = 1; i < MAX_LU_TSIH; i++) {
        !           556:                if (lu->tsih[i].initiator_port == NULL)
        !           557:                        continue;
        !           558:                if (lu->tsih[i].tsih != tsih)
        !           559:                        continue;
        !           560: 
        !           561:                if (strcasecmp(initiator_port, lu->tsih[i].initiator_port) == 0) {
        !           562:                        lu->tsih[i].tag = 0;
        !           563:                        lu->tsih[i].tsih = 0;
        !           564:                        xfree(lu->tsih[i].initiator_port);
        !           565:                        lu->tsih[i].initiator_port = NULL;
        !           566:                        lu->maxtsih--;
        !           567:                        break;
        !           568:                }
        !           569:        }
        !           570:        MTX_UNLOCK(&lu->mutex);
        !           571:        return;
        !           572: }
        !           573: 
        !           574: char *
        !           575: istgt_lu_get_media_flags_string(int flags, char *buf, size_t len)
        !           576: {
        !           577:        char *p;
        !           578:        size_t rest;
        !           579: 
        !           580:        p = buf;
        !           581:        rest = len;
        !           582:        if (flags & ISTGT_LU_FLAG_MEDIA_READONLY) {
        !           583:                snprintf(p, rest, "%s", "ro");
        !           584:        } else {
        !           585:                snprintf(p, rest, "%s", "rw");
        !           586:        }
        !           587:        p = buf + strlen(buf);
        !           588:        rest = len - strlen(buf);
        !           589:        if (flags & ISTGT_LU_FLAG_MEDIA_EXTEND) {
        !           590:                snprintf(p, rest, ",%s", "extend");
        !           591:        }
        !           592:        p = buf + strlen(buf);
        !           593:        rest = len - strlen(buf);
        !           594:        if (flags & ISTGT_LU_FLAG_MEDIA_DYNAMIC) {
        !           595:                snprintf(p, rest, ",%s", "dynamic");
        !           596:        }
        !           597:        return buf;
        !           598: }
        !           599: 
        !           600: uint64_t
        !           601: istgt_lu_get_devsize(const char *file)
        !           602: {
        !           603:        uint64_t val;
        !           604:        struct stat st;
        !           605:        int fd;
        !           606:        int rc;
        !           607: 
        !           608:        val = 0ULL;
        !           609:        rc = lstat(file, &st);
        !           610:        if (rc != 0)
        !           611:                return val;
        !           612:        if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode))
        !           613:                return val;
        !           614: 
        !           615:        fd = open(file, O_RDONLY, 0);
        !           616:        if (fd >= 0) {
        !           617: #ifdef DIOCGMEDIASIZE
        !           618:                if (val == 0) {
        !           619:                        off_t offset;
        !           620:                        rc = ioctl(fd, DIOCGMEDIASIZE, &offset);
        !           621:                        if (rc != -1) {
        !           622:                                val = (uint64_t) offset;
        !           623:                        }
        !           624:                }
        !           625: #endif /* DIOCGMEDIASIZE */
        !           626: #ifdef DIOCGDINFO
        !           627:                if (val == 0) {
        !           628:                        struct disklabel dl;
        !           629:                        rc = ioctl(fd, DIOCGDINFO, &dl);
        !           630:                        if (rc != -1) {
        !           631:                                val = (uint64_t) dl.d_secperunit;
        !           632:                                val *= (uint64_t) dl.d_secsize;
        !           633:                        }
        !           634:                }
        !           635: #endif /* DIOCGDINFO */
        !           636: #if defined(DKIOCGETBLOCKSIZE) && defined(DKIOCGETBLOCKCOUNT)
        !           637:                if (val == 0) {
        !           638:                        uint32_t blocklen;
        !           639:                        uint64_t blockcnt;
        !           640:                        rc = ioctl(fd, DKIOCGETBLOCKSIZE, &blocklen);
        !           641:                        if (rc != -1) {
        !           642:                                rc = ioctl(fd, DKIOCGETBLOCKCOUNT, &blockcnt);
        !           643:                                if (rc != -1) {
        !           644:                                        val = (uint64_t) blocklen;
        !           645:                                        val *= (uint64_t) blockcnt;
        !           646:                                }
        !           647:                        }
        !           648:                }
        !           649: #endif /* DKIOCGETBLOCKSIZE && DKIOCGETBLOCKCOUNT */
        !           650: #ifdef __linux__
        !           651: #ifdef BLKGETSIZE64
        !           652:                if (val == 0) {
        !           653:                        uint64_t blocksize;
        !           654:                        rc = ioctl(fd, BLKGETSIZE64, &blocksize);
        !           655:                        if (rc != -1) {
        !           656:                                val = (uint64_t) blocksize;
        !           657:                        }
        !           658:                }
        !           659: #endif /* BLKGETSIZE64 */
        !           660: #ifdef BLKGETSIZE
        !           661:                if (val == 0) {
        !           662:                        uint32_t blocksize;
        !           663:                        rc = ioctl(fd, BLKGETSIZE, &blocksize);
        !           664:                        if (rc != -1) {
        !           665:                                val = (uint64_t) 512;
        !           666:                                val *= (uint64_t) blocksize;
        !           667:                        }
        !           668:                }
        !           669: #endif /* BLKGETSIZE */
        !           670: #endif /* __linux__ */
        !           671:                if (val == 0) {
        !           672:                        ISTGT_ERRLOG("unknown device size\n");
        !           673:                }
        !           674:                (void) close(fd);
        !           675:        } else {
        !           676:                if (g_trace_flag) {
        !           677:                        ISTGT_WARNLOG("open error %s (errno=%d)\n", file, errno);
        !           678:                }
        !           679:                val = 0ULL;
        !           680:        }
        !           681:        return val;
        !           682: }
        !           683: 
        !           684: uint64_t
        !           685: istgt_lu_get_filesize(const char *file)
        !           686: {
        !           687:        uint64_t val;
        !           688:        struct stat st;
        !           689:        int rc;
        !           690: 
        !           691:        val = 0ULL;
        !           692:        rc = lstat(file, &st);
        !           693:        if (rc < 0)
        !           694:                return val;
        !           695:        if (S_ISLNK(st.st_mode))
        !           696:                return val;
        !           697: 
        !           698:        if (S_ISCHR(st.st_mode)) {
        !           699:                val = istgt_lu_get_devsize(file);
        !           700:        } else if (S_ISBLK(st.st_mode)) {
        !           701:                val = istgt_lu_get_devsize(file);
        !           702:        } else if (S_ISREG(st.st_mode)) {
        !           703:                val = st.st_size;
        !           704:        } else {
        !           705:                ISTGT_ERRLOG("lstat is neither REG, CHR nor BLK\n");
        !           706:                val = 0ULL;
        !           707:        }
        !           708:        return val;
        !           709: }
        !           710: 
        !           711: uint64_t
        !           712: istgt_lu_parse_size(const char *size)
        !           713: {
        !           714:        uint64_t val, val1, val2;
        !           715:        char *endp, *p;
        !           716:        size_t idx;
        !           717:        int sign;
        !           718: 
        !           719:        val1 = (uint64_t) strtoull(size, &endp, 10);
        !           720:        val = val1;
        !           721:        val2 = 0;
        !           722:        if (endp != NULL) {
        !           723:                p = endp;
        !           724:                switch (toupper((int) *p)) {
        !           725:                case 'Z': val1 *= (uint64_t) 1024ULL;
        !           726:                case 'E': val1 *= (uint64_t) 1024ULL;
        !           727:                case 'P': val1 *= (uint64_t) 1024ULL;
        !           728:                case 'T': val1 *= (uint64_t) 1024ULL;
        !           729:                case 'G': val1 *= (uint64_t) 1024ULL;
        !           730:                case 'M': val1 *= (uint64_t) 1024ULL;
        !           731:                case 'K': val1 *= (uint64_t) 1024ULL;
        !           732:                        break;
        !           733:                }
        !           734:                val = val1;
        !           735:                p++;
        !           736:                idx = strspn(p, "Bb \t");
        !           737:                p += idx;
        !           738:                if (*p == '-' || *p == '+') {
        !           739:                        sign = (int) *p++;
        !           740:                        idx = strspn(p, " \t");
        !           741:                        p += idx;
        !           742:                        val2 = (uint64_t) strtoull(p, &endp, 10);
        !           743:                        if (endp != NULL) {
        !           744:                                p = endp;
        !           745:                                switch (toupper((int) *p)) {
        !           746:                                case 'Z': val2 *= (uint64_t) 1024ULL;
        !           747:                                case 'E': val2 *= (uint64_t) 1024ULL;
        !           748:                                case 'P': val2 *= (uint64_t) 1024ULL;
        !           749:                                case 'T': val2 *= (uint64_t) 1024ULL;
        !           750:                                case 'G': val2 *= (uint64_t) 1024ULL;
        !           751:                                case 'M': val2 *= (uint64_t) 1024ULL;
        !           752:                                case 'K': val2 *= (uint64_t) 1024ULL;
        !           753:                                        break;
        !           754:                                }
        !           755:                        }
        !           756:                        if (sign == '-') {
        !           757:                                if (val2 > val1) {
        !           758:                                        /* underflow */
        !           759:                                        val = (uint64_t) 0ULL;
        !           760:                                } else {
        !           761:                                        val = val1 - val2;
        !           762:                                }
        !           763:                        } else {
        !           764:                                if (val2 > (UINT64_MAX - val1)) {
        !           765:                                        /* overflow */
        !           766:                                        val = UINT64_MAX;
        !           767:                                } else {
        !           768:                                        val = val1 + val2;
        !           769:                                }
        !           770:                        }
        !           771:                }
        !           772:        }
        !           773:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !           774:            "size=%s, val=%"PRIu64", val1=%"PRIu64", val2=%"PRIu64"\n",
        !           775:            size, val, val1, val2);
        !           776:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !           777:            "size=%s, val=%"PRIx64", val1=%"PRIx64", val2=%"PRIx64"\n",
        !           778:            size, val, val1, val2);
        !           779: 
        !           780:        return val;
        !           781: }
        !           782: 
        !           783: int
        !           784: istgt_lu_parse_media_flags(const char *flags)
        !           785: {
        !           786:        char buf[MAX_TMPBUF];
        !           787:        const char *delim = ",";
        !           788:        char *next_p;
        !           789:        char *p;
        !           790:        int mflags;
        !           791: 
        !           792:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "mflags=%s\n", flags);
        !           793:        mflags = 0;
        !           794:        strlcpy(buf, flags, MAX_TMPBUF);
        !           795:        next_p = buf;
        !           796:        while ((p = strsep(&next_p, delim)) != NULL) {
        !           797:                if (strcasecmp(p, "ro") == 0) {
        !           798:                        mflags |= ISTGT_LU_FLAG_MEDIA_READONLY;
        !           799:                } else if (strcasecmp(p, "rw") == 0) {
        !           800:                        mflags &= ~ISTGT_LU_FLAG_MEDIA_READONLY;
        !           801:                } else if (strcasecmp(p, "extend") == 0) {
        !           802:                        mflags |= ISTGT_LU_FLAG_MEDIA_EXTEND;
        !           803:                } else if (strcasecmp(p, "dynamic") == 0) {
        !           804:                        mflags |= ISTGT_LU_FLAG_MEDIA_DYNAMIC;
        !           805:                } else {
        !           806:                        ISTGT_ERRLOG("unknown media flag %.64s\n", p);
        !           807:                }
        !           808:        }
        !           809: 
        !           810:        return mflags;
        !           811: }
        !           812: 
        !           813: uint64_t
        !           814: istgt_lu_parse_media_size(const char *file, const char *size, int *flags)
        !           815: {
        !           816:        uint64_t msize, fsize;
        !           817: 
        !           818:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "msize=%s\n", size);
        !           819:        if (strcasecmp(file, "/dev/null") == 0) {
        !           820:                return 0;
        !           821:        }
        !           822:        if (strcasecmp(size, "Auto") == 0
        !           823:            || strcasecmp(size, "Size") == 0) {
        !           824:                msize = istgt_lu_get_filesize(file);
        !           825:                if (msize == 0) {
        !           826:                        msize = ISTGT_LU_MEDIA_SIZE_MIN;
        !           827:                }
        !           828:                *flags |= ISTGT_LU_FLAG_MEDIA_AUTOSIZE;
        !           829:        } else {
        !           830:                msize = istgt_lu_parse_size(size);
        !           831:                if (*flags & ISTGT_LU_FLAG_MEDIA_EXTEND) {
        !           832:                        fsize = istgt_lu_get_filesize(file);
        !           833:                        if (fsize > msize) {
        !           834:                                msize = fsize;
        !           835:                        }
        !           836:                }
        !           837:        }
        !           838: 
        !           839:        if (*flags & ISTGT_LU_FLAG_MEDIA_DYNAMIC) {
        !           840:                if (msize < ISTGT_LU_MEDIA_SIZE_MIN) {
        !           841:                        msize = ISTGT_LU_MEDIA_SIZE_MIN;
        !           842:                }
        !           843:        } else {
        !           844:                if (msize < ISTGT_LU_MEDIA_SIZE_MIN) {
        !           845:                        ISTGT_ERRLOG("media size too small\n");
        !           846:                        return 0ULL;
        !           847:                }
        !           848:        }
        !           849: 
        !           850:        return msize;
        !           851: }
        !           852: 
        !           853: PORTAL *
        !           854: istgt_lu_find_portalgroup(ISTGT_Ptr istgt, int tag)
        !           855: {
        !           856:        PORTAL *pp;
        !           857:        int i;
        !           858: 
        !           859:        for (i = 0; i < istgt->nportal; i++) {
        !           860:                if (istgt->portal[i].tag == tag) {
        !           861:                        pp = &istgt->portal[i];
        !           862:                        return pp;
        !           863:                }
        !           864:        }
        !           865:        return NULL;
        !           866: }
        !           867: 
        !           868: INITIATOR_GROUP *
        !           869: istgt_lu_find_initiatorgroup(ISTGT_Ptr istgt, int tag)
        !           870: {
        !           871:        INITIATOR_GROUP *igp;
        !           872:        int i;
        !           873: 
        !           874:        for (i = 0; i < istgt->ninitiator_group; i++) {
        !           875:                if (istgt->initiator_group[i].tag == tag) {
        !           876:                        igp = &istgt->initiator_group[i];
        !           877:                        return igp;
        !           878:                }
        !           879:        }
        !           880:        return NULL;
        !           881: }
        !           882: 
        !           883: static int
        !           884: istgt_lu_check_iscsi_name(const char *name)
        !           885: {
        !           886:        const unsigned char *up = (const unsigned char *) name;
        !           887:        size_t n;
        !           888: 
        !           889:        /* valid iSCSI name? */
        !           890:        for (n = 0; up[n] != 0; n++) {
        !           891:                if (up[n] > 0x00U && up[n] <= 0x2cU)
        !           892:                        return -1;
        !           893:                if (up[n] == 0x2fU)
        !           894:                        return -1;
        !           895:                if (up[n] >= 0x3bU && up[n] <= 0x40U)
        !           896:                        return -1;
        !           897:                if (up[n] >= 0x5bU && up[n] <= 0x60U)
        !           898:                        return -1;
        !           899:                if (up[n] >= 0x7bU && up[n] <= 0x7fU)
        !           900:                        return -1;
        !           901:                if (isspace(up[n]))
        !           902:                        return -1;
        !           903:        }
        !           904:        /* valid format? */
        !           905:        if (strncasecmp(name, "iqn.", 4) == 0) {
        !           906:                /* iqn.YYYY-MM.reversed.domain.name */
        !           907:                if (!isdigit(up[4]) || !isdigit(up[5]) || !isdigit(up[6])
        !           908:                    || !isdigit(up[7]) || up[8] != '-' || !isdigit(up[9])
        !           909:                    || !isdigit(up[10]) || up[11] != '.') {
        !           910:                        ISTGT_ERRLOG("invalid iqn format. "
        !           911:                            "expect \"iqn.YYYY-MM.reversed.domain.name\"\n");
        !           912:                        return -1;
        !           913:                }
        !           914:        } else if (strncasecmp(name, "eui.", 4) == 0) {
        !           915:                /* EUI-64 -> 16bytes */
        !           916:                /* XXX */
        !           917:        } else if (strncasecmp(name, "naa.", 4) == 0) {
        !           918:                /* 64bit -> 16bytes, 128bit -> 32bytes */
        !           919:                /* XXX */
        !           920:        }
        !           921:        /* OK */
        !           922:        return 0;
        !           923: }
        !           924: 
        !           925: static uint64_t
        !           926: istgt_lu_get_nbserial(const char *nodebase)
        !           927: {
        !           928:        ISTGT_MD5CTX md5ctx;
        !           929:        uint8_t nbsmd5[ISTGT_MD5DIGEST_LEN];
        !           930:        char buf[MAX_TMPBUF];
        !           931:        uint64_t nbs;
        !           932:        int idx;
        !           933:        int i;
        !           934: 
        !           935:        snprintf(buf, sizeof buf, "%s", nodebase);
        !           936:        if (strcasecmp(buf, "iqn.2007-09.jp.ne.peach.istgt") == 0
        !           937:            || strcasecmp(buf, "iqn.2007-09.jp.ne.peach") == 0) {
        !           938:                /* always zero */
        !           939:                return 0;
        !           940:        }
        !           941: 
        !           942:        istgt_md5init(&md5ctx);
        !           943:        istgt_md5update(&md5ctx, buf, strlen(buf));
        !           944:        istgt_md5final(nbsmd5, &md5ctx);
        !           945: 
        !           946:        nbs = 0U;
        !           947:        idx = ISTGT_MD5DIGEST_LEN - 8;
        !           948:        if (idx < 0) {
        !           949:                ISTGT_WARNLOG("missing MD5 length\n");
        !           950:                idx = 0;
        !           951:        }
        !           952:        for (i = idx; i < ISTGT_MD5DIGEST_LEN; i++) {
        !           953:                nbs |= (uint64_t) nbsmd5[i];
        !           954:                nbs = nbs << 8;
        !           955:        }
        !           956:        return nbs;
        !           957: }
        !           958: 
        !           959: static int
        !           960: istgt_lu_set_local_settings(ISTGT_Ptr istgt, CF_SECTION *sp, ISTGT_LU_Ptr lu)
        !           961: {
        !           962:        const char *val;
        !           963: 
        !           964:        val = istgt_get_val(sp, "MaxOutstandingR2T");
        !           965:        if (val == NULL) {
        !           966:                lu->MaxOutstandingR2T = lu->istgt->MaxOutstandingR2T;
        !           967:        } else {
        !           968:                lu->MaxOutstandingR2T = (int)strtol(val, NULL, 10);
        !           969:                if (lu->MaxOutstandingR2T < 1) {
        !           970:                        lu->MaxOutstandingR2T = DEFAULT_MAXOUTSTANDINGR2T;
        !           971:                }
        !           972:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxOutstandingR2T %d\n",
        !           973:                    lu->MaxOutstandingR2T);
        !           974:        }
        !           975: 
        !           976:        val = istgt_get_val(sp, "DefaultTime2Wait");
        !           977:        if (val == NULL) {
        !           978:                lu->DefaultTime2Wait = lu->istgt->DefaultTime2Wait;
        !           979:        } else {
        !           980:                lu->DefaultTime2Wait = (int)strtol(val, NULL, 10);
        !           981:                if (lu->DefaultTime2Wait < 0) {
        !           982:                        lu->DefaultTime2Wait = DEFAULT_DEFAULTTIME2WAIT;
        !           983:                }
        !           984:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DefaultTime2Wait %d\n",
        !           985:                    lu->DefaultTime2Wait);
        !           986:        }
        !           987: 
        !           988:        val = istgt_get_val(sp, "DefaultTime2Retain");
        !           989:        if (val == NULL) {
        !           990:                lu->DefaultTime2Retain = lu->istgt->DefaultTime2Retain;
        !           991:        } else {
        !           992:                lu->DefaultTime2Retain = (int)strtol(val, NULL, 10);
        !           993:                if (lu->DefaultTime2Retain < 0) {
        !           994:                        lu->DefaultTime2Retain = DEFAULT_DEFAULTTIME2RETAIN;
        !           995:                }
        !           996:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DefaultTime2Retain %d\n",
        !           997:                    lu->DefaultTime2Retain);
        !           998:        }
        !           999: 
        !          1000:        /* check size limit - RFC3720(12.15, 12.16, 12.17) */
        !          1001:        if (lu->MaxOutstandingR2T > 65535) {
        !          1002:                ISTGT_ERRLOG("MaxOutstandingR2T(%d) > 65535\n",
        !          1003:                    lu->MaxOutstandingR2T);
        !          1004:                return -1;
        !          1005:        }
        !          1006:        if (lu->DefaultTime2Wait > 3600) {
        !          1007:                ISTGT_ERRLOG("DefaultTime2Wait(%d) > 3600\n",
        !          1008:                    lu->DefaultTime2Wait);
        !          1009:                return -1;
        !          1010:        }
        !          1011:        if (lu->DefaultTime2Retain > 3600) {
        !          1012:                ISTGT_ERRLOG("DefaultTime2Retain(%d) > 3600\n",
        !          1013:                    lu->DefaultTime2Retain);
        !          1014:                return -1;
        !          1015:        }
        !          1016: 
        !          1017:        val = istgt_get_val(sp, "FirstBurstLength");
        !          1018:        if (val == NULL) {
        !          1019:                lu->FirstBurstLength = lu->istgt->FirstBurstLength;
        !          1020:        } else {
        !          1021:                lu->FirstBurstLength = (int)strtol(val, NULL, 10);
        !          1022:                if (lu->FirstBurstLength < 0) {
        !          1023:                        lu->FirstBurstLength = DEFAULT_FIRSTBURSTLENGTH;
        !          1024:                }
        !          1025:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "FirstBurstLength %d\n",
        !          1026:                    lu->FirstBurstLength);
        !          1027:        }
        !          1028: 
        !          1029:        val = istgt_get_val(sp, "MaxBurstLength");
        !          1030:        if (val == NULL) {
        !          1031:                lu->MaxBurstLength = lu->istgt->MaxBurstLength;
        !          1032:        } else {
        !          1033:                lu->MaxBurstLength = (int)strtol(val, NULL, 10);
        !          1034:                if (lu->MaxBurstLength < 0) {
        !          1035:                        lu->MaxBurstLength = DEFAULT_MAXBURSTLENGTH;
        !          1036:                }
        !          1037:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "MaxBurstLength %d\n",
        !          1038:                    lu->MaxBurstLength);
        !          1039:        }
        !          1040: 
        !          1041:        val = istgt_get_val(sp, "MaxRecvDataSegmentLength");
        !          1042:        if (val == NULL) {
        !          1043:                lu->MaxRecvDataSegmentLength
        !          1044:                        = lu->istgt->MaxRecvDataSegmentLength;
        !          1045:        } else {
        !          1046:                lu->MaxRecvDataSegmentLength = (int)strtol(val, NULL, 10);
        !          1047:                if (lu->MaxRecvDataSegmentLength < 0) {
        !          1048:                        lu->MaxRecvDataSegmentLength
        !          1049:                                = DEFAULT_MAXRECVDATASEGMENTLENGTH;
        !          1050:                }
        !          1051:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !          1052:                    "MaxRecvDataSegmentLength %d\n",
        !          1053:                    lu->MaxRecvDataSegmentLength);
        !          1054:        }
        !          1055: 
        !          1056:        /* check size limit (up to 24bits - RFC3720(12.12)) */
        !          1057:        if (lu->MaxBurstLength < 512) {
        !          1058:                ISTGT_ERRLOG("MaxBurstLength(%d) < 512\n",
        !          1059:                    lu->MaxBurstLength);
        !          1060:                return -1;
        !          1061:        }
        !          1062:        if (lu->FirstBurstLength < 512) {
        !          1063:                ISTGT_ERRLOG("FirstBurstLength(%d) < 512\n",
        !          1064:                    lu->FirstBurstLength);
        !          1065:                return -1;
        !          1066:        }
        !          1067:        if (lu->FirstBurstLength > lu->MaxBurstLength) {
        !          1068:                ISTGT_ERRLOG("FirstBurstLength(%d) > MaxBurstLength(%d)\n",
        !          1069:                    lu->FirstBurstLength, istgt->MaxBurstLength);
        !          1070:                return -1;
        !          1071:        }
        !          1072:        if (lu->MaxBurstLength > 0x00ffffff) {
        !          1073:                ISTGT_ERRLOG("MaxBurstLength(%d) > 0x00ffffff\n",
        !          1074:                    lu->MaxBurstLength);
        !          1075:                return -1;
        !          1076:        }
        !          1077:        if (lu->MaxRecvDataSegmentLength < 512) {
        !          1078:                ISTGT_ERRLOG("MaxRecvDataSegmentLength(%d) < 512\n",
        !          1079:                    lu->MaxRecvDataSegmentLength);
        !          1080:                return -1;
        !          1081:        }
        !          1082:        if (lu->MaxRecvDataSegmentLength > 0x00ffffff) {
        !          1083:                ISTGT_ERRLOG("MaxRecvDataSegmentLength(%d) > 0x00ffffff\n",
        !          1084:                    lu->MaxRecvDataSegmentLength);
        !          1085:                return -1;
        !          1086:        }
        !          1087: 
        !          1088:        val = istgt_get_val(sp, "InitialR2T");
        !          1089:        if (val == NULL) {
        !          1090:                lu->InitialR2T = lu->istgt->InitialR2T;
        !          1091:        } else {
        !          1092:                if (strcasecmp(val, "Yes") == 0) {
        !          1093:                        lu->InitialR2T = 1;
        !          1094:                } else if (strcasecmp(val, "No") == 0) {
        !          1095: #if 0
        !          1096:                        lu->InitialR2T = 0;
        !          1097: #else
        !          1098:                        ISTGT_ERRLOG("not supported value %s\n", val);
        !          1099:                        return -1;
        !          1100: #endif
        !          1101:                } else {
        !          1102:                        ISTGT_ERRLOG("unknown value %s\n", val);
        !          1103:                        return -1;
        !          1104:                }
        !          1105:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "InitialR2T %s\n",
        !          1106:                    lu->InitialR2T ? "Yes" : "No");
        !          1107:        }
        !          1108: 
        !          1109:        val = istgt_get_val(sp, "ImmediateData");
        !          1110:        if (val == NULL) {
        !          1111:                lu->ImmediateData = lu->istgt->ImmediateData;
        !          1112:        } else {
        !          1113:                if (strcasecmp(val, "Yes") == 0) {
        !          1114:                        lu->ImmediateData = 1;
        !          1115:                } else if (strcasecmp(val, "No") == 0) {
        !          1116:                        lu->ImmediateData = 0;
        !          1117:                } else {
        !          1118:                        ISTGT_ERRLOG("unknown value %s\n", val);
        !          1119:                        return -1;
        !          1120:                }
        !          1121:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "ImmediateData %s\n",
        !          1122:                    lu->ImmediateData ? "Yes" : "No");
        !          1123:        }
        !          1124: 
        !          1125:        val = istgt_get_val(sp, "DataPDUInOrder");
        !          1126:        if (val == NULL) {
        !          1127:                lu->DataPDUInOrder = lu->istgt->DataPDUInOrder;
        !          1128:        } else {
        !          1129:                if (strcasecmp(val, "Yes") == 0) {
        !          1130:                        lu->DataPDUInOrder = 1;
        !          1131:                } else if (strcasecmp(val, "No") == 0) {
        !          1132: #if 0
        !          1133:                        lu->DataPDUInOrder = 0;
        !          1134: #else
        !          1135:                        ISTGT_ERRLOG("not supported value %s\n", val);
        !          1136:                        return -1;
        !          1137: #endif
        !          1138:                } else {
        !          1139:                        ISTGT_ERRLOG("unknown value %s\n", val);
        !          1140:                        return -1;
        !          1141:                }
        !          1142:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DataPDUInOrder %s\n",
        !          1143:                    lu->DataPDUInOrder ? "Yes" : "No");
        !          1144:        }
        !          1145: 
        !          1146:        val = istgt_get_val(sp, "DataSequenceInOrder");
        !          1147:        if (val == NULL) {
        !          1148:                lu->DataSequenceInOrder = lu->istgt->DataSequenceInOrder;
        !          1149:        } else {
        !          1150:                if (strcasecmp(val, "Yes") == 0) {
        !          1151:                        lu->DataSequenceInOrder = 1;
        !          1152:                } else if (strcasecmp(val, "No") == 0) {
        !          1153: #if 0
        !          1154:                        lu->DataSequenceInOrder = 0;
        !          1155: #else
        !          1156:                        ISTGT_ERRLOG("not supported value %s\n", val);
        !          1157:                        return -1;
        !          1158: #endif
        !          1159:                } else {
        !          1160:                        ISTGT_ERRLOG("unknown value %s\n", val);
        !          1161:                        return -1;
        !          1162:                }
        !          1163:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "DataSequenceInOrder %s\n",
        !          1164:                    lu->DataSequenceInOrder ? "Yes" : "No");
        !          1165:        }
        !          1166: 
        !          1167:        val = istgt_get_val(sp, "ErrorRecoveryLevel");
        !          1168:        if (val == NULL) {
        !          1169:                lu->ErrorRecoveryLevel = lu->istgt->ErrorRecoveryLevel;
        !          1170:        } else {
        !          1171:                lu->ErrorRecoveryLevel = (int)strtol(val, NULL, 10);
        !          1172:                if (lu->ErrorRecoveryLevel < 0) {
        !          1173:                        lu->ErrorRecoveryLevel = DEFAULT_ERRORRECOVERYLEVEL;
        !          1174:                } else if (lu->ErrorRecoveryLevel == 0) {
        !          1175:                        lu->ErrorRecoveryLevel = 0;
        !          1176:                } else if (lu->ErrorRecoveryLevel == 1) {
        !          1177: #if 0
        !          1178:                        lu->ErrorRecoveryLevel = 1;
        !          1179: #else
        !          1180:                        ISTGT_ERRLOG("not supported value %d\n",
        !          1181:                            lu->ErrorRecoveryLevel);
        !          1182:                        return -1;
        !          1183: #endif
        !          1184:                } else if (lu->ErrorRecoveryLevel == 2) {
        !          1185: #if 0
        !          1186:                        lu->ErrorRecoveryLevel = 2;
        !          1187: #else
        !          1188:                        ISTGT_ERRLOG("not supported value %d\n",
        !          1189:                            lu->ErrorRecoveryLevel);
        !          1190:                        return -1;
        !          1191: #endif
        !          1192:                } else {
        !          1193:                        ISTGT_ERRLOG("not supported value %d\n",
        !          1194:                            lu->ErrorRecoveryLevel);
        !          1195:                        return -1;
        !          1196:                }
        !          1197:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "ErrorRecoveryLevel %d\n",
        !          1198:                    istgt->ErrorRecoveryLevel);
        !          1199:        }
        !          1200: 
        !          1201:        return 0;
        !          1202: }
        !          1203: 
        !          1204: static int
        !          1205: istgt_lu_add_unit(ISTGT_Ptr istgt, CF_SECTION *sp)
        !          1206: {
        !          1207:        char buf[MAX_TMPBUF], buf2[MAX_TMPBUF];
        !          1208:        ISTGT_LU_Ptr lu;
        !          1209:        const char *vendor, *product, *revision, *serial;
        !          1210:        const char *pg_tag, *ig_tag;
        !          1211:        const char *ag_tag;
        !          1212:        const char *flags, *file, *size;
        !          1213:        const char *key, *val;
        !          1214:        uint64_t msize;
        !          1215:        uint64_t nbs64;
        !          1216:        int pg_tag_i, ig_tag_i;
        !          1217:        int ag_tag_i;
        !          1218:        int rpm, formfactor;
        !          1219:        int mflags;
        !          1220:        int slot;
        !          1221:        int nbs;
        !          1222:        int i, j, k;
        !          1223:        int rc;
        !          1224: 
        !          1225:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "add unit %d\n", sp->num);
        !          1226: 
        !          1227:        if (sp->num >= MAX_LOGICAL_UNIT) {
        !          1228:                ISTGT_ERRLOG("LU%d: over maximum unit number\n", sp->num);
        !          1229:                return -1;
        !          1230:        }
        !          1231:        if (istgt->logical_unit[sp->num] != NULL) {
        !          1232:                ISTGT_ERRLOG("LU%d: duplicate unit\n", sp->num);
        !          1233:                return -1;
        !          1234:        }
        !          1235: 
        !          1236:        lu = xmalloc(sizeof *lu);
        !          1237:        memset(lu, 0, sizeof *lu);
        !          1238:        lu->num = sp->num;
        !          1239:        lu->istgt = istgt;
        !          1240:        istgt_lu_set_state(lu, ISTGT_STATE_INVALID);
        !          1241:        nbs64 = istgt_lu_get_nbserial(istgt->nodebase);
        !          1242: #if 0
        !          1243:        /* disabled now */
        !          1244:        nbs = (int) (nbs64 % 900) * 100000;
        !          1245: #else
        !          1246:        nbs = 0;
        !          1247: #endif
        !          1248: 
        !          1249:        val = istgt_get_val(sp, "Comment");
        !          1250:        if (val != NULL) {
        !          1251:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Comment %s\n", val);
        !          1252:        }
        !          1253: 
        !          1254:        val = istgt_get_val(sp, "TargetName");
        !          1255:        if (val == NULL) {
        !          1256:                ISTGT_ERRLOG("LU%d: TargetName not found\n", lu->num);
        !          1257:                goto error_return;
        !          1258:        }
        !          1259:        if (strncasecmp(val, "iqn.", 4) != 0
        !          1260:                && strncasecmp(val, "eui.", 4) != 0
        !          1261:                && strncasecmp(val, "naa.", 4) != 0) {
        !          1262:                snprintf(buf, sizeof buf, "%s:%s", istgt->nodebase, val);
        !          1263:        } else {
        !          1264:                snprintf(buf, sizeof buf, "%s", val);
        !          1265:        }
        !          1266:        if (istgt_lu_check_iscsi_name(buf) != 0) {
        !          1267:                ISTGT_ERRLOG("TargetName %s contains an invalid character or format.\n",
        !          1268:                    buf);
        !          1269: #if 0
        !          1270:                goto error_return;
        !          1271: #endif
        !          1272:        }
        !          1273:        lu->name = xstrdup(buf);
        !          1274:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "TargetName %s\n",
        !          1275:                                   lu->name);
        !          1276: 
        !          1277:        val = istgt_get_val(sp, "TargetAlias");
        !          1278:        if (val == NULL) {
        !          1279:                lu->alias = NULL;
        !          1280:        } else {
        !          1281:                lu->alias = xstrdup(val);
        !          1282:        }
        !          1283:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "TargetAlias %s\n",
        !          1284:            lu->alias);
        !          1285: 
        !          1286:        val = istgt_get_val(sp, "Mapping");
        !          1287:        if (val == NULL) {
        !          1288:                /* no map */
        !          1289:                lu->maxmap = 0;
        !          1290:        } else {
        !          1291:                lu->maxmap = 0;
        !          1292:                for (i = 0; ; i++) {
        !          1293:                        val = istgt_get_nmval(sp, "Mapping", i, 0);
        !          1294:                        if (val == NULL)
        !          1295:                                break;
        !          1296:                        if (lu->maxmap >= MAX_LU_MAP) {
        !          1297:                                ISTGT_ERRLOG("LU%d: too many mapping\n", lu->num);
        !          1298:                                goto error_return;
        !          1299:                        }
        !          1300:                        pg_tag = istgt_get_nmval(sp, "Mapping", i, 0);
        !          1301:                        ig_tag = istgt_get_nmval(sp, "Mapping", i, 1);
        !          1302:                        if (pg_tag == NULL || ig_tag == NULL) {
        !          1303:                                ISTGT_ERRLOG("LU%d: mapping error\n", lu->num);
        !          1304:                                goto error_return;
        !          1305:                        }
        !          1306:                        if (strncasecmp(pg_tag, "PortalGroup",
        !          1307:                                strlen("PortalGroup")) != 0
        !          1308:                            || sscanf(pg_tag, "%*[^0-9]%d", &pg_tag_i) != 1) {
        !          1309:                                ISTGT_ERRLOG("LU%d: mapping portal error\n", lu->num);
        !          1310:                                goto error_return;
        !          1311:                        }
        !          1312:                        if (strncasecmp(ig_tag, "InitiatorGroup",
        !          1313:                                strlen("InitiatorGroup")) != 0
        !          1314:                            || sscanf(ig_tag, "%*[^0-9]%d", &ig_tag_i) != 1) {
        !          1315:                                ISTGT_ERRLOG("LU%d: mapping initiator error\n", lu->num);
        !          1316:                                goto error_return;
        !          1317:                        }
        !          1318:                        if (pg_tag_i < 1 || ig_tag_i < 1) {
        !          1319:                                ISTGT_ERRLOG("LU%d: invalid group tag\n", lu->num);
        !          1320:                                goto error_return;
        !          1321:                        }
        !          1322:                        if (istgt_lu_find_portalgroup(istgt, pg_tag_i) == NULL) {
        !          1323:                                ISTGT_ERRLOG("LU%d: PortalGroup%d not found\n",
        !          1324:                                                         lu->num, pg_tag_i);
        !          1325:                                goto error_return;
        !          1326:                        }
        !          1327:                        if (istgt_lu_find_initiatorgroup(istgt, ig_tag_i) == NULL) {
        !          1328:                                ISTGT_ERRLOG("LU%d: InitiatorGroup%d not found\n",
        !          1329:                                    lu->num, ig_tag_i);
        !          1330:                                goto error_return;
        !          1331:                        }
        !          1332:                        lu->map[i].pg_tag = pg_tag_i;
        !          1333:                        lu->map[i].pg_aas = AAS_ACTIVE_OPTIMIZED;
        !          1334:                        //lu->map[i].pg_aas = AAS_ACTIVE_NON_OPTIMIZED;
        !          1335:                        lu->map[i].pg_aas |= AAS_STATUS_IMPLICIT;
        !          1336:                        lu->map[i].ig_tag = ig_tag_i;
        !          1337:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !          1338:                            "Mapping PortalGroup%d InitiatorGroup%d\n",
        !          1339:                            lu->map[i].pg_tag, lu->map[i].ig_tag);
        !          1340:                        lu->maxmap = i + 1;
        !          1341:                }
        !          1342:        }
        !          1343:        if (lu->maxmap == 0) {
        !          1344:                ISTGT_ERRLOG("LU%d: no Mapping\n", lu->num);
        !          1345:                goto error_return;
        !          1346:        }
        !          1347: 
        !          1348:        val = istgt_get_val(sp, "AuthMethod");
        !          1349:        if (val == NULL) {
        !          1350:                /* none */
        !          1351:                lu->no_auth_chap = 0;
        !          1352:                lu->auth_chap = 0;
        !          1353:                lu->auth_chap_mutual = 0;
        !          1354:        } else {
        !          1355:                lu->no_auth_chap = 0;
        !          1356:                for (i = 0; ; i++) {
        !          1357:                        val = istgt_get_nmval(sp, "AuthMethod", 0, i);
        !          1358:                        if (val == NULL)
        !          1359:                                break;
        !          1360:                        if (strcasecmp(val, "CHAP") == 0) {
        !          1361:                                lu->auth_chap = 1;
        !          1362:                        } else if (strcasecmp(val, "Mutual") == 0) {
        !          1363:                                lu->auth_chap_mutual = 1;
        !          1364:                        } else if (strcasecmp(val, "Auto") == 0) {
        !          1365:                                lu->auth_chap = 0;
        !          1366:                                lu->auth_chap_mutual = 0;
        !          1367:                        } else if (strcasecmp(val, "None") == 0) {
        !          1368:                                lu->no_auth_chap = 1;
        !          1369:                                lu->auth_chap = 0;
        !          1370:                                lu->auth_chap_mutual = 0;
        !          1371:                        } else {
        !          1372:                                ISTGT_ERRLOG("LU%d: unknown auth\n", lu->num);
        !          1373:                                goto error_return;
        !          1374:                        }
        !          1375:                }
        !          1376:                if (lu->auth_chap_mutual && !lu->auth_chap) {
        !          1377:                        ISTGT_ERRLOG("LU%d: Mutual but not CHAP\n", lu->num);
        !          1378:                        goto error_return;
        !          1379:                }
        !          1380:        }
        !          1381:        if (lu->no_auth_chap != 0) {
        !          1382:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthMethod None\n");
        !          1383:        } else if (lu->auth_chap == 0) {
        !          1384:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthMethod Auto\n");
        !          1385:        } else {
        !          1386:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthMethod %s %s\n",
        !          1387:                    lu->auth_chap ? "CHAP" : "",
        !          1388:                    lu->auth_chap_mutual ? "Mutual" : "");
        !          1389:        }
        !          1390: 
        !          1391:        val = istgt_get_val(sp, "AuthGroup");
        !          1392:        if (val == NULL) {
        !          1393:                lu->auth_group = 0;
        !          1394:        } else {
        !          1395:                ag_tag = val;
        !          1396:                if (strcasecmp(ag_tag, "None") == 0) {
        !          1397:                        ag_tag_i = 0;
        !          1398:                } else {
        !          1399:                        if (strncasecmp(ag_tag, "AuthGroup",
        !          1400:                                strlen("AuthGroup")) != 0
        !          1401:                            || sscanf(ag_tag, "%*[^0-9]%d", &ag_tag_i) != 1) {
        !          1402:                                ISTGT_ERRLOG("LU%d: auth group error\n", lu->num);
        !          1403:                                goto error_return;
        !          1404:                        }
        !          1405:                        if (ag_tag_i == 0) {
        !          1406:                                ISTGT_ERRLOG("LU%d: invalid auth group %d\n", ag_tag_i);
        !          1407:                                goto error_return;
        !          1408:                        }
        !          1409:                }
        !          1410:                lu->auth_group = ag_tag_i;
        !          1411:        }
        !          1412:        if (lu->auth_group == 0) {
        !          1413:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthGroup None\n");
        !          1414:        } else {
        !          1415:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthGroup AuthGroup%d\n",
        !          1416:                    lu->auth_group);
        !          1417:        }
        !          1418: 
        !          1419:        val = istgt_get_val(sp, "UseDigest");
        !          1420:        if (val != NULL) {
        !          1421:                for (i = 0; ; i++) {
        !          1422:                        val = istgt_get_nmval(sp, "UseDigest", 0, i);
        !          1423:                        if (val == NULL)
        !          1424:                                break;
        !          1425:                        if (strcasecmp(val, "Header") == 0) {
        !          1426:                                lu->header_digest = 1;
        !          1427:                        } else if (strcasecmp(val, "Data") == 0) {
        !          1428:                                lu->data_digest = 1;
        !          1429:                        } else if (strcasecmp(val, "Auto") == 0) {
        !          1430:                                lu->header_digest = 0;
        !          1431:                                lu->data_digest = 0;
        !          1432:                        } else {
        !          1433:                                ISTGT_ERRLOG("LU%d: unknown digest\n", lu->num);
        !          1434:                                goto error_return;
        !          1435:                        }
        !          1436:                }
        !          1437:        }
        !          1438:        if (lu->header_digest == 0 && lu->data_digest == 0) {
        !          1439:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "UseDigest Auto\n");
        !          1440:        } else {
        !          1441:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "UseDigest %s %s\n",
        !          1442:                    lu->header_digest ? "Header" : "",
        !          1443:                    lu->data_digest ? "Data" : "");
        !          1444:        }
        !          1445: 
        !          1446:        val = istgt_get_val(sp, "ReadOnly");
        !          1447:        if (val == NULL) {
        !          1448:                lu->readonly = 0;
        !          1449:        } else if (strcasecmp(val, "Yes") == 0) {
        !          1450:                lu->readonly = 1;
        !          1451:        }
        !          1452:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "ReadOnly %s\n",
        !          1453:            lu->readonly ? "Yes" : "No");
        !          1454: 
        !          1455:        val = istgt_get_val(sp, "UnitType");
        !          1456:        if (val == NULL) {
        !          1457:                ISTGT_ERRLOG("LU%d: unknown unit type\n", lu->num);
        !          1458:                goto error_return;
        !          1459:        }
        !          1460:        if (strcasecmp(val, "Pass") == 0) {
        !          1461:                lu->type = ISTGT_LU_TYPE_PASS;
        !          1462:        } else if (strcasecmp(val, "Disk") == 0) {
        !          1463:                lu->type = ISTGT_LU_TYPE_DISK;
        !          1464:        } else if (strcasecmp(val, "DVD") == 0) {
        !          1465:                lu->type = ISTGT_LU_TYPE_DVD;
        !          1466:        } else if (strcasecmp(val, "Tape") == 0) {
        !          1467:                lu->type = ISTGT_LU_TYPE_TAPE;
        !          1468:        } else {
        !          1469:                ISTGT_ERRLOG("LU%d: unknown unit type\n", lu->num);
        !          1470:                goto error_return;
        !          1471:        }
        !          1472:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "UnitType %d (%s)\n",
        !          1473:            lu->type, val);
        !          1474: 
        !          1475:        val = istgt_get_val(sp, "UnitOnline");
        !          1476:        if (val == NULL) {
        !          1477:                lu->online = 1;
        !          1478:        } else if (strcasecmp(val, "Yes") == 0) {
        !          1479:                lu->online = 1;
        !          1480:        }
        !          1481:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "UnitOnline %s\n",
        !          1482:            lu->online ? "Yes" : "No");
        !          1483: 
        !          1484:        vendor = istgt_get_nmval(sp, "UnitInquiry", 0, 0);
        !          1485:        product = istgt_get_nmval(sp, "UnitInquiry", 0, 1);
        !          1486:        revision = istgt_get_nmval(sp, "UnitInquiry", 0, 2);
        !          1487:        serial = istgt_get_nmval(sp, "UnitInquiry", 0, 3);
        !          1488:        switch (lu->type) {
        !          1489:        case ISTGT_LU_TYPE_DISK:
        !          1490:                if (vendor == NULL || strlen(vendor) == 0)
        !          1491:                        vendor = DEFAULT_LU_VENDOR_DISK;
        !          1492:                if (product == NULL || strlen(product) == 0)
        !          1493:                        product = DEFAULT_LU_PRODUCT_DISK;
        !          1494:                if (revision == NULL || strlen(revision) == 0)
        !          1495:                        revision = DEFAULT_LU_REVISION_DISK;
        !          1496:                if (serial == NULL || strlen(serial) == 0) {
        !          1497:                        snprintf(buf, sizeof buf, "%.8d", 10000000 + nbs + lu->num);
        !          1498:                        serial = (const char *) &buf[0];
        !          1499:                }
        !          1500:                break;
        !          1501:        case ISTGT_LU_TYPE_DVD:
        !          1502:                if (vendor == NULL || strlen(vendor) == 0)
        !          1503:                        vendor = DEFAULT_LU_VENDOR_DVD;
        !          1504:                if (product == NULL || strlen(product) == 0)
        !          1505:                        product = DEFAULT_LU_PRODUCT_DVD;
        !          1506:                if (revision == NULL || strlen(revision) == 0)
        !          1507:                        revision = DEFAULT_LU_REVISION_DVD;
        !          1508:                if (serial == NULL || strlen(serial) == 0) {
        !          1509:                        snprintf(buf, sizeof buf, "%.8d", 10000000 + nbs + lu->num);
        !          1510:                        serial = (const char *) &buf[0];
        !          1511:                }
        !          1512:                break;
        !          1513:        case ISTGT_LU_TYPE_TAPE:
        !          1514:                if (vendor == NULL || strlen(vendor) == 0)
        !          1515:                        vendor = DEFAULT_LU_VENDOR_TAPE;
        !          1516:                if (product == NULL || strlen(product) == 0)
        !          1517:                        product = DEFAULT_LU_PRODUCT_TAPE;
        !          1518:                if (revision == NULL || strlen(revision) == 0)
        !          1519:                        revision = DEFAULT_LU_REVISION_TAPE;
        !          1520:                if (serial == NULL || strlen(serial) == 0) {
        !          1521: #ifdef USE_LU_TAPE_DLT8000
        !          1522:                        snprintf(buf, sizeof buf, "CX%.8d", 10000000 + nbs + lu->num);
        !          1523: #else
        !          1524:                        snprintf(buf, sizeof buf, "%.8d", 10000000 + nbs + lu->num);
        !          1525: #endif /* USE_LU_TAPE_DLT8000 */
        !          1526:                        serial = (const char *) &buf[0];
        !          1527:                }
        !          1528:                break;
        !          1529:        default:
        !          1530:                if (vendor == NULL || strlen(vendor) == 0)
        !          1531:                        vendor = DEFAULT_LU_VENDOR;
        !          1532:                if (product == NULL || strlen(product) == 0)
        !          1533:                        product = DEFAULT_LU_PRODUCT;
        !          1534:                if (revision == NULL || strlen(revision) == 0)
        !          1535:                        revision = DEFAULT_LU_REVISION;
        !          1536:                if (serial == NULL || strlen(serial) == 0) {
        !          1537:                        snprintf(buf, sizeof buf, "%.8d", 10000000 + nbs + lu->num);
        !          1538:                        serial = (const char *) &buf[0];
        !          1539:                }
        !          1540:                break;
        !          1541:        }
        !          1542:        lu->inq_vendor = xstrdup(vendor);
        !          1543:        lu->inq_product = xstrdup(product);
        !          1544:        lu->inq_revision = xstrdup(revision);
        !          1545:        lu->inq_serial = xstrdup(serial);
        !          1546:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "UnitInquiry %s %s %s %s\n",
        !          1547:            lu->inq_vendor, lu->inq_product, lu->inq_revision,
        !          1548:            lu->inq_serial);
        !          1549: 
        !          1550:        val = istgt_get_val(sp, "BlockLength");
        !          1551:        if (val == NULL) {
        !          1552:                switch (lu->type) {
        !          1553:                case ISTGT_LU_TYPE_DISK:
        !          1554:                        lu->blocklen = DEFAULT_LU_BLOCKLEN_DISK;
        !          1555:                        break;
        !          1556:                case ISTGT_LU_TYPE_DVD:
        !          1557:                        lu->blocklen = DEFAULT_LU_BLOCKLEN_DVD;
        !          1558:                        break;
        !          1559:                case ISTGT_LU_TYPE_TAPE:
        !          1560:                        lu->blocklen = DEFAULT_LU_BLOCKLEN_TAPE;
        !          1561:                        break;
        !          1562:                default:
        !          1563:                        lu->blocklen = DEFAULT_LU_BLOCKLEN;
        !          1564:                        break;
        !          1565:                }
        !          1566:        } else {
        !          1567:                lu->blocklen = (int) strtol(val, NULL, 10);
        !          1568:        }
        !          1569:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "BlockLength %d\n",
        !          1570:            lu->blocklen);
        !          1571: 
        !          1572:        val = istgt_get_val(sp, "QueueDepth");
        !          1573:        if (val == NULL) {
        !          1574:                switch (lu->type) {
        !          1575:                case ISTGT_LU_TYPE_DISK:
        !          1576:                        lu->queue_depth = DEFAULT_LU_QUEUE_DEPTH;
        !          1577:                        //lu->queue_depth = 0;
        !          1578:                        break;
        !          1579:                case ISTGT_LU_TYPE_DVD:
        !          1580:                case ISTGT_LU_TYPE_TAPE:
        !          1581:                default:
        !          1582:                        lu->queue_depth = 0;
        !          1583:                        break;
        !          1584:                }
        !          1585:        } else {
        !          1586:                lu->queue_depth = (int) strtol(val, NULL, 10);
        !          1587:        }
        !          1588:        if (lu->queue_depth < 0 || lu->queue_depth >= MAX_LU_QUEUE_DEPTH) {
        !          1589:                ISTGT_ERRLOG("LU%d: queue depth range error\n");
        !          1590:                goto error_return;
        !          1591:        }
        !          1592:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "QueueDepth %d\n",
        !          1593:            lu->queue_depth);
        !          1594: 
        !          1595:        lu->maxlun = 0;
        !          1596:        for (i = 0; i < MAX_LU_LUN; i++) {
        !          1597:                lu->lun[i].type = ISTGT_LU_LUN_TYPE_NONE;
        !          1598:                lu->lun[i].rotationrate = DEFAULT_LU_ROTATIONRATE;
        !          1599:                lu->lun[i].formfactor = DEFAULT_LU_FORMFACTOR;
        !          1600:                lu->lun[i].readcache = 1;
        !          1601:                lu->lun[i].writecache = 1;
        !          1602:                lu->lun[i].serial = NULL;
        !          1603:                lu->lun[i].spec = NULL;
        !          1604:                snprintf(buf, sizeof buf, "LUN%d", i);
        !          1605:                val = istgt_get_val(sp, buf);
        !          1606:                if (val == NULL)
        !          1607:                        continue;
        !          1608:                if (i != 0) {
        !          1609:                        /* default LUN serial (except LUN0) */
        !          1610:                        snprintf(buf2, sizeof buf2, "%sL%d", lu->inq_serial, i);
        !          1611:                        lu->lun[i].serial = xstrdup(buf2);
        !          1612:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LUN%d Serial %s (default)\n",
        !          1613:                            i, buf2);
        !          1614:                }
        !          1615:                for (j = 0; ; j++) {
        !          1616:                        val = istgt_get_nmval(sp, buf, j, 0);
        !          1617:                        if (val == NULL)
        !          1618:                                break;
        !          1619:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LUN%d\n", i);
        !          1620:                        if (strcasecmp(val, "Device") == 0) {
        !          1621:                                if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_NONE) {
        !          1622:                                        ISTGT_ERRLOG("LU%d: duplicate LUN%d\n", lu->num, i);
        !          1623:                                        goto error_return;
        !          1624:                                }
        !          1625:                                lu->lun[i].type = ISTGT_LU_LUN_TYPE_DEVICE;
        !          1626: 
        !          1627:                                file = istgt_get_nmval(sp, buf, j, 1);
        !          1628:                                if (file == NULL) {
        !          1629:                                        ISTGT_ERRLOG("LU%d: LUN%d: format error\n", lu->num, i);
        !          1630:                                        goto error_return;
        !          1631:                                }
        !          1632:                                lu->lun[i].u.device.file = xstrdup(file);
        !          1633:                                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Device file=%s\n",
        !          1634:                                                           lu->lun[i].u.device.file);
        !          1635:                        } else if (strcasecmp(val, "Storage") == 0) {
        !          1636:                                if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_NONE) {
        !          1637:                                        ISTGT_ERRLOG("LU%d: duplicate LUN%d\n", lu->num, i);
        !          1638:                                        goto error_return;
        !          1639:                                }
        !          1640:                                lu->lun[i].type = ISTGT_LU_LUN_TYPE_STORAGE;
        !          1641: 
        !          1642:                                file = istgt_get_nmval(sp, buf, j, 1);
        !          1643:                                size = istgt_get_nmval(sp, buf, j, 2);
        !          1644:                                if (file == NULL || size == NULL) {
        !          1645:                                        ISTGT_ERRLOG("LU%d: LUN%d: format error\n", lu->num, i);
        !          1646:                                        goto error_return;
        !          1647:                                }
        !          1648:                                if (strcasecmp(size, "Auto") == 0
        !          1649:                                    || strcasecmp(size, "Size") == 0) {
        !          1650:                                        lu->lun[i].u.storage.size = istgt_lu_get_filesize(file);
        !          1651:                                } else {
        !          1652:                                        lu->lun[i].u.storage.size = istgt_lu_parse_size(size);
        !          1653:                                }
        !          1654:                                if (lu->lun[i].u.storage.size == 0) {
        !          1655:                                        ISTGT_ERRLOG("LU%d: LUN%d: Auto size error (%s)\n", lu->num, i, file);
        !          1656:                                        goto error_return;
        !          1657:                                }
        !          1658:                                lu->lun[i].u.storage.fd = -1;
        !          1659:                                lu->lun[i].u.storage.file = xstrdup(file);
        !          1660:                                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !          1661:                                    "Storage file=%s, size=%"PRIu64"\n",
        !          1662:                                    lu->lun[i].u.storage.file,
        !          1663:                                    lu->lun[i].u.storage.size);
        !          1664:                        } else if (strcasecmp(val, "Removable") == 0) {
        !          1665:                                if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_NONE) {
        !          1666:                                        ISTGT_ERRLOG("LU%d: duplicate LUN%d\n", lu->num, i);
        !          1667:                                        goto error_return;
        !          1668:                                }
        !          1669:                                lu->lun[i].type = ISTGT_LU_LUN_TYPE_REMOVABLE;
        !          1670: 
        !          1671:                                flags = istgt_get_nmval(sp, buf, j, 1);
        !          1672:                                file = istgt_get_nmval(sp, buf, j, 2);
        !          1673:                                size = istgt_get_nmval(sp, buf, j, 3);
        !          1674:                                if (flags == NULL || file == NULL || size == NULL) {
        !          1675:                                        ISTGT_ERRLOG("LU%d: LUN%d: format error\n", lu->num, i);
        !          1676:                                        goto error_return;
        !          1677:                                }
        !          1678:                                mflags = istgt_lu_parse_media_flags(flags);
        !          1679:                                msize = istgt_lu_parse_media_size(file, size, &mflags);
        !          1680:                                if (msize == 0 && strcasecmp(file, "/dev/null") == 0) {
        !          1681:                                        /* empty media */
        !          1682:                                } else if (msize == 0) {
        !          1683:                                        ISTGT_ERRLOG("LU%d: LUN%d: format error\n", lu->num, i);
        !          1684:                                        goto error_return;
        !          1685:                                }
        !          1686:                                lu->lun[i].u.removable.type = 0;
        !          1687:                                lu->lun[i].u.removable.id = 0;
        !          1688:                                lu->lun[i].u.removable.fd = -1;
        !          1689:                                lu->lun[i].u.removable.flags = mflags;
        !          1690:                                lu->lun[i].u.removable.file = xstrdup(file);
        !          1691:                                lu->lun[i].u.removable.size = msize;
        !          1692:                                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !          1693:                                    "Removable file=%s, size=%"PRIu64", flags=%x\n",
        !          1694:                                    lu->lun[i].u.removable.file,
        !          1695:                                    lu->lun[i].u.removable.size,
        !          1696:                                    lu->lun[i].u.removable.flags);
        !          1697:                        } else if (strncasecmp(val, "Slot", 4) == 0) {
        !          1698:                                if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) {
        !          1699:                                        lu->lun[i].u.slot.maxslot = 0;
        !          1700:                                        for (k = 0; k < MAX_LU_LUN_SLOT; k++) {
        !          1701:                                                lu->lun[i].u.slot.present[k] = 0;
        !          1702:                                                lu->lun[i].u.slot.flags[k] = 0;
        !          1703:                                                lu->lun[i].u.slot.file[k] = NULL;
        !          1704:                                                lu->lun[i].u.slot.size[k] = 0;
        !          1705:                                        }
        !          1706:                                } else if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_SLOT) {
        !          1707:                                        ISTGT_ERRLOG("LU%d: duplicate LUN%d\n", lu->num, i);
        !          1708:                                        goto error_return;
        !          1709:                                }
        !          1710:                                lu->lun[i].type = ISTGT_LU_LUN_TYPE_SLOT;
        !          1711:                                if (sscanf(val, "%*[^0-9]%d", &slot) != 1) {
        !          1712:                                        ISTGT_ERRLOG("LU%d: slot number error\n", lu->num);
        !          1713:                                        goto error_return;
        !          1714:                                }
        !          1715:                                if (slot < 0 || slot >= MAX_LU_LUN_SLOT) {
        !          1716:                                        ISTGT_ERRLOG("LU%d: slot number range error\n", lu->num);
        !          1717:                                        goto error_return;
        !          1718:                                }
        !          1719:                                if (lu->lun[i].u.slot.present[slot]) {
        !          1720:                                        ISTGT_ERRLOG("LU%d: duplicate slot %d\n", lu->num, slot);
        !          1721:                                        goto error_return;
        !          1722:                                }
        !          1723:                                lu->lun[i].u.slot.present[slot] = 1;
        !          1724:                                if (slot + 1 > lu->lun[i].u.slot.maxslot) {
        !          1725:                                        lu->lun[i].u.slot.maxslot = slot + 1;
        !          1726:                                }
        !          1727: 
        !          1728:                                flags = istgt_get_nmval(sp, buf, j, 1);
        !          1729:                                file = istgt_get_nmval(sp, buf, j, 2);
        !          1730:                                size = istgt_get_nmval(sp, buf, j, 3);
        !          1731:                                if (flags == NULL || file == NULL || size == NULL) {
        !          1732:                                        ISTGT_ERRLOG("LU%d: LUN%d: format error\n", lu->num, i);
        !          1733:                                        goto error_return;
        !          1734:                                }
        !          1735:                                mflags = istgt_lu_parse_media_flags(flags);
        !          1736:                                msize = istgt_lu_parse_media_size(file, size, &mflags);
        !          1737:                                if (msize == 0) {
        !          1738:                                        ISTGT_ERRLOG("LU%d: LUN%d: format error\n", lu->num, i);
        !          1739:                                        goto error_return;
        !          1740:                                }
        !          1741:                                lu->lun[i].u.slot.flags[slot] = mflags;
        !          1742:                                lu->lun[i].u.slot.file[slot] = xstrdup(file);
        !          1743:                                lu->lun[i].u.slot.size[slot] = msize;
        !          1744:                                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !          1745:                                    "Slot%d file=%s, size=%"PRIu64", flags=%x\n",
        !          1746:                                    slot,
        !          1747:                                    lu->lun[i].u.slot.file[slot],
        !          1748:                                    lu->lun[i].u.slot.size[slot],
        !          1749:                                    lu->lun[i].u.slot.flags[slot]);
        !          1750:                        } else if (strncasecmp(val, "Option", 6) == 0) {
        !          1751:                                key = istgt_get_nmval(sp, buf, j, 1);
        !          1752:                                val = istgt_get_nmval(sp, buf, j, 2);
        !          1753:                                if (key == NULL || val == NULL) {
        !          1754:                                        ISTGT_ERRLOG("LU%d: LUN%d: format error\n", lu->num, i);
        !          1755:                                        goto error_return;
        !          1756:                                }
        !          1757:                                if (strcasecmp(key, "Serial") == 0) {
        !          1758:                                        /* set LUN serial */
        !          1759:                                        if (strlen(val) == 0) {
        !          1760:                                                ISTGT_ERRLOG("LU%d: LUN%d: no serial\n",
        !          1761:                                                    lu->num, i);
        !          1762:                                                goto error_return;
        !          1763:                                        }
        !          1764:                                        xfree(lu->lun[i].serial);
        !          1765:                                        lu->lun[i].serial = xstrdup(val);
        !          1766:                                } else if (strcasecmp(key, "RPM") == 0) {
        !          1767:                                        rpm = (int)strtol(val, NULL, 10);
        !          1768:                                        if (rpm < 0) {
        !          1769:                                                rpm = 0;
        !          1770:                                        } else if (rpm > 0xfffe) {
        !          1771:                                                rpm = 0xfffe;
        !          1772:                                        }
        !          1773:                                        lu->lun[i].rotationrate = rpm;
        !          1774:                                } else if (strcasecmp(key, "FormFactor") == 0) {
        !          1775:                                        formfactor = (int)strtol(val, NULL, 10);
        !          1776:                                        if (formfactor < 0) {
        !          1777:                                                formfactor = 0;
        !          1778:                                        } else if (formfactor > 0x0f) {
        !          1779:                                                formfactor = 0xf;
        !          1780:                                        }
        !          1781:                                        lu->lun[i].formfactor = formfactor;
        !          1782:                                } else if (strcasecmp(key, "ReadCache") == 0) {
        !          1783:                                        if (strcasecmp(val, "Enable") == 0) {
        !          1784:                                                lu->lun[i].readcache = 1;
        !          1785:                                        } else if (strcasecmp(val, "Disable") == 0) {
        !          1786:                                                lu->lun[i].readcache = 0;
        !          1787:                                        } else {
        !          1788:                                                ISTGT_ERRLOG("LU%d: LUN%d: unknown val(%s)\n",
        !          1789:                                                    lu->num, i, val);
        !          1790:                                        }
        !          1791:                                } else if (strcasecmp(key, "WriteCache") == 0) {
        !          1792:                                        if (strcasecmp(val, "Enable") == 0) {
        !          1793:                                                lu->lun[i].writecache = 1;
        !          1794:                                        } else if (strcasecmp(val, "Disable") == 0) {
        !          1795:                                                lu->lun[i].writecache = 0;
        !          1796:                                        } else {
        !          1797:                                                ISTGT_ERRLOG("LU%d: LUN%d: unknown val(%s)\n",
        !          1798:                                                    lu->num, i, val);
        !          1799:                                        }
        !          1800:                                } else {
        !          1801:                                        ISTGT_WARNLOG("LU%d: LUN%d: unknown key(%s)\n",
        !          1802:                                            lu->num, i, key);
        !          1803:                                        continue;
        !          1804:                                }
        !          1805:                                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LUN%d Option %s => %s\n",
        !          1806:                                    i, key, val);
        !          1807:                                continue;
        !          1808:                        } else {
        !          1809:                                ISTGT_ERRLOG("LU%d: unknown lun type\n", lu->num);
        !          1810:                                goto error_return;
        !          1811:                        }
        !          1812:                }
        !          1813:                if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_SLOT) {
        !          1814:                        if (lu->lun[i].u.slot.maxslot == 0) {
        !          1815:                                ISTGT_ERRLOG("LU%d: no slot\n", lu->num);
        !          1816:                                goto error_return;
        !          1817:                        }
        !          1818:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "maxslot=%d\n",
        !          1819:                            lu->lun[i].u.slot.maxslot);
        !          1820:                }
        !          1821:                lu->maxlun = i + 1;
        !          1822:        }
        !          1823:        if (lu->maxlun == 0) {
        !          1824:                ISTGT_ERRLOG("LU%d: no LUN\n", lu->num);
        !          1825:                goto error_return;
        !          1826:        }
        !          1827:        if (lu->lun[0].type == ISTGT_LU_LUN_TYPE_NONE) {
        !          1828:                ISTGT_ERRLOG("LU%d: no LUN0\n", lu->num);
        !          1829:                goto error_return;
        !          1830:        }
        !          1831: 
        !          1832:        /* set local values if any */
        !          1833:        rc = istgt_lu_set_local_settings(istgt, sp, lu);
        !          1834:        if (rc < 0) {
        !          1835:                ISTGT_ERRLOG("LU%d: local setting error\n", lu->num);
        !          1836:                goto error_return;
        !          1837:        }
        !          1838: 
        !          1839:        /* tsih 0 is reserved */
        !          1840:        for (i = 0; i < MAX_LU_TSIH; i++) {
        !          1841:                lu->tsih[i].tag = 0;
        !          1842:                lu->tsih[i].tsih = 0;
        !          1843:                lu->tsih[i].initiator_port = NULL;
        !          1844:        }
        !          1845:        lu->maxtsih = 1;
        !          1846:        lu->last_tsih = 0;
        !          1847: 
        !          1848:        MTX_LOCK(&istgt->mutex);
        !          1849:        istgt->nlogical_unit++;
        !          1850:        istgt->logical_unit[lu->num] = lu;
        !          1851:        MTX_UNLOCK(&istgt->mutex);
        !          1852:        return 0;
        !          1853: 
        !          1854:  error_return:
        !          1855:        xfree(lu->name);
        !          1856:        xfree(lu->alias);
        !          1857:        xfree(lu->inq_vendor);
        !          1858:        xfree(lu->inq_product);
        !          1859:        xfree(lu->inq_revision);
        !          1860:        for (i = 0; i < MAX_LU_LUN; i++) {
        !          1861:                switch (lu->lun[i].type) {
        !          1862:                case ISTGT_LU_LUN_TYPE_DEVICE:
        !          1863:                        xfree(lu->lun[i].u.device.file);
        !          1864:                        break;
        !          1865:                case ISTGT_LU_LUN_TYPE_STORAGE:
        !          1866:                        xfree(lu->lun[i].u.storage.file);
        !          1867:                        break;
        !          1868:                case ISTGT_LU_LUN_TYPE_REMOVABLE:
        !          1869:                        xfree(lu->lun[i].u.removable.file);
        !          1870:                        break;
        !          1871:                case ISTGT_LU_LUN_TYPE_SLOT:
        !          1872:                        for (j = 0; j < lu->lun[i].u.slot.maxslot; j++) {
        !          1873:                                xfree(lu->lun[i].u.slot.file[j]);
        !          1874:                        }
        !          1875:                        break;
        !          1876:                case ISTGT_LU_LUN_TYPE_NONE:
        !          1877:                default:
        !          1878:                        break;
        !          1879:                }
        !          1880:        }
        !          1881:        for (i = 0; i < MAX_LU_TSIH; i++) {
        !          1882:                xfree(lu->tsih[i].initiator_port);
        !          1883:        }
        !          1884:        for (i = 0; i < lu->maxmap; i++) {
        !          1885:                /* nothing */
        !          1886:        }
        !          1887: 
        !          1888:        xfree(lu);
        !          1889:        return -1;
        !          1890: }
        !          1891: 
        !          1892: static int
        !          1893: istgt_lu_del_unit(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu)
        !          1894: {
        !          1895:        int i, j;
        !          1896: 
        !          1897:        if (lu ==NULL)
        !          1898:                return 0;
        !          1899:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "del unit %d\n", lu->num);
        !          1900: 
        !          1901:        MTX_LOCK(&istgt->mutex);
        !          1902:        istgt->nlogical_unit--;
        !          1903:        istgt->logical_unit[lu->num] = NULL;
        !          1904:        MTX_UNLOCK(&istgt->mutex);
        !          1905: 
        !          1906:        xfree(lu->name);
        !          1907:        xfree(lu->alias);
        !          1908:        xfree(lu->inq_vendor);
        !          1909:        xfree(lu->inq_product);
        !          1910:        xfree(lu->inq_revision);
        !          1911:        xfree(lu->inq_serial);
        !          1912:        for (i = 0; i < MAX_LU_LUN; i++) {
        !          1913:                xfree(lu->lun[i].serial);
        !          1914:                switch (lu->lun[i].type) {
        !          1915:                case ISTGT_LU_LUN_TYPE_DEVICE:
        !          1916:                        xfree(lu->lun[i].u.device.file);
        !          1917:                        break;
        !          1918:                case ISTGT_LU_LUN_TYPE_STORAGE:
        !          1919:                        xfree(lu->lun[i].u.storage.file);
        !          1920:                        break;
        !          1921:                case ISTGT_LU_LUN_TYPE_REMOVABLE:
        !          1922:                        xfree(lu->lun[i].u.removable.file);
        !          1923:                        break;
        !          1924:                case ISTGT_LU_LUN_TYPE_SLOT:
        !          1925:                        for (j = 0; j < lu->lun[i].u.slot.maxslot; j++) {
        !          1926:                                xfree(lu->lun[i].u.slot.file[j]);
        !          1927:                        }
        !          1928:                        break;
        !          1929:                case ISTGT_LU_LUN_TYPE_NONE:
        !          1930:                default:
        !          1931:                        break;
        !          1932:                }
        !          1933:        }
        !          1934:        for (i = 0; i < MAX_LU_TSIH; i++) {
        !          1935:                xfree(lu->tsih[i].initiator_port);
        !          1936:        }
        !          1937:        for (i = 0; i < lu->maxmap; i++) {
        !          1938:                /* nothing */
        !          1939:        }
        !          1940: 
        !          1941:        return 0;
        !          1942: }
        !          1943: 
        !          1944: static void *luworker(void *arg);
        !          1945: 
        !          1946: int
        !          1947: istgt_lu_init(ISTGT_Ptr istgt)
        !          1948: {
        !          1949:        ISTGT_LU_Ptr lu;
        !          1950:        CF_SECTION *sp;
        !          1951:        int rc;
        !          1952:        int i;
        !          1953: 
        !          1954:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_init\n");
        !          1955:        sp = istgt_find_cf_section(istgt->config, "Global");
        !          1956:        if (sp == NULL) {
        !          1957:                ISTGT_ERRLOG("find_cf_section failed()\n");
        !          1958:                return -1;
        !          1959:        }
        !          1960: 
        !          1961:        sp = istgt->config->section;
        !          1962:        while (sp != NULL) {
        !          1963:                if (sp->type == ST_LOGICAL_UNIT) {
        !          1964:                        if (sp->num == 0) {
        !          1965:                                ISTGT_ERRLOG("Unit 0 is invalid\n");
        !          1966:                                return -1;
        !          1967:                        }
        !          1968:                        if (sp->num > ISTGT_LU_TAG_MAX) {
        !          1969:                                ISTGT_ERRLOG("tag %d is invalid\n", sp->num);
        !          1970:                                return -1;
        !          1971:                        }
        !          1972:                        rc = istgt_lu_add_unit(istgt, sp);
        !          1973:                        if (rc < 0) {
        !          1974:                                ISTGT_ERRLOG("lu_add_unit() failed\n");
        !          1975:                                return -1;
        !          1976:                        }
        !          1977:                }
        !          1978:                sp = sp->next;
        !          1979:        }
        !          1980: 
        !          1981:        for (i = 0; i < MAX_LOGICAL_UNIT; i++) {
        !          1982:                lu = istgt->logical_unit[i];
        !          1983:                if (lu == NULL)
        !          1984:                        continue;
        !          1985: 
        !          1986:                rc = pthread_mutex_init(&lu->mutex, NULL);
        !          1987:                if (rc != 0) {
        !          1988:                        ISTGT_ERRLOG("LU%d: mutex_init() failed\n", lu->num);
        !          1989:                        return -1;
        !          1990:                }
        !          1991:                rc = pthread_mutex_init(&lu->state_mutex, NULL);
        !          1992:                if (rc != 0) {
        !          1993:                        ISTGT_ERRLOG("LU%d: mutex_init() failed\n", lu->num);
        !          1994:                        return -1;
        !          1995:                }
        !          1996:                rc = pthread_mutex_init(&lu->queue_mutex, NULL);
        !          1997:                if (rc != 0) {
        !          1998:                        ISTGT_ERRLOG("LU%d: mutex_init() failed\n", lu->num);
        !          1999:                        return -1;
        !          2000:                }
        !          2001:                rc = pthread_cond_init(&lu->queue_cond, NULL);
        !          2002:                if (rc != 0) {
        !          2003:                        ISTGT_ERRLOG("LU%d: cond_init() failed\n", lu->num);
        !          2004:                        return -1;
        !          2005:                }
        !          2006: 
        !          2007:                switch (lu->type) {
        !          2008:                case ISTGT_LU_TYPE_PASS:
        !          2009:                        rc = istgt_lu_pass_init(istgt, lu);
        !          2010:                        if (rc < 0) {
        !          2011:                                ISTGT_ERRLOG("LU%d: lu_pass_init() failed\n", lu->num);
        !          2012:                                return -1;
        !          2013:                        }
        !          2014:                        break;
        !          2015: 
        !          2016:                case ISTGT_LU_TYPE_DISK:
        !          2017:                        rc = istgt_lu_disk_init(istgt, lu);
        !          2018:                        if (rc < 0) {
        !          2019:                                ISTGT_ERRLOG("LU%d: lu_disk_init() failed\n", lu->num);
        !          2020:                                return -1;
        !          2021:                        }
        !          2022:                        break;
        !          2023: 
        !          2024:                case ISTGT_LU_TYPE_DVD:
        !          2025:                        rc = istgt_lu_dvd_init(istgt, lu);
        !          2026:                        if (rc < 0) {
        !          2027:                                ISTGT_ERRLOG("LU%d: lu_dvd_init() failed\n", lu->num);
        !          2028:                                return -1;
        !          2029:                        }
        !          2030:                        break;
        !          2031: 
        !          2032:                case ISTGT_LU_TYPE_TAPE:
        !          2033:                        rc = istgt_lu_tape_init(istgt, lu);
        !          2034:                        if (rc < 0) {
        !          2035:                                ISTGT_ERRLOG("LU%d: lu_tape_init() failed\n", lu->num);
        !          2036:                                return -1;
        !          2037:                        }
        !          2038:                        break;
        !          2039: 
        !          2040:                case ISTGT_LU_TYPE_NONE:
        !          2041:                        //ISTGT_ERRLOG("LU%d: dummy type\n", lu->num);
        !          2042:                        break;
        !          2043:                default:
        !          2044:                        ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
        !          2045:                        return -1;
        !          2046:                }
        !          2047: 
        !          2048:                istgt_lu_set_state(lu, ISTGT_STATE_INITIALIZED);
        !          2049:        }
        !          2050: 
        !          2051:        return 0;
        !          2052: }
        !          2053: 
        !          2054: int
        !          2055: istgt_lu_set_all_state(ISTGT_Ptr istgt, ISTGT_STATE state)
        !          2056: {
        !          2057:        ISTGT_LU_Ptr lu;
        !          2058:        int i;
        !          2059: 
        !          2060:        for (i = 0; i < MAX_LOGICAL_UNIT; i++) {
        !          2061:                lu = istgt->logical_unit[i];
        !          2062:                if (lu == NULL)
        !          2063:                        continue;
        !          2064: 
        !          2065:                istgt_lu_set_state(lu, state);
        !          2066:        }
        !          2067: 
        !          2068:        return 0;
        !          2069: }
        !          2070: 
        !          2071: int
        !          2072: istgt_lu_create_threads(ISTGT_Ptr istgt)
        !          2073: {
        !          2074: #ifdef HAVE_PTHREAD_SET_NAME_NP
        !          2075:        char buf[MAX_TMPBUF];
        !          2076: #endif
        !          2077:        ISTGT_LU_Ptr lu;
        !          2078:        int rc;
        !          2079:        int i;
        !          2080: 
        !          2081:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_create_threads\n");
        !          2082: 
        !          2083:        for (i = 0; i < MAX_LOGICAL_UNIT; i++) {
        !          2084:                lu = istgt->logical_unit[i];
        !          2085:                if (lu == NULL)
        !          2086:                        continue;
        !          2087: 
        !          2088:                if (lu->queue_depth != 0) {
        !          2089:                        /* create LU thread */
        !          2090: #ifdef ISTGT_STACKSIZE
        !          2091:                        rc = pthread_create(&lu->thread, &istgt->attr, &luworker, (void *)lu);
        !          2092: #else
        !          2093:                        rc = pthread_create(&lu->thread, NULL, &luworker, (void *)lu);
        !          2094: #endif
        !          2095:                        if (rc != 0) {
        !          2096:                                ISTGT_ERRLOG("pthread_create() failed\n");
        !          2097:                                return -1;
        !          2098:                        }
        !          2099: #if 0
        !          2100:                        rc = pthread_detach(lu->thread);
        !          2101:                        if (rc != 0) {
        !          2102:                                ISTGT_ERRLOG("pthread_detach() failed\n");
        !          2103:                                return -1;
        !          2104:                        }
        !          2105: #endif
        !          2106: #ifdef HAVE_PTHREAD_SET_NAME_NP
        !          2107:                        snprintf(buf, sizeof buf, "luthread #%d", i);
        !          2108:                        pthread_set_name_np(lu->thread, buf);
        !          2109: #endif
        !          2110:                }
        !          2111:        }
        !          2112: 
        !          2113:        return 0;
        !          2114: }
        !          2115: 
        !          2116: int
        !          2117: istgt_lu_shutdown(ISTGT_Ptr istgt)
        !          2118: {
        !          2119:        ISTGT_LU_Ptr lu;
        !          2120:        int rc;
        !          2121:        int i;
        !          2122: 
        !          2123:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_shutdown\n");
        !          2124: 
        !          2125:        for (i = 0; i < MAX_LOGICAL_UNIT; i++) {
        !          2126:                lu = istgt->logical_unit[i];
        !          2127:                if (lu == NULL)
        !          2128:                        continue;
        !          2129:                istgt_lu_set_state(lu, ISTGT_STATE_SHUTDOWN);
        !          2130: 
        !          2131:                switch (lu->type) {
        !          2132:                case ISTGT_LU_TYPE_PASS:
        !          2133:                        rc = istgt_lu_pass_shutdown(istgt, lu);
        !          2134:                        if (rc < 0) {
        !          2135:                                ISTGT_ERRLOG("LU%d: lu_pass_shutdown() failed\n", lu->num);
        !          2136:                                /* ignore error */
        !          2137:                        }
        !          2138:                        break;
        !          2139: 
        !          2140:                case ISTGT_LU_TYPE_DISK:
        !          2141:                        rc = istgt_lu_disk_shutdown(istgt, lu);
        !          2142:                        if (rc < 0) {
        !          2143:                                ISTGT_ERRLOG("LU%d: lu_disk_shutdown() failed\n", lu->num);
        !          2144:                                /* ignore error */
        !          2145:                        }
        !          2146:                        break;
        !          2147: 
        !          2148:                case ISTGT_LU_TYPE_DVD:
        !          2149:                        rc = istgt_lu_dvd_shutdown(istgt, lu);
        !          2150:                        if (rc < 0) {
        !          2151:                                ISTGT_ERRLOG("LU%d: lu_dvd_shutdown() failed\n", lu->num);
        !          2152:                                /* ignore error */
        !          2153:                        }
        !          2154:                        break;
        !          2155: 
        !          2156:                case ISTGT_LU_TYPE_TAPE:
        !          2157:                        rc = istgt_lu_tape_shutdown(istgt, lu);
        !          2158:                        if (rc < 0) {
        !          2159:                                ISTGT_ERRLOG("LU%d: lu_tape_shutdown() failed\n", lu->num);
        !          2160:                                /* ignore error */
        !          2161:                        }
        !          2162:                        break;
        !          2163: 
        !          2164:                case ISTGT_LU_TYPE_NONE:
        !          2165:                        //ISTGT_ERRLOG("LU%d: dummy type\n", lu->num);
        !          2166:                        break;
        !          2167:                default:
        !          2168:                        ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
        !          2169:                        return -1;
        !          2170:                }
        !          2171: 
        !          2172:                rc = istgt_lu_del_unit(istgt, lu);
        !          2173:                if (rc < 0) {
        !          2174:                        ISTGT_ERRLOG("LU%d: lu_del_unit() failed\n", lu->num);
        !          2175:                        /* ignore error */
        !          2176:                }
        !          2177: 
        !          2178:                if (lu->queue_depth != 0) {
        !          2179:                        rc = pthread_cond_broadcast(&lu->queue_cond);
        !          2180:                        if (rc != 0) {
        !          2181:                                ISTGT_ERRLOG("LU%d: cond_broadcast() failed\n", lu->num);
        !          2182:                        }
        !          2183:                        rc = pthread_join(lu->thread, NULL);
        !          2184:                        if (rc != 0) {
        !          2185:                                ISTGT_ERRLOG("LU%d: pthread_join() failed\n", lu->num);
        !          2186:                        }
        !          2187:                }
        !          2188:                rc = pthread_cond_destroy(&lu->queue_cond);
        !          2189:                if (rc != 0) {
        !          2190:                        ISTGT_ERRLOG("LU%d: cond_destroy() failed\n", lu->num);
        !          2191:                        /* ignore error */
        !          2192:                }
        !          2193:                rc = pthread_mutex_destroy(&lu->queue_mutex);
        !          2194:                if (rc != 0) {
        !          2195:                        ISTGT_ERRLOG("LU%d: mutex_destroy() failed\n", lu->num);
        !          2196:                        /* ignore error */
        !          2197:                }
        !          2198:                rc = pthread_mutex_destroy(&lu->state_mutex);
        !          2199:                if (rc != 0) {
        !          2200:                        ISTGT_ERRLOG("LU%d: mutex_destroy() failed\n", lu->num);
        !          2201:                        /* ignore error */
        !          2202:                }
        !          2203:                rc = pthread_mutex_destroy(&lu->mutex);
        !          2204:                if (rc != 0) {
        !          2205:                        ISTGT_ERRLOG("LU%d: mutex_destroy() failed\n", lu->num);
        !          2206:                        /* ignore error */
        !          2207:                }
        !          2208:                xfree(lu);
        !          2209:                istgt->logical_unit[i] = NULL;
        !          2210:        }
        !          2211: 
        !          2212:        return 0;
        !          2213: }
        !          2214: 
        !          2215: int
        !          2216: istgt_lu_islun2lun(uint64_t islun)
        !          2217: {
        !          2218:        uint64_t fmt_lun;
        !          2219:        uint64_t method;
        !          2220:        int lun_i;
        !          2221: 
        !          2222:        fmt_lun = islun;
        !          2223:        method = (fmt_lun >> 62) & 0x03U;
        !          2224:        fmt_lun = fmt_lun >> 48;
        !          2225:        if (method == 0x00U) {
        !          2226:                lun_i = (int) (fmt_lun & 0x00ffU);
        !          2227:        } else if (method == 0x01U) {
        !          2228:                lun_i = (int) (fmt_lun & 0x3fffU);
        !          2229:        } else {
        !          2230:                lun_i = 0xffffU;
        !          2231:        }
        !          2232:        return lun_i;
        !          2233: }
        !          2234: 
        !          2235: uint64_t
        !          2236: istgt_lu_lun2islun(int lun, int maxlun)
        !          2237: {
        !          2238:        uint64_t fmt_lun;
        !          2239:        uint64_t method;
        !          2240:        uint64_t islun;
        !          2241: 
        !          2242:        islun = (uint64_t) lun;
        !          2243:        if (maxlun <= 0x0100) {
        !          2244:                /* below 256 */
        !          2245:                method = 0x00U;
        !          2246:                fmt_lun = (method & 0x03U) << 62;
        !          2247:                fmt_lun |= (islun & 0x00ffU) << 48;
        !          2248:        } else if (maxlun <= 0x4000U) {
        !          2249:                /* below 16384 */
        !          2250:                method = 0x01U;
        !          2251:                fmt_lun = (method & 0x03U) << 62;
        !          2252:                fmt_lun |= (islun & 0x3fffU) << 48;
        !          2253:        } else {
        !          2254:                /* XXX */
        !          2255:                fmt_lun = ~((uint64_t) 0);
        !          2256:        }
        !          2257:        return fmt_lun;
        !          2258: }
        !          2259: 
        !          2260: int
        !          2261: istgt_lu_reset(ISTGT_LU_Ptr lu, uint64_t lun)
        !          2262: {
        !          2263:        int lun_i;
        !          2264:        int rc;
        !          2265: 
        !          2266:        if (lu == NULL)
        !          2267:                return -1;
        !          2268: 
        !          2269:        lun_i = istgt_lu_islun2lun(lun);
        !          2270: 
        !          2271:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: Name=%s, LUN=%d\n",
        !          2272:            lu->num, lu->name, lun_i);
        !          2273: 
        !          2274:        switch (lu->type) {
        !          2275:        case ISTGT_LU_TYPE_PASS:
        !          2276:                MTX_LOCK(&lu->mutex);
        !          2277:                rc = istgt_lu_pass_reset(lu, lun_i);
        !          2278:                MTX_UNLOCK(&lu->mutex);
        !          2279:                if (rc < 0) {
        !          2280:                        ISTGT_ERRLOG("LU%d: lu_pass_reset() failed\n", lu->num);
        !          2281:                        return -1;
        !          2282:                }
        !          2283:                break;
        !          2284: 
        !          2285:        case ISTGT_LU_TYPE_DISK:
        !          2286:                MTX_LOCK(&lu->mutex);
        !          2287:                rc = istgt_lu_disk_reset(lu, lun_i);
        !          2288:                MTX_UNLOCK(&lu->mutex);
        !          2289:                if (rc < 0) {
        !          2290:                        ISTGT_ERRLOG("LU%d: lu_disk_reset() failed\n", lu->num);
        !          2291:                        return -1;
        !          2292:                }
        !          2293:                break;
        !          2294: 
        !          2295:        case ISTGT_LU_TYPE_DVD:
        !          2296:                MTX_LOCK(&lu->mutex);
        !          2297:                rc = istgt_lu_dvd_reset(lu, lun_i);
        !          2298:                MTX_UNLOCK(&lu->mutex);
        !          2299:                if (rc < 0) {
        !          2300:                        ISTGT_ERRLOG("LU%d: lu_dvd_reset() failed\n", lu->num);
        !          2301:                        return -1;
        !          2302:                }
        !          2303:                break;
        !          2304: 
        !          2305:        case ISTGT_LU_TYPE_TAPE:
        !          2306:                MTX_LOCK(&lu->mutex);
        !          2307:                rc = istgt_lu_tape_reset(lu, lun_i);
        !          2308:                MTX_UNLOCK(&lu->mutex);
        !          2309:                if (rc < 0) {
        !          2310:                        ISTGT_ERRLOG("LU%d: lu_tape_reset() failed\n", lu->num);
        !          2311:                        return -1;
        !          2312:                }
        !          2313:                break;
        !          2314: 
        !          2315:        case ISTGT_LU_TYPE_NONE:
        !          2316:                //ISTGT_ERRLOG("LU%d: dummy type\n", lu->num);
        !          2317:                break;
        !          2318:        default:
        !          2319:                ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
        !          2320:                return -1;
        !          2321:        }
        !          2322: 
        !          2323:        return 0;
        !          2324: }
        !          2325: 
        !          2326: int
        !          2327: istgt_lu_execute(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
        !          2328: {
        !          2329:        ISTGT_LU_Ptr lu;
        !          2330:        int rc;
        !          2331: 
        !          2332:        if (lu_cmd == NULL)
        !          2333:                return -1;
        !          2334:        lu = lu_cmd->lu;
        !          2335:        if (lu == NULL)
        !          2336:                return -1;
        !          2337: 
        !          2338:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !          2339:            "LU%d: PG=0x%4.4x, Name=%s, LUN=0x%16.16"PRIx64"\n",
        !          2340:            lu->num, conn->portal.tag, lu->name, lu_cmd->lun);
        !          2341: 
        !          2342:        if (lu->online == 0) {
        !          2343:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "LU%d: offline\n", lu->num);
        !          2344:                /* LOGICAL UNIT NOT READY, CAUSE NOT REPORTABLE */
        !          2345:                lu_cmd->sense_data_len
        !          2346:                        = istgt_lu_scsi_build_sense_data(lu_cmd->sense_data,
        !          2347:                            ISTGT_SCSI_SENSE_NOT_READY,
        !          2348:                            0x04, 0x00);
        !          2349:                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          2350:                return 0;
        !          2351:        }
        !          2352: 
        !          2353:        rc = 0;
        !          2354:        switch (lu->type) {
        !          2355:        case ISTGT_LU_TYPE_PASS:
        !          2356:                MTX_LOCK(&lu->mutex);
        !          2357:                rc = istgt_lu_pass_execute(conn, lu_cmd);
        !          2358:                MTX_UNLOCK(&lu->mutex);
        !          2359:                if (rc < 0) {
        !          2360:                        ISTGT_ERRLOG("LU%d: lu_pass_execute() failed\n",
        !          2361:                            lu->num);
        !          2362:                        return -1;
        !          2363:                }
        !          2364:                break;
        !          2365: 
        !          2366:        case ISTGT_LU_TYPE_DISK:
        !          2367:                if (lu->queue_depth != 0) {
        !          2368:                        //MTX_LOCK(&lu->queue_mutex);
        !          2369:                        rc = istgt_lu_disk_queue(conn, lu_cmd);
        !          2370:                        //MTX_UNLOCK(&lu->queue_mutex);
        !          2371:                        if (rc < 0) {
        !          2372:                                ISTGT_ERRLOG("LU%d: lu_disk_queue() failed\n",
        !          2373:                                    lu->num);
        !          2374:                                return -1;
        !          2375:                        }
        !          2376:                } else {
        !          2377:                        MTX_LOCK(&lu->mutex);
        !          2378:                        rc = istgt_lu_disk_execute(conn, lu_cmd);
        !          2379:                        MTX_UNLOCK(&lu->mutex);
        !          2380:                        if (rc < 0) {
        !          2381:                                ISTGT_ERRLOG("LU%d: lu_disk_execute() failed\n",
        !          2382:                                    lu->num);
        !          2383:                                return -1;
        !          2384:                        }
        !          2385:                }
        !          2386:                break;
        !          2387: 
        !          2388:        case ISTGT_LU_TYPE_DVD:
        !          2389:                MTX_LOCK(&lu->mutex);
        !          2390:                rc = istgt_lu_dvd_execute(conn, lu_cmd);
        !          2391:                MTX_UNLOCK(&lu->mutex);
        !          2392:                if (rc < 0) {
        !          2393:                        ISTGT_ERRLOG("LU%d: lu_dvd_execute() failed\n",
        !          2394:                            lu->num);
        !          2395:                        return -1;
        !          2396:                }
        !          2397:                break;
        !          2398: 
        !          2399:        case ISTGT_LU_TYPE_TAPE:
        !          2400:                MTX_LOCK(&lu->mutex);
        !          2401:                rc = istgt_lu_tape_execute(conn, lu_cmd);
        !          2402:                MTX_UNLOCK(&lu->mutex);
        !          2403:                if (rc < 0) {
        !          2404:                        ISTGT_ERRLOG("LU%d: lu_tape_execute() failed\n",
        !          2405:                            lu->num);
        !          2406:                        return -1;
        !          2407:                }
        !          2408:                break;
        !          2409: 
        !          2410:        case ISTGT_LU_TYPE_NONE:
        !          2411:                //ISTGT_ERRLOG("LU%d: dummy type\n", lu->num);
        !          2412:                break;
        !          2413:        default:
        !          2414:                ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
        !          2415:                return -1;
        !          2416:        }
        !          2417: 
        !          2418:        return rc;
        !          2419: }
        !          2420: 
        !          2421: int
        !          2422: istgt_lu_create_task(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, ISTGT_LU_TASK_Ptr lu_task, int lun)
        !          2423: {
        !          2424:        ISCSI_PDU_Ptr dst_pdu, src_pdu;
        !          2425:        uint8_t *cdb;
        !          2426:        int alloc_len;
        !          2427: #if 0
        !          2428:        int rc;
        !          2429: #endif
        !          2430: 
        !          2431:        if (lu_task == NULL)
        !          2432:                return -1;
        !          2433: 
        !          2434:        lu_task->type = ISTGT_LU_TASK_RESPONSE;
        !          2435:        lu_task->conn = conn;
        !          2436:        strncpy(lu_task->initiator_name, conn->initiator_name,
        !          2437:            sizeof lu_task->initiator_name);
        !          2438:        strncpy(lu_task->initiator_port, conn->initiator_port,
        !          2439:            sizeof lu_task->initiator_port);
        !          2440: 
        !          2441:        lu_task->lun = (int) lun;
        !          2442:        lu_task->use_cond = 0;
        !          2443:        lu_task->dup_iobuf = 0;
        !          2444:        lu_task->iobuf = NULL;
        !          2445:        lu_task->data = NULL;
        !          2446:        lu_task->sense_data = NULL;
        !          2447:        lu_task->create_time = 0;
        !          2448:        lu_task->condwait = 0;
        !          2449:        lu_task->offset = 0;
        !          2450:        lu_task->req_execute = 0;
        !          2451:        lu_task->req_transfer_out = 0;
        !          2452:        lu_task->error = 0;
        !          2453:        lu_task->abort = 0;
        !          2454:        lu_task->execute = 0;
        !          2455:        lu_task->complete = 0;
        !          2456:        lu_task->lock = 0;
        !          2457: 
        !          2458: #if 0
        !          2459:        rc = pthread_mutex_init(&lu_task->trans_mutex, NULL);
        !          2460:        if (rc != 0) {
        !          2461:                ISTGT_ERRLOG("mutex_init() failed\n");
        !          2462:                return -1;
        !          2463:        }
        !          2464:        rc = pthread_cond_init(&lu_task->trans_cond, NULL);
        !          2465:        if (rc != 0) {
        !          2466:                ISTGT_ERRLOG("cond_init() failed\n");
        !          2467:                return -1;
        !          2468:        }
        !          2469:        rc = pthread_cond_init(&lu_task->exec_cond, NULL);
        !          2470:        if (rc != 0) {
        !          2471:                ISTGT_ERRLOG("cond_init() failed\n");
        !          2472:                return -1;
        !          2473:        }
        !          2474: #endif
        !          2475: 
        !          2476:        lu_task->lu_cmd.pdu = xmalloc(sizeof *lu_task->lu_cmd.pdu);
        !          2477:        memset(lu_task->lu_cmd.pdu, 0, sizeof *lu_task->lu_cmd.pdu);
        !          2478: 
        !          2479:        /* copy PDU */
        !          2480:        dst_pdu = lu_task->lu_cmd.pdu;
        !          2481:        src_pdu = lu_cmd->pdu;
        !          2482:        memcpy(&dst_pdu->bhs, &src_pdu->bhs, ISCSI_BHS_LEN);
        !          2483:        dst_pdu->ahs = src_pdu->ahs;
        !          2484:        memcpy(dst_pdu->header_digest, src_pdu->header_digest, ISCSI_DIGEST_LEN);
        !          2485:        if (src_pdu->data == src_pdu->shortdata) {
        !          2486:                memcpy(dst_pdu->shortdata, src_pdu->shortdata,
        !          2487:                    sizeof src_pdu->shortdata);
        !          2488:                dst_pdu->data = dst_pdu->shortdata;
        !          2489:        } else {
        !          2490:                dst_pdu->data = src_pdu->data;
        !          2491:        }
        !          2492:        memcpy(dst_pdu->data_digest, src_pdu->data_digest, ISCSI_DIGEST_LEN);
        !          2493:        dst_pdu->total_ahs_len = src_pdu->total_ahs_len;
        !          2494:        dst_pdu->data_segment_len = src_pdu->data_segment_len;
        !          2495:        dst_pdu->copy_pdu = 0;
        !          2496:        src_pdu->copy_pdu = 1;
        !          2497: 
        !          2498:        /* copy other lu_cmd */
        !          2499:        lu_task->lu_cmd.lu = lu_cmd->lu;
        !          2500:        cdb = ((uint8_t *) &lu_task->lu_cmd.pdu->bhs) + 32;
        !          2501:        lu_task->lu_cmd.I_bit = lu_cmd->I_bit;
        !          2502:        lu_task->lu_cmd.F_bit = lu_cmd->F_bit;
        !          2503:        lu_task->lu_cmd.R_bit = lu_cmd->R_bit;
        !          2504:        lu_task->lu_cmd.W_bit = lu_cmd->W_bit;
        !          2505:        lu_task->lu_cmd.Attr_bit = lu_cmd->Attr_bit;
        !          2506:        lu_task->lu_cmd.lun = lu_cmd->lun;
        !          2507:        lu_task->lu_cmd.task_tag = lu_cmd->task_tag;
        !          2508:        lu_task->lu_cmd.transfer_len = lu_cmd->transfer_len;
        !          2509:        //lu_task->lu_cmd.cdb = lu_cmd->cdb;
        !          2510:        lu_task->lu_cmd.cdb = cdb;
        !          2511:        lu_task->lu_cmd.CmdSN = lu_cmd->CmdSN;
        !          2512: 
        !          2513:        //lu_task->lu_cmd.iobuf = lu_cmd->iobuf;
        !          2514:        lu_task->lu_cmd.iobuf = NULL;
        !          2515:        lu_task->lu_cmd.iobufsize = lu_cmd->iobufsize;
        !          2516:        lu_task->lu_cmd.data = lu_cmd->data;
        !          2517:        lu_task->lu_cmd.data_len = lu_cmd->data_len;
        !          2518:        lu_task->lu_cmd.alloc_len = lu_cmd->alloc_len;
        !          2519: 
        !          2520:        lu_task->lu_cmd.status = lu_cmd->status;
        !          2521:        lu_task->lu_cmd.sense_data = lu_cmd->sense_data;
        !          2522:        lu_task->lu_cmd.sense_data_len = lu_cmd->sense_data_len;
        !          2523:        lu_task->lu_cmd.sense_alloc_len = lu_cmd->sense_alloc_len;
        !          2524: 
        !          2525:        /* pre allocate buffer */
        !          2526:        lu_task->lu_cmd.iobufsize = lu_cmd->transfer_len + 65536;
        !          2527: #if 0
        !          2528:        lu_task->data = xmalloc(lu_cmd->alloc_len);
        !          2529:        lu_task->sense_data = xmalloc(lu_cmd->sense_alloc_len);
        !          2530:        lu_task->iobuf = xmalloc(lu_task->lu_cmd.iobufsize);
        !          2531: #else
        !          2532:        alloc_len = ISCSI_ALIGN(lu_cmd->alloc_len);
        !          2533:        alloc_len += ISCSI_ALIGN(lu_cmd->sense_alloc_len);
        !          2534:        alloc_len += ISCSI_ALIGN(lu_task->lu_cmd.iobufsize);
        !          2535:        lu_task->data = xmalloc(alloc_len);
        !          2536:        lu_task->sense_data = lu_task->data + ISCSI_ALIGN(lu_cmd->alloc_len);
        !          2537:        lu_task->iobuf = lu_task->sense_data + ISCSI_ALIGN(lu_cmd->sense_alloc_len);
        !          2538: #endif
        !          2539: 
        !          2540:        /* creation time */
        !          2541:        lu_task->create_time = time(NULL);
        !          2542:        /* wait time */
        !          2543:        lu_task->condwait = conn->timeout * 1000;
        !          2544:        if (lu_task->condwait < ISTGT_CONDWAIT_MIN) {
        !          2545:                lu_task->condwait = ISTGT_CONDWAIT_MIN;
        !          2546:        }
        !          2547: 
        !          2548:        return 0;
        !          2549: }
        !          2550: 
        !          2551: int
        !          2552: istgt_lu_destroy_task(ISTGT_LU_TASK_Ptr lu_task)
        !          2553: {
        !          2554:        int rc;
        !          2555: 
        !          2556:        if (lu_task == NULL)
        !          2557:                return -1;
        !          2558: 
        !          2559:        if (lu_task->use_cond != 0) {
        !          2560:                rc = pthread_mutex_destroy(&lu_task->trans_mutex);
        !          2561:                if (rc != 0) {
        !          2562:                        ISTGT_ERRLOG("mutex_destroy() failed\n");
        !          2563:                        return -1;
        !          2564:                }
        !          2565:                rc = pthread_cond_destroy(&lu_task->trans_cond);
        !          2566:                if (rc != 0) {
        !          2567:                        ISTGT_ERRLOG("cond_destroy() failed\n");
        !          2568:                        return -1;
        !          2569:                }
        !          2570:                rc = pthread_cond_destroy(&lu_task->exec_cond);
        !          2571:                if (rc != 0) {
        !          2572:                        ISTGT_ERRLOG("cond_destroy() failed\n");
        !          2573:                        return -1;
        !          2574:                }
        !          2575:        }
        !          2576:        if (lu_task->lu_cmd.pdu != NULL) {
        !          2577:                if (lu_task->lu_cmd.pdu->copy_pdu == 0) {
        !          2578:                        xfree(lu_task->lu_cmd.pdu->ahs);
        !          2579:                        if (lu_task->lu_cmd.pdu->data
        !          2580:                            != lu_task->lu_cmd.pdu->shortdata) {
        !          2581:                                xfree(lu_task->lu_cmd.pdu->data);
        !          2582:                        }
        !          2583:                }
        !          2584:                xfree(lu_task->lu_cmd.pdu);
        !          2585:        }
        !          2586: #if 0
        !          2587:        if (lu_task->dup_iobuf == 0) {
        !          2588:                xfree(lu_task->iobuf);
        !          2589:        }
        !          2590:        xfree(lu_task->data);
        !          2591:        xfree(lu_task->sense_data);
        !          2592: #else
        !          2593:        xfree(lu_task->data);
        !          2594: #endif
        !          2595:        xfree(lu_task);
        !          2596:        return 0;
        !          2597: }
        !          2598: 
        !          2599: int
        !          2600: istgt_lu_clear_task_IT(CONN_Ptr conn, ISTGT_LU_Ptr lu)
        !          2601: {
        !          2602:        int rc;
        !          2603: 
        !          2604:        if (lu == NULL)
        !          2605:                return -1;
        !          2606: 
        !          2607:        if (lu->queue_depth == 0)
        !          2608:                return 0;
        !          2609: 
        !          2610:        rc = 0;
        !          2611:        switch (lu->type) {
        !          2612:        case ISTGT_LU_TYPE_DISK:
        !          2613:                MTX_LOCK(&lu->mutex);
        !          2614:                rc = istgt_lu_disk_queue_clear_IT(conn, lu);
        !          2615:                MTX_UNLOCK(&lu->mutex);
        !          2616:                if (rc < 0) {
        !          2617:                        ISTGT_ERRLOG("LU%d: lu_disk_queue_clear_IT() failed\n", lu->num);
        !          2618:                        return -1;
        !          2619:                }
        !          2620:                break;
        !          2621: 
        !          2622:        case ISTGT_LU_TYPE_DVD:
        !          2623:        case ISTGT_LU_TYPE_TAPE:
        !          2624:        case ISTGT_LU_TYPE_NONE:
        !          2625:        default:
        !          2626:                ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
        !          2627:                return -1;
        !          2628:        }
        !          2629: 
        !          2630:        return 0;
        !          2631: }
        !          2632: 
        !          2633: int
        !          2634: istgt_lu_clear_task_ITL(CONN_Ptr conn, ISTGT_LU_Ptr lu, uint64_t lun)
        !          2635: {
        !          2636:        int lun_i;
        !          2637:        int rc;
        !          2638: 
        !          2639:        if (lu == NULL)
        !          2640:                return -1;
        !          2641: 
        !          2642:        if (lu->queue_depth == 0)
        !          2643:                return 0;
        !          2644: 
        !          2645:        lun_i = istgt_lu_islun2lun(lun);
        !          2646: 
        !          2647:        rc = 0;
        !          2648:        switch (lu->type) {
        !          2649:        case ISTGT_LU_TYPE_DISK:
        !          2650:                MTX_LOCK(&lu->mutex);
        !          2651:                rc = istgt_lu_disk_queue_clear_ITL(conn, lu, lun_i);
        !          2652:                MTX_UNLOCK(&lu->mutex);
        !          2653:                if (rc < 0) {
        !          2654:                        ISTGT_ERRLOG("LU%d: lu_disk_queue_clear_ITL() failed\n", lu->num);
        !          2655:                        return -1;
        !          2656:                }
        !          2657:                break;
        !          2658: 
        !          2659:        case ISTGT_LU_TYPE_DVD:
        !          2660:        case ISTGT_LU_TYPE_TAPE:
        !          2661:        case ISTGT_LU_TYPE_NONE:
        !          2662:        default:
        !          2663:                ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
        !          2664:                return -1;
        !          2665:        }
        !          2666: 
        !          2667:        return 0;
        !          2668: }
        !          2669: 
        !          2670: int
        !          2671: istgt_lu_clear_task_ITLQ(CONN_Ptr conn, ISTGT_LU_Ptr lu, uint64_t lun, uint32_t CmdSN)
        !          2672: {
        !          2673:        int lun_i;
        !          2674:        int rc;
        !          2675: 
        !          2676:        if (lu == NULL)
        !          2677:                return -1;
        !          2678: 
        !          2679:        if (lu->queue_depth == 0)
        !          2680:                return 0;
        !          2681: 
        !          2682:        lun_i = istgt_lu_islun2lun(lun);
        !          2683: 
        !          2684:        rc = 0;
        !          2685:        switch (lu->type) {
        !          2686:        case ISTGT_LU_TYPE_DISK:
        !          2687:                MTX_LOCK(&lu->mutex);
        !          2688:                rc = istgt_lu_disk_queue_clear_ITLQ(conn, lu, lun_i, CmdSN);
        !          2689:                MTX_UNLOCK(&lu->mutex);
        !          2690:                if (rc < 0) {
        !          2691:                        ISTGT_ERRLOG("LU%d: lu_disk_queue_clear_ITLQ() failed\n", lu->num);
        !          2692:                        return -1;
        !          2693:                }
        !          2694:                break;
        !          2695: 
        !          2696:        case ISTGT_LU_TYPE_DVD:
        !          2697:        case ISTGT_LU_TYPE_TAPE:
        !          2698:        case ISTGT_LU_TYPE_NONE:
        !          2699:        default:
        !          2700:                ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
        !          2701:                return -1;
        !          2702:        }
        !          2703: 
        !          2704:        return 0;
        !          2705: }
        !          2706: 
        !          2707: int
        !          2708: istgt_lu_clear_all_task(ISTGT_LU_Ptr lu, uint64_t lun)
        !          2709: {
        !          2710:        int rc;
        !          2711: 
        !          2712:        if (lu == NULL)
        !          2713:                return -1;
        !          2714: 
        !          2715:        if (lu->queue_depth == 0)
        !          2716:                return 0;
        !          2717: 
        !          2718:        rc = 0;
        !          2719:        switch (lu->type) {
        !          2720:        case ISTGT_LU_TYPE_DISK:
        !          2721:                MTX_LOCK(&lu->mutex);
        !          2722:                rc = istgt_lu_disk_queue_clear_all(lu, lun);
        !          2723:                MTX_UNLOCK(&lu->mutex);
        !          2724:                if (rc < 0) {
        !          2725:                        ISTGT_ERRLOG("LU%d: lu_disk_queue_clear_all() failed\n", lu->num);
        !          2726:                        return -1;
        !          2727:                }
        !          2728:                break;
        !          2729: 
        !          2730:        case ISTGT_LU_TYPE_DVD:
        !          2731:        case ISTGT_LU_TYPE_TAPE:
        !          2732:        case ISTGT_LU_TYPE_NONE:
        !          2733:        default:
        !          2734:                ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
        !          2735:                return -1;
        !          2736:        }
        !          2737: 
        !          2738:        return 0;
        !          2739: }
        !          2740: 
        !          2741: static void *
        !          2742: luworker(void *arg)
        !          2743: {
        !          2744:        ISTGT_LU_Ptr lu = (ISTGT_LU_Ptr) arg;
        !          2745:        sigset_t signew, sigold;
        !          2746: #if 0
        !          2747:        struct timespec abstime;
        !          2748:        time_t now;
        !          2749:        int timeout = 20; /* XXX */
        !          2750: #endif
        !          2751:        int qcnt;
        !          2752:        int lun;
        !          2753:        int rc;
        !          2754: 
        !          2755:        sigemptyset(&signew);
        !          2756:        sigemptyset(&sigold);
        !          2757:        sigaddset(&signew, ISTGT_SIGWAKEUP);
        !          2758:        pthread_sigmask(SIG_UNBLOCK, &signew, &sigold);
        !          2759: 
        !          2760:        while (istgt_get_state(lu->istgt) != ISTGT_STATE_RUNNING) {
        !          2761:                if (istgt_get_state(lu->istgt) == ISTGT_STATE_EXITING
        !          2762:                    || istgt_get_state(lu->istgt) == ISTGT_STATE_SHUTDOWN) {
        !          2763:                        ISTGT_ERRLOG("exit before running\n");
        !          2764:                        return NULL;
        !          2765:                }
        !          2766:                //ISTGT_WARNLOG("Wait for running\n");
        !          2767:                sleep(1);
        !          2768:                continue;
        !          2769:        }
        !          2770: 
        !          2771:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d loop start\n", lu->num);
        !          2772:        lun = 0;
        !          2773:        qcnt = 0;
        !          2774: #if 0
        !          2775:        memset(&abstime, 0, sizeof abstime);
        !          2776: #endif
        !          2777:        while (1) {
        !          2778:                switch (lu->type) {
        !          2779:                case ISTGT_LU_TYPE_DISK:
        !          2780:                        while (1) {
        !          2781:                                if (istgt_lu_get_state(lu) != ISTGT_STATE_RUNNING) {
        !          2782:                                        goto loop_exit;
        !          2783:                                }
        !          2784:                                MTX_LOCK(&lu->queue_mutex);
        !          2785:                                qcnt = istgt_lu_disk_queue_count(lu, &lun);
        !          2786:                                if (qcnt == 0) {
        !          2787: #if 0
        !          2788:                                        now = time(NULL);
        !          2789:                                        abstime.tv_sec = now + timeout;
        !          2790:                                        abstime.tv_nsec = 0;
        !          2791:                                        rc = pthread_cond_timedwait(&lu->queue_cond,
        !          2792:                                            &lu->queue_mutex, &abstime);
        !          2793:                                        if (rc == ETIMEDOUT) {
        !          2794:                                                /* nothing */
        !          2795:                                        }
        !          2796: #else
        !          2797:                                        pthread_cond_wait(&lu->queue_cond,
        !          2798:                                            &lu->queue_mutex);
        !          2799: #endif
        !          2800:                                        qcnt = istgt_lu_disk_queue_count(lu, &lun);
        !          2801:                                        if (qcnt == 0) {
        !          2802:                                                MTX_UNLOCK(&lu->queue_mutex);
        !          2803:                                                continue;
        !          2804:                                        }
        !          2805:                                }
        !          2806:                                MTX_UNLOCK(&lu->queue_mutex);
        !          2807:                                break;
        !          2808:                        }
        !          2809:                        if (qcnt < 0) {
        !          2810:                                ISTGT_ERRLOG("LU%d: lu_disk_queue_count() failed\n",
        !          2811:                                    lu->num);
        !          2812:                                break;
        !          2813:                        }
        !          2814:                        rc = istgt_lu_disk_queue_start(lu, lun);
        !          2815:                        lun++;
        !          2816:                        if (rc == -2) {
        !          2817:                                ISTGT_WARNLOG("LU%d: lu_disk_queue_start() aborted\n",
        !          2818:                                    lu->num);
        !          2819:                                break;
        !          2820:                        }
        !          2821:                        if (rc < 0) {
        !          2822:                                ISTGT_ERRLOG("LU%d: lu_disk_queue_start() failed\n",
        !          2823:                                    lu->num);
        !          2824:                                break;
        !          2825:                        }
        !          2826:                        break;
        !          2827: 
        !          2828:                case ISTGT_LU_TYPE_DVD:
        !          2829:                case ISTGT_LU_TYPE_TAPE:
        !          2830:                case ISTGT_LU_TYPE_NONE:
        !          2831:                default:
        !          2832:                        ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
        !          2833:                        return NULL;
        !          2834:                }
        !          2835: 
        !          2836: #if 0
        !          2837:                /* still running? */
        !          2838:                if (qcnt <= 1) {
        !          2839:                        if (istgt_lu_get_state(lu) != ISTGT_STATE_RUNNING) {
        !          2840:                                goto loop_exit;
        !          2841:                        }
        !          2842:                }
        !          2843: #endif
        !          2844:        }
        !          2845:  loop_exit:
        !          2846:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d loop ended\n", lu->num);
        !          2847: 
        !          2848:        return NULL;
        !          2849: }

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