Annotation of embedaddon/istgt/src/istgt_lu_disk.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 <errno.h>
        !            36: #include <stdio.h>
        !            37: #include <string.h>
        !            38: #include <pthread.h>
        !            39: #include <time.h>
        !            40: 
        !            41: #include <fcntl.h>
        !            42: #include <unistd.h>
        !            43: 
        !            44: #ifdef HAVE_UUID_H
        !            45: #include <uuid.h>
        !            46: #endif
        !            47: 
        !            48: #include "istgt.h"
        !            49: #include "istgt_ver.h"
        !            50: #include "istgt_log.h"
        !            51: #include "istgt_conf.h"
        !            52: #include "istgt_sock.h"
        !            53: #include "istgt_misc.h"
        !            54: #include "istgt_crc32c.h"
        !            55: #include "istgt_md5.h"
        !            56: #include "istgt_iscsi.h"
        !            57: #include "istgt_lu.h"
        !            58: #include "istgt_proto.h"
        !            59: #include "istgt_scsi.h"
        !            60: #include "istgt_queue.h"
        !            61: 
        !            62: #ifndef O_FSYNC
        !            63: #define O_FSYNC O_SYNC
        !            64: #endif
        !            65: 
        !            66: //#define ISTGT_TRACE_DISK
        !            67: 
        !            68: typedef enum {
        !            69:        ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE = 0x01,
        !            70:        ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS = 0x03,
        !            71:        ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY = 0x05,
        !            72:        ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY = 0x06,
        !            73:        ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS = 0x07,
        !            74:        ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS = 0x08,
        !            75: } ISTGT_LU_PR_TYPE;
        !            76: 
        !            77: #define PR_ALLOW(WE,EA,ALLRR,WERR,EARR) \
        !            78:        ((((WE)&1) << 4) | (((EA)&1) << 3) | (((ALLRR)&1) << 2) \
        !            79:         | (((WERR)&1) << 1) | (((EARR)&1) << 0))
        !            80: #define PR_ALLOW_WE    0x0010
        !            81: #define PR_ALLOW_EA    0x0008
        !            82: #define PR_ALLOW_ALLRR 0x0004
        !            83: #define PR_ALLOW_WERR  0x0002
        !            84: #define PR_ALLOW_EARR  0x0001
        !            85: 
        !            86: typedef struct istgt_lu_pr_key_t {
        !            87:        uint64_t key;
        !            88: 
        !            89:        /* transport IDs */
        !            90:        char *registered_initiator_port;
        !            91:        char *registered_target_port;
        !            92:        /* PERSISTENT RESERVE OUT received from */
        !            93:        int pg_idx; /* relative target port */
        !            94:        int pg_tag; /* target port group */
        !            95: 
        !            96:        int ninitiator_ports;
        !            97:        char **initiator_ports;
        !            98:        int all_tpg;
        !            99: } ISTGT_LU_PR_KEY;
        !           100: 
        !           101: typedef struct istgt_lu_disk_t {
        !           102:        ISTGT_LU_Ptr lu;
        !           103:        int num;
        !           104:        int lun;
        !           105: 
        !           106:        int fd;
        !           107:        const char *file;
        !           108:        uint64_t fsize;
        !           109:        uint64_t foffset;
        !           110:        uint64_t size;
        !           111:        uint64_t blocklen;
        !           112:        uint64_t blockcnt;
        !           113: 
        !           114: #ifdef HAVE_UUID_H
        !           115:        uuid_t uuid;
        !           116: #endif /* HAVE_UUID_H */
        !           117: 
        !           118:        /* cache flags */
        !           119:        int read_cache;
        !           120:        int write_cache;
        !           121:        /* parts for cache */
        !           122:        int wbufsize;
        !           123:        uint8_t *wbuf;
        !           124:        uint64_t woffset;
        !           125:        uint64_t wnbytes;
        !           126:        int req_write_cache;
        !           127:        int err_write_cache;
        !           128: 
        !           129:        /* thin provisioning */
        !           130:        int thin_provisioning;
        !           131: 
        !           132:        /* for ats */
        !           133:        pthread_mutex_t ats_mutex;
        !           134: 
        !           135:        int queue_depth;
        !           136:        pthread_mutex_t cmd_queue_mutex;
        !           137:        ISTGT_QUEUE cmd_queue;
        !           138:        pthread_mutex_t wait_lu_task_mutex;
        !           139:        ISTGT_LU_TASK_Ptr wait_lu_task;
        !           140: 
        !           141:        /* PERSISTENT RESERVE */
        !           142:        int npr_keys;
        !           143:        ISTGT_LU_PR_KEY pr_keys[MAX_LU_RESERVE];
        !           144:        uint32_t pr_generation;
        !           145: 
        !           146:        char *rsv_port;
        !           147:        uint64_t rsv_key;
        !           148:        int rsv_scope;
        !           149:        int rsv_type;
        !           150: 
        !           151:        /* SCSI sense code */
        !           152:        volatile int sense;
        !           153: } ISTGT_LU_DISK;
        !           154: 
        !           155: #define BUILD_SENSE(SK,ASC,ASCQ)                                       \
        !           156:        do {                                                            \
        !           157:                *sense_len =                                            \
        !           158:                        istgt_lu_disk_build_sense_data(spec, sense_data, \
        !           159:                            ISTGT_SCSI_SENSE_ ## SK,                    \
        !           160:                            (ASC), (ASCQ));                             \
        !           161:        } while (0)
        !           162: #define BUILD_SENSE2(SK,ASC,ASCQ)                                      \
        !           163:        do {                                                            \
        !           164:                *sense_len =                                            \
        !           165:                        istgt_lu_disk_build_sense_data2(spec, sense_data, \
        !           166:                            ISTGT_SCSI_SENSE_ ## SK,                    \
        !           167:                            (ASC), (ASCQ));                             \
        !           168:        } while (0)
        !           169: 
        !           170: static void istgt_lu_disk_free_pr_key(ISTGT_LU_PR_KEY *prkey);
        !           171: static int istgt_lu_disk_build_sense_data(ISTGT_LU_DISK *spec, uint8_t *data, int sk, int asc, int ascq);
        !           172: static int istgt_lu_disk_queue_abort_ITL(ISTGT_LU_DISK *spec, const char *initiator_port);
        !           173: 
        !           174: static int
        !           175: istgt_lu_disk_open(ISTGT_LU_DISK *spec, int flags, int mode)
        !           176: {
        !           177:        int rc;
        !           178: 
        !           179:        rc = open(spec->file, flags, mode);
        !           180:        if (rc < 0) {
        !           181:                return -1;
        !           182:        }
        !           183:        spec->fd = rc;
        !           184:        spec->foffset = 0;
        !           185:        return 0;
        !           186: }
        !           187: 
        !           188: static int
        !           189: istgt_lu_disk_close(ISTGT_LU_DISK *spec)
        !           190: {
        !           191:        int rc;
        !           192: 
        !           193:        if (spec->fd == -1)
        !           194:                return 0;
        !           195:        rc = close(spec->fd);
        !           196:        if (rc < 0) {
        !           197:                return -1;
        !           198:        }
        !           199:        spec->fd = -1;
        !           200:        spec->foffset = 0;
        !           201:        return 0;
        !           202: }
        !           203: 
        !           204: #if 0
        !           205: static off_t
        !           206: istgt_lu_disk_lseek(ISTGT_LU_DISK *spec, off_t offset, int whence)
        !           207: {
        !           208:        off_t rc;
        !           209: 
        !           210:        rc = lseek(spec->fd, offset, whence);
        !           211:        if (rc < 0) {
        !           212:                return -1;
        !           213:        }
        !           214:        spec->foffset = offset;
        !           215:        return rc;
        !           216: }
        !           217: #endif
        !           218: 
        !           219: static int64_t
        !           220: istgt_lu_disk_seek(ISTGT_LU_DISK *spec, uint64_t offset)
        !           221: {
        !           222:        off_t rc;
        !           223: 
        !           224:        rc = lseek(spec->fd, (off_t) offset, SEEK_SET);
        !           225:        if (rc < 0) {
        !           226:                return -1;
        !           227:        }
        !           228:        spec->foffset = offset;
        !           229:        return 0;
        !           230: }
        !           231: 
        !           232: static int64_t
        !           233: istgt_lu_disk_read(ISTGT_LU_DISK *spec, void *buf, uint64_t nbytes)
        !           234: {
        !           235:        int64_t rc;
        !           236: 
        !           237:        if (spec->lu->istgt->swmode >= ISTGT_SWMODE_EXPERIMENTAL) {
        !           238:                if (spec->foffset + nbytes <= spec->fsize) {
        !           239:                        /* inside media */
        !           240:                        rc = (int64_t) read(spec->fd, buf, (size_t) nbytes);
        !           241:                } else if (spec->foffset >= spec->fsize) {
        !           242:                        /* outside media */
        !           243:                        memset(buf, 0, nbytes);
        !           244:                        rc = nbytes;
        !           245:                        if (spec->foffset + nbytes >= spec->size) {
        !           246:                                rc = spec->size - spec->foffset;
        !           247:                        }
        !           248:                } else if (spec->foffset + nbytes > spec->fsize) {
        !           249:                        /* both */
        !           250:                        uint64_t request = spec->fsize - spec->foffset;
        !           251:                        memset(buf, 0, nbytes);
        !           252:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !           253:                            "read %"PRIu64" bytes at %"PRIu64"/%"PRIu64"\n",
        !           254:                                    request, spec->foffset, spec->fsize);
        !           255:                        rc = (int64_t) read(spec->fd, buf, (size_t) request);
        !           256:                        if (rc < 0) {
        !           257:                                return -1;
        !           258:                        }
        !           259:                        if (rc != request) {
        !           260:                                /* read size < request */
        !           261:                                if (spec->foffset + rc >= spec->size) {
        !           262:                                        rc = spec->size - spec->foffset;
        !           263:                                }
        !           264:                                spec->foffset += rc;
        !           265:                                return rc;
        !           266:                        }
        !           267:                        rc = nbytes;
        !           268:                        if (spec->foffset + nbytes >= spec->size) {
        !           269:                                rc = spec->size - spec->foffset;
        !           270:                        }
        !           271:                } else {
        !           272:                        rc = -1;
        !           273:                }
        !           274:                if (rc < 0) {
        !           275:                        return -1;
        !           276:                }
        !           277:                spec->foffset += rc;
        !           278:                return rc;
        !           279:        }
        !           280:        rc = (int64_t) read(spec->fd, buf, (size_t) nbytes);
        !           281:        if (rc < 0) {
        !           282:                return -1;
        !           283:        }
        !           284:        spec->foffset += rc;
        !           285:        return rc;
        !           286: }
        !           287: 
        !           288: static int64_t
        !           289: istgt_lu_disk_write(ISTGT_LU_DISK *spec, const void *buf, uint64_t nbytes)
        !           290: {
        !           291:        int64_t rc;
        !           292: 
        !           293:        if (spec->lu->istgt->swmode >= ISTGT_SWMODE_EXPERIMENTAL) {
        !           294:                if (spec->foffset + nbytes <= spec->fsize) {
        !           295:                        /* inside media */
        !           296:                        rc = (int64_t) write(spec->fd, buf, (size_t) nbytes);
        !           297:                } else if (spec->foffset + nbytes <= ISTGT_LU_MEDIA_SIZE_MIN) {
        !           298:                        /* allways write in minimum size */
        !           299:                        rc = (int64_t) write(spec->fd, buf, (size_t) nbytes);
        !           300:                } else if (spec->foffset >= spec->fsize) {
        !           301:                        /* outside media */
        !           302:                        const uint8_t *p = (const uint8_t *) buf;
        !           303:                        uint64_t n;
        !           304:                        for (n = 0; n < nbytes; n++) {
        !           305:                                if (p[n] != 0)
        !           306:                                        break;
        !           307:                        }
        !           308:                        if (n == nbytes) {
        !           309:                                /* write all zero (skip) */
        !           310:                                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !           311:                                    "write zero %"PRIu64" bytes at %"PRIu64"/%"PRIu64"\n",
        !           312:                                    nbytes, spec->foffset, spec->fsize);
        !           313:                                rc = nbytes;
        !           314:                                spec->foffset += rc;
        !           315:                                return rc;
        !           316:                        }
        !           317:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !           318:                            "write %"PRIu64" bytes at %"PRIu64"/%"PRIu64"\n",
        !           319:                            nbytes, spec->foffset, spec->fsize);
        !           320:                        rc = (int64_t) write(spec->fd, buf, (size_t) nbytes);
        !           321:                } else if (spec->foffset + nbytes > spec->fsize) {
        !           322:                        /* both */
        !           323:                        rc = (int64_t) write(spec->fd, buf, (size_t) nbytes);
        !           324:                } else {
        !           325:                        rc = -1;
        !           326:                }
        !           327:                if (rc < 0) {
        !           328:                        return -1;
        !           329:                }
        !           330:                spec->foffset += rc;
        !           331:                if (spec->foffset > spec->fsize) {
        !           332:                        spec->fsize = spec->foffset;
        !           333:                }
        !           334:                return rc;
        !           335:        }
        !           336:        rc = (int64_t) write(spec->fd, buf, (size_t) nbytes);
        !           337:        if (rc < 0) {
        !           338:                return -1;
        !           339:        }
        !           340:        spec->foffset += rc;
        !           341:        if (spec->foffset > spec->fsize) {
        !           342:                spec->fsize = spec->foffset;
        !           343:        }
        !           344:        return rc;
        !           345: }
        !           346: 
        !           347: static int64_t
        !           348: istgt_lu_disk_sync(ISTGT_LU_DISK *spec, uint64_t offset, uint64_t nbytes)
        !           349: {
        !           350:        int64_t rc;
        !           351: 
        !           352:        rc = (int64_t) fsync(spec->fd);
        !           353:        if (rc < 0) {
        !           354:                return -1;
        !           355:        }
        !           356:        spec->foffset = offset + nbytes;
        !           357:        return rc;
        !           358: }
        !           359: 
        !           360: static int
        !           361: istgt_lu_disk_allocate(ISTGT_LU_DISK *spec)
        !           362: {
        !           363:        uint8_t *data;
        !           364:        uint64_t fsize;
        !           365:        uint64_t size;
        !           366:        uint64_t blocklen;
        !           367:        uint64_t offset;
        !           368:        uint64_t nbytes;
        !           369:        int64_t rc;
        !           370: 
        !           371:        size = spec->size;
        !           372:        blocklen = spec->blocklen;
        !           373:        nbytes = blocklen;
        !           374:        data = xmalloc(nbytes);
        !           375:        memset(data, 0, nbytes);
        !           376: 
        !           377:        fsize = istgt_lu_get_filesize(spec->file);
        !           378:        if (fsize > size) {
        !           379:                xfree(data);
        !           380:                return 0;
        !           381:        }
        !           382:        spec->fsize = fsize;
        !           383: 
        !           384:        offset = size - nbytes;
        !           385:        rc = istgt_lu_disk_seek(spec, offset);
        !           386:        if (rc == -1) {
        !           387:                ISTGT_ERRLOG("lu_disk_seek() failed\n");
        !           388:                xfree(data);
        !           389:                return -1;
        !           390:        }
        !           391:        rc = istgt_lu_disk_read(spec, data, nbytes);
        !           392:        /* EOF is OK */
        !           393:        if (rc == -1) {
        !           394:                ISTGT_ERRLOG("lu_disk_read() failed\n");
        !           395:                xfree(data);
        !           396:                return -1;
        !           397:        }
        !           398:        if (spec->lu->istgt->swmode >= ISTGT_SWMODE_EXPERIMENTAL) {
        !           399:                /* allocate minimum size */
        !           400:                if (fsize < ISTGT_LU_MEDIA_SIZE_MIN) {
        !           401:                        fsize = ISTGT_LU_MEDIA_SIZE_MIN;
        !           402:                        if (size < ISTGT_LU_MEDIA_SIZE_MIN) {
        !           403:                                fsize = size;
        !           404:                        }
        !           405:                        offset = fsize - nbytes;
        !           406:                        rc = istgt_lu_disk_seek(spec, offset);
        !           407:                        if (rc == -1) {
        !           408:                                ISTGT_ERRLOG("lu_disk_seek() failed\n");
        !           409:                                xfree(data);
        !           410:                                return -1;
        !           411:                        }
        !           412:                        rc = istgt_lu_disk_write(spec, data, nbytes);
        !           413:                        if (rc == -1 || rc != nbytes) {
        !           414:                                ISTGT_ERRLOG("lu_disk_write() failed\n");
        !           415:                                xfree(data);
        !           416:                                return -1;
        !           417:                        }
        !           418:                        spec->fsize = fsize;
        !           419:                        spec->foffset = fsize;
        !           420:                }
        !           421:        } else {
        !           422:                /* allocate complete size */
        !           423:                rc = istgt_lu_disk_seek(spec, offset);
        !           424:                if (rc == -1) {
        !           425:                        ISTGT_ERRLOG("lu_disk_seek() failed\n");
        !           426:                        xfree(data);
        !           427:                        return -1;
        !           428:                }
        !           429:                rc = istgt_lu_disk_write(spec, data, nbytes);
        !           430:                if (rc == -1 || rc != nbytes) {
        !           431:                        ISTGT_ERRLOG("lu_disk_write() failed\n");
        !           432:                        xfree(data);
        !           433:                        return -1;
        !           434:                }
        !           435:                spec->foffset = size;
        !           436:        }
        !           437: 
        !           438:        xfree(data);
        !           439:        return 0;
        !           440: }
        !           441: 
        !           442: static int
        !           443: istgt_lu_disk_setcache(ISTGT_LU_DISK *spec)
        !           444: {
        !           445:        int flags;
        !           446:        int rc;
        !           447:        int fd;
        !           448: 
        !           449:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_disk_setcache\n");
        !           450: 
        !           451:        fd = spec->fd;
        !           452:        if (spec->read_cache) {
        !           453:                /* not implement */
        !           454:        } else {
        !           455:                /* not implement */
        !           456:        }
        !           457:        flags = fcntl(fd , F_GETFL, 0);
        !           458:        if (flags != -1) {
        !           459:                if (spec->write_cache) {
        !           460:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "write cache enable\n");
        !           461:                        rc = fcntl(fd, F_SETFL, (flags & ~O_FSYNC));
        !           462:                        spec->write_cache = 1;
        !           463:                } else {
        !           464:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "write cache disable\n");
        !           465:                        rc = fcntl(fd, F_SETFL, (flags | O_FSYNC));
        !           466:                        spec->write_cache = 0;
        !           467:                }
        !           468:                if (rc == -1) {
        !           469: #if 0
        !           470:                        ISTGT_ERRLOG("LU%d: LUN%d: fcntl(F_SETFL) failed(errno=%d)\n",
        !           471:                            spec->num, spec->lun, errno);
        !           472: #endif
        !           473:                }
        !           474:        } else {
        !           475:                ISTGT_ERRLOG("LU%d: LUN%d: fcntl(F_GETFL) failed(errno=%d)\n",
        !           476:                    spec->num, spec->lun, errno);
        !           477:        }
        !           478:        return 0;
        !           479: }
        !           480: 
        !           481: int
        !           482: istgt_lu_disk_init(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu)
        !           483: {
        !           484:        ISTGT_LU_DISK *spec;
        !           485:        uint64_t gb_size;
        !           486:        uint64_t mb_size;
        !           487: #ifdef HAVE_UUID_H
        !           488:        uint32_t status;
        !           489: #endif /* HAVE_UUID_H */
        !           490:        int mb_digit;
        !           491:        int flags;
        !           492:        int newfile;
        !           493:        int rc;
        !           494:        int i, j;
        !           495: 
        !           496:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_disk_init\n");
        !           497: 
        !           498:        printf("LU%d HDD UNIT\n", lu->num);
        !           499:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d TargetName=%s\n",
        !           500:            lu->num, lu->name);
        !           501:        for (i = 0; i < lu->maxlun; i++) {
        !           502:                if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) {
        !           503:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d none\n",
        !           504:                            lu->num, i);
        !           505:                        lu->lun[i].spec = NULL;
        !           506:                        continue;
        !           507:                }
        !           508:                if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_STORAGE) {
        !           509:                        ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
        !           510:                        return -1;
        !           511:                }
        !           512:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d storage\n",
        !           513:                    lu->num, i);
        !           514: 
        !           515:                spec = xmalloc(sizeof *spec);
        !           516:                memset(spec, 0, sizeof *spec);
        !           517:                spec->lu = lu;
        !           518:                spec->num = lu->num;
        !           519:                spec->lun = i;
        !           520:                spec->fd = -1;
        !           521:                if (spec->lu->lun[i].readcache) {
        !           522:                        spec->read_cache = 1;
        !           523:                } else {
        !           524:                        spec->read_cache = 0;
        !           525:                }
        !           526:                if (spec->lu->lun[i].writecache) {
        !           527:                        spec->write_cache = 1;
        !           528:                } else {
        !           529:                        spec->write_cache = 0;
        !           530:                }
        !           531:                if (spec->lu->istgt->swmode >= ISTGT_SWMODE_EXPERIMENTAL) {
        !           532:                        spec->wbufsize = ISTGT_LU_MAX_WRITE_CACHE_SIZE;
        !           533:                        spec->wbuf = xmalloc(spec->wbufsize);
        !           534:                        memset(spec->wbuf, 0, spec->wbufsize);
        !           535:                } else {
        !           536:                        spec->wbufsize = 0;
        !           537:                        spec->wbuf = NULL;
        !           538:                }
        !           539:                spec->woffset = 0;
        !           540:                spec->wnbytes = 0;
        !           541:                spec->req_write_cache = 0;
        !           542:                spec->err_write_cache = 0;
        !           543:                spec->thin_provisioning = 0;
        !           544: 
        !           545:                rc = pthread_mutex_init(&spec->ats_mutex, NULL);
        !           546:                if (rc != 0) {
        !           547:                        ISTGT_ERRLOG("LU%d: mutex_init() failed\n", lu->num);
        !           548:                        return -1;
        !           549:                }
        !           550: 
        !           551:                spec->queue_depth = lu->queue_depth;
        !           552:                rc = pthread_mutex_init(&spec->cmd_queue_mutex, NULL);
        !           553:                if (rc != 0) {
        !           554:                        ISTGT_ERRLOG("LU%d: mutex_init() failed\n", lu->num);
        !           555:                        return -1;
        !           556:                }
        !           557:                istgt_queue_init(&spec->cmd_queue);
        !           558:                rc = pthread_mutex_init(&spec->wait_lu_task_mutex, NULL);
        !           559:                if (rc != 0) {
        !           560:                        ISTGT_ERRLOG("LU%d: mutex_init() failed\n", lu->num);
        !           561:                        return -1;
        !           562:                }
        !           563:                spec->wait_lu_task = NULL;
        !           564: 
        !           565:                spec->npr_keys = 0;
        !           566:                for (j = 0; j < MAX_LU_RESERVE; j++) {
        !           567:                        spec->pr_keys[j].registered_initiator_port = NULL;
        !           568:                }
        !           569:                spec->pr_generation = 0;
        !           570:                spec->rsv_port = NULL;
        !           571:                spec->rsv_key = 0;
        !           572:                spec->rsv_scope = 0;
        !           573:                spec->rsv_type = 0;
        !           574: 
        !           575:                spec->sense = 0;
        !           576:                {
        !           577:                        int sk, asc, ascq;
        !           578:                        /* POWER ON, RESET, OR BUS DEVICE RESET OCCURRED */
        !           579:                        sk = ISTGT_SCSI_SENSE_UNIT_ATTENTION;
        !           580:                        asc = 0x29;
        !           581:                        ascq = 0x00;
        !           582:                        spec->sense = (((sk & 0xffU) << 16)
        !           583:                            | ((asc & 0xffU) << 8)
        !           584:                            | ((ascq & 0xffU) << 0));
        !           585:                }
        !           586: 
        !           587: #ifdef HAVE_UUID_H
        !           588:                uuid_create(&spec->uuid, &status);
        !           589:                if (status != uuid_s_ok) {
        !           590:                        ISTGT_ERRLOG("LU%d: LUN%d: uuid_create() failed\n", lu->num, i);
        !           591:                        (void) pthread_mutex_destroy(&spec->cmd_queue_mutex);
        !           592:                        istgt_queue_destroy(&spec->cmd_queue);
        !           593:                        xfree(spec);
        !           594:                        return -1;
        !           595:                }
        !           596: #endif /* HAVE_UUID_H */
        !           597: 
        !           598:                spec->file = lu->lun[i].u.storage.file;
        !           599:                spec->size = lu->lun[i].u.storage.size;
        !           600:                spec->blocklen = lu->blocklen;
        !           601:                if (spec->blocklen != 512
        !           602:                    && spec->blocklen != 1024
        !           603:                    && spec->blocklen != 2048
        !           604:                    && spec->blocklen != 4096
        !           605:                    && spec->blocklen != 8192
        !           606:                    && spec->blocklen != 16384
        !           607:                    && spec->blocklen != 32768
        !           608:                    && spec->blocklen != 65536
        !           609:                    && spec->blocklen != 131072
        !           610:                    && spec->blocklen != 262144
        !           611:                    && spec->blocklen != 524288) {
        !           612:                        ISTGT_ERRLOG("LU%d: LUN%d: invalid blocklen %"PRIu64"\n",
        !           613:                            lu->num, i, spec->blocklen);
        !           614:                error_return:
        !           615:                        (void) pthread_mutex_destroy(&spec->cmd_queue_mutex);
        !           616:                        istgt_queue_destroy(&spec->cmd_queue);
        !           617:                        xfree(spec);
        !           618:                        return -1;
        !           619:                }
        !           620:                spec->blockcnt = spec->size / spec->blocklen;
        !           621:                if (spec->blockcnt == 0) {
        !           622:                        ISTGT_ERRLOG("LU%d: LUN%d: size zero\n", lu->num, i);
        !           623:                        goto error_return;
        !           624:                }
        !           625: 
        !           626: #if 0
        !           627:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !           628:                    "LU%d: LUN%d file=%s, size=%"PRIu64"\n",
        !           629:                    lu->num, i, spec->file, spec->size);
        !           630:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !           631:                    "LU%d: LUN%d %"PRIu64" blocks, %"
        !           632:                    PRIu64" bytes/block\n",
        !           633:                    lu->num, i, spec->blockcnt, spec->blocklen);
        !           634: #endif
        !           635:                printf("LU%d: LUN%d file=%s, size=%"PRIu64"\n",
        !           636:                    lu->num, i, spec->file, spec->size);
        !           637:                printf("LU%d: LUN%d %"PRIu64" blocks, %"PRIu64" bytes/block\n",
        !           638:                    lu->num, i, spec->blockcnt, spec->blocklen);
        !           639: 
        !           640:                flags = lu->readonly ? O_RDONLY : O_RDWR;
        !           641:                newfile = 0;
        !           642:                rc = istgt_lu_disk_open(spec, flags, 0666);
        !           643:                if (rc < 0) {
        !           644:                        newfile = 1;
        !           645:                        flags = lu->readonly ? O_RDONLY : (O_CREAT | O_EXCL | O_RDWR);
        !           646:                        rc = istgt_lu_disk_open(spec, flags, 0666);
        !           647:                        if (rc < 0) {
        !           648:                                ISTGT_ERRLOG("LU%d: LUN%d: open error\n", lu->num, i);
        !           649:                                goto error_return;
        !           650:                        }
        !           651:                }
        !           652:                if (!lu->readonly) {
        !           653:                        rc = istgt_lu_disk_allocate(spec);
        !           654:                        if (rc < 0) {
        !           655:                                ISTGT_ERRLOG("LU%d: LUN%d: allocate error\n", lu->num, i);
        !           656:                                goto error_return;
        !           657:                        }
        !           658:                }
        !           659:                rc = istgt_lu_disk_setcache(spec);
        !           660:                if (rc < 0) {
        !           661:                        ISTGT_ERRLOG("LU%d: LUN%d: setcache error\n", lu->num, i);
        !           662:                        goto error_return;
        !           663:                }
        !           664: 
        !           665:                gb_size = spec->size / ISTGT_LU_1GB;
        !           666:                mb_size = (spec->size % ISTGT_LU_1GB) / ISTGT_LU_1MB;
        !           667:                if (gb_size > 0) {
        !           668:                        mb_digit = (int) (((mb_size * 100) / 1024) / 10);
        !           669: #if 0
        !           670:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !           671:                            "LU%d LUN%d %"PRIu64".%dGB %sstorage for %s\n",
        !           672:                            lu->num, i, gb_size, mb_digit,
        !           673:                            lu->readonly ? "readonly " : "", lu->name);
        !           674: #endif
        !           675:                        printf("LU%d: LUN%d %"PRIu64".%dGB %sstorage for %s\n",
        !           676:                            lu->num, i, gb_size, mb_digit,
        !           677:                            lu->readonly ? "readonly " : "", lu->name);
        !           678:                } else {
        !           679: #if 0
        !           680:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !           681:                            "LU%d: LUN%d %"PRIu64"MB %sstorage for %s\n",
        !           682:                            lu->num, i, mb_size,
        !           683:                            lu->readonly ? "readonly " : "", lu->name);
        !           684: #endif
        !           685:                        printf("LU%d: LUN%d %"PRIu64"MB %sstorage for %s\n",
        !           686:                            lu->num, i, mb_size,
        !           687:                            lu->readonly ? "readonly " : "", lu->name);
        !           688:                }
        !           689:                if (spec->lu->lun[i].serial != NULL) {
        !           690:                        printf("LU%d: LUN%d serial %s\n",
        !           691:                            lu->num, i, spec->lu->lun[i].serial);
        !           692:                } else {
        !           693:                        printf("LU%d: LUN%d serial %s\n",
        !           694:                            lu->num, i, spec->lu->inq_serial);
        !           695:                }
        !           696:                printf("LU%d: LUN%d ", lu->num, i);
        !           697:                if (spec->read_cache) {
        !           698:                        printf("read cache enabled");
        !           699:                } else {
        !           700:                        printf("read cache disabled");
        !           701:                }
        !           702:                printf(", ");
        !           703:                if (spec->write_cache) {
        !           704:                        printf("write cache enabled");
        !           705:                } else {
        !           706:                        printf("write cache disabled");
        !           707:                }
        !           708:                printf("\n");
        !           709:                if (spec->queue_depth != 0) {
        !           710:                        printf("LU%d: LUN%d command queuing enabled, depth %d\n",
        !           711:                            lu->num, i, spec->queue_depth);
        !           712:                } else {
        !           713:                        printf("LU%d: LUN%d command queuing disabled\n",
        !           714:                            lu->num, i);
        !           715:                }
        !           716: #if 0
        !           717:                if (spec->write_cache && spec->wbufsize) {
        !           718:                        mb_size = (spec->wbufsize / ISTGT_LU_1MB);
        !           719:                        printf("LU%d: LUN%d write buffer %"PRIu64"MB\n",
        !           720:                            lu->num, i, mb_size);
        !           721:                }
        !           722: #endif
        !           723: 
        !           724:                lu->lun[i].spec = spec;
        !           725:        }
        !           726: 
        !           727:        return 0;
        !           728: }
        !           729: 
        !           730: int
        !           731: istgt_lu_disk_shutdown(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu)
        !           732: {
        !           733:        ISTGT_LU_DISK *spec;
        !           734:        ISTGT_LU_PR_KEY *prkey;
        !           735:        int rc;
        !           736:        int i, j;
        !           737: 
        !           738:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_disk_shutdown\n");
        !           739: 
        !           740:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d TargetName=%s\n",
        !           741:            lu->num, lu->name);
        !           742:        for (i = 0; i < lu->maxlun; i++) {
        !           743:                if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) {
        !           744:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d none\n",
        !           745:                            lu->num, i);
        !           746:                        continue;
        !           747:                }
        !           748:                if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_STORAGE) {
        !           749:                        ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
        !           750:                        return -1;
        !           751:                }
        !           752:                spec = (ISTGT_LU_DISK *) lu->lun[i].spec;
        !           753: 
        !           754:                if (!spec->lu->readonly) {
        !           755:                        rc = istgt_lu_disk_sync(spec, 0, spec->size);
        !           756:                        if (rc < 0) {
        !           757:                                //ISTGT_ERRLOG("LU%d: lu_disk_sync() failed\n", lu->num);
        !           758:                                /* ignore error */
        !           759:                        }
        !           760:                }
        !           761:                rc = istgt_lu_disk_close(spec);
        !           762:                if (rc < 0) {
        !           763:                        //ISTGT_ERRLOG("LU%d: lu_disk_close() failed\n", lu->num);
        !           764:                        /* ignore error */
        !           765:                }
        !           766: 
        !           767:                for (j = 0; j < spec->npr_keys; j++) {
        !           768:                        prkey = &spec->pr_keys[j];
        !           769:                        istgt_lu_disk_free_pr_key(prkey);
        !           770:                }
        !           771:                if (spec->rsv_key != 0) {
        !           772:                        xfree(spec->rsv_port);
        !           773:                        spec->rsv_port = NULL;
        !           774:                }
        !           775: 
        !           776:                rc = pthread_mutex_destroy(&spec->ats_mutex);
        !           777:                if (rc != 0) {
        !           778:                        //ISTGT_ERRLOG("LU%d: mutex_destroy() failed\n", lu->num);
        !           779:                        /* ignore error */
        !           780:                }
        !           781: 
        !           782:                istgt_queue_destroy(&spec->cmd_queue);
        !           783:                rc = pthread_mutex_destroy(&spec->cmd_queue_mutex);
        !           784:                if (rc != 0) {
        !           785:                        //ISTGT_ERRLOG("LU%d: mutex_destroy() failed\n", lu->num);
        !           786:                        /* ignore error */
        !           787:                }
        !           788:                rc = pthread_mutex_destroy(&spec->wait_lu_task_mutex);
        !           789:                if (rc != 0) {
        !           790:                        //ISTGT_ERRLOG("LU%d: mutex_destroy() failed\n", lu->num);
        !           791:                        /* ignore error */
        !           792:                }
        !           793:                xfree(spec->wbuf);
        !           794:                xfree(spec);
        !           795:                lu->lun[i].spec = NULL;
        !           796:        }
        !           797: 
        !           798:        return 0;
        !           799: }
        !           800: 
        !           801: void
        !           802: istgt_scsi_dump_cdb(uint8_t *cdb)
        !           803: {
        !           804:        int group;
        !           805:        int cdblen = 0;
        !           806:        int i;
        !           807: 
        !           808:        if (cdb == NULL)
        !           809:                return;
        !           810: 
        !           811:        group = (cdb[0] >> 5) & 0x07;
        !           812:        switch (group) {
        !           813:        case 0x00:
        !           814:                /* 6byte commands */
        !           815:                cdblen = 6;
        !           816:                break;
        !           817:        case 0x01:
        !           818:                /* 10byte commands */
        !           819:                cdblen = 10;
        !           820:                break;
        !           821:        case 0x02:
        !           822:                /* 10byte commands */
        !           823:                cdblen = 10;
        !           824:                break;
        !           825:        case 0x03:
        !           826:                /* reserved */
        !           827:                if (cdb[0] == 0x7f) {
        !           828:                        /* variable length */
        !           829:                        cdblen = 8 + (cdb[7] & 0xff);
        !           830:                } else {
        !           831:                        /* XXX */
        !           832:                        cdblen = 6;
        !           833:                }
        !           834:                break;
        !           835:        case 0x04:
        !           836:                /* 16byte commands */
        !           837:                cdblen = 16;
        !           838:                break;
        !           839:        case 0x05:
        !           840:                /* 12byte commands */
        !           841:                cdblen = 12;
        !           842:                break;
        !           843:        case 0x06:
        !           844:        case 0x07:
        !           845:                /* vendor specific */
        !           846:                cdblen = 6;
        !           847:                break;
        !           848:        }
        !           849: 
        !           850:        printf("CDB=");
        !           851:        for (i = 0; i < cdblen; i++) {
        !           852:                printf("%2.2x ", cdb[i]);
        !           853:        }
        !           854:        printf("\n");
        !           855: }
        !           856: 
        !           857: void
        !           858: istgt_strcpy_pad(uint8_t *dst, size_t size, const char *src, int pad)
        !           859: {
        !           860:        size_t len;
        !           861: 
        !           862:        len = strlen(src);
        !           863:        if (len < size) {
        !           864:                memcpy(dst, src, len);
        !           865:                memset(dst + len, pad, (size - len));
        !           866:        } else {
        !           867:                memcpy(dst, src, size);
        !           868:        }
        !           869: }
        !           870: 
        !           871: #ifdef HAVE_UUID_H
        !           872: uint64_t
        !           873: istgt_uuid2uint64(uuid_t *uuid)
        !           874: {
        !           875:        uint64_t low, mid, hi;
        !           876:        uint64_t r;
        !           877: 
        !           878:        low = (uint64_t) uuid->time_low;
        !           879:        mid = (uint64_t) uuid->time_mid;
        !           880:        hi  = (uint64_t) uuid->time_hi_and_version;
        !           881:        r = (hi & 0xffffULL) << 48;
        !           882:        r |= (mid & 0xffffULL) << 32;
        !           883:        r |= (low & 0xffffffffULL);
        !           884:        return r;
        !           885: }
        !           886: #endif /* HAVE_UUID_H */
        !           887: 
        !           888: uint64_t
        !           889: istgt_get_lui(const char *name, int lun)
        !           890: {
        !           891:        char buf[MAX_TMPBUF];
        !           892:        uint32_t crc32c;
        !           893:        uint64_t r;
        !           894: 
        !           895:        if (lun >= 0) {
        !           896:                snprintf(buf, sizeof buf, "%s,%d",
        !           897:                    name, lun);
        !           898:        } else {
        !           899:                snprintf(buf, sizeof buf, "%s",
        !           900:                    name);
        !           901:        }
        !           902:        crc32c = istgt_crc32c((uint8_t *) buf, strlen(buf));
        !           903:        r = (uint64_t) crc32c;
        !           904:        return r;
        !           905: }
        !           906: 
        !           907: uint64_t
        !           908: istgt_get_rkey(const char *initiator_name, uint64_t lui)
        !           909: {
        !           910:        ISTGT_MD5CTX md5ctx;
        !           911:        uint8_t rkeymd5[ISTGT_MD5DIGEST_LEN];
        !           912:        char buf[MAX_TMPBUF];
        !           913:        uint64_t rkey;
        !           914:        int idx;
        !           915:        int i;
        !           916: 
        !           917:        snprintf(buf, sizeof buf, "%s,%16.16" PRIx64,
        !           918:            initiator_name, lui);
        !           919: 
        !           920:        istgt_md5init(&md5ctx);
        !           921:        istgt_md5update(&md5ctx, buf, strlen(buf));
        !           922:        istgt_md5final(rkeymd5, &md5ctx);
        !           923: 
        !           924:        rkey = 0U;
        !           925:        idx = ISTGT_MD5DIGEST_LEN - 8;
        !           926:        if (idx < 0) {
        !           927:                ISTGT_WARNLOG("missing MD5 length\n");
        !           928:                idx = 0;
        !           929:        }
        !           930:        for (i = idx; i < ISTGT_MD5DIGEST_LEN; i++) {
        !           931:                rkey |= (uint64_t) rkeymd5[i];
        !           932:                rkey = rkey << 8;
        !           933:        }
        !           934:        return rkey;
        !           935: }
        !           936: 
        !           937: /* XXX */
        !           938: #define COMPANY_ID 0xACDE48U // 24bits
        !           939: 
        !           940: int
        !           941: istgt_lu_set_lid(uint8_t *buf, uint64_t vid)
        !           942: {
        !           943:        uint64_t naa;
        !           944:        uint64_t enc;
        !           945:        int total;
        !           946: 
        !           947:        naa = 0x3; // Locally Assigned
        !           948: 
        !           949:        /* NAA + LOCALLY ADMINISTERED VALUE */
        !           950:        enc = (naa & 0xfULL) << (64-4); // 4bits
        !           951:        enc |= vid & 0xfffffffffffffffULL; //60bits
        !           952:        DSET64(&buf[0], enc);
        !           953: 
        !           954:        total = 8;
        !           955:        return total;
        !           956: }
        !           957: 
        !           958: int
        !           959: istgt_lu_set_id(uint8_t *buf, uint64_t vid)
        !           960: {
        !           961:        uint64_t naa;
        !           962:        uint64_t cid;
        !           963:        uint64_t enc;
        !           964:        int total;
        !           965: 
        !           966:        naa = 0x5; // IEEE Registered
        !           967:        cid = COMPANY_ID; //IEEE COMPANY_ID
        !           968: 
        !           969:        /* NAA + COMPANY_ID + VENDOR SPECIFIC IDENTIFIER */
        !           970:        enc = (naa & 0xfULL) << (64-4); // 4bits
        !           971:        enc |= (cid & 0xffffffULL) << (64-4-24); // 24bits
        !           972:        enc |= vid & 0xfffffffffULL; //36bits
        !           973:        DSET64(&buf[0], enc);
        !           974: 
        !           975:        total = 8;
        !           976:        return total;
        !           977: }
        !           978: 
        !           979: int
        !           980: istgt_lu_set_extid(uint8_t *buf, uint64_t vid, uint64_t vide)
        !           981: {
        !           982:        uint64_t naa;
        !           983:        uint64_t cid;
        !           984:        uint64_t enc;
        !           985:        int total;
        !           986: 
        !           987:        naa = 0x6; // IEEE Registered Extended
        !           988:        cid = COMPANY_ID; //IEEE COMPANY_ID
        !           989: 
        !           990:        /* NAA + COMPANY_ID + VENDOR SPECIFIC IDENTIFIER */
        !           991:        enc = (naa & 0xfULL) << (64-4); // 4bits
        !           992:        enc |= (cid & 0xffffffULL) << (64-4-24); // 24bits
        !           993:        enc |= vid & 0xfffffffffULL; //36bits
        !           994:        DSET64(&buf[0], enc);
        !           995:        /* VENDOR SPECIFIC IDENTIFIER EXTENSION */
        !           996:        DSET64(&buf[8], vide);
        !           997: 
        !           998:        total = 16;
        !           999:        return total;
        !          1000: }
        !          1001: 
        !          1002: static int
        !          1003: istgt_lu_disk_scsi_report_luns(ISTGT_LU_Ptr lu, CONN_Ptr conn, uint8_t *cdb, int sel, uint8_t *data, int alloc_len)
        !          1004: {
        !          1005:        uint64_t fmt_lun, lun, method;
        !          1006:        int hlen = 0, len = 0;
        !          1007:        int i;
        !          1008: 
        !          1009:        if (alloc_len < 8) {
        !          1010:                return -1;
        !          1011:        }
        !          1012: 
        !          1013:        if (sel == 0x00) {
        !          1014:                /* logical unit with addressing method */
        !          1015:        } else if (sel == 0x01) {
        !          1016:                /* well known logical unit */
        !          1017:        } else if (sel == 0x02) {
        !          1018:                /* logical unit */
        !          1019:        } else {
        !          1020:                return -1;
        !          1021:        }
        !          1022: 
        !          1023:        /* LUN LIST LENGTH */
        !          1024:        DSET32(&data[0], 0);
        !          1025:        /* Reserved */
        !          1026:        DSET32(&data[4], 0);
        !          1027:        hlen = 8;
        !          1028: 
        !          1029:        for (i = 0; i < lu->maxlun; i++) {
        !          1030:                if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) {
        !          1031: #if 0
        !          1032:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d none\n",
        !          1033:                            lu->num, i);
        !          1034: #endif
        !          1035:                        continue;
        !          1036:                }
        !          1037:                if (alloc_len - (hlen + len) < 8) {
        !          1038:                        return -1;
        !          1039:                }
        !          1040:                lun = (uint64_t) i;
        !          1041:                if (lu->maxlun <= 0x0100) {
        !          1042:                        /* below 256 */
        !          1043:                        method = 0x00U;
        !          1044:                        fmt_lun = (method & 0x03U) << 62;
        !          1045:                        fmt_lun |= (lun & 0x00ffU) << 48;
        !          1046:                } else if (lu->maxlun <= 0x4000U) {
        !          1047:                        /* below 16384 */
        !          1048:                        method = 0x01U;
        !          1049:                        fmt_lun = (method & 0x03U) << 62;
        !          1050:                        fmt_lun |= (lun & 0x3fffU) << 48;
        !          1051:                } else {
        !          1052:                        /* XXX */
        !          1053:                        fmt_lun = 0;
        !          1054:                }
        !          1055:                /* LUN */
        !          1056:                DSET64(&data[hlen + len], fmt_lun);
        !          1057:                len += 8;
        !          1058:        }
        !          1059:        /* LUN LIST LENGTH */
        !          1060:        DSET32(&data[0], len);
        !          1061:        return hlen + len;
        !          1062: }
        !          1063: 
        !          1064: static int
        !          1065: istgt_lu_disk_scsi_inquiry(ISTGT_LU_DISK *spec, CONN_Ptr conn, uint8_t *cdb, uint8_t *data, int alloc_len)
        !          1066: {
        !          1067:        uint64_t LUI;
        !          1068:        uint8_t *cp, *cp2;
        !          1069:        uint32_t blocks;
        !          1070:        int hlen = 0, len = 0, plen, plen2;
        !          1071:        int pc;
        !          1072:        int pq, pd;
        !          1073:        int rmb;
        !          1074:        int evpd;
        !          1075:        int pg_tag;
        !          1076:        int i, j;
        !          1077: 
        !          1078:        if (alloc_len < 0xff) {
        !          1079:                return -1;
        !          1080:        }
        !          1081: 
        !          1082:        pq = 0x00;
        !          1083:        pd = SPC_PERIPHERAL_DEVICE_TYPE_DISK;
        !          1084:        rmb = 0;
        !          1085: 
        !          1086: #if 0
        !          1087:        LUI = istgt_uuid2uint64(&spec->uuid);
        !          1088: #else
        !          1089:        LUI = istgt_get_lui(spec->lu->name, spec->lun & 0xffffU);
        !          1090: #endif
        !          1091: 
        !          1092:        pc = cdb[2];
        !          1093:        evpd = BGET8(&cdb[1], 0);
        !          1094:        if (evpd) {
        !          1095:                /* Vital product data */
        !          1096:                switch (pc) {
        !          1097:                case SPC_VPD_SUPPORTED_VPD_PAGES:
        !          1098:                        /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
        !          1099:                        BDSET8W(&data[0], pq, 7, 3);
        !          1100:                        BDADD8W(&data[0], pd, 4, 5);
        !          1101:                        /* PAGE CODE */
        !          1102:                        data[1] = pc;
        !          1103:                        /* Reserved */
        !          1104:                        data[2] = 0;
        !          1105:                        /* PAGE LENGTH */
        !          1106:                        data[3] = 0;
        !          1107:                        hlen = 4;
        !          1108: 
        !          1109:                        data[4] = SPC_VPD_SUPPORTED_VPD_PAGES;      /* 0x00 */
        !          1110:                        data[5] = SPC_VPD_UNIT_SERIAL_NUMBER;       /* 0x80 */
        !          1111:                        data[6] = SPC_VPD_DEVICE_IDENTIFICATION;    /* 0x83 */
        !          1112:                        data[7] = SPC_VPD_MANAGEMENT_NETWORK_ADDRESSES; /* 0x85 */
        !          1113:                        data[8] = SPC_VPD_EXTENDED_INQUIRY_DATA;    /* 0x86 */
        !          1114:                        data[9] = SPC_VPD_MODE_PAGE_POLICY;         /* 0x87 */
        !          1115:                        data[10]= SPC_VPD_SCSI_PORTS;               /* 0x88 */
        !          1116:                        data[11]= 0xb0; /* SBC Block Limits */
        !          1117:                        data[12]= 0xb1; /* SBC Block Device Characteristics */
        !          1118:                        len = 13 - hlen;
        !          1119:                        if (spec->thin_provisioning) {
        !          1120:                                data[13]= 0xb2; /* SBC Thin Provisioning */
        !          1121:                                len++;
        !          1122:                        }
        !          1123: 
        !          1124:                        /* PAGE LENGTH */
        !          1125:                        data[3] = len;
        !          1126:                        break;
        !          1127: 
        !          1128:                case SPC_VPD_UNIT_SERIAL_NUMBER:
        !          1129:                        /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
        !          1130:                        BDSET8W(&data[0], pq, 7, 3);
        !          1131:                        BDADD8W(&data[0], pd, 4, 5);
        !          1132:                        /* PAGE CODE */
        !          1133:                        data[1] = pc;
        !          1134:                        /* Reserved */
        !          1135:                        data[2] = 0;
        !          1136:                        /* PAGE LENGTH */
        !          1137:                        data[3] = 0;
        !          1138:                        hlen = 4;
        !          1139: 
        !          1140:                        /* PRODUCT SERIAL NUMBER */
        !          1141:                        if (spec->lu->lun[spec->lun].serial != NULL) {
        !          1142:                                len = strlen(spec->lu->lun[spec->lun].serial);
        !          1143:                                if (len > MAX_LU_SERIAL_STRING) {
        !          1144:                                        len = MAX_LU_SERIAL_STRING;
        !          1145:                                }
        !          1146:                                istgt_strcpy_pad(&data[4], len,
        !          1147:                                    spec->lu->lun[spec->lun].serial, ' ');
        !          1148:                        } else {
        !          1149:                                len = strlen(spec->lu->inq_serial);
        !          1150:                                if (len > MAX_LU_SERIAL_STRING) {
        !          1151:                                        len = MAX_LU_SERIAL_STRING;
        !          1152:                                }
        !          1153:                                istgt_strcpy_pad(&data[4], len,
        !          1154:                                    spec->lu->inq_serial, ' ');
        !          1155:                        }
        !          1156: 
        !          1157:                        /* PAGE LENGTH */
        !          1158:                        data[3] = len;
        !          1159:                        break;
        !          1160: 
        !          1161:                case SPC_VPD_DEVICE_IDENTIFICATION:
        !          1162:                        /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
        !          1163:                        BDSET8W(&data[0], pq, 7, 3);
        !          1164:                        BDADD8W(&data[0], pd, 4, 5);
        !          1165:                        /* PAGE CODE */
        !          1166:                        data[1] = pc;
        !          1167:                        /* PAGE LENGTH */
        !          1168:                        DSET16(&data[2], 0);
        !          1169:                        hlen = 4;
        !          1170: 
        !          1171:                        /* Identification descriptor 1 */
        !          1172:                        /* Logical Unit */
        !          1173:                        cp = &data[hlen + len];
        !          1174: 
        !          1175:                        /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
        !          1176:                        BDSET8W(&cp[0], 0, 7, 4);
        !          1177:                        BDADD8W(&cp[0], SPC_VPD_CODE_SET_BINARY, 3, 4);
        !          1178:                        /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
        !          1179:                        BDSET8W(&cp[1], 0, 7, 1); /* PIV=0 */
        !          1180:                        BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_LOGICAL_UNIT, 5, 2);
        !          1181:                        BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_NAA, 3, 4);
        !          1182:                        /* Reserved */
        !          1183:                        cp[2] = 0;
        !          1184:                        /* IDENTIFIER LENGTH */
        !          1185:                        cp[3] = 0;
        !          1186: 
        !          1187:                        /* IDENTIFIER */
        !          1188: #if 0
        !          1189:                        /* 16bytes ID */
        !          1190:                        plen = istgt_lu_set_extid(&cp[4], 0, LUI);
        !          1191: #else
        !          1192:                        plen = istgt_lu_set_lid(&cp[4], LUI);
        !          1193: #endif
        !          1194: 
        !          1195:                        cp[3] = plen;
        !          1196:                        len += 4 + plen;
        !          1197: 
        !          1198:                        /* Identification descriptor 2 */
        !          1199:                        /* T10 VENDOR IDENTIFICATION */
        !          1200:                        cp = &data[hlen + len];
        !          1201: 
        !          1202:                        /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
        !          1203:                        BDSET8W(&cp[0], 0, 7, 4);
        !          1204:                        BDADD8W(&cp[0], SPC_VPD_CODE_SET_UTF8, 3, 4);
        !          1205:                        /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
        !          1206:                        BDSET8W(&cp[1], 0, 7, 1); /* PIV=0 */
        !          1207:                        BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_LOGICAL_UNIT, 5, 2);
        !          1208:                        BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_T10_VENDOR_ID, 3, 4);
        !          1209:                        /* Reserved */
        !          1210:                        cp[2] = 0;
        !          1211:                        /* IDENTIFIER LENGTH */
        !          1212:                        cp[3] = 0;
        !          1213: 
        !          1214:                        /* IDENTIFIER */
        !          1215:                        /* T10 VENDOR IDENTIFICATION */
        !          1216:                        istgt_strcpy_pad(&cp[4], 8, spec->lu->inq_vendor, ' ');
        !          1217:                        plen = 8;
        !          1218:                        /* VENDOR SPECIFIC IDENTIFIER */
        !          1219:                        /* PRODUCT IDENTIFICATION */
        !          1220:                        istgt_strcpy_pad(&cp[12], 16, spec->lu->inq_product, ' ');
        !          1221:                        /* PRODUCT SERIAL NUMBER */
        !          1222:                        if (spec->lu->lun[spec->lun].serial != NULL) {
        !          1223:                                istgt_strcpy_pad(&cp[28], MAX_LU_SERIAL_STRING,
        !          1224:                                    spec->lu->lun[spec->lun].serial, ' ');
        !          1225:                        } else {
        !          1226:                                istgt_strcpy_pad(&cp[28], MAX_LU_SERIAL_STRING,
        !          1227:                                    spec->lu->inq_serial, ' ');
        !          1228:                        }
        !          1229:                        plen += 16 + MAX_LU_SERIAL_STRING;
        !          1230: 
        !          1231:                        cp[3] = plen;
        !          1232:                        len += 4 + plen;
        !          1233: 
        !          1234:                        /* Identification descriptor 3 */
        !          1235:                        /* Target Device */
        !          1236:                        cp = &data[hlen + len];
        !          1237: 
        !          1238:                        /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
        !          1239:                        BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4);
        !          1240:                        BDADD8W(&cp[0], SPC_VPD_CODE_SET_UTF8, 3, 4);
        !          1241:                        /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
        !          1242:                        BDSET8W(&cp[1], 1, 7, 1); /* PIV */
        !          1243:                        BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_TARGET_DEVICE, 5, 2);
        !          1244:                        BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_SCSI_NAME, 3, 4);
        !          1245:                        /* Reserved */
        !          1246:                        cp[2] = 0;
        !          1247:                        /* IDENTIFIER LENGTH */
        !          1248:                        cp[3] = 0;
        !          1249: 
        !          1250:                        /* IDENTIFIER */
        !          1251:                        plen = snprintf((char *) &cp[4], MAX_TARGET_NAME,
        !          1252:                            "%s",
        !          1253:                            spec->lu->name);
        !          1254:                        cp[3] = plen;
        !          1255:                        len += 4 + plen;
        !          1256: 
        !          1257:                        /* Identification descriptor 4 */
        !          1258:                        /* Target Port */
        !          1259:                        cp = &data[hlen + len];
        !          1260: 
        !          1261:                        /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
        !          1262:                        BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4);
        !          1263:                        BDADD8W(&cp[0], SPC_VPD_CODE_SET_UTF8, 3, 4);
        !          1264:                        /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
        !          1265:                        BDSET8W(&cp[1], 1, 7, 1); /* PIV */
        !          1266:                        BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_TARGET_PORT, 5, 2);
        !          1267:                        BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_SCSI_NAME, 3, 4);
        !          1268:                        /* Reserved */
        !          1269:                        cp[2] = 0;
        !          1270:                        /* IDENTIFIER LENGTH */
        !          1271:                        cp[3] = 0;
        !          1272: 
        !          1273:                        /* IDENTIFIER */
        !          1274:                        plen = snprintf((char *) &cp[4], MAX_TARGET_NAME,
        !          1275:                            "%s"",t,0x""%4.4x",
        !          1276:                            spec->lu->name,
        !          1277:                            conn->portal.tag);
        !          1278:                        cp[3] = plen;
        !          1279:                        len += 4 + plen;
        !          1280: 
        !          1281:                        /* Identification descriptor 5 */
        !          1282:                        /* Relative Target Port */
        !          1283:                        cp = &data[hlen + len];
        !          1284: 
        !          1285:                        /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
        !          1286:                        BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4);
        !          1287:                        BDADD8W(&cp[0], SPC_VPD_CODE_SET_BINARY, 3, 4);
        !          1288:                        /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
        !          1289:                        BDSET8W(&cp[1], 1, 7, 1); /* PIV */
        !          1290:                        BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_TARGET_PORT, 5, 2);
        !          1291:                        BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_RELATIVE_TARGET_PORT,
        !          1292:                            3, 4);
        !          1293:                        /* Reserved */
        !          1294:                        cp[2] = 0;
        !          1295:                        /* IDENTIFIER LENGTH */
        !          1296:                        cp[3] = 0;
        !          1297: 
        !          1298:                        /* IDENTIFIER */
        !          1299:                        /* Obsolete */
        !          1300:                        DSET16(&cp[4], 0);
        !          1301:                        /* Relative Target Port Identifier */
        !          1302:                        //DSET16(&cp[6], 1); /* port1 as port A */
        !          1303:                        //DSET16(&cp[6], 2); /* port2 as port B */
        !          1304:                        DSET16(&cp[6], (uint16_t) (1 + conn->portal.idx));
        !          1305:                        plen = 4;
        !          1306: 
        !          1307:                        cp[3] = plen;
        !          1308:                        len += 4 + plen;
        !          1309: 
        !          1310:                        /* Identification descriptor 6 */
        !          1311:                        /* Target port group */
        !          1312:                        cp = &data[hlen + len];
        !          1313: 
        !          1314:                        /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
        !          1315:                        BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4);
        !          1316:                        BDADD8W(&cp[0], SPC_VPD_CODE_SET_BINARY, 3, 4);
        !          1317:                        /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
        !          1318:                        BDSET8W(&cp[1], 1, 7, 1); /* PIV */
        !          1319:                        BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_TARGET_PORT, 5, 2);
        !          1320:                        BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_TARGET_PORT_GROUP,
        !          1321:                            3, 4);
        !          1322:                        /* Reserved */
        !          1323:                        cp[2] = 0;
        !          1324:                        /* IDENTIFIER LENGTH */
        !          1325:                        cp[3] = 0;
        !          1326: 
        !          1327:                        /* IDENTIFIER */
        !          1328:                        /* Reserved */
        !          1329:                        DSET16(&cp[4], 0);
        !          1330:                        /* TARGET PORT GROUP */
        !          1331:                        DSET16(&cp[6], (uint16_t) (conn->portal.tag));
        !          1332:                        plen = 4;
        !          1333: 
        !          1334:                        cp[3] = plen;
        !          1335:                        len += 4 + plen;
        !          1336: 
        !          1337:                        /* Identification descriptor 7 */
        !          1338:                        /* Logical unit group */
        !          1339:                        cp = &data[hlen + len];
        !          1340: 
        !          1341:                        /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
        !          1342:                        BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4);
        !          1343:                        BDADD8W(&cp[0], SPC_VPD_CODE_SET_BINARY, 3, 4);
        !          1344:                        /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
        !          1345:                        BDSET8W(&cp[1], 1, 7, 1); /* PIV */
        !          1346:                        BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_TARGET_PORT, 5, 2);
        !          1347:                        BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_LOGICAL_UNIT_GROUP,
        !          1348:                            3, 4);
        !          1349:                        /* Reserved */
        !          1350:                        cp[2] = 0;
        !          1351:                        /* IDENTIFIER LENGTH */
        !          1352:                        cp[3] = 0;
        !          1353: 
        !          1354:                        /* IDENTIFIER */
        !          1355:                        /* Reserved */
        !          1356:                        DSET16(&cp[4], 0);
        !          1357:                        /* LOGICAL UNIT GROUP */
        !          1358:                        DSET16(&cp[6], (uint16_t) (spec->lu->num));
        !          1359:                        plen = 4;
        !          1360: 
        !          1361:                        cp[3] = plen;
        !          1362:                        len += 4 + plen;
        !          1363: 
        !          1364:                        /* PAGE LENGTH */
        !          1365:                        if (len > 0xffff) {
        !          1366:                                len = 0xffff;
        !          1367:                        }
        !          1368:                        DSET16(&data[2], len);
        !          1369:                        break;
        !          1370: 
        !          1371:                case SPC_VPD_EXTENDED_INQUIRY_DATA:
        !          1372:                        /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
        !          1373:                        BDSET8W(&data[0], pq, 7, 3);
        !          1374:                        BDADD8W(&data[0], pd, 4, 5);
        !          1375:                        /* PAGE CODE */
        !          1376:                        data[1] = pc;
        !          1377:                        /* Reserved */
        !          1378:                        data[2] = 0;
        !          1379:                        /* PAGE LENGTH */
        !          1380:                        data[3] = 0;
        !          1381:                        hlen = 4;
        !          1382: 
        !          1383:                        /* RTO(3) GRD_CHK(2) APP_CHK(1) REF_CHK(0) */
        !          1384:                        data[4] = 0;
        !          1385:                        /* GROUP_SUP(4) PRIOR_SUP(3) HEADSUP(2) ORDSUP(1) SIMPSUP(0) */
        !          1386:                        data[5] = 0;
        !          1387:                        if (spec->queue_depth != 0) {
        !          1388:                                BDADD8(&data[5], 1, 2);     /* HEADSUP */
        !          1389:                                //BDADD8(&data[5], 1, 1);     /* ORDSUP */
        !          1390:                                BDADD8(&data[5], 1, 0);     /* SIMPSUP */
        !          1391:                        }
        !          1392:                        /* NV_SUP(1) V_SUP(0) */
        !          1393:                        data[6] = 0;
        !          1394:                        /* Reserved[7-63] */
        !          1395:                        memset(&data[7], 0, (64 - 7));
        !          1396:                        len = 64 - hlen;
        !          1397: 
        !          1398:                        /* PAGE LENGTH */
        !          1399:                        data[3] = len;
        !          1400:                        break;
        !          1401: 
        !          1402:                case SPC_VPD_MANAGEMENT_NETWORK_ADDRESSES:
        !          1403:                        /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
        !          1404:                        BDSET8W(&data[0], pq, 7, 3);
        !          1405:                        BDADD8W(&data[0], pd, 4, 5);
        !          1406:                        /* PAGE CODE */
        !          1407:                        data[1] = pc;
        !          1408:                        /* PAGE LENGTH */
        !          1409:                        DSET16(&data[2], 0);
        !          1410:                        hlen = 4;
        !          1411: 
        !          1412: #if 0
        !          1413:                        /* Network services descriptor N */
        !          1414:                        cp = &data[hlen + len];
        !          1415: 
        !          1416:                        /* ASSOCIATION(6-5) SERVICE TYPE(4-0) */
        !          1417:                        BDSET8W(&cp[0], 0x00, 6, 2);
        !          1418:                        BDADD8W(&cp[0], 0x00, 4, 5);
        !          1419:                        /* Reserved */
        !          1420:                        cp[1] = 0;
        !          1421:                        /* NETWORK ADDRESS LENGTH */
        !          1422:                        DSET16(&cp[2], 0);
        !          1423:                        /* NETWORK ADDRESS */
        !          1424:                        cp[4] = 0;
        !          1425:                        /* ... */
        !          1426:                        plen = 0;
        !          1427:                        DSET16(&cp[2], plen);
        !          1428:                        len += 4 + plen;
        !          1429: #endif
        !          1430: 
        !          1431:                        /* PAGE LENGTH */
        !          1432:                        if (len > 0xffff) {
        !          1433:                                len = 0xffff;
        !          1434:                        }
        !          1435:                        DSET16(&data[2], len);
        !          1436:                        break;
        !          1437: 
        !          1438:                case SPC_VPD_MODE_PAGE_POLICY:
        !          1439:                        /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
        !          1440:                        BDSET8W(&data[0], pq, 7, 3);
        !          1441:                        BDADD8W(&data[0], pd, 4, 5);
        !          1442:                        /* PAGE CODE */
        !          1443:                        data[1] = pc;
        !          1444:                        /* PAGE LENGTH */
        !          1445:                        DSET16(&data[2], 0);
        !          1446:                        hlen = 4;
        !          1447: 
        !          1448:                        /* Mode page policy descriptor 1 */
        !          1449:                        cp = &data[hlen + len];
        !          1450: 
        !          1451:                        /* POLICY PAGE CODE(5-0) */
        !          1452:                        BDSET8W(&cp[0], 0x3f, 5, 6);    /* all page code */
        !          1453:                        /* POLICY SUBPAGE CODE */
        !          1454:                        cp[1] = 0xff;                   /* all sub page */
        !          1455:                        /* MLUS(7) MODE PAGE POLICY(1-0) */
        !          1456:                        //BDSET8(&cp[2], 1, 7); /* multiple logical units share */
        !          1457:                        BDSET8(&cp[2], 0, 7); /* own copy */
        !          1458:                        BDADD8W(&cp[2], 0x00, 1, 2); /* Shared */
        !          1459:                        //BDADD8W(&cp[2], 0x01, 1, 2); /* Per target port */
        !          1460:                        //BDADD8W(&cp[2], 0x02, 1, 2); /* Per initiator port */
        !          1461:                        //BDADD8W(&cp[2], 0x03, 1, 2); /* Per I_T nexus */
        !          1462:                        /* Reserved */
        !          1463:                        cp[3] = 0;
        !          1464:                        len += 4;
        !          1465: 
        !          1466:                        /* PAGE LENGTH */
        !          1467:                        if (len > 0xffff) {
        !          1468:                                len = 0xffff;
        !          1469:                        }
        !          1470:                        DSET16(&data[2], len);
        !          1471:                        break;
        !          1472: 
        !          1473:                case SPC_VPD_SCSI_PORTS:
        !          1474:                        /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
        !          1475:                        BDSET8W(&data[0], pq, 7, 3);
        !          1476:                        BDADD8W(&data[0], pd, 4, 5);
        !          1477:                        /* PAGE CODE */
        !          1478:                        data[1] = pc;
        !          1479:                        /* PAGE LENGTH */
        !          1480:                        DSET16(&data[2], 0);
        !          1481:                        hlen = 4;
        !          1482: 
        !          1483:                        /* Identification descriptor list */
        !          1484:                        for (i = 0; i < spec->lu->maxmap; i++) {
        !          1485:                                pg_tag = spec->lu->map[i].pg_tag;
        !          1486:                                /* skip same pg_tag */
        !          1487:                                for (j = 0; j < i; j++) {
        !          1488:                                        if (spec->lu->map[j].pg_tag == pg_tag) {
        !          1489:                                                goto skip_pg_tag;
        !          1490:                                        }
        !          1491:                                }
        !          1492: 
        !          1493:                                /* Identification descriptor N */
        !          1494:                                cp = &data[hlen + len];
        !          1495: 
        !          1496:                                /* Reserved */
        !          1497:                                DSET16(&cp[0], 0);
        !          1498:                                /* RELATIVE PORT IDENTIFIER */
        !          1499:                                DSET16(&cp[2], (uint16_t) (1 + pg_tag));
        !          1500:                                /* Reserved */
        !          1501:                                DSET16(&cp[4], 0);
        !          1502:                                /* INITIATOR PORT TRANSPORTID LENGTH */
        !          1503:                                DSET16(&cp[6], 0);
        !          1504:                                /* Reserved */
        !          1505:                                DSET16(&cp[8], 0);
        !          1506:                                /* TARGET PORT DESCRIPTORS LENGTH */
        !          1507:                                DSET16(&cp[10], 0);
        !          1508:                                len += 12;
        !          1509: 
        !          1510:                                plen2 = 0;
        !          1511:                                /* Target port descriptor 1 */
        !          1512:                                cp2 = &data[hlen + len + plen2];
        !          1513: 
        !          1514:                                /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
        !          1515:                                BDSET8W(&cp2[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4);
        !          1516:                                BDADD8W(&cp2[0], SPC_VPD_CODE_SET_UTF8, 3, 4);
        !          1517:                                /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
        !          1518:                                BDSET8W(&cp2[1], 1, 7, 1); /* PIV */
        !          1519:                                BDADD8W(&cp2[1], SPC_VPD_ASSOCIATION_TARGET_PORT, 5, 2);
        !          1520:                                BDADD8W(&cp2[1], SPC_VPD_IDENTIFIER_TYPE_SCSI_NAME, 3, 4);
        !          1521:                                /* Reserved */
        !          1522:                                cp2[2] = 0;
        !          1523:                                /* IDENTIFIER LENGTH */
        !          1524:                                cp2[3] = 0;
        !          1525: 
        !          1526:                                /* IDENTIFIER */
        !          1527:                                plen = snprintf((char *) &cp2[4], MAX_TARGET_NAME,
        !          1528:                                    "%s"",t,0x""%4.4x",
        !          1529:                                    spec->lu->name,
        !          1530:                                    pg_tag);
        !          1531:                                cp2[3] = plen;
        !          1532:                                plen2 += 4 + plen;
        !          1533: 
        !          1534:                                /* TARGET PORT DESCRIPTORS LENGTH */
        !          1535:                                DSET16(&cp[10], plen2);
        !          1536:                                len += plen2;
        !          1537:                        skip_pg_tag:
        !          1538:                                ;
        !          1539:                        }
        !          1540: 
        !          1541:                        /* PAGE LENGTH */
        !          1542:                        if (len > 0xffff) {
        !          1543:                                len = 0xffff;
        !          1544:                        }
        !          1545:                        DSET16(&data[2], len);
        !          1546:                        break;
        !          1547: 
        !          1548:                case 0xb0: /* SBC Block Limits */
        !          1549:                        /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
        !          1550:                        BDSET8W(&data[0], pq, 7, 3);
        !          1551:                        BDADD8W(&data[0], pd, 4, 5);
        !          1552:                        /* PAGE CODE */
        !          1553:                        data[1] = pc;
        !          1554:                        /* PAGE LENGTH */
        !          1555:                        DSET16(&data[2], 0);
        !          1556:                        hlen = 4;
        !          1557: 
        !          1558:                        /* WSNZ(0) */
        !          1559:                        BDSET8(&data[4], 0, 0); /* support zero length in WRITE SAME */
        !          1560:                        /* MAXIMUM COMPARE AND WRITE LENGTH */
        !          1561:                        blocks = ISTGT_LU_WORK_BLOCK_SIZE / (uint32_t) spec->blocklen;
        !          1562:                        if (blocks > 0xff) {
        !          1563:                                blocks = 0xff;
        !          1564:                        }
        !          1565:                        data[5] = (uint8_t) blocks;
        !          1566:                        if (spec->lu->istgt->swmode == ISTGT_SWMODE_TRADITIONAL) {
        !          1567:                                /* no support compare and write */
        !          1568:                                data[5] = 0;
        !          1569:                        }
        !          1570: 
        !          1571:                        /* force align to 4KB */
        !          1572:                        if (spec->blocklen < 4096) {
        !          1573:                                blocks = 4096 / (uint32_t) spec->blocklen;
        !          1574:                                /* OPTIMAL TRANSFER LENGTH GRANULARITY */
        !          1575:                                DSET16(&data[6], blocks);
        !          1576:                                /* MAXIMUM TRANSFER LENGTH */
        !          1577:                                DSET32(&data[8], 0); /* no limit */
        !          1578:                                /* OPTIMAL TRANSFER LENGTH */
        !          1579:                                blocks = ISTGT_LU_WORK_BLOCK_SIZE / (uint32_t) spec->blocklen;
        !          1580:                                DSET32(&data[12], blocks);
        !          1581:                                /* MAXIMUM PREFETCH XDREAD XDWRITE TRANSFER LENGTH */
        !          1582:                                DSET32(&data[16], 0);
        !          1583:                        } else {
        !          1584:                                blocks = 1;
        !          1585:                                /* OPTIMAL TRANSFER LENGTH GRANULARITY */
        !          1586:                                DSET16(&data[6], blocks);
        !          1587:                                /* MAXIMUM TRANSFER LENGTH */
        !          1588:                                DSET32(&data[8], 0); /* no limit */
        !          1589:                                /* OPTIMAL TRANSFER LENGTH */
        !          1590:                                blocks = ISTGT_LU_WORK_BLOCK_SIZE / (uint32_t) spec->blocklen;
        !          1591:                                DSET32(&data[12], blocks);
        !          1592:                                /* MAXIMUM PREFETCH XDREAD XDWRITE TRANSFER LENGTH */
        !          1593:                                DSET32(&data[16], 0);
        !          1594:                        }
        !          1595:                        len = 20 - hlen;
        !          1596: 
        !          1597:                        if (1 || spec->thin_provisioning) {
        !          1598:                                /* MAXIMUM UNMAP LBA COUNT */
        !          1599:                                DSET32(&data[20], 0); /* not implement UNMAP */
        !          1600:                                /* MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT */
        !          1601:                                DSET32(&data[24], 0); /* not implement UNMAP */
        !          1602:                                /* OPTIMAL UNMAP GRANULARITY */
        !          1603:                                DSET32(&data[28], 0); /* not specified */
        !          1604:                                /* UNMAP GRANULARITY ALIGNMENT */
        !          1605:                                DSET32(&data[32], (0 & 0x7fffffffU));
        !          1606:                                /* UGAVALID(7) */
        !          1607:                                BDADD8(&data[32], 0, 7); /* not valid ALIGNMENT */
        !          1608:                                /* MAXIMUM WRITE SAME LENGTH */
        !          1609:                                DSET64(&data[36], 0); /* no limit */
        !          1610:                                /* Reserved */
        !          1611:                                memset(&data[44], 0x00, 64-44);
        !          1612:                                len = 64 - hlen;
        !          1613:                        }
        !          1614: 
        !          1615:                        DSET16(&data[2], len);
        !          1616:                        break;
        !          1617: 
        !          1618:                case 0xb1: /* SBC Block Device Characteristics */
        !          1619:                        /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
        !          1620:                        BDSET8W(&data[0], pq, 7, 3);
        !          1621:                        BDADD8W(&data[0], pd, 4, 5);
        !          1622:                        /* PAGE CODE */
        !          1623:                        data[1] = pc;
        !          1624:                        /* PAGE LENGTH */
        !          1625:                        DSET16(&data[2], 0);
        !          1626:                        hlen = 4;
        !          1627: 
        !          1628:                        /* MEDIUM ROTATION RATE */
        !          1629:                        //DSET16(&data[4], 0x0000); /* not reported */
        !          1630:                        //DSET16(&data[4], 0x0001); /* Non-rotating medium (solid state) */
        !          1631:                        //DSET16(&data[4], 5400); /* rotation rate (5400rpm) */
        !          1632:                        //DSET16(&data[4], 7200); /* rotation rate (7200rpm) */
        !          1633:                        //DSET16(&data[4], 10000); /* rotation rate (10000rpm) */
        !          1634:                        //DSET16(&data[4], 15000); /* rotation rate (15000rpm) */
        !          1635:                        DSET16(&data[4], spec->lu->lun[spec->lun].rotationrate);
        !          1636:                        /* Reserved */
        !          1637:                        data[6] = 0;
        !          1638:                        /* NOMINAL FORM FACTOR(3-0) */
        !          1639:                        //BDSET8W(&data[7], 0x00, 3, 4); /* not reported */
        !          1640:                        //BDSET8W(&data[7], 0x01, 3, 4); /* 5.25 inch */
        !          1641:                        //BDSET8W(&data[7], 0x02, 3, 4); /* 3.5 inch */
        !          1642:                        //BDSET8W(&data[7], 0x03, 3, 4); /* 2.5 inch */
        !          1643:                        //BDSET8W(&data[7], 0x04, 3, 4); /* 1.8 inch */
        !          1644:                        //BDSET8W(&data[7], 0x05, 3, 4); /* less 1.8 inch */
        !          1645:                        BDSET8W(&data[7], spec->lu->lun[spec->lun].formfactor, 3, 4);
        !          1646:                        /* Reserved */
        !          1647:                        memset(&data[8], 0x00, 64-8);
        !          1648: 
        !          1649:                        len = 64 - hlen;
        !          1650:                        DSET16(&data[2], len);
        !          1651:                        break;
        !          1652: 
        !          1653:                case 0xb2: /* SBC Thin Provisioning */
        !          1654:                        if (!spec->thin_provisioning) {
        !          1655:                                ISTGT_ERRLOG("unsupported INQUIRY VPD page 0x%x\n", pc);
        !          1656:                                return -1;
        !          1657:                        }
        !          1658: 
        !          1659:                        /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
        !          1660:                        BDSET8W(&data[0], pq, 7, 3);
        !          1661:                        BDADD8W(&data[0], pd, 4, 5);
        !          1662:                        /* PAGE CODE */
        !          1663:                        data[1] = pc;
        !          1664:                        /* PAGE LENGTH */
        !          1665:                        DSET16(&data[2], 0);
        !          1666:                        hlen = 4;
        !          1667: 
        !          1668:                        /* THRESHOLD EXPONENT */
        !          1669:                        data[4] = 0;
        !          1670:                        /* DP(0) */
        !          1671:                        BDSET8(&data[5], 0, 0);
        !          1672:                        /* Reserved */
        !          1673:                        DSET16(&data[6], 0);
        !          1674:                        len = 6 - hlen;
        !          1675: #if 0
        !          1676:                        /* XXX not yet */
        !          1677:                        /* PROVISIONING GROUP DESCRIPTOR ... */
        !          1678:                        DSET16(&data[8], 0);
        !          1679:                        len = 8 - hlen;
        !          1680: #endif
        !          1681: 
        !          1682:                        DSET16(&data[2], len);
        !          1683:                        break;
        !          1684: 
        !          1685:                default:
        !          1686:                        if (pc >= 0xc0 && pc <= 0xff) {
        !          1687:                                ISTGT_WARNLOG("Vendor specific INQUIRY VPD page 0x%x\n", pc);
        !          1688:                        } else {
        !          1689:                                ISTGT_ERRLOG("unsupported INQUIRY VPD page 0x%x\n", pc);
        !          1690:                        }
        !          1691:                        return -1;
        !          1692:                }
        !          1693:        } else {
        !          1694:                /* Standard INQUIRY data */
        !          1695:                /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
        !          1696:                BDSET8W(&data[0], pq, 7, 3);
        !          1697:                BDADD8W(&data[0], pd, 4, 5);
        !          1698:                /* RMB(7) */
        !          1699:                BDSET8W(&data[1], rmb, 7, 1);
        !          1700:                /* VERSION */
        !          1701:                /* See SPC3/SBC2/MMC4/SAM2 for more details */
        !          1702:                data[2] = SPC_VERSION_SPC3;
        !          1703:                /* NORMACA(5) HISUP(4) RESPONSE DATA FORMAT(3-0) */
        !          1704:                BDSET8W(&data[3], 2, 3, 4);             /* format 2 */
        !          1705:                BDADD8(&data[1], 1, 4);         /* hierarchical support */
        !          1706:                /* ADDITIONAL LENGTH */
        !          1707:                data[4] = 0;
        !          1708:                hlen = 5;
        !          1709: 
        !          1710:                /* SCCS(7) ACC(6) TPGS(5-4) 3PC(3) PROTECT(0) */
        !          1711:                data[5] = 0;
        !          1712:                //BDADD8W(&data[5], 1, 7, 1); /* storage array controller */
        !          1713:                BDADD8W(&data[5], 0x00, 5, 2); /* Not support TPGS */
        !          1714:                //BDADD8W(&data[5], 0x01, 5, 2); /* Only implicit */
        !          1715:                //BDADD8W(&data[5], 0x02, 5, 2); /* Only explicit */
        !          1716:                //BDADD8W(&data[5], 0x03, 5, 2); /* Both explicit and implicit */
        !          1717:                /* BQUE(7) ENCSERV(6) VS(5) MULTIP(4) MCHNGR(3) ADDR16(0) */
        !          1718:                data[6] = 0;
        !          1719:                BDADD8W(&data[6], 1, 4, 1); /* MULTIP */
        !          1720:                /* WBUS16(5) SYNC(4) LINKED(3) CMDQUE(1) VS(0) */
        !          1721:                data[7] = 0;
        !          1722:                if (spec->queue_depth != 0) {
        !          1723:                        BDADD8(&data[7], 1, 1);     /* CMDQUE */
        !          1724:                }
        !          1725:                /* T10 VENDOR IDENTIFICATION */
        !          1726:                istgt_strcpy_pad(&data[8], 8, spec->lu->inq_vendor, ' ');
        !          1727:                /* PRODUCT IDENTIFICATION */
        !          1728:                istgt_strcpy_pad(&data[16], 16, spec->lu->inq_product, ' ');
        !          1729:                /* PRODUCT REVISION LEVEL */
        !          1730:                istgt_strcpy_pad(&data[32], 4, spec->lu->inq_revision, ' ');
        !          1731:                /* Vendor specific */
        !          1732:                memset(&data[36], 0x20, 20);
        !          1733:                /* CLOCKING(3-2) QAS(1) IUS(0) */
        !          1734:                data[56] = 0;
        !          1735:                /* Reserved */
        !          1736:                data[57] = 0;
        !          1737:                /* VERSION DESCRIPTOR 1-8 */
        !          1738:                DSET16(&data[58], 0x0960); /* iSCSI (no version claimed) */
        !          1739:                DSET16(&data[60], 0x0300); /* SPC-3 (no version claimed) */
        !          1740:                DSET16(&data[62], 0x0320); /* SBC-2 (no version claimed) */
        !          1741:                DSET16(&data[64], 0x0040); /* SAM-2 (no version claimed) */
        !          1742:                DSET16(&data[66], 0x0000);
        !          1743:                DSET16(&data[68], 0x0000);
        !          1744:                DSET16(&data[70], 0x0000);
        !          1745:                DSET16(&data[72], 0x0000);
        !          1746:                /* Reserved[74-95] */
        !          1747:                memset(&data[74], 0, (96 - 74));
        !          1748:                /* Vendor specific parameters[96-n] */
        !          1749:                //data[96] = 0;
        !          1750:                len = 96 - hlen;
        !          1751: 
        !          1752:                /* ADDITIONAL LENGTH */
        !          1753:                data[4] = len;
        !          1754:        }
        !          1755: 
        !          1756:        return hlen + len;
        !          1757: }
        !          1758: 
        !          1759: #define MODE_SENSE_PAGE_INIT(B,L,P,SP)                                 \
        !          1760:        do {                                                            \
        !          1761:                memset((B), 0, (L));                                    \
        !          1762:                if ((SP) != 0x00) {                                     \
        !          1763:                        (B)[0] = (P) | 0x40; /* PAGE + SPF=1 */         \
        !          1764:                        (B)[1] = (SP);                                  \
        !          1765:                        DSET16(&(B)[2], (L) - 4);                       \
        !          1766:                } else {                                                \
        !          1767:                        (B)[0] = (P);                                   \
        !          1768:                        (B)[1] = (L) - 2;                               \
        !          1769:                }                                                       \
        !          1770:        } while (0)
        !          1771: 
        !          1772: static int
        !          1773: istgt_lu_disk_scsi_mode_sense_page(ISTGT_LU_DISK *spec, CONN_Ptr conn, uint8_t *cdb, int pc, int page, int subpage, uint8_t *data, int alloc_len)
        !          1774: {
        !          1775:        uint8_t *cp;
        !          1776:        int len = 0;
        !          1777:        int plen;
        !          1778:        int rc;
        !          1779:        int i;
        !          1780: 
        !          1781: #if 0
        !          1782:        printf("pc=%d, page=%2.2x, subpage=%2.2x\n", pc, page, subpage);
        !          1783: #endif
        !          1784: #if 0
        !          1785:        ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE: pc=%d, page=%2.2x, subpage=%2.2x\n", pc, page, subpage);
        !          1786: #endif
        !          1787: 
        !          1788:        if (pc == 0x00) {
        !          1789:                /* Current values */
        !          1790:        } else if (pc == 0x01) {
        !          1791:                /* Changeable values */
        !          1792:                if (page != 0x08) {
        !          1793:                        /* not supported */
        !          1794:                        return 0;
        !          1795:                }
        !          1796:        } else if (pc == 0x02) {
        !          1797:                /* Default values */
        !          1798:        } else {
        !          1799:                /* Saved values */
        !          1800:        }
        !          1801: 
        !          1802:        cp = &data[len];
        !          1803:        switch (page) {
        !          1804:        case 0x00:
        !          1805:                /* Vendor specific */
        !          1806:                break;
        !          1807:        case 0x01:
        !          1808:                /* Read-Write Error Recovery */
        !          1809:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Read-Write Error Recovery\n");
        !          1810:                if (subpage != 0x00)
        !          1811:                        break;
        !          1812:                plen = 0x0a + 2;
        !          1813:                MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
        !          1814:                len += plen;
        !          1815:                break;
        !          1816:        case 0x02:
        !          1817:                /* Disconnect-Reconnect */
        !          1818:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Disconnect-Reconnect\n");
        !          1819:                if (subpage != 0x00)
        !          1820:                        break;
        !          1821:                plen = 0x0e + 2;
        !          1822:                MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
        !          1823:                len += plen;
        !          1824:                break;
        !          1825:        case 0x03:
        !          1826:                /* Obsolete (Format Device) */
        !          1827:                break;
        !          1828:        case 0x04:
        !          1829:                /* Obsolete (Rigid Disk Geometry) */
        !          1830:                break;
        !          1831:        case 0x05:
        !          1832:                /* Obsolete (Rigid Disk Geometry) */
        !          1833:                break;
        !          1834:        case 0x06:
        !          1835:                /* Reserved */
        !          1836:                break;
        !          1837:        case 0x07:
        !          1838:                /* Verify Error Recovery */
        !          1839:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Verify Error Recovery\n");
        !          1840:                if (subpage != 0x00)
        !          1841:                        break;
        !          1842:                plen = 0x0a + 2;
        !          1843:                MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
        !          1844:                len += plen;
        !          1845:                break;
        !          1846:        case 0x08:
        !          1847:                /* Caching */
        !          1848:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Caching\n");
        !          1849:                if (subpage != 0x00)
        !          1850:                        break;
        !          1851: 
        !          1852:                plen = 0x12 + 2;
        !          1853:                MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
        !          1854:                BDADD8(&cp[0], 1, 7); /* PS */
        !          1855:                BDADD8(&cp[2], 1, 2); /* WCE */
        !          1856:                //BDADD8(&cp[2], 1, 0); /* RCD */
        !          1857:                {
        !          1858:                        int fd;
        !          1859:                        fd = spec->fd;
        !          1860:                        rc = fcntl(fd , F_GETFL, 0);
        !          1861:                        if (rc != -1 && !(rc & O_FSYNC)) {
        !          1862:                                BDADD8(&cp[2], 1, 2); /* WCE=1 */
        !          1863:                        } else {
        !          1864:                                BDADD8(&cp[2], 0, 2); /* WCE=0 */
        !          1865:                        }
        !          1866:                }
        !          1867:                if (spec->read_cache == 0) {
        !          1868:                        BDADD8(&cp[2], 1, 0); /* RCD=1 */
        !          1869:                } else {
        !          1870:                        BDADD8(&cp[2], 0, 0); /* RCD=0 */
        !          1871:                }
        !          1872:                len += plen;
        !          1873:                break;
        !          1874:        case 0x09:
        !          1875:                /* Obsolete */
        !          1876:                break;
        !          1877:        case 0x0a:
        !          1878:                switch (subpage) {
        !          1879:                case 0x00:
        !          1880:                        /* Control */
        !          1881:                        ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Control\n");
        !          1882:                        plen = 0x0a + 2;
        !          1883:                        MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
        !          1884:                        len += plen;
        !          1885:                        break;
        !          1886:                case 0x01:
        !          1887:                        /* Control Extension */
        !          1888:                        ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Control Extension\n");
        !          1889:                        plen = 0x1c + 4;
        !          1890:                        MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
        !          1891:                        len += plen;
        !          1892:                        break;
        !          1893:                case 0xff:
        !          1894:                        /* All subpages */
        !          1895:                        len += istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, page, 0x00, &data[len], alloc_len);
        !          1896:                        len += istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, page, 0x01, &data[len], alloc_len);
        !          1897:                        break;
        !          1898:                default:
        !          1899:                        /* 0x02-0x3e: Reserved */
        !          1900:                        break;
        !          1901:                }
        !          1902:                break;
        !          1903:        case 0x0b:
        !          1904:                /* Obsolete (Medium Types Supported) */
        !          1905:                break;
        !          1906:        case 0x0c:
        !          1907:                /* Obsolete (Notch And Partitio) */
        !          1908:                break;
        !          1909:        case 0x0d:
        !          1910:                /* Obsolete */
        !          1911:                break;
        !          1912:        case 0x0e:
        !          1913:        case 0x0f:
        !          1914:                /* Reserved */
        !          1915:                break;
        !          1916:        case 0x10:
        !          1917:                /* XOR Control */
        !          1918:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE XOR Control\n");
        !          1919:                if (subpage != 0x00)
        !          1920:                        break;
        !          1921:                plen = 0x16 + 2;
        !          1922:                MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
        !          1923:                len += plen;
        !          1924:                break;
        !          1925:        case 0x11:
        !          1926:        case 0x12:
        !          1927:        case 0x13:
        !          1928:                /* Reserved */
        !          1929:                break;
        !          1930:        case 0x14:
        !          1931:                /* Enclosure Services Management */
        !          1932:                break;
        !          1933:        case 0x15:
        !          1934:        case 0x16:
        !          1935:        case 0x17:
        !          1936:                /* Reserved */
        !          1937:                break;
        !          1938:        case 0x18:
        !          1939:                /* Protocol-Specific LUN */
        !          1940: #if 0
        !          1941:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Protocol-Specific LUN\n");
        !          1942:                if (subpage != 0x00)
        !          1943:                        break;
        !          1944:                plen = 0x04 + 0x00 + 2;
        !          1945:                MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
        !          1946:                len += plen;
        !          1947: #endif
        !          1948:                break;
        !          1949:        case 0x19:
        !          1950:                /* Protocol-Specific Port */
        !          1951: #if 0
        !          1952:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Protocol-Specific Port\n");
        !          1953:                if (subpage != 0x00)
        !          1954:                        break;
        !          1955:                plen = 0x04 + 0x00 + 2;
        !          1956:                MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
        !          1957:                len += plen;
        !          1958: #endif
        !          1959:                break;
        !          1960:        case 0x1a:
        !          1961:                /* Power Condition */
        !          1962:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Power Condition\n");
        !          1963:                if (subpage != 0x00)
        !          1964:                        break;
        !          1965:                plen = 0x0a + 2;
        !          1966:                MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
        !          1967:                len += plen;
        !          1968:                break;
        !          1969:        case 0x1b:
        !          1970:                /* Reserved */
        !          1971:                break;
        !          1972:        case 0x1c:
        !          1973:                /* Informational Exceptions Control */
        !          1974:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Informational Exceptions Control\n");
        !          1975:                if (subpage != 0x00)
        !          1976:                        break;
        !          1977: 
        !          1978:                plen = 0x0a + 2;
        !          1979:                MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
        !          1980:                len += plen;
        !          1981:                break;
        !          1982:        case 0x1d:
        !          1983:        case 0x1e:
        !          1984:        case 0x1f:
        !          1985:                /* Reserved */
        !          1986:                break;
        !          1987:        case 0x20:
        !          1988:        case 0x21:
        !          1989:        case 0x22:
        !          1990:        case 0x23:
        !          1991:        case 0x24:
        !          1992:        case 0x25:
        !          1993:        case 0x26:
        !          1994:        case 0x27:
        !          1995:        case 0x28:
        !          1996:        case 0x29:
        !          1997:        case 0x2a:
        !          1998:        case 0x2b:
        !          1999:        case 0x2c:
        !          2000:        case 0x2d:
        !          2001:        case 0x2e:
        !          2002:        case 0x2f:
        !          2003:        case 0x30:
        !          2004:        case 0x31:
        !          2005:        case 0x32:
        !          2006:        case 0x33:
        !          2007:        case 0x34:
        !          2008:        case 0x35:
        !          2009:        case 0x36:
        !          2010:        case 0x37:
        !          2011:        case 0x38:
        !          2012:        case 0x39:
        !          2013:        case 0x3a:
        !          2014:        case 0x3b:
        !          2015:        case 0x3c:
        !          2016:        case 0x3d:
        !          2017:        case 0x3e:
        !          2018:                /* Vendor-specific */
        !          2019:                break;
        !          2020:        case 0x3f:
        !          2021:                switch (subpage) {
        !          2022:                case 0x00:
        !          2023:                        /* All mode pages */
        !          2024:                        for (i = 0x00; i < 0x3e; i ++) {
        !          2025:                                len += istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, i, 0x00, &cp[len], alloc_len);
        !          2026:                        }
        !          2027:                        break;
        !          2028:                case 0xff:
        !          2029:                        /* All mode pages and subpages */
        !          2030:                        for (i = 0x00; i < 0x3e; i ++) {
        !          2031:                                len += istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, i, 0x00, &cp[len], alloc_len);
        !          2032:                        }
        !          2033:                        for (i = 0x00; i < 0x3e; i ++) {
        !          2034:                                len += istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, i, 0xff, &cp[len], alloc_len);
        !          2035:                        }
        !          2036:                        break;
        !          2037:                default:
        !          2038:                        /* 0x01-0x3e: Reserved */
        !          2039:                        break;
        !          2040:                }
        !          2041:        }
        !          2042: 
        !          2043:        return len;
        !          2044: }
        !          2045: 
        !          2046: static int
        !          2047: istgt_lu_disk_scsi_mode_sense6(ISTGT_LU_DISK *spec, CONN_Ptr conn, uint8_t *cdb, int dbd, int pc, int page, int subpage, uint8_t *data, int alloc_len)
        !          2048: {
        !          2049:        uint8_t *cp;
        !          2050:        int hlen = 0, len = 0, plen;
        !          2051:        int total;
        !          2052:        int llbaa = 0;
        !          2053: 
        !          2054:        data[0] = 0;                    /* Mode Data Length */
        !          2055:        data[1] = 0;                    /* Medium Type */
        !          2056:        data[2] = 0;                    /* Device-Specific Parameter */
        !          2057:        if (spec->lu->readonly) {
        !          2058:                BDADD8(&data[2], 1, 7);     /* WP */
        !          2059:        }
        !          2060:        data[3] = 0;                    /* Block Descripter Length */
        !          2061:        hlen = 4;
        !          2062: 
        !          2063:        cp = &data[4];
        !          2064:        if (dbd) {                      /* Disable Block Descripters */
        !          2065:                len = 0;
        !          2066:        } else {
        !          2067:                if (llbaa) {
        !          2068:                        /* Number of Blocks */
        !          2069:                        DSET64(&cp[0], spec->blockcnt);
        !          2070:                        /* Reserved */
        !          2071:                        DSET32(&cp[8], 0);
        !          2072:                        /* Block Length */
        !          2073:                        DSET32(&cp[12], (uint32_t) spec->blocklen);
        !          2074:                        len = 16;
        !          2075:                } else {
        !          2076:                        /* Number of Blocks */
        !          2077:                        if (spec->blockcnt > 0xffffffffULL) {
        !          2078:                                DSET32(&cp[0], 0xffffffffUL);
        !          2079:                        } else {
        !          2080:                                DSET32(&cp[0], (uint32_t) spec->blockcnt);
        !          2081:                        }
        !          2082:                        /* Block Length */
        !          2083:                        DSET32(&cp[4], (uint32_t) spec->blocklen);
        !          2084:                        len = 8;
        !          2085:                }
        !          2086:                cp += len;
        !          2087:        }
        !          2088:        data[3] = len;                  /* Block Descripter Length */
        !          2089: 
        !          2090:        plen = istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, page, subpage, &cp[0], alloc_len);
        !          2091:        cp += plen;
        !          2092: 
        !          2093:        total = hlen + len + plen;
        !          2094:        data[0] = total - 1;            /* Mode Data Length */
        !          2095: 
        !          2096:        return total;
        !          2097: }
        !          2098: 
        !          2099: static int
        !          2100: istgt_lu_disk_scsi_mode_sense10(ISTGT_LU_DISK *spec, CONN_Ptr conn, uint8_t *cdb, int dbd, int llbaa, int pc, int page, int subpage, uint8_t *data, int alloc_len)
        !          2101: {
        !          2102:        uint8_t *cp;
        !          2103:        int hlen = 0, len = 0, plen;
        !          2104:        int total;
        !          2105: 
        !          2106:        DSET16(&data[0], 0);            /* Mode Data Length */
        !          2107:        data[2] = 0;                    /* Medium Type */
        !          2108:        data[3] = 0;                    /* Device-Specific Parameter */
        !          2109:        if (spec->lu->readonly) {
        !          2110:                BDADD8(&data[3], 1, 7);     /* WP */
        !          2111:        }
        !          2112:        if (llbaa) {
        !          2113:                BDSET8(&data[4], 1, 1);      /* Long LBA */
        !          2114:        } else {
        !          2115:                BDSET8(&data[4], 0, 1);      /* Short LBA */
        !          2116:        }
        !          2117:        data[5] = 0;                    /* Reserved */
        !          2118:        DSET16(&data[6], 0);                /* Block Descripter Length */
        !          2119:        hlen = 8;
        !          2120: 
        !          2121:        cp = &data[8];
        !          2122:        if (dbd) {                      /* Disable Block Descripters */
        !          2123:                len = 0;
        !          2124:        } else {
        !          2125:                if (llbaa) {
        !          2126:                        /* Number of Blocks */
        !          2127:                        DSET64(&cp[0], spec->blockcnt);
        !          2128:                        /* Reserved */
        !          2129:                        DSET32(&cp[8], 0);
        !          2130:                        /* Block Length */
        !          2131:                        DSET32(&cp[12], (uint32_t) spec->blocklen);
        !          2132:                        len = 16;
        !          2133:                } else {
        !          2134:                        /* Number of Blocks */
        !          2135:                        if (spec->blockcnt > 0xffffffffULL) {
        !          2136:                                DSET32(&cp[0], 0xffffffffUL);
        !          2137:                        } else {
        !          2138:                                DSET32(&cp[0], (uint32_t) spec->blockcnt);
        !          2139:                        }
        !          2140:                        /* Block Length */
        !          2141:                        DSET32(&cp[4], (uint32_t) spec->blocklen);
        !          2142:                        len = 8;
        !          2143:                }
        !          2144:                cp += len;
        !          2145:        }
        !          2146:        DSET16(&data[6], len);          /* Block Descripter Length */
        !          2147: 
        !          2148:        plen = istgt_lu_disk_scsi_mode_sense_page(spec, conn, cdb, pc, page, subpage, &cp[0], alloc_len);
        !          2149:        cp += plen;
        !          2150: 
        !          2151:        total = hlen + len + plen;
        !          2152:        DSET16(&data[0], total - 2);    /* Mode Data Length */
        !          2153: 
        !          2154:        return total;
        !          2155: }
        !          2156: 
        !          2157: static int
        !          2158: istgt_lu_disk_transfer_data(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint8_t *buf, size_t bufsize, size_t len)
        !          2159: {
        !          2160:        int rc;
        !          2161: 
        !          2162:        if (lu_cmd->lu->queue_depth == 0) {
        !          2163:                if (len > bufsize) {
        !          2164:                        ISTGT_ERRLOG("bufsize(%d) too small\n", bufsize);
        !          2165:                        return -1;
        !          2166:                }
        !          2167:                rc = istgt_iscsi_transfer_out(conn, lu_cmd, buf, bufsize, len);
        !          2168:                if (rc < 0) {
        !          2169:                        ISTGT_ERRLOG("iscsi_transfer_out()\n");
        !          2170:                        return -1;
        !          2171:                }
        !          2172:        }
        !          2173:        return 0;
        !          2174: }
        !          2175: 
        !          2176: static int
        !          2177: istgt_lu_disk_scsi_mode_select_page(ISTGT_LU_DISK *spec, CONN_Ptr conn, uint8_t *cdb, int pf, int sp, uint8_t *data, size_t len)
        !          2178: {
        !          2179:        int ps, spf, page, subpage;
        !          2180:        int hlen, plen;
        !          2181:        int rc;
        !          2182: 
        !          2183:        if (pf == 0) {
        !          2184:                /* vendor specific */
        !          2185:                return 0;
        !          2186:        }
        !          2187: 
        !          2188:        if (len < 1)
        !          2189:                return 0;
        !          2190:        ps = BGET8(&data[0], 7);
        !          2191:        spf = BGET8(&data[0], 6);
        !          2192:        page = data[0] & 0x3f;
        !          2193:        if (spf) {
        !          2194:                /* Sub_page mode page format */
        !          2195:                hlen = 4;
        !          2196:                if (len < hlen)
        !          2197:                        return 0;
        !          2198:                subpage = data[1];
        !          2199: 
        !          2200:                plen = DGET16(&data[2]);
        !          2201:        } else {
        !          2202:                /* Page_0 mode page format */
        !          2203:                hlen = 2;
        !          2204:                if (len < hlen)
        !          2205:                        return 0;
        !          2206:                subpage = 0;
        !          2207:                plen = data[1];
        !          2208:        }
        !          2209:        plen += hlen;
        !          2210:        if (len < plen)
        !          2211:                return 0;
        !          2212: 
        !          2213: #if 0
        !          2214:        printf("ps=%d, page=%2.2x, subpage=%2.2x\n", ps, page, subpage);
        !          2215: #endif
        !          2216:        switch (page) {
        !          2217:        case 0x08:
        !          2218:                /* Caching */
        !          2219:                {
        !          2220:                        int wce, rcd;
        !          2221: 
        !          2222:                        ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SELECT Caching\n");
        !          2223:                        if (subpage != 0x00)
        !          2224:                                break;
        !          2225:                        if (plen != 0x12 + hlen) {
        !          2226:                                /* unknown format */
        !          2227:                                break;
        !          2228:                        }
        !          2229:                        wce = BGET8(&data[2], 2); /* WCE */
        !          2230:                        rcd = BGET8(&data[2], 0); /* RCD */
        !          2231: 
        !          2232:                        {
        !          2233:                                int fd;
        !          2234:                                fd = spec->fd;
        !          2235:                                rc = fcntl(fd , F_GETFL, 0);
        !          2236:                                if (rc != -1) {
        !          2237:                                        if (wce) {
        !          2238:                                                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SELECT Writeback cache enable\n");
        !          2239:                                                rc = fcntl(fd, F_SETFL, (rc & ~O_FSYNC));
        !          2240:                                                spec->write_cache = 1;
        !          2241:                                        } else {
        !          2242:                                                rc = fcntl(fd, F_SETFL, (rc | O_FSYNC));
        !          2243:                                                spec->write_cache = 0;
        !          2244:                                        }
        !          2245:                                        if (rc == -1) {
        !          2246:                                                /* XXX */
        !          2247:                                                //ISTGT_ERRLOG("fcntl(F_SETFL) failed\n");
        !          2248:                                        }
        !          2249:                                }
        !          2250:                        }
        !          2251:                        if (rcd) {
        !          2252:                                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SELECT Read cache disable\n");
        !          2253:                                spec->read_cache = 0;
        !          2254:                        } else {
        !          2255:                                spec->read_cache = 1;
        !          2256:                        }
        !          2257:                }
        !          2258:                break;
        !          2259:        default:
        !          2260:                /* not supported */
        !          2261:                break;
        !          2262:        }
        !          2263: 
        !          2264:        len -= plen;
        !          2265:        if (len != 0) {
        !          2266:                rc = istgt_lu_disk_scsi_mode_select_page(spec, conn, cdb,  pf, sp, &data[plen], len);
        !          2267:                if (rc < 0) {
        !          2268:                        return rc;
        !          2269:                }
        !          2270:        }
        !          2271:        return 0;
        !          2272: }
        !          2273: 
        !          2274: #if 0
        !          2275: static int
        !          2276: istgt_lu_disk_scsi_request_sense(ISTGT_LU_DISK *spec, CONN_Ptr conn, uint8_t *cdb, int desc, uint8_t *data, int alloc_len)
        !          2277: {
        !          2278:        int len = 0, plen;
        !          2279: 
        !          2280:        if (alloc_len < 18) {
        !          2281:                ISTGT_ERRLOG("alloc_len(%d) too small\n", alloc_len);
        !          2282:                return -1;
        !          2283:        }
        !          2284: 
        !          2285:        /* XXX TODO: fix */
        !          2286:        if (desc == 0) {
        !          2287:                /* fixed format */
        !          2288:                /* NO ADDITIONAL SENSE INFORMATION */
        !          2289:                /* BUILD_SENSE(NO_SENSE, 0x00, 0x00); */
        !          2290: 
        !          2291:                /* VALID(7) RESPONSE CODE(6-0) */
        !          2292:                BDSET8(&data[0], 0, 7);
        !          2293:                BDADD8W(&data[0], 0x70, 6, 7);
        !          2294:                /* Obsolete */
        !          2295:                data[1] = 0;
        !          2296:                /* FILEMARK(7) EOM(6) ILI(5) SENSE KEY(3-0) */
        !          2297:                BDSET8W(&data[2], ISTGT_SCSI_SENSE_NO_SENSE, 3, 4);
        !          2298:                /* INFORMATION */
        !          2299:                memset(&data[3], 0, 4);
        !          2300:                /* ADDITIONAL SENSE LENGTH */
        !          2301:                data[7] = 0;
        !          2302:                len = 8;
        !          2303: 
        !          2304:                /* COMMAND-SPECIFIC INFORMATION */
        !          2305:                memset(&data[8], 0, 4);
        !          2306:                /* ADDITIONAL SENSE CODE */
        !          2307:                data[12] = 0x00;
        !          2308:                /* ADDITIONAL SENSE CODE QUALIFIER */
        !          2309:                data[13] = 0x00;
        !          2310:                /* FIELD REPLACEABLE UNIT CODE */
        !          2311:                data[14] = 0;
        !          2312:                /* SKSV(7) SENSE KEY SPECIFIC(6-0,7-0,7-0) */
        !          2313:                data[15] = 0;
        !          2314:                data[16] = 0;
        !          2315:                data[17] = 0;
        !          2316:                plen = 18 - len;
        !          2317: 
        !          2318:                /* ADDITIONAL SENSE LENGTH */
        !          2319:                data[7] = plen;
        !          2320:        } else {
        !          2321:                /* descriptor format */
        !          2322:                /* NO ADDITIONAL SENSE INFORMATION */
        !          2323:                /* BUILD_SENSE(NO_SENSE, 0x00, 0x00); */
        !          2324: 
        !          2325:                /* RESPONSE CODE(6-0) */
        !          2326:                BDSET8W(&data[0], 0x72, 6, 7);
        !          2327:                /* SENSE KEY(3-0) */
        !          2328:                BDSET8W(&data[1], ISTGT_SCSI_SENSE_NO_SENSE, 3, 4);
        !          2329:                /* ADDITIONAL SENSE CODE */
        !          2330:                data[2] = 0x00;
        !          2331:                /* ADDITIONAL SENSE CODE QUALIFIER */
        !          2332:                data[3] = 0x00;
        !          2333:                /* Reserved */
        !          2334:                data[4] = 0;
        !          2335:                data[5] = 0;
        !          2336:                data[6] = 0;
        !          2337:                /* ADDITIONAL SENSE LENGTH */
        !          2338:                data[7] = 0;
        !          2339:                len = 8;
        !          2340: 
        !          2341:                /* Sense data descriptor(s) */
        !          2342:                plen = 8 - len;
        !          2343: 
        !          2344:                /* ADDITIONAL SENSE LENGTH */
        !          2345:                data[7] = plen;
        !          2346:        }
        !          2347:        return len;
        !          2348: }
        !          2349: #endif
        !          2350: 
        !          2351: static int
        !          2352: istgt_lu_disk_scsi_report_target_port_groups(ISTGT_LU_DISK *spec, CONN_Ptr conn, uint8_t *cdb, uint8_t *data, int alloc_len)
        !          2353: {
        !          2354:        ISTGT_Ptr istgt;
        !          2355:        ISTGT_LU_Ptr lu;
        !          2356:        uint8_t *cp;
        !          2357:        uint8_t *cp_count;
        !          2358:        int hlen = 0, len = 0, plen;
        !          2359:        int total;
        !          2360:        int pg_tag;
        !          2361:        int nports;
        !          2362:        int i, j;
        !          2363: 
        !          2364:        if (alloc_len < 0xfff) {
        !          2365:                return -1;
        !          2366:        }
        !          2367: 
        !          2368:        istgt = conn->istgt;
        !          2369:        lu = spec->lu;
        !          2370: 
        !          2371:        /* RETURN DATA LENGTH */
        !          2372:        DSET32(&data[0], 0);
        !          2373:        hlen = 4;
        !          2374: 
        !          2375:        MTX_LOCK(&istgt->mutex);
        !          2376:        for (i = 0; i < lu->maxmap; i++) {
        !          2377:                pg_tag = lu->map[i].pg_tag;
        !          2378:                /* skip same pg_tag */
        !          2379:                for (j = 0; j < i; j++) {
        !          2380:                        if (lu->map[j].pg_tag == pg_tag) {
        !          2381:                                goto skip_pg_tag;
        !          2382:                        }
        !          2383:                }
        !          2384: 
        !          2385:                /* Target port group descriptor N */
        !          2386:                cp = &data[hlen + len];
        !          2387: 
        !          2388:                /* PREF(7) ASYMMETRIC ACCESS STATE(3-0) */
        !          2389:                cp[0] = 0;
        !          2390:                BDSET8(&cp[0], 1, 7); /* PREF */
        !          2391:                switch (lu->map[j].pg_aas & 0x0f) {
        !          2392:                case AAS_ACTIVE_OPTIMIZED:
        !          2393:                        BDADD8W(&cp[0], AAS_ACTIVE_OPTIMIZED, 3, 4);
        !          2394:                        break;
        !          2395:                case AAS_ACTIVE_NON_OPTIMIZED:
        !          2396:                        BDADD8W(&cp[0], AAS_ACTIVE_NON_OPTIMIZED, 3, 4);
        !          2397:                        break;
        !          2398:                case AAS_STANDBY:
        !          2399:                        BDADD8W(&cp[0], AAS_STANDBY, 3, 4);
        !          2400:                        break;
        !          2401:                case AAS_UNAVAILABLE:
        !          2402:                        BDADD8W(&cp[0], AAS_UNAVAILABLE, 3, 4);
        !          2403:                        break;
        !          2404:                case AAS_TRANSITIONING:
        !          2405:                        BDADD8W(&cp[0], AAS_TRANSITIONING, 3, 4);
        !          2406:                        break;
        !          2407:                default:
        !          2408:                        ISTGT_ERRLOG("unsupported AAS\n");
        !          2409:                        break;
        !          2410:                }
        !          2411:                /* T_SUP(7) U_SUP(3) S_SUP(2) S_SUP AN_SUP(1) AO_SUP(0) */
        !          2412:                cp[1] = 0;
        !          2413:                //BDADD8(&cp[1], 1, 7); /* transitioning supported */
        !          2414:                //BDADD8(&cp[1], 1, 3); /* unavailable supported */
        !          2415:                //BDADD8(&cp[1], 1, 2); /* standby supported */
        !          2416:                BDADD8(&cp[1], 1, 1); /* active/non-optimized supported */
        !          2417:                BDADD8(&cp[1], 1, 0); /* active/optimized supported */
        !          2418:                /* TARGET PORT GROUP */
        !          2419:                DSET16(&cp[2], pg_tag);
        !          2420:                /* Reserved */
        !          2421:                cp[4] = 0;
        !          2422:                /* STATUS CODE */
        !          2423:                if (lu->map[j].pg_aas & AAS_STATUS_IMPLICIT) {
        !          2424:                        cp[5] = 0x02; /* by implicit */
        !          2425:                } else if (lu->map[j].pg_aas & AAS_STATUS_STPG) {
        !          2426:                        cp[5] = 0x01; /* by SET TARGET PORT GROUPS */
        !          2427:                } else {
        !          2428:                        cp[5] = 0;    /* No status */
        !          2429:                }
        !          2430:                /* Vendor specific */
        !          2431:                cp[6] = 0;
        !          2432:                /* TARGET PORT COUNT */
        !          2433:                cp[7] = 0;
        !          2434:                cp_count = &cp[7];
        !          2435:                plen = 8;
        !          2436:                len += plen;
        !          2437: 
        !          2438:                nports = 0;
        !          2439:                for (j = 0; j < istgt->nportal; j ++) {
        !          2440:                        if (istgt->portal[j].tag != pg_tag)
        !          2441:                                continue;
        !          2442:                        /* Target port descriptor(s) */
        !          2443:                        cp = &data[hlen + len];
        !          2444:                        /* Obsolete */
        !          2445:                        DSET16(&cp[0], 0);
        !          2446:                        /* RELATIVE TARGET PORT IDENTIFIER */
        !          2447:                        DSET16(&cp[2], (uint16_t) (1 + istgt->portal[j].idx));
        !          2448:                        plen = 4;
        !          2449:                        len += plen;
        !          2450:                        nports++;
        !          2451:                }
        !          2452: 
        !          2453:                if (nports > 0xff) {
        !          2454:                        ISTGT_ERRLOG("too many portals in portal group\n");
        !          2455:                        MTX_UNLOCK(&istgt->mutex);
        !          2456:                        return -1;
        !          2457:                }
        !          2458: 
        !          2459:                /* TARGET PORT COUNT */
        !          2460:                cp_count[0] = nports;
        !          2461: 
        !          2462:        skip_pg_tag:
        !          2463:                ;
        !          2464:        }
        !          2465:        MTX_UNLOCK(&istgt->mutex);
        !          2466: 
        !          2467:        total = hlen + len;
        !          2468:        if (total > alloc_len) {
        !          2469:                ISTGT_ERRLOG("alloc_len(%d) too small\n", alloc_len);
        !          2470:                return -1;
        !          2471:        }
        !          2472: 
        !          2473:        /* RETURN DATA LENGTH */
        !          2474:        DSET32(&data[0], total - 4);
        !          2475: 
        !          2476:        return total;
        !          2477: }
        !          2478: 
        !          2479: static int
        !          2480: istgt_lu_disk_scsi_set_target_port_groups(ISTGT_LU_DISK *spec, CONN_Ptr conn, uint8_t *cdb, uint8_t *data, int len)
        !          2481: {
        !          2482:        ISTGT_LU_Ptr lu;
        !          2483:        int pg_tag;
        !          2484:        int aas;
        !          2485:        int pg;
        !          2486:        int rc;
        !          2487:        int i;
        !          2488: 
        !          2489:        if (len < 4) {
        !          2490:                return -1;
        !          2491:        }
        !          2492: 
        !          2493:        lu = spec->lu;
        !          2494: 
        !          2495:        aas = BGET8W(&data[0], 3, 4);
        !          2496:        pg = DGET16(&data[2]);
        !          2497: 
        !          2498:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AAS=0x%x, PG=0x%4.4x\n", aas, pg);
        !          2499: 
        !          2500:        for (i = 0; i < lu->maxmap; i++) {
        !          2501:                pg_tag = lu->map[i].pg_tag;
        !          2502:                if (pg != pg_tag)
        !          2503:                        continue;
        !          2504: 
        !          2505:                switch (aas) {
        !          2506:                case AAS_ACTIVE_OPTIMIZED:
        !          2507:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Active/optimized\n");
        !          2508:                        break;
        !          2509:                case AAS_ACTIVE_NON_OPTIMIZED:
        !          2510:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Active/non-optimized\n");
        !          2511:                        break;
        !          2512: #if 0
        !          2513:                case AAS_STANDBY:
        !          2514:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Standby\n");
        !          2515:                        break;
        !          2516:                case AAS_UNAVAILABLE:
        !          2517:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Unavailable\n");
        !          2518:                        break;
        !          2519: #endif
        !          2520:                case AAS_TRANSITIONING:
        !          2521:                        return -1;
        !          2522:                default:
        !          2523:                        ISTGT_ERRLOG("unsupported AAS 0x%x\n", aas);
        !          2524:                        return -1;
        !          2525:                }
        !          2526:                lu->map[i].pg_aas = aas;
        !          2527:                lu->map[i].pg_aas |= AAS_STATUS_STPG;
        !          2528:        }
        !          2529: 
        !          2530:        len -=4;
        !          2531:        if (len != 0) {
        !          2532:                rc = istgt_lu_disk_scsi_set_target_port_groups(spec, conn, cdb, data, len);
        !          2533:                if (rc < 0) {
        !          2534:                        return rc;
        !          2535:                }
        !          2536:        }
        !          2537:        return 0;
        !          2538: }
        !          2539: 
        !          2540: static void
        !          2541: istgt_lu_disk_free_pr_key(ISTGT_LU_PR_KEY *prkey)
        !          2542: {
        !          2543:        int i;
        !          2544: 
        !          2545:        if (prkey == NULL)
        !          2546:                return;
        !          2547:        xfree(prkey->registered_initiator_port);
        !          2548:        prkey->registered_initiator_port = NULL;
        !          2549:        xfree(prkey->registered_target_port);
        !          2550:        prkey->registered_target_port = NULL;
        !          2551:        prkey->pg_idx = 0;
        !          2552:        prkey->pg_tag = 0;
        !          2553:        for (i = 0; i < prkey->ninitiator_ports; i++) {
        !          2554:                xfree(prkey->initiator_ports[i]);
        !          2555:                prkey->initiator_ports[i] = NULL;
        !          2556:        }
        !          2557:        xfree(prkey->initiator_ports);
        !          2558:        prkey->initiator_ports = NULL;
        !          2559:        prkey->all_tpg = 0;
        !          2560: }
        !          2561: 
        !          2562: static ISTGT_LU_PR_KEY *
        !          2563: istgt_lu_disk_find_pr_key(ISTGT_LU_DISK *spec, const char *initiator_port, const char *target_port, uint64_t key)
        !          2564: {
        !          2565:        ISTGT_LU_PR_KEY *prkey;
        !          2566:        int i;
        !          2567: 
        !          2568:        /* return pointer if I_T nexus is registered */
        !          2569: #ifdef ISTGT_TRACE_DISK
        !          2570:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !          2571:            "find prkey=0x%16.16"PRIx64", port=%s\n",
        !          2572:            key, ((initiator_port != NULL) ? initiator_port : "N/A"));
        !          2573: #endif /* ISTGT_TRACE_DISK */
        !          2574: 
        !          2575:        if (initiator_port == NULL)
        !          2576:                return NULL;
        !          2577:        for (i = 0; i < spec->npr_keys; i++) {
        !          2578:                prkey = &spec->pr_keys[i];
        !          2579:                if (prkey == NULL)
        !          2580:                        continue;
        !          2581: #ifdef ISTGT_TRACE_DISK
        !          2582:                if (key != 0) {
        !          2583:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !          2584:                            "prkey=0x%16.16"PRIx64"\n",
        !          2585:                            prkey->key);
        !          2586:                }
        !          2587: #endif /* ISTGT_TRACE_DISK */
        !          2588:                if (key != 0 && prkey->key != key)
        !          2589:                        continue;
        !          2590: #ifdef ISTGT_TRACE_DISK
        !          2591:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "pript=%s, ipt=%s\n",
        !          2592:                    prkey->registered_initiator_port,
        !          2593:                    initiator_port);
        !          2594: #endif /* ISTGT_TRACE_DISK */
        !          2595:                if (strcmp(prkey->registered_initiator_port,
        !          2596:                        initiator_port) == 0) {
        !          2597: #ifdef ISTGT_TRACE_DISK
        !          2598:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "prtpt=%s, tpt=%s\n",
        !          2599:                            prkey->registered_target_port,
        !          2600:                            target_port);
        !          2601: #endif /* ISTGT_TRACE_DISK */
        !          2602:                        if (prkey->all_tpg != 0
        !          2603:                            || target_port == NULL
        !          2604:                            || strcmp(prkey->registered_target_port,
        !          2605:                                target_port) == 0) {
        !          2606:                                return prkey;
        !          2607:                        }
        !          2608:                }
        !          2609:        }
        !          2610:        return NULL;
        !          2611: }
        !          2612: 
        !          2613: static int
        !          2614: istgt_lu_disk_remove_other_pr_key(ISTGT_LU_DISK *spec, CONN_Ptr conn, const char *initiator_port, const char *target_port, uint64_t key)
        !          2615: {
        !          2616:        ISTGT_LU_PR_KEY *prkey, *prkey1, *prkey2;
        !          2617:        int i, j;
        !          2618: 
        !          2619:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !          2620:            "remove other prkey=0x%16.16"PRIx64", port=%s\n",
        !          2621:            key, ((initiator_port != NULL) ? initiator_port : "N/A"));
        !          2622: 
        !          2623:        for (i = 0; i < spec->npr_keys; i++) {
        !          2624:                prkey = &spec->pr_keys[i];
        !          2625:                if (prkey == NULL)
        !          2626:                        continue;
        !          2627:                if (key == 0 || prkey->key == key)
        !          2628:                        continue;
        !          2629:                if (initiator_port == NULL ||
        !          2630:                    strcasecmp(prkey->registered_initiator_port,
        !          2631:                        initiator_port) == 0)
        !          2632:                        continue;
        !          2633:                if (prkey->all_tpg != 0
        !          2634:                    || target_port == NULL
        !          2635:                    || strcasecmp(prkey->registered_target_port,
        !          2636:                        target_port) == 0)
        !          2637:                        continue;
        !          2638: 
        !          2639:                istgt_lu_disk_free_pr_key(prkey);
        !          2640:                for (j = i; j < spec->npr_keys - 1; j++) {
        !          2641:                        prkey1 = &spec->pr_keys[j];
        !          2642:                        prkey2 = &spec->pr_keys[j+1];
        !          2643: 
        !          2644:                        prkey1->registered_initiator_port
        !          2645:                                = prkey2->registered_initiator_port;
        !          2646:                        prkey2->registered_initiator_port = NULL;
        !          2647:                        prkey1->registered_target_port
        !          2648:                                = prkey2->registered_target_port;
        !          2649:                        prkey2->registered_target_port = NULL;
        !          2650:                        prkey1->pg_idx = prkey2->pg_idx;
        !          2651:                        prkey2->pg_idx = 0;
        !          2652:                        prkey1->pg_tag = prkey2->pg_tag;
        !          2653:                        prkey2->pg_tag = 0;
        !          2654:                        prkey1->ninitiator_ports = prkey2->ninitiator_ports;
        !          2655:                        prkey2->ninitiator_ports = 0;
        !          2656:                        prkey1->initiator_ports = prkey2->initiator_ports;
        !          2657:                        prkey2->initiator_ports = NULL;
        !          2658:                        prkey1->all_tpg = prkey2->all_tpg;
        !          2659:                        prkey2->all_tpg = 0;
        !          2660:                }
        !          2661:                spec->npr_keys--;
        !          2662:        }
        !          2663:        return 0;
        !          2664: }
        !          2665: 
        !          2666: static int
        !          2667: istgt_lu_disk_remove_pr_key(ISTGT_LU_DISK *spec, CONN_Ptr conn, const char *initiator_port, const char *target_port, uint64_t key)
        !          2668: {
        !          2669:        ISTGT_LU_PR_KEY *prkey, *prkey1, *prkey2;
        !          2670:        int i, j;
        !          2671: 
        !          2672:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !          2673:            "remove prkey=0x%16.16"PRIx64", port=%s\n",
        !          2674:            key, ((initiator_port != NULL) ? initiator_port : "N/A"));
        !          2675: 
        !          2676:        for (i = 0; i < spec->npr_keys; i++) {
        !          2677:                prkey = &spec->pr_keys[i];
        !          2678:                if (prkey == NULL)
        !          2679:                        continue;
        !          2680:                if (key != 0 && prkey->key != key)
        !          2681:                        continue;
        !          2682:                if (initiator_port != NULL
        !          2683:                    && strcasecmp(prkey->registered_initiator_port,
        !          2684:                        initiator_port) != 0)
        !          2685:                        continue;
        !          2686:                if (prkey->all_tpg == 0
        !          2687:                    && target_port != NULL
        !          2688:                    && strcasecmp(prkey->registered_target_port,
        !          2689:                        target_port) != 0)
        !          2690:                        continue;
        !          2691: 
        !          2692:                istgt_lu_disk_free_pr_key(prkey);
        !          2693:                for (j = i; j < spec->npr_keys - 1; j++) {
        !          2694:                        prkey1 = &spec->pr_keys[j];
        !          2695:                        prkey2 = &spec->pr_keys[j+1];
        !          2696: 
        !          2697:                        prkey1->registered_initiator_port
        !          2698:                                = prkey2->registered_initiator_port;
        !          2699:                        prkey2->registered_initiator_port = NULL;
        !          2700:                        prkey1->registered_target_port
        !          2701:                                = prkey2->registered_target_port;
        !          2702:                        prkey2->registered_target_port = NULL;
        !          2703:                        prkey1->pg_idx = prkey2->pg_idx;
        !          2704:                        prkey2->pg_idx = 0;
        !          2705:                        prkey1->pg_tag = prkey2->pg_tag;
        !          2706:                        prkey2->pg_tag = 0;
        !          2707:                        prkey1->ninitiator_ports = prkey2->ninitiator_ports;
        !          2708:                        prkey2->ninitiator_ports = 0;
        !          2709:                        prkey1->initiator_ports = prkey2->initiator_ports;
        !          2710:                        prkey2->initiator_ports = NULL;
        !          2711:                        prkey1->all_tpg = prkey2->all_tpg;
        !          2712:                        prkey2->all_tpg = 0;
        !          2713:                }
        !          2714:                spec->npr_keys--;
        !          2715:        }
        !          2716:        return 0;
        !          2717: }
        !          2718: 
        !          2719: static int
        !          2720: istgt_lu_parse_transport_id(char **tid, uint8_t *data, int len)
        !          2721: {
        !          2722:        int fc, pi;
        !          2723:        int hlen, plen;
        !          2724: 
        !          2725:        if (tid == NULL)
        !          2726:                return -1;
        !          2727:        if (data == NULL)
        !          2728:                return -1;
        !          2729: 
        !          2730:        fc = BGET8W(&data[0], 7, 2);
        !          2731:        pi = BGET8W(&data[0], 3, 4);
        !          2732:        if (fc != 0) {
        !          2733:                ISTGT_ERRLOG("FORMAT CODE != 0\n");
        !          2734:                return -1;
        !          2735:        }
        !          2736:        if (pi != SPC_VPD_IDENTIFIER_TYPE_SCSI_NAME) {
        !          2737:                ISTGT_ERRLOG("PROTOCOL IDENTIFIER != ISCSI\n");
        !          2738:                return -1;
        !          2739:        }
        !          2740: 
        !          2741:        /* PROTOCOL IDENTIFIER = 0x05 */
        !          2742:        hlen = 4;
        !          2743:        /* ADDITIONAL LENGTH */
        !          2744:        plen = DGET16(&data[2]);
        !          2745:        if (plen > len) {
        !          2746:                ISTGT_ERRLOG("invalid length %d (expected %d)\n",
        !          2747:                    plen, len);
        !          2748:                return -1;
        !          2749:        }
        !          2750:        if (plen > MAX_ISCSI_NAME) {
        !          2751:                ISTGT_ERRLOG("invalid length %d (expected %d)\n",
        !          2752:                    plen, MAX_ISCSI_NAME);
        !          2753:                return -1;
        !          2754:        }
        !          2755: 
        !          2756:        /* ISCSI NAME */
        !          2757:        *tid = xmalloc(plen + 1);
        !          2758:        memcpy(*tid, data, plen);
        !          2759:        (*tid)[plen] = '\0';
        !          2760:        strlwr(*tid);
        !          2761: 
        !          2762:        return hlen + plen;
        !          2763: }
        !          2764: 
        !          2765: static int
        !          2766: istgt_lu_disk_scsi_persistent_reserve_in(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, int sa, uint8_t *data, int alloc_len)
        !          2767: {
        !          2768:        ISTGT_LU_PR_KEY *prkey;
        !          2769:        uint8_t *sense_data;
        !          2770:        int *sense_len;
        !          2771:        uint8_t *cp;
        !          2772:        int hlen = 0, len = 0, plen;
        !          2773:        int total;
        !          2774:        int i;
        !          2775: 
        !          2776:        sense_data = lu_cmd->sense_data;
        !          2777:        sense_len = &lu_cmd->sense_data_len;
        !          2778:        *sense_len = 0;
        !          2779: 
        !          2780:        cp = &data[hlen + len];
        !          2781:        total = 0;
        !          2782:        switch (sa) {
        !          2783:        case 0x00: /* READ KEYS */
        !          2784:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "READ KEYS\n");
        !          2785: 
        !          2786:                /* PRGENERATION */
        !          2787:                DSET32(&data[0], spec->pr_generation);
        !          2788:                /* ADDITIONAL LENGTH  */
        !          2789:                DSET32(&data[4], 0);
        !          2790:                hlen = 8;
        !          2791: 
        !          2792:                for (i = 0; i < spec->npr_keys; i++) {
        !          2793:                        prkey = &spec->pr_keys[i];
        !          2794:                        /* reservation key N */
        !          2795:                        cp = &data[hlen + len];
        !          2796:                        DSET64(&cp[0], prkey->key);
        !          2797:                        len += 8;
        !          2798:                }
        !          2799:                total = hlen + len;
        !          2800:                /* ADDITIONAL LENGTH  */
        !          2801:                DSET32(&data[4], total - hlen);
        !          2802:                break;
        !          2803: 
        !          2804:        case 0x01: /* READ RESERVATION */
        !          2805:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "READ RESERVATION\n");
        !          2806: 
        !          2807:                /* PRGENERATION */
        !          2808:                DSET32(&data[0], spec->pr_generation);
        !          2809:                /* ADDITIONAL LENGTH  */
        !          2810:                DSET32(&data[4], 0);
        !          2811:                hlen = 8;
        !          2812: 
        !          2813:                if (spec->rsv_key != 0) {
        !          2814:                        /* RESERVATION KEY */
        !          2815:                        DSET64(&data[8], spec->rsv_key);
        !          2816:                        /* Obsolete */
        !          2817:                        DSET32(&data[16], 0);
        !          2818:                        /* Reserved */
        !          2819:                        data[20] = 0;
        !          2820:                        /* SCOPE(7-4) TYPE(3-0) */
        !          2821:                        BDSET8W(&data[21], spec->rsv_scope, 7, 4);
        !          2822:                        BDADD8W(&data[21], spec->rsv_type, 3, 4);
        !          2823:                        /* Obsolete */
        !          2824:                        DSET16(&data[22], 0);
        !          2825:                        len = 24 - hlen;
        !          2826:                }
        !          2827: 
        !          2828:                total = hlen + len;
        !          2829:                /* ADDITIONAL LENGTH  */
        !          2830:                DSET32(&data[4], total - hlen);
        !          2831:                break;
        !          2832: 
        !          2833:        case 0x02: /* REPORT CAPABILITIES */
        !          2834:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "REPORT CAPABILITIES\n");
        !          2835: 
        !          2836:                /* LENGTH */
        !          2837:                DSET16(&data[0], 0x0008);
        !          2838:                /* CRH(4) SIP_C(3) ATP_C(2) PTPL_C(0) */
        !          2839:                data[2] = 0;
        !          2840:                //BDADD8(&data[2], 1, 4); /* Compatible Reservation Handling */
        !          2841:                BDADD8(&data[2], 1, 3); /* Specify Initiator Ports Capable */
        !          2842:                BDADD8(&data[2], 1, 2); /* All Target Ports Capable */
        !          2843:                //BDADD8(&data[2], 1, 0); /* Persist Through Power Loss Capable */
        !          2844:                /* TMV(7) PTPL_A(0) */
        !          2845:                data[3] = 0;
        !          2846:                //BDADD8(&data[2], 1, 7); /* Type Mask Valid */
        !          2847:                //BDADD8(&data[2], 1, 0); /* Persist Through Power Loss Activated */
        !          2848:                /* PERSISTENT RESERVATION TYPE MASK */
        !          2849:                DSET16(&data[4], 0);
        !          2850:                /* Reserved */
        !          2851:                DSET16(&data[6], 0);
        !          2852:                hlen = 8;
        !          2853: 
        !          2854:                total = hlen + len;
        !          2855:                break;
        !          2856: 
        !          2857:        case 0x03: /* READ FULL STATUS */
        !          2858:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "READ FULL STATUS\n");
        !          2859: 
        !          2860:                /* PRGENERATION */
        !          2861:                DSET32(&data[0], spec->pr_generation);
        !          2862:                /* ADDITIONAL LENGTH  */
        !          2863:                DSET32(&data[4], 0);
        !          2864:                hlen = 8;
        !          2865: 
        !          2866:                for (i = 0; i < spec->npr_keys; i++) {
        !          2867:                        prkey = &spec->pr_keys[i];
        !          2868:                        /* Full status descriptors N */
        !          2869:                        cp = &data[hlen + len];
        !          2870: 
        !          2871:                        /* RESERVATION KEY */
        !          2872:                        DSET64(&cp[0], prkey->key);
        !          2873:                        /* Reserved */
        !          2874:                        DSET64(&cp[8], 0);
        !          2875:                        /* ALL_TG_PT(1) R_HOLDER(0) */
        !          2876:                        cp[12] = 0;
        !          2877:                        if (prkey->all_tpg) {
        !          2878:                                BDADD8(&cp[12], 1, 1);
        !          2879:                        }
        !          2880:                        /* SCOPE(7-4) TYPE(3-0) */
        !          2881:                        cp[13] = 0;
        !          2882:                        if (spec->rsv_key != 0) {
        !          2883:                                if (spec->rsv_key == prkey->key) {
        !          2884:                                        BDADD8(&cp[12], 1, 0);
        !          2885:                                        BDADD8W(&cp[13], spec->rsv_scope & 0x0f, 7, 4);
        !          2886:                                        BDADD8W(&cp[13], spec->rsv_type & 0x0f, 3, 4);
        !          2887:                                }
        !          2888:                        }
        !          2889:                        /* Reserved */
        !          2890:                        DSET32(&cp[14], 0);
        !          2891:                        /* RELATIVE TARGET PORT IDENTIFIER */
        !          2892:                        DSET16(&cp[18], 1 + prkey->pg_idx);
        !          2893:                        /* ADDITIONAL DESCRIPTOR LENGTH */
        !          2894:                        DSET32(&cp[20], 0);
        !          2895: 
        !          2896:                        /* TRANSPORTID */
        !          2897:                        plen = snprintf((char *) &cp[24], MAX_INITIATOR_NAME,
        !          2898:                            "%s",
        !          2899:                            prkey->registered_initiator_port);
        !          2900:                        
        !          2901:                        /* ADDITIONAL DESCRIPTOR LENGTH */
        !          2902:                        DSET32(&cp[20], plen);
        !          2903:                        len += 24 + plen;
        !          2904:                }
        !          2905: 
        !          2906:                total = hlen + len;
        !          2907:                /* ADDITIONAL LENGTH  */
        !          2908:                DSET32(&data[4], total - hlen);
        !          2909:                break;
        !          2910: 
        !          2911:        default:
        !          2912:                ISTGT_ERRLOG("unsupported service action 0x%x\n", sa);
        !          2913:                /* INVALID FIELD IN CDB */
        !          2914:                BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
        !          2915:                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          2916:                return -1;
        !          2917:        }
        !          2918: 
        !          2919:        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          2920:        return total;
        !          2921: }
        !          2922: 
        !          2923: static int
        !          2924: istgt_lu_disk_scsi_persistent_reserve_out(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, int sa, int scope, int type, uint8_t *data, int len)
        !          2925: {
        !          2926:        ISTGT_LU_PR_KEY *prkey;
        !          2927:        uint8_t *sense_data;
        !          2928:        int *sense_len;
        !          2929:        char *old_rsv_port = NULL;
        !          2930:        char **initiator_ports;
        !          2931:        int maxports, nports;
        !          2932:        int plen, total;
        !          2933:        uint64_t rkey;
        !          2934:        uint64_t sarkey;
        !          2935:        int spec_i_pt, all_tg_pt, aptpl;
        !          2936:        int task_abort;
        !          2937:        int idx;
        !          2938:        int rc;
        !          2939:        int i;
        !          2940: 
        !          2941:        sense_data = lu_cmd->sense_data;
        !          2942:        sense_len = &lu_cmd->sense_data_len;
        !          2943:        *sense_len = 0;
        !          2944: 
        !          2945:        rkey = DGET64(&data[0]);
        !          2946:        sarkey = DGET64(&data[8]);
        !          2947:        spec_i_pt = BGET8(&data[20], 3);
        !          2948:        all_tg_pt = BGET8(&data[20], 2);
        !          2949:        aptpl = BGET8(&data[20], 0);
        !          2950: 
        !          2951:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !          2952:            "sa=0x%2.2x, key=0x%16.16"PRIx64", sakey=0x%16.16"PRIx64
        !          2953:            ", ipt=%d, tgpt=%d, aptpl=%d\n",
        !          2954:            sa, rkey, sarkey, spec_i_pt, all_tg_pt, aptpl);
        !          2955:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "port=%s\n",
        !          2956:            conn->initiator_port);
        !          2957: 
        !          2958:        switch (sa) {
        !          2959:        case 0x00: /* REGISTER */
        !          2960:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "REGISTER\n");
        !          2961: 
        !          2962:                if (aptpl != 0) {
        !          2963:                        /* Activate Persist Through Power Loss */
        !          2964:                        ISTGT_ERRLOG("unsupport Activate Persist Through Power Loss\n");
        !          2965:                        /* INVALID FIELD IN PARAMETER LIST */
        !          2966:                        BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00);
        !          2967:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          2968:                        return -1;
        !          2969:                }
        !          2970:                /* lost reservations if daemon restart */
        !          2971: 
        !          2972:                prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
        !          2973:                    conn->target_port, 0);
        !          2974:                if (prkey == NULL) {
        !          2975:                        /* unregistered port */
        !          2976:                        if (rkey != 0) {
        !          2977:                                lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          2978:                                return -1;
        !          2979:                        }
        !          2980:                        if (sarkey != 0) {
        !          2981:                                /* XXX check spec_i_pt */
        !          2982:                        }
        !          2983:                } else {
        !          2984:                        /* registered port */
        !          2985:                        if (spec_i_pt) {
        !          2986:                                /* INVALID FIELD IN CDB */
        !          2987:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
        !          2988:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          2989:                                return -1;
        !          2990:                        }
        !          2991: 
        !          2992:                        prkey = istgt_lu_disk_find_pr_key(spec,
        !          2993:                            conn->initiator_port, conn->target_port, rkey);
        !          2994:                        if (prkey == NULL) {
        !          2995:                                /* not found key */
        !          2996:                                lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          2997:                                return -1;
        !          2998:                        }
        !          2999:                        /* remove existing keys */
        !          3000:                        rc = istgt_lu_disk_remove_pr_key(spec, conn,
        !          3001:                            conn->initiator_port, conn->target_port, rkey);
        !          3002:                        if (rc < 0) {
        !          3003:                                ISTGT_ERRLOG("lu_disk_remove_pr_key() failed\n");
        !          3004:                                /* INTERNAL TARGET FAILURE */
        !          3005:                                BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
        !          3006:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3007:                                return -1;
        !          3008:                        }
        !          3009:                }
        !          3010: 
        !          3011:                /* unregister? */
        !          3012:                if (sarkey == 0) {
        !          3013:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          3014:                        return 0;
        !          3015:                }
        !          3016: 
        !          3017:                goto do_register;
        !          3018: 
        !          3019:        case 0x01: /* RESERVE */
        !          3020:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RESERVE\n");
        !          3021: 
        !          3022:                prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
        !          3023:                    conn->target_port, 0);
        !          3024:                if (prkey == NULL) {
        !          3025:                        /* unregistered port */
        !          3026:                        lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          3027:                        return -1;
        !          3028:                }
        !          3029: 
        !          3030:                prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
        !          3031:                    conn->target_port, rkey);
        !          3032:                if (prkey == NULL) {
        !          3033:                        /* not found key */
        !          3034:                        lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          3035:                        return -1;
        !          3036:                }
        !          3037:                if (spec->rsv_key == 0) {
        !          3038:                        /* no reservation */
        !          3039:                } else {
        !          3040:                        if (prkey->key != spec->rsv_key) {
        !          3041:                                lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          3042:                                return -1;
        !          3043:                        }
        !          3044:                        if (strcasecmp(spec->rsv_port, conn->initiator_port) != 0) {
        !          3045:                                lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          3046:                                return -1;
        !          3047:                        }
        !          3048:                        if (g_trace_flag) {
        !          3049:                                ISTGT_WARNLOG("LU%d: duplicate reserve\n", spec->lu->num);
        !          3050:                        }
        !          3051:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          3052:                        return 0;
        !          3053:                }
        !          3054: 
        !          3055:                if (scope != 0x00) { // !LU_SCOPE
        !          3056:                        /* INVALID FIELD IN CDB */
        !          3057:                        BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
        !          3058:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3059:                        return -1;
        !          3060:                }
        !          3061:                if (type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE
        !          3062:                    && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS
        !          3063:                    && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY
        !          3064:                    && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY
        !          3065:                    && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS
        !          3066:                    && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS) {
        !          3067:                        ISTGT_ERRLOG("unsupported type 0x%x\n", type);
        !          3068:                        /* INVALID FIELD IN CDB */
        !          3069:                        BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
        !          3070:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3071:                        return -1;
        !          3072:                }
        !          3073: 
        !          3074:                /* establish reservation by key */
        !          3075:                xfree(spec->rsv_port);
        !          3076:                spec->rsv_port = xstrdup(conn->initiator_port);
        !          3077:                strlwr(spec->rsv_port);
        !          3078:                spec->rsv_key = rkey;
        !          3079:                spec->rsv_scope = scope;
        !          3080:                spec->rsv_type = type;
        !          3081: 
        !          3082:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !          3083:                    "LU%d: reserved (scope=%d, type=%d) by key=0x%16.16"
        !          3084:                    PRIx64"\n",
        !          3085:                    spec->lu->num, scope, type, rkey);
        !          3086:                break;
        !          3087: 
        !          3088:        case 0x02: /* RELEASE */
        !          3089:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RELEASE\n");
        !          3090: 
        !          3091:                prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
        !          3092:                    conn->target_port, 0);
        !          3093:                if (prkey == NULL) {
        !          3094:                        /* unregistered port */
        !          3095:                        lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          3096:                        return -1;
        !          3097:                }
        !          3098: 
        !          3099:                prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
        !          3100:                    conn->target_port, rkey);
        !          3101:                if (prkey == NULL) {
        !          3102:                        /* not found key */
        !          3103:                        lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          3104:                        return -1;
        !          3105:                }
        !          3106:                if (spec->rsv_key == 0) {
        !          3107:                        /* no reservation */
        !          3108:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          3109:                        return 0;
        !          3110:                }
        !          3111:                if (prkey->key != spec->rsv_key) {
        !          3112:                        /* INVALID RELEASE OF PERSISTENT RESERVATION */
        !          3113:                        BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x04);
        !          3114:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3115:                        return -1;
        !          3116:                }
        !          3117:                if (strcasecmp(spec->rsv_port, conn->initiator_port) != 0) {
        !          3118:                        /* INVALID RELEASE OF PERSISTENT RESERVATION */
        !          3119:                        BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x04);
        !          3120:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3121:                        return -1;
        !          3122:                }
        !          3123: 
        !          3124:                if (scope != 0x00) { // !LU_SCOPE
        !          3125:                        /* INVALID FIELD IN CDB */
        !          3126:                        BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
        !          3127:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3128:                        return -1;
        !          3129:                }
        !          3130:                if (type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE
        !          3131:                    && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS
        !          3132:                    && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY
        !          3133:                    && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY
        !          3134:                    && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS
        !          3135:                    && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS) {
        !          3136:                        ISTGT_ERRLOG("unsupported type 0x%x\n", type);
        !          3137:                        /* INVALID FIELD IN CDB */
        !          3138:                        BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
        !          3139:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3140:                        return -1;
        !          3141:                }
        !          3142:                if (spec->rsv_scope != scope || spec->rsv_type != type) {
        !          3143:                        /* INVALID RELEASE OF PERSISTENT RESERVATION */
        !          3144:                        BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x04);
        !          3145:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3146:                        return -1;
        !          3147:                }
        !          3148: 
        !          3149:                /* release reservation by key */
        !          3150:                xfree(spec->rsv_port);
        !          3151:                spec->rsv_port = NULL;
        !          3152:                spec->rsv_key = 0;
        !          3153:                spec->rsv_scope = 0;
        !          3154:                spec->rsv_type = 0;
        !          3155: 
        !          3156:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !          3157:                    "LU%d: released (scope=%d, type=%d) by key=0x%16.16"
        !          3158:                    PRIx64"\n",
        !          3159:                    spec->lu->num, scope, type, rkey);
        !          3160:                break;
        !          3161: 
        !          3162:        case 0x03: /* CLEAR */
        !          3163:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "CLEAR\n");
        !          3164: 
        !          3165:                prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
        !          3166:                    conn->target_port, 0);
        !          3167:                if (prkey == NULL) {
        !          3168:                        /* unregistered port */
        !          3169:                        lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          3170:                        return -1;
        !          3171:                }
        !          3172: 
        !          3173:                /* release reservation */
        !          3174:                xfree(spec->rsv_port);
        !          3175:                spec->rsv_port = NULL;
        !          3176:                spec->rsv_key = 0;
        !          3177:                spec->rsv_scope = 0;
        !          3178:                spec->rsv_type = 0;
        !          3179: 
        !          3180:                /* remove all registrations */
        !          3181:                for (i = 0; i < spec->npr_keys; i++) {
        !          3182:                        prkey = &spec->pr_keys[i];
        !          3183:                        istgt_lu_disk_free_pr_key(prkey);
        !          3184:                }
        !          3185:                spec->npr_keys = 0;
        !          3186:                break;
        !          3187: 
        !          3188:        case 0x04: /* PREEMPT */
        !          3189:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "PREEMPT\n");
        !          3190: 
        !          3191:                task_abort = 0;
        !          3192:        do_preempt:
        !          3193:                prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
        !          3194:                    conn->target_port, 0);
        !          3195:                if (prkey == NULL) {
        !          3196:                        /* unregistered port */
        !          3197:                        lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          3198:                        return -1;
        !          3199:                }
        !          3200: 
        !          3201:                if (spec->rsv_key == 0) {
        !          3202:                        /* no reservation */
        !          3203:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "no reservation\n");
        !          3204:                        /* remove registration */
        !          3205:                        rc = istgt_lu_disk_remove_pr_key(spec, conn,
        !          3206:                            NULL, NULL, sarkey);
        !          3207:                        if (rc < 0) {
        !          3208:                                ISTGT_ERRLOG("lu_disk_remove_pr_key() failed\n");
        !          3209:                                /* INTERNAL TARGET FAILURE */
        !          3210:                                BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
        !          3211:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3212:                                return -1;
        !          3213:                        }
        !          3214: 
        !          3215:                        /* update generation */
        !          3216:                        spec->pr_generation++;
        !          3217: 
        !          3218:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          3219:                        break;
        !          3220:                }
        !          3221:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "rsv_key=0x%16.16"PRIx64"\n",
        !          3222:                    spec->rsv_key);
        !          3223: 
        !          3224:                if (spec->rsv_type == ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS
        !          3225:                    || spec->rsv_type == ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS) {
        !          3226:                        if (sarkey != 0) {
        !          3227:                                /* remove registration */
        !          3228:                                rc = istgt_lu_disk_remove_pr_key(spec, conn,
        !          3229:                                    NULL, NULL, sarkey);
        !          3230:                                if (rc < 0) {
        !          3231:                                        ISTGT_ERRLOG("lu_disk_remove_pr_key() failed\n");
        !          3232:                                        /* INTERNAL TARGET FAILURE */
        !          3233:                                        BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
        !          3234:                                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3235:                                        return -1;
        !          3236:                                }
        !          3237: 
        !          3238:                                /* update generation */
        !          3239:                                spec->pr_generation++;
        !          3240: 
        !          3241:                                lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          3242:                                break;
        !          3243:                        } else {
        !          3244:                                /* remove other registrations */
        !          3245:                                rc = istgt_lu_disk_remove_other_pr_key(spec, conn,
        !          3246:                                    conn->initiator_port,
        !          3247:                                    conn->target_port,
        !          3248:                                    rkey);
        !          3249:                                if (rc < 0) {
        !          3250:                                        ISTGT_ERRLOG("lu_disk_remove_other_pr_key() failed\n");
        !          3251:                                        /* INTERNAL TARGET FAILURE */
        !          3252:                                        BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
        !          3253:                                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3254:                                        return -1;
        !          3255:                                }
        !          3256: 
        !          3257:                                if (scope != 0x00) { // !LU_SCOPE
        !          3258:                                        /* INVALID FIELD IN CDB */
        !          3259:                                        BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
        !          3260:                                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3261:                                        return -1;
        !          3262:                                }
        !          3263:                                if (type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE
        !          3264:                                    && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS
        !          3265:                                    && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY
        !          3266:                                    && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY
        !          3267:                                    && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS
        !          3268:                                    && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS) {
        !          3269:                                        ISTGT_ERRLOG("unsupported type 0x%x\n", type);
        !          3270:                                        /* INVALID FIELD IN CDB */
        !          3271:                                        BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
        !          3272:                                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3273:                                        return -1;
        !          3274:                                }
        !          3275: 
        !          3276:                                /* release reservation */
        !          3277:                                //xfree(spec->rsv_port);
        !          3278:                                old_rsv_port = spec->rsv_port;
        !          3279:                                spec->rsv_port = NULL;
        !          3280:                                spec->rsv_key = 0;
        !          3281:                                spec->rsv_scope = 0;
        !          3282:                                spec->rsv_type = 0;
        !          3283:                                /* establish new reservation */
        !          3284:                                spec->rsv_port = xstrdup(conn->initiator_port);
        !          3285:                                strlwr(spec->rsv_port);
        !          3286:                                spec->rsv_key = rkey;
        !          3287:                                spec->rsv_scope = scope;
        !          3288:                                spec->rsv_type = type;
        !          3289: 
        !          3290:                                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !          3291:                                    "LU%d: reserved (scope=%d, type=%d)"
        !          3292:                                    "by key=0x%16.16"PRIx64"\n",
        !          3293:                                    spec->lu->num, scope, type, rkey);
        !          3294: 
        !          3295:                                /* update generation */
        !          3296:                                spec->pr_generation++;
        !          3297: 
        !          3298:                                /* XXX TODO fix */
        !          3299:                                if (task_abort) {
        !          3300:                                        /* abort all tasks for preempted I_T nexus */
        !          3301:                                        if (old_rsv_port != NULL) {
        !          3302:                                                rc = istgt_lu_disk_queue_abort_ITL(spec, old_rsv_port);
        !          3303:                                                xfree(old_rsv_port);
        !          3304:                                                old_rsv_port = NULL;
        !          3305:                                                if (rc < 0) {
        !          3306:                                                        /* INTERNAL TARGET FAILURE */
        !          3307:                                                        BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
        !          3308:                                                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3309:                                                        return -1;
        !          3310:                                                }
        !          3311:                                        }
        !          3312:                                }
        !          3313:                                if (old_rsv_port != NULL) {
        !          3314:                                        xfree(old_rsv_port);
        !          3315:                                        old_rsv_port = NULL;
        !          3316:                                }
        !          3317: 
        !          3318:                                lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          3319:                                break;
        !          3320:                        }
        !          3321:                }
        !          3322: 
        !          3323:                prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
        !          3324:                    conn->target_port, rkey);
        !          3325: 
        !          3326:                if (prkey == NULL) {
        !          3327:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !          3328:                            "prkey == NULL\n");
        !          3329:                } else {
        !          3330:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !          3331:                            "prkey key=%16.16"PRIx64"\n",
        !          3332:                            prkey->key);
        !          3333:                }
        !          3334: 
        !          3335:                if (prkey == NULL
        !          3336:                    || sarkey != spec->rsv_key) {
        !          3337:                        if (sarkey != 0) {
        !          3338:                                /* remove registration */
        !          3339:                                rc = istgt_lu_disk_remove_pr_key(spec, conn,
        !          3340:                                    NULL, NULL, sarkey);
        !          3341:                                if (rc < 0) {
        !          3342:                                        ISTGT_ERRLOG("lu_disk_remove_pr_key() failed\n");
        !          3343:                                        /* INTERNAL TARGET FAILURE */
        !          3344:                                        BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
        !          3345:                                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3346:                                        return -1;
        !          3347:                                }
        !          3348:                                lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          3349:                                break;
        !          3350:                        } else {
        !          3351:                                /* INVALID FIELD IN PARAMETER LIST */
        !          3352:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00);
        !          3353:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3354:                                return -1;
        !          3355:                        }
        !          3356:                }
        !          3357: 
        !          3358:                /* remove registration */
        !          3359:                rc = istgt_lu_disk_remove_pr_key(spec, conn,
        !          3360:                    NULL, NULL, sarkey);
        !          3361:                if (rc < 0) {
        !          3362:                        ISTGT_ERRLOG("lu_disk_remove_pr_key() failed\n");
        !          3363:                        /* INTERNAL TARGET FAILURE */
        !          3364:                        BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
        !          3365:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3366:                        return -1;
        !          3367:                }
        !          3368: 
        !          3369:                if (scope != 0x00) { // !LU_SCOPE
        !          3370:                        /* INVALID FIELD IN CDB */
        !          3371:                        BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
        !          3372:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3373:                        return -1;
        !          3374:                }
        !          3375:                if (type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE
        !          3376:                    && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS
        !          3377:                    && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY
        !          3378:                    && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY
        !          3379:                    && type != ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS
        !          3380:                    && type != ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS) {
        !          3381:                        ISTGT_ERRLOG("unsupported type 0x%x\n", type);
        !          3382:                        /* INVALID FIELD IN CDB */
        !          3383:                        BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
        !          3384:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3385:                        return -1;
        !          3386:                }
        !          3387: 
        !          3388:                /* release reservation */
        !          3389:                //xfree(spec->rsv_port);
        !          3390:                old_rsv_port = spec->rsv_port;
        !          3391:                spec->rsv_port = NULL;
        !          3392:                spec->rsv_key = 0;
        !          3393:                spec->rsv_scope = 0;
        !          3394:                spec->rsv_type = 0;
        !          3395:                /* establish new reservation */
        !          3396:                spec->rsv_port = xstrdup(conn->initiator_port);
        !          3397:                strlwr(spec->rsv_port);
        !          3398:                spec->rsv_key = rkey;
        !          3399:                spec->rsv_scope = scope;
        !          3400:                spec->rsv_type = type;
        !          3401: 
        !          3402:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !          3403:                    "LU%d: reserved (scope=%d, type=%d) by key=0x%16.16"
        !          3404:                    PRIx64"\n",
        !          3405:                    spec->lu->num, scope, type, rkey);
        !          3406: 
        !          3407:                /* update generation */
        !          3408:                spec->pr_generation++;
        !          3409: 
        !          3410:                /* XXX TODO fix */
        !          3411:                if (task_abort) {
        !          3412:                        /* abort all tasks for preempted I_T nexus */
        !          3413:                        if (old_rsv_port != NULL) {
        !          3414:                                rc = istgt_lu_disk_queue_abort_ITL(spec, old_rsv_port);
        !          3415:                                xfree(old_rsv_port);
        !          3416:                                old_rsv_port = NULL;
        !          3417:                                if (rc < 0) {
        !          3418:                                        /* INTERNAL TARGET FAILURE */
        !          3419:                                        BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
        !          3420:                                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3421:                                        return -1;
        !          3422:                                }
        !          3423:                        }
        !          3424:                }
        !          3425:                if (old_rsv_port != NULL) {
        !          3426:                        xfree(old_rsv_port);
        !          3427:                        old_rsv_port = NULL;
        !          3428:                }
        !          3429: 
        !          3430:                lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          3431:                break;
        !          3432: 
        !          3433:        case 0x05: /* PREEMPT AND ABORT */
        !          3434:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "PREEMPT AND ABORT\n");
        !          3435: 
        !          3436:                task_abort = 1;
        !          3437:                goto do_preempt;
        !          3438: 
        !          3439:        case 0x06: /* REGISTER AND IGNORE EXISTING KEY */
        !          3440:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "REGISTER AND IGNORE EXISTING KEY\n");
        !          3441: 
        !          3442:                if (aptpl != 0) {
        !          3443:                        /* Activate Persist Through Power Loss */
        !          3444:                        ISTGT_ERRLOG("unsupport Activate Persist Through Power Loss\n");
        !          3445:                        /* INVALID FIELD IN PARAMETER LIST */
        !          3446:                        BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00);
        !          3447:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3448:                        return -1;
        !          3449:                }
        !          3450:                /* lost reservations if daemon restart */
        !          3451: 
        !          3452:                prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
        !          3453:                    conn->target_port, 0);
        !          3454:                if (prkey == NULL) {
        !          3455:                        /* unregistered port */
        !          3456:                        if (sarkey != 0) {
        !          3457:                                if (spec_i_pt) {
        !          3458:                                        /* INVALID FIELD IN CDB */
        !          3459:                                        BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
        !          3460:                                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3461:                                        return -1;
        !          3462:                                }
        !          3463:                        }
        !          3464:                } else {
        !          3465:                        /* registered port */
        !          3466:                        if (spec_i_pt) {
        !          3467:                                /* INVALID FIELD IN CDB */
        !          3468:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
        !          3469:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3470:                                return -1;
        !          3471:                        }
        !          3472:                }
        !          3473: 
        !          3474:                /* remove existing keys */
        !          3475:                rc = istgt_lu_disk_remove_pr_key(spec, conn,
        !          3476:                    conn->initiator_port,
        !          3477:                    conn->target_port, 0);
        !          3478:                if (rc < 0) {
        !          3479:                        ISTGT_ERRLOG("lu_disk_remove_pr_key() failed\n");
        !          3480:                        /* INTERNAL TARGET FAILURE */
        !          3481:                        BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
        !          3482:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3483:                        return -1;
        !          3484:                }
        !          3485: 
        !          3486:                /* unregister? */
        !          3487:                if (sarkey == 0) {
        !          3488:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          3489:                        return 0;
        !          3490:                }
        !          3491: 
        !          3492:        do_register:
        !          3493:                /* specified port? */
        !          3494:                nports = 0;
        !          3495:                initiator_ports = NULL;
        !          3496:                if (spec_i_pt) {
        !          3497:                        if (len < 28) {
        !          3498:                                /* INVALID FIELD IN PARAMETER LIST */
        !          3499:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00);
        !          3500:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3501:                                return -1;
        !          3502:                        }
        !          3503: 
        !          3504:                        /* TRANSPORTID PARAMETER DATA LENGTH */
        !          3505:                        plen = DGET32(&data[24]);
        !          3506:                        if (28 + plen > len) {
        !          3507:                                ISTGT_ERRLOG("invalid length %d (expect %d)\n",
        !          3508:                                    len, 28 + plen);
        !          3509:                                /* INVALID FIELD IN PARAMETER LIST */
        !          3510:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00);
        !          3511:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3512:                                return -1;
        !          3513:                        }
        !          3514: 
        !          3515:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !          3516:                            "TransportID parameter data length %d\n",
        !          3517:                            plen);
        !          3518:                        if (plen != 0) {
        !          3519:                                maxports = MAX_LU_RESERVE_IPT;
        !          3520:                                initiator_ports = xmalloc(sizeof (char *) * maxports);
        !          3521:                                memset(initiator_ports, 0, sizeof (char *) * maxports);
        !          3522:                                nports = 0;
        !          3523:                                total = 0;
        !          3524:                                while (total < plen) {
        !          3525:                                        if (nports >= MAX_LU_RESERVE_IPT) {
        !          3526:                                                ISTGT_ERRLOG("maximum transport IDs\n");
        !          3527:                                                /* INSUFFICIENT REGISTRATION RESOURCES */
        !          3528:                                                BUILD_SENSE(ILLEGAL_REQUEST, 0x55, 0x04);
        !          3529:                                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3530:                                                return -1;
        !          3531:                                        }
        !          3532:                                        rc = istgt_lu_parse_transport_id
        !          3533:                                                (&initiator_ports[nports],
        !          3534:                                                 &data[24] + total, plen - total);
        !          3535:                                        if (rc < 0) {
        !          3536:                                                /* INVALID FIELD IN PARAMETER LIST */
        !          3537:                                                BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00);
        !          3538:                                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3539:                                                return -1;
        !          3540:                                        }
        !          3541:                                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "got TransportID %s\n",
        !          3542:                                            initiator_ports[nports]);
        !          3543:                                        total += rc;
        !          3544:                                        nports++;
        !          3545:                                }
        !          3546:                        }
        !          3547:                        /* check all port unregistered? */
        !          3548:                        for (i = 0; i < nports; i++) {
        !          3549:                                prkey = istgt_lu_disk_find_pr_key(spec,
        !          3550:                                    initiator_ports[i], NULL, 0);
        !          3551:                                if (prkey != NULL) {
        !          3552:                                        /* registered port */
        !          3553:                                        /* INVALID FIELD IN CDB */
        !          3554:                                        BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
        !          3555:                                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3556:                                        return -1;
        !          3557:                                }
        !          3558:                        }
        !          3559:                        /* OK, all port unregistered */
        !          3560:                        idx = spec->npr_keys;
        !          3561:                        if (idx + nports >= MAX_LU_RESERVE) {
        !          3562:                                /* INSUFFICIENT REGISTRATION RESOURCES */
        !          3563:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x55, 0x04);
        !          3564:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3565:                                return -1;
        !          3566:                        }
        !          3567:                        /* register each I_T nexus */
        !          3568:                        for (i = 0; i < nports; i++) {
        !          3569:                                prkey = &spec->pr_keys[idx + i];
        !          3570: 
        !          3571:                                /* register new key */
        !          3572:                                prkey->key = sarkey;
        !          3573: 
        !          3574:                                /* command received port */
        !          3575:                                prkey->registered_initiator_port
        !          3576:                                        = xstrdup(conn->initiator_port);
        !          3577:                                strlwr(prkey->registered_initiator_port);
        !          3578:                                prkey->registered_target_port
        !          3579:                                        = xstrdup(conn->target_port);
        !          3580:                                strlwr(prkey->registered_target_port);
        !          3581:                                prkey->pg_idx = conn->portal.idx;
        !          3582:                                prkey->pg_tag = conn->portal.tag;
        !          3583: 
        !          3584:                                /* specified ports */
        !          3585:                                prkey->ninitiator_ports = 0;
        !          3586:                                prkey->initiator_ports = NULL;
        !          3587:                                prkey->all_tpg = (all_tg_pt) ? 1 : 0;
        !          3588:                        }
        !          3589:                        spec->npr_keys = idx + nports;
        !          3590:                }
        !          3591: 
        !          3592:                idx = spec->npr_keys;
        !          3593:                if (idx >= MAX_LU_RESERVE) {
        !          3594:                        /* INSUFFICIENT REGISTRATION RESOURCES */
        !          3595:                        BUILD_SENSE(ILLEGAL_REQUEST, 0x55, 0x04);
        !          3596:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3597:                        return -1;
        !          3598:                }
        !          3599:                prkey = &spec->pr_keys[idx];
        !          3600: 
        !          3601:                /* register new key */
        !          3602:                prkey->key = sarkey;
        !          3603: 
        !          3604:                /* command received port */
        !          3605:                prkey->registered_initiator_port = xstrdup(conn->initiator_port);
        !          3606:                strlwr(prkey->registered_initiator_port);
        !          3607:                prkey->registered_target_port = xstrdup(conn->target_port);
        !          3608:                strlwr(prkey->registered_target_port);
        !          3609:                prkey->pg_idx = conn->portal.idx;
        !          3610:                prkey->pg_tag = conn->portal.tag;
        !          3611: 
        !          3612:                /* specified ports */
        !          3613:                prkey->ninitiator_ports = nports;
        !          3614:                prkey->initiator_ports = initiator_ports;
        !          3615:                prkey->all_tpg = (all_tg_pt) ? 1 : 0;
        !          3616: 
        !          3617:                /* count up keys */
        !          3618:                idx++;
        !          3619:                spec->npr_keys = idx;
        !          3620: 
        !          3621:                /* update generation */
        !          3622:                spec->pr_generation++;
        !          3623:                break;
        !          3624: 
        !          3625:        case 0x07: /* REGISTER AND MOVE */
        !          3626:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "REGISTER AND MOVE\n");
        !          3627:                /* INVALID FIELD IN CDB */
        !          3628:                BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
        !          3629:                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3630:                return -1;
        !          3631: 
        !          3632:        default:
        !          3633:                ISTGT_ERRLOG("unsupported service action 0x%x\n", sa);
        !          3634:                /* INVALID FIELD IN CDB */
        !          3635:                BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
        !          3636:                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3637:                return -1;
        !          3638:        }
        !          3639: 
        !          3640:        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          3641:        return 0;
        !          3642: }
        !          3643: 
        !          3644: static int
        !          3645: istgt_lu_disk_check_pr(ISTGT_LU_DISK *spec, CONN_Ptr conn, int pr_allow)
        !          3646: {
        !          3647:        ISTGT_LU_PR_KEY *prkey;
        !          3648: 
        !          3649: #ifdef ISTGT_TRACE_DISK
        !          3650:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !          3651:            "RSV_KEY=0x%16.16"PRIx64", RSV_TYPE=0x%x, PR_ALLOW=0x%x\n",
        !          3652:            spec->rsv_key, spec->rsv_type, pr_allow);
        !          3653: #endif /* ISTGT_TRACE_DISK */
        !          3654: 
        !          3655:        prkey = istgt_lu_disk_find_pr_key(spec, conn->initiator_port,
        !          3656:            conn->target_port, 0);
        !          3657:        if (prkey != NULL) {
        !          3658: #ifdef ISTGT_TRACE_DISK
        !          3659:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !          3660:                    "PRKEY(0x%16.16"PRIx64") found for %s\n",
        !          3661:                    prkey->key, conn->initiator_port);
        !          3662: #endif /* ISTGT_TRACE_DISK */
        !          3663: 
        !          3664:                if (spec->rsv_key == prkey->key) {
        !          3665:                        /* reservation holder */
        !          3666:                        return 0;
        !          3667:                }
        !          3668: 
        !          3669:                switch (spec->rsv_type) {
        !          3670:                case ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS:
        !          3671:                        if (pr_allow & PR_ALLOW_ALLRR)
        !          3672:                                return 0;
        !          3673:                        return -1;
        !          3674:                case ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS:
        !          3675:                        if (pr_allow & PR_ALLOW_ALLRR)
        !          3676:                                return 0;
        !          3677:                        return -1;
        !          3678:                case ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY:
        !          3679:                        if (pr_allow & PR_ALLOW_ALLRR)
        !          3680:                                return 0;
        !          3681:                        return -1;
        !          3682:                case ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY:
        !          3683:                        if (pr_allow & PR_ALLOW_ALLRR)
        !          3684:                                return 0;
        !          3685:                        return -1;
        !          3686:                }
        !          3687:        } else {
        !          3688: #ifdef ISTGT_TRACE_DISK
        !          3689:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !          3690:                    "PRKEY not found for %s\n",
        !          3691:                    conn->initiator_port);
        !          3692: #endif /* ISTGT_TRACE_DISK */
        !          3693: 
        !          3694:                switch (spec->rsv_type) {
        !          3695:                case ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_ALL_REGISTRANTS:
        !          3696:                        if (pr_allow & PR_ALLOW_WERR)
        !          3697:                                return 0;
        !          3698:                        return -1;
        !          3699:                case ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE_REGISTRANTS_ONLY:
        !          3700:                        if (pr_allow & PR_ALLOW_WERR)
        !          3701:                                return 0;
        !          3702:                        return -1;
        !          3703:                case ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_ALL_REGISTRANTS:
        !          3704:                        if (pr_allow & PR_ALLOW_EARR)
        !          3705:                                return 0;
        !          3706:                        return -1;
        !          3707:                case ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS_REGISTRANTS_ONLY:
        !          3708:                        if (pr_allow & PR_ALLOW_EARR)
        !          3709:                                return 0;
        !          3710:                        return -1;
        !          3711:                }
        !          3712:        }
        !          3713: 
        !          3714: #ifdef ISTGT_TRACE_DISK
        !          3715:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "non registrans type\n");
        !          3716: #endif /* ISTGT_TRACE_DISK */
        !          3717:        /* any I_T nexus */
        !          3718:        switch (spec->rsv_type) {
        !          3719:        case ISTGT_LU_PR_TYPE_WRITE_EXCLUSIVE:
        !          3720:                if (pr_allow & PR_ALLOW_WE)
        !          3721:                        return 0;
        !          3722:                return -1;
        !          3723:        case ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS:
        !          3724:                if (pr_allow & PR_ALLOW_EA)
        !          3725:                        return 0;
        !          3726:                return -1;
        !          3727:        }
        !          3728: 
        !          3729:        /* NG */
        !          3730:        return -1;
        !          3731: }
        !          3732: 
        !          3733: static int
        !          3734: istgt_lu_disk_scsi_release(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
        !          3735: {
        !          3736:        ISTGT_LU_CMD lu_cmd2;
        !          3737:        uint8_t *sense_data;
        !          3738:        int *sense_len;
        !          3739:        uint64_t LUI;
        !          3740:        uint64_t rkey;
        !          3741:        uint8_t cdb[10];
        !          3742:        uint8_t PRO_data[24];
        !          3743:        int parameter_len;
        !          3744:        int rc;
        !          3745: 
        !          3746:        sense_data = lu_cmd->sense_data;
        !          3747:        sense_len = &lu_cmd->sense_data_len;
        !          3748:        *sense_len = 0;
        !          3749: 
        !          3750:        memset(&lu_cmd2, 0, sizeof lu_cmd2);
        !          3751:        lu_cmd2.sense_data = lu_cmd->sense_data;
        !          3752:        lu_cmd2.sense_data_len = lu_cmd->sense_data_len;
        !          3753:        memset(&cdb, 0, sizeof cdb);
        !          3754:        parameter_len = sizeof PRO_data;
        !          3755: 
        !          3756:        LUI = istgt_get_lui(spec->lu->name, spec->lun & 0xffffU);
        !          3757:        rkey = istgt_get_rkey(conn->initiator_name, LUI);
        !          3758: 
        !          3759:        /* issue release action of PERSISTENT RESERVE OUT */
        !          3760:        cdb[0] = SPC_PERSISTENT_RESERVE_OUT;
        !          3761:        BDSET8W(&cdb[1], 0x02, 4, 5); /* RELEASE */
        !          3762:        BDSET8W(&cdb[2], 0x00, 7, 4); /* LU_SCOPE */
        !          3763:        BDADD8W(&cdb[2], 0x03, 3, 4); /* ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS */
        !          3764:        cdb[3] = 0;
        !          3765:        cdb[4] = 0;
        !          3766:        DSET32(&cdb[5], parameter_len);
        !          3767:        cdb[9] = 0;
        !          3768:        lu_cmd2.cdb = &cdb[0];
        !          3769: 
        !          3770:        memset(&PRO_data, 0, sizeof PRO_data);
        !          3771:        DSET64(&PRO_data[0], rkey); // RESERVATION KEY
        !          3772:        DSET64(&PRO_data[8], 0);
        !          3773: 
        !          3774:        rc = istgt_lu_disk_scsi_persistent_reserve_out(spec, conn, &lu_cmd2,
        !          3775:            0x02, 0x00, 0x03,
        !          3776:            PRO_data, parameter_len);
        !          3777:        if (rc < 0) {
        !          3778:                lu_cmd->status = lu_cmd2.status;
        !          3779:                if (lu_cmd->status == ISTGT_SCSI_STATUS_RESERVATION_CONFLICT) {
        !          3780:                        return -1;
        !          3781:                }
        !          3782:                /* INTERNAL TARGET FAILURE */
        !          3783:                BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
        !          3784:                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3785:                return -1;
        !          3786:        }
        !          3787: 
        !          3788:        /* issue unregister action of PERSISTENT RESERVE OUT */
        !          3789:        cdb[0] = SPC_PERSISTENT_RESERVE_OUT;
        !          3790:        BDSET8W(&cdb[1], 0x06, 4, 5); /* REGISTER AND IGNORE EXISTING KEY */
        !          3791:        cdb[2] = 0;
        !          3792:        cdb[3] = 0;
        !          3793:        cdb[4] = 0;
        !          3794:        DSET32(&cdb[5], parameter_len);
        !          3795:        cdb[9] = 0;
        !          3796:        lu_cmd2.cdb = &cdb[0];
        !          3797: 
        !          3798:        memset(&PRO_data, 0, sizeof PRO_data);
        !          3799:        DSET64(&PRO_data[0], rkey); // RESERVATION KEY
        !          3800:        DSET64(&PRO_data[8], 0); // unregister
        !          3801: 
        !          3802:        rc = istgt_lu_disk_scsi_persistent_reserve_out(spec, conn, &lu_cmd2,
        !          3803:            0x06, 0, 0,
        !          3804:            PRO_data, parameter_len);
        !          3805:        if (rc < 0) {
        !          3806:                lu_cmd->status = lu_cmd2.status;
        !          3807:                if (lu_cmd->status == ISTGT_SCSI_STATUS_RESERVATION_CONFLICT) {
        !          3808:                        return -1;
        !          3809:                }
        !          3810:                /* INTERNAL TARGET FAILURE */
        !          3811:                BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
        !          3812:                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3813:                return -1;
        !          3814:        }
        !          3815: 
        !          3816:        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          3817:        return 0;
        !          3818: }
        !          3819: 
        !          3820: static int
        !          3821: istgt_lu_disk_scsi_reserve(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
        !          3822: {
        !          3823:        ISTGT_LU_CMD lu_cmd2;
        !          3824:        uint8_t *sense_data;
        !          3825:        int *sense_len;
        !          3826:        uint64_t LUI;
        !          3827:        uint64_t rkey;
        !          3828:        uint8_t cdb[10];
        !          3829:        uint8_t PRO_data[24];
        !          3830:        int parameter_len;
        !          3831:        int rc;
        !          3832: 
        !          3833:        sense_data = lu_cmd->sense_data;
        !          3834:        sense_len = &lu_cmd->sense_data_len;
        !          3835:        *sense_len = 0;
        !          3836: 
        !          3837:        memset(&lu_cmd2, 0, sizeof lu_cmd2);
        !          3838:        lu_cmd2.sense_data = lu_cmd->sense_data;
        !          3839:        lu_cmd2.sense_data_len = lu_cmd->sense_data_len;
        !          3840:        memset(&cdb, 0, sizeof cdb);
        !          3841:        parameter_len = sizeof PRO_data;
        !          3842: 
        !          3843:        LUI = istgt_get_lui(spec->lu->name, spec->lun & 0xffffU);
        !          3844:        rkey = istgt_get_rkey(conn->initiator_name, LUI);
        !          3845: 
        !          3846:        /* issue register action of PERSISTENT RESERVE OUT */
        !          3847:        cdb[0] = SPC_PERSISTENT_RESERVE_OUT;
        !          3848:        BDSET8W(&cdb[1], 0x06, 4, 5); /* REGISTER AND IGNORE EXISTING KEY */
        !          3849:        cdb[2] = 0;
        !          3850:        cdb[3] = 0;
        !          3851:        cdb[4] = 0;
        !          3852:        DSET32(&cdb[5], parameter_len);
        !          3853:        cdb[9] = 0;
        !          3854:        lu_cmd2.cdb = &cdb[0];
        !          3855: 
        !          3856:        memset(&PRO_data, 0, sizeof PRO_data);
        !          3857:        DSET64(&PRO_data[0], 0);
        !          3858:        DSET64(&PRO_data[8], rkey); // SERVICE ACTION RESERVATION KEY
        !          3859: 
        !          3860:        rc = istgt_lu_disk_scsi_persistent_reserve_out(spec, conn, &lu_cmd2,
        !          3861:            0x06, 0, 0,
        !          3862:            PRO_data, parameter_len);
        !          3863:        if (rc < 0) {
        !          3864:                lu_cmd->status = lu_cmd2.status;
        !          3865:                if (lu_cmd->status == ISTGT_SCSI_STATUS_RESERVATION_CONFLICT) {
        !          3866:                        return -1;
        !          3867:                }
        !          3868:                /* INTERNAL TARGET FAILURE */
        !          3869:                BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
        !          3870:                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3871:                return -1;
        !          3872:        }
        !          3873: 
        !          3874:        /* issue reserve action of PERSISTENT RESERVE OUT */
        !          3875:        cdb[0] = SPC_PERSISTENT_RESERVE_OUT;
        !          3876:        BDSET8W(&cdb[1], 0x01, 4, 5); /* RESERVE */
        !          3877:        BDSET8W(&cdb[2], 0x00, 7, 4); /* LU_SCOPE */
        !          3878:        BDADD8W(&cdb[2], 0x03, 3, 4); /* ISTGT_LU_PR_TYPE_EXCLUSIVE_ACCESS */
        !          3879:        cdb[3] = 0;
        !          3880:        cdb[4] = 0;
        !          3881:        DSET32(&cdb[5], parameter_len);
        !          3882:        cdb[9] = 0;
        !          3883:        lu_cmd2.cdb = &cdb[0];
        !          3884: 
        !          3885:        memset(&PRO_data, 0, sizeof PRO_data);
        !          3886:        DSET64(&PRO_data[0], rkey); // RESERVATION KEY
        !          3887:        DSET64(&PRO_data[8], 0);
        !          3888: 
        !          3889:        rc = istgt_lu_disk_scsi_persistent_reserve_out(spec, conn, &lu_cmd2,
        !          3890:            0x01, 0x00, 0x03,
        !          3891:            PRO_data, parameter_len);
        !          3892:        if (rc < 0) {
        !          3893:                lu_cmd->status = lu_cmd2.status;
        !          3894:                if (lu_cmd->status == ISTGT_SCSI_STATUS_RESERVATION_CONFLICT) {
        !          3895:                        return -1;
        !          3896:                }
        !          3897:                /* INTERNAL TARGET FAILURE */
        !          3898:                BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
        !          3899:                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          3900:                return -1;
        !          3901:        }
        !          3902: 
        !          3903:        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          3904:        return 0;
        !          3905: }
        !          3906: 
        !          3907: static int
        !          3908: istgt_lu_disk_lbread(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint64_t lba, uint32_t len)
        !          3909: {
        !          3910:        uint8_t *data;
        !          3911:        uint64_t maxlba;
        !          3912:        uint64_t llen;
        !          3913:        uint64_t blen;
        !          3914:        uint64_t offset;
        !          3915:        uint64_t nbytes;
        !          3916:        int64_t rc;
        !          3917: 
        !          3918:        if (len == 0) {
        !          3919:                lu_cmd->data = NULL;
        !          3920:                lu_cmd->data_len = 0;
        !          3921:                return 0;
        !          3922:        }
        !          3923: 
        !          3924:        maxlba = spec->blockcnt;
        !          3925:        llen = (uint64_t) len;
        !          3926:        blen = spec->blocklen;
        !          3927:        offset = lba * blen;
        !          3928:        nbytes = llen * blen;
        !          3929: 
        !          3930:        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
        !          3931:            "Read: max=%"PRIu64", lba=%"PRIu64", len=%u\n",
        !          3932:            maxlba, lba, len);
        !          3933: 
        !          3934:        if (lba >= maxlba || llen > maxlba || lba > (maxlba - llen)) {
        !          3935:                ISTGT_ERRLOG("end of media\n");
        !          3936:                return -1;
        !          3937:        }
        !          3938: 
        !          3939:        if (nbytes > lu_cmd->iobufsize) {
        !          3940:                ISTGT_ERRLOG("nbytes(%u) > iobufsize(%u)\n",
        !          3941:                    nbytes, lu_cmd->iobufsize);
        !          3942:                return -1;
        !          3943:        }
        !          3944:        data = lu_cmd->iobuf;
        !          3945: 
        !          3946:        rc = istgt_lu_disk_seek(spec, offset);
        !          3947:        if (rc < 0) {
        !          3948:                ISTGT_ERRLOG("lu_disk_seek() failed\n");
        !          3949:                return -1;
        !          3950:        }
        !          3951: 
        !          3952:        rc = istgt_lu_disk_read(spec, data, nbytes);
        !          3953:        if (rc < 0) {
        !          3954:                ISTGT_ERRLOG("lu_disk_read() failed\n");
        !          3955:                return -1;
        !          3956:        }
        !          3957:        ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "Read %"PRId64"/%"PRIu64" bytes\n",
        !          3958:            rc, nbytes);
        !          3959: 
        !          3960:        lu_cmd->data = data;
        !          3961:        lu_cmd->data_len = rc;
        !          3962: 
        !          3963:        return 0;
        !          3964: }
        !          3965: 
        !          3966: static int
        !          3967: istgt_lu_disk_lbwrite(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint64_t lba, uint32_t len)
        !          3968: {
        !          3969:        uint8_t *data;
        !          3970:        uint64_t maxlba;
        !          3971:        uint64_t llen;
        !          3972:        uint64_t blen;
        !          3973:        uint64_t offset;
        !          3974:        uint64_t nbytes;
        !          3975:        int64_t rc;
        !          3976: 
        !          3977:        if (len == 0) {
        !          3978:                lu_cmd->data_len = 0;
        !          3979:                return 0;
        !          3980:        }
        !          3981: 
        !          3982:        maxlba = spec->blockcnt;
        !          3983:        llen = (uint64_t) len;
        !          3984:        blen = spec->blocklen;
        !          3985:        offset = lba * blen;
        !          3986:        nbytes = llen * blen;
        !          3987: 
        !          3988:        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
        !          3989:            "Write: max=%"PRIu64", lba=%"PRIu64", len=%u\n",
        !          3990:            maxlba, lba, len);
        !          3991: 
        !          3992:        if (lba >= maxlba || llen > maxlba || lba > (maxlba - llen)) {
        !          3993:                ISTGT_ERRLOG("end of media\n");
        !          3994:                return -1;
        !          3995:        }
        !          3996: 
        !          3997:        if (nbytes > lu_cmd->iobufsize) {
        !          3998:                ISTGT_ERRLOG("nbytes(%u) > iobufsize(%u)\n",
        !          3999:                    nbytes, lu_cmd->iobufsize);
        !          4000:                return -1;
        !          4001:        }
        !          4002:        data = lu_cmd->iobuf;
        !          4003: 
        !          4004:        rc = istgt_lu_disk_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
        !          4005:            lu_cmd->iobufsize, nbytes);
        !          4006:        if (rc < 0) {
        !          4007:                ISTGT_ERRLOG("lu_disk_transfer_data() failed\n");
        !          4008:                return -1;
        !          4009:        }
        !          4010: 
        !          4011:        if (spec->lu->readonly) {
        !          4012:                ISTGT_ERRLOG("LU%d: readonly unit\n", spec->lu->num);
        !          4013:                return -1;
        !          4014:        }
        !          4015: 
        !          4016:        spec->req_write_cache = 0;
        !          4017:        rc = istgt_lu_disk_seek(spec, offset);
        !          4018:        if (rc < 0) {
        !          4019:                ISTGT_ERRLOG("lu_disk_seek() failed\n");
        !          4020:                return -1;
        !          4021:        }
        !          4022: 
        !          4023:        rc = istgt_lu_disk_write(spec, data, nbytes);
        !          4024:        if (rc < 0 || rc != nbytes) {
        !          4025:                ISTGT_ERRLOG("lu_disk_write() failed\n");
        !          4026:                return -1;
        !          4027:        }
        !          4028:        ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "Wrote %"PRId64"/%"PRIu64" bytes\n",
        !          4029:            rc, nbytes);
        !          4030: 
        !          4031:        lu_cmd->data_len = rc;
        !          4032: 
        !          4033:        return 0;
        !          4034: }
        !          4035: 
        !          4036: static int
        !          4037: istgt_lu_disk_lbwrite_same(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint64_t lba, uint32_t len)
        !          4038: {
        !          4039:        uint8_t *data;
        !          4040:        uint64_t maxlba;
        !          4041:        uint64_t llen;
        !          4042:        uint64_t blen;
        !          4043:        uint64_t offset;
        !          4044:        uint64_t nbytes;
        !          4045:        uint64_t nblocks;
        !          4046:        uint64_t wblocks;
        !          4047:        int64_t rc;
        !          4048: 
        !          4049:        maxlba = spec->blockcnt;
        !          4050:        llen = (uint64_t) len;
        !          4051:        if (llen == 0) {
        !          4052:                if (lba >= maxlba) {
        !          4053:                        ISTGT_ERRLOG("end of media\n");
        !          4054:                        return -1;
        !          4055:                }
        !          4056:                llen = maxlba - lba;
        !          4057:        }
        !          4058:        blen = spec->blocklen;
        !          4059:        offset = lba * blen;
        !          4060:        nbytes = 1 * blen;
        !          4061: 
        !          4062:        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
        !          4063:            "Write Same: max=%"PRIu64", lba=%"PRIu64", len=%u\n",
        !          4064:            maxlba, lba, len);
        !          4065: 
        !          4066:        if (lba >= maxlba || llen > maxlba || lba > (maxlba - llen)) {
        !          4067:                ISTGT_ERRLOG("end of media\n");
        !          4068:                return -1;
        !          4069:        }
        !          4070: 
        !          4071:        if (nbytes > lu_cmd->iobufsize) {
        !          4072:                ISTGT_ERRLOG("nbytes(%u) > iobufsize(%u)\n",
        !          4073:                    nbytes, lu_cmd->iobufsize);
        !          4074:                return -1;
        !          4075:        }
        !          4076:        data = lu_cmd->iobuf;
        !          4077: 
        !          4078:        rc = istgt_lu_disk_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
        !          4079:            lu_cmd->iobufsize, nbytes);
        !          4080:        if (rc < 0) {
        !          4081:                ISTGT_ERRLOG("lu_disk_transfer_data() failed\n");
        !          4082:                return -1;
        !          4083:        }
        !          4084: 
        !          4085:        if (spec->lu->readonly) {
        !          4086:                ISTGT_ERRLOG("LU%d: readonly unit\n", spec->lu->num);
        !          4087:                return -1;
        !          4088:        }
        !          4089: 
        !          4090:        if (conn->workbuf == NULL) {
        !          4091:                conn->worksize = ISTGT_LU_WORK_BLOCK_SIZE;
        !          4092:                conn->workbuf = xmalloc(conn->worksize);
        !          4093:        }
        !          4094:        wblocks = (int64_t)conn->worksize / nbytes;
        !          4095:        if (wblocks == 0) {
        !          4096:                ISTGT_ERRLOG("work buffer is too small\n");
        !          4097:                return -1;
        !          4098:        }
        !          4099: 
        !          4100:        spec->req_write_cache = 0;
        !          4101:        rc = istgt_lu_disk_seek(spec, offset);
        !          4102:        if (rc < 0) {
        !          4103:                ISTGT_ERRLOG("lu_disk_seek() failed\n");
        !          4104:                return -1;
        !          4105:        }
        !          4106: 
        !          4107: #if 0
        !          4108:        nblocks = 0;
        !          4109:        while (nblocks < llen) {
        !          4110:                rc = istgt_lu_disk_write(spec, data, nbytes);
        !          4111:                if (rc < 0 || rc != nbytes) {
        !          4112:                        ISTGT_ERRLOG("lu_disk_write() failed\n");
        !          4113:                        return -1;
        !          4114:                }
        !          4115:                nblocks++;
        !          4116:        }
        !          4117: #else
        !          4118:        nblocks = 0;
        !          4119:        while (nblocks < wblocks) {
        !          4120:                memcpy(conn->workbuf + (nblocks * nbytes), data, nbytes);
        !          4121:                nblocks++;
        !          4122:        }
        !          4123: 
        !          4124:        nblocks = 0;
        !          4125:        while (nblocks < llen) {
        !          4126:                uint64_t reqblocks = DMIN64(wblocks, (llen - nblocks));
        !          4127:                rc = istgt_lu_disk_write(spec, conn->workbuf, (reqblocks * nbytes));
        !          4128:                if (rc < 0 || rc != (reqblocks * nbytes)) {
        !          4129:                        ISTGT_ERRLOG("lu_disk_write() failed\n");
        !          4130:                        return -1;
        !          4131:                }
        !          4132:                nblocks += reqblocks;
        !          4133:        }
        !          4134: #endif
        !          4135:        ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "Wrote %"PRId64"/%"PRIu64" bytes\n",
        !          4136:            (nblocks * nbytes), (llen * nbytes));
        !          4137: 
        !          4138:        lu_cmd->data_len = nbytes;
        !          4139: 
        !          4140:        return 0;
        !          4141: }
        !          4142: 
        !          4143: static int
        !          4144: istgt_lu_disk_lbwrite_ats(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint64_t lba, uint32_t len)
        !          4145: {
        !          4146:        uint8_t *tmp;
        !          4147:        uint8_t *data;
        !          4148:        uint64_t maxlba;
        !          4149:        uint64_t llen;
        !          4150:        uint64_t blen;
        !          4151:        uint64_t offset;
        !          4152:        uint64_t nbytes;
        !          4153:        int64_t rc;
        !          4154:        uint8_t *sense_data;
        !          4155:        int *sense_len;
        !          4156: 
        !          4157:        if (len == 0) {
        !          4158:                lu_cmd->data_len = 0;
        !          4159:                return 0;
        !          4160:        }
        !          4161: 
        !          4162:        sense_data = lu_cmd->sense_data;
        !          4163:        sense_len = &lu_cmd->sense_data_len;
        !          4164:        *sense_len = 0;
        !          4165: 
        !          4166:        maxlba = spec->blockcnt;
        !          4167:        llen = (uint64_t) len;
        !          4168:        blen = spec->blocklen;
        !          4169:        offset = lba * blen;
        !          4170:        nbytes = llen * blen;
        !          4171: 
        !          4172:        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
        !          4173:            "Write ATS: max=%"PRIu64", lba=%"PRIu64", len=%u\n",
        !          4174:            maxlba, lba, len);
        !          4175: 
        !          4176:        if (lba >= maxlba || llen > maxlba || lba > (maxlba - llen)) {
        !          4177:                ISTGT_ERRLOG("end of media\n");
        !          4178:                return -1;
        !          4179:        }
        !          4180: 
        !          4181:        if (nbytes > lu_cmd->iobufsize) {
        !          4182:                ISTGT_ERRLOG("nbytes(%u) > iobufsize(%u)\n",
        !          4183:                    nbytes, lu_cmd->iobufsize);
        !          4184:                return -1;
        !          4185:        }
        !          4186:        data = lu_cmd->iobuf;
        !          4187: 
        !          4188:        rc = istgt_lu_disk_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
        !          4189:            lu_cmd->iobufsize, nbytes * 2);
        !          4190:        if (rc < 0) {
        !          4191:                ISTGT_ERRLOG("lu_disk_transfer_data() failed\n");
        !          4192:                return -1;
        !          4193:        }
        !          4194: 
        !          4195:        if (spec->lu->readonly) {
        !          4196:                ISTGT_ERRLOG("LU%d: readonly unit\n", spec->lu->num);
        !          4197:                return -1;
        !          4198:        }
        !          4199: 
        !          4200:        tmp = xmalloc(nbytes);
        !          4201:        spec->req_write_cache = 0;
        !          4202:        /* start atomic test and set */
        !          4203:        MTX_LOCK(&spec->ats_mutex);
        !          4204: 
        !          4205:        rc = istgt_lu_disk_seek(spec, offset);
        !          4206:        if (rc < 0) {
        !          4207:                MTX_UNLOCK(&spec->ats_mutex);
        !          4208:                ISTGT_ERRLOG("lu_disk_seek() failed\n");
        !          4209:                xfree(tmp);
        !          4210:                return -1;
        !          4211:        }
        !          4212: 
        !          4213:        rc = istgt_lu_disk_read(spec, tmp, nbytes);
        !          4214:        if (rc < 0 || rc != nbytes) {
        !          4215:                MTX_UNLOCK(&spec->ats_mutex);
        !          4216:                ISTGT_ERRLOG("lu_disk_read() failed\n");
        !          4217:                xfree(tmp);
        !          4218:                return -1;
        !          4219:        }
        !          4220: 
        !          4221: #if 0
        !          4222:        ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "ATS VERIFY", data, nbytes);
        !          4223:        ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "ATS WRITE", data + nbytes, nbytes);
        !          4224:        ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "ATS DATA", tmp, nbytes);
        !          4225: #endif
        !          4226:        if (memcmp(tmp, data, nbytes) != 0) {
        !          4227:                MTX_UNLOCK(&spec->ats_mutex);
        !          4228:                //ISTGT_ERRLOG("compare failed\n");
        !          4229:                xfree(tmp);
        !          4230:                /* MISCOMPARE DURING VERIFY OPERATION */
        !          4231:                BUILD_SENSE(MISCOMPARE, 0x1d, 0x00);
        !          4232:                return -1;
        !          4233:        }
        !          4234: 
        !          4235:        rc = istgt_lu_disk_seek(spec, offset);
        !          4236:        if (rc < 0) {
        !          4237:                MTX_UNLOCK(&spec->ats_mutex);
        !          4238:                ISTGT_ERRLOG("lu_disk_seek() failed\n");
        !          4239:                xfree(tmp);
        !          4240:                return -1;
        !          4241:        }
        !          4242:        rc = istgt_lu_disk_write(spec, data + nbytes, nbytes);
        !          4243:        if (rc < 0 || rc != nbytes) {
        !          4244:                MTX_UNLOCK(&spec->ats_mutex);
        !          4245:                ISTGT_ERRLOG("lu_disk_write() failed\n");
        !          4246:                xfree(tmp);
        !          4247:                return -1;
        !          4248:        }
        !          4249:        ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "Wrote %"PRId64"/%"PRIu64" bytes\n",
        !          4250:            rc, nbytes);
        !          4251: 
        !          4252:        MTX_UNLOCK(&spec->ats_mutex);
        !          4253:        /* end atomic test and set */
        !          4254:        xfree(tmp);
        !          4255: 
        !          4256:        lu_cmd->data_len = nbytes * 2;
        !          4257: 
        !          4258:        return 0;
        !          4259: }
        !          4260: 
        !          4261: static int
        !          4262: istgt_lu_disk_lbsync(ISTGT_LU_DISK *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint64_t lba, uint32_t len)
        !          4263: {
        !          4264:        uint64_t maxlba;
        !          4265:        uint64_t llen;
        !          4266:        uint64_t blen;
        !          4267:        uint64_t offset;
        !          4268:        uint64_t nbytes;
        !          4269:        int64_t rc;
        !          4270: 
        !          4271:        if (len == 0) {
        !          4272:                return 0;
        !          4273:        }
        !          4274: 
        !          4275:        maxlba = spec->blockcnt;
        !          4276:        llen = (uint64_t) len;
        !          4277:        blen = spec->blocklen;
        !          4278:        offset = lba * blen;
        !          4279:        nbytes = llen * blen;
        !          4280: 
        !          4281:        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
        !          4282:            "Sync: max=%"PRIu64", lba=%"PRIu64", len=%u\n",
        !          4283:            maxlba, lba, len);
        !          4284: 
        !          4285:        if (lba >= maxlba || llen > maxlba || lba > (maxlba - llen)) {
        !          4286:                ISTGT_ERRLOG("end of media\n");
        !          4287:                return -1;
        !          4288:        }
        !          4289: 
        !          4290:        rc = istgt_lu_disk_sync(spec, offset, nbytes);
        !          4291:        if (rc < 0) {
        !          4292:                ISTGT_ERRLOG("lu_disk_sync() failed\n");
        !          4293:                return -1;
        !          4294:        }
        !          4295: 
        !          4296:        return 0;
        !          4297: }
        !          4298: 
        !          4299: int
        !          4300: istgt_lu_scsi_build_sense_data(uint8_t *data, int sk, int asc, int ascq)
        !          4301: {
        !          4302:        uint8_t *cp;
        !          4303:        int resp_code;
        !          4304:        int hlen = 0, len = 0, plen;
        !          4305:        int total;
        !          4306: 
        !          4307:        resp_code = 0x70; /* Current + Fixed format */
        !          4308: 
        !          4309:        /* SenseLength */
        !          4310:        DSET16(&data[0], 0);
        !          4311:        hlen = 2;
        !          4312: 
        !          4313:        /* Sense Data */
        !          4314:        cp = &data[hlen + len];
        !          4315: 
        !          4316:        /* VALID(7) RESPONSE CODE(6-0) */
        !          4317:        BDSET8(&cp[0], 1, 7);
        !          4318:        BDADD8W(&cp[0], resp_code, 6, 7);
        !          4319:        /* Obsolete */
        !          4320:        cp[1] = 0;
        !          4321:        /* FILEMARK(7) EOM(6) ILI(5) SENSE KEY(3-0) */
        !          4322:        BDSET8W(&cp[2], sk, 3, 4);
        !          4323:        /* INFORMATION */
        !          4324:        memset(&cp[3], 0, 4);
        !          4325:        /* ADDITIONAL SENSE LENGTH */
        !          4326:        cp[7] = 0;
        !          4327:        len = 8;
        !          4328: 
        !          4329:        /* COMMAND-SPECIFIC INFORMATION */
        !          4330:        memset(&cp[8], 0, 4);
        !          4331:        /* ADDITIONAL SENSE CODE */
        !          4332:        cp[12] = asc;
        !          4333:        /* ADDITIONAL SENSE CODE QUALIFIER */
        !          4334:        cp[13] = ascq;
        !          4335:        /* FIELD REPLACEABLE UNIT CODE */
        !          4336:        cp[14] = 0;
        !          4337:        /* SKSV(7) SENSE KEY SPECIFIC(6-0,7-0,7-0) */
        !          4338:        cp[15] = 0;
        !          4339:        cp[16] = 0;
        !          4340:        cp[17] = 0;
        !          4341:        /* Additional sense bytes */
        !          4342:        //data[18] = 0;
        !          4343:        plen = 18 - len;
        !          4344: 
        !          4345:        /* ADDITIONAL SENSE LENGTH */
        !          4346:        cp[7] = plen;
        !          4347: 
        !          4348:        total = hlen + len + plen;
        !          4349: 
        !          4350:        /* SenseLength */
        !          4351:        DSET16(&data[0], total - 2);
        !          4352: 
        !          4353:        return total;
        !          4354: }
        !          4355: 
        !          4356: static int
        !          4357: istgt_lu_disk_build_sense_data(ISTGT_LU_DISK *spec, uint8_t *data, int sk, int asc, int ascq)
        !          4358: {
        !          4359:        int rc;
        !          4360: 
        !          4361:        rc = istgt_lu_scsi_build_sense_data(data, sk, asc, ascq);
        !          4362:        if (rc < 0) {
        !          4363:                return -1;
        !          4364:        }
        !          4365:        return rc;
        !          4366: }
        !          4367: 
        !          4368: int
        !          4369: istgt_lu_scsi_build_sense_data2(uint8_t *data, int sk, int asc, int ascq)
        !          4370: {
        !          4371:        uint8_t *cp;
        !          4372:        int resp_code;
        !          4373:        int hlen = 0, len = 0, plen;
        !          4374:        int total;
        !          4375: 
        !          4376:        resp_code = 0x71; /* Deferred + Fixed format */
        !          4377: 
        !          4378:        /* SenseLength */
        !          4379:        DSET16(&data[0], 0);
        !          4380:        hlen = 2;
        !          4381: 
        !          4382:        /* Sense Data */
        !          4383:        cp = &data[hlen + len];
        !          4384: 
        !          4385:        /* VALID(7) RESPONSE CODE(6-0) */
        !          4386:        BDSET8(&cp[0], 1, 7);
        !          4387:        BDADD8W(&cp[0], resp_code, 6, 7);
        !          4388:        /* Obsolete */
        !          4389:        cp[1] = 0;
        !          4390:        /* FILEMARK(7) EOM(6) ILI(5) SENSE KEY(3-0) */
        !          4391:        BDSET8W(&cp[2], sk, 3, 4);
        !          4392:        /* INFORMATION */
        !          4393:        memset(&cp[3], 0, 4);
        !          4394:        /* ADDITIONAL SENSE LENGTH */
        !          4395:        cp[7] = 0;
        !          4396:        len = 8;
        !          4397: 
        !          4398:        /* COMMAND-SPECIFIC INFORMATION */
        !          4399:        memset(&cp[8], 0, 4);
        !          4400:        /* ADDITIONAL SENSE CODE */
        !          4401:        cp[12] = asc;
        !          4402:        /* ADDITIONAL SENSE CODE QUALIFIER */
        !          4403:        cp[13] = ascq;
        !          4404:        /* FIELD REPLACEABLE UNIT CODE */
        !          4405:        cp[14] = 0;
        !          4406:        /* SKSV(7) SENSE KEY SPECIFIC(6-0,7-0,7-0) */
        !          4407:        cp[15] = 0;
        !          4408:        cp[16] = 0;
        !          4409:        cp[17] = 0;
        !          4410:        /* Additional sense bytes */
        !          4411:        //data[18] = 0;
        !          4412:        plen = 18 - len;
        !          4413: 
        !          4414:        /* ADDITIONAL SENSE LENGTH */
        !          4415:        cp[7] = plen;
        !          4416: 
        !          4417:        total = hlen + len + plen;
        !          4418: 
        !          4419:        /* SenseLength */
        !          4420:        DSET16(&data[0], total - 2);
        !          4421: 
        !          4422:        return total;
        !          4423: }
        !          4424: 
        !          4425: static int
        !          4426: istgt_lu_disk_build_sense_data2(ISTGT_LU_DISK *spec, uint8_t *data, int sk, int asc, int ascq)
        !          4427: {
        !          4428:        int rc;
        !          4429: 
        !          4430:        rc = istgt_lu_scsi_build_sense_data2(data, sk, asc, ascq);
        !          4431:        if (rc < 0) {
        !          4432:                return -1;
        !          4433:        }
        !          4434:        return rc;
        !          4435: }
        !          4436: 
        !          4437: int
        !          4438: istgt_lu_disk_reset(ISTGT_LU_Ptr lu, int lun)
        !          4439: {
        !          4440:        ISTGT_LU_DISK *spec;
        !          4441:        int flags;
        !          4442:        int rc;
        !          4443: 
        !          4444:        if (lu == NULL) {
        !          4445:                return -1;
        !          4446:        }
        !          4447:        if (lun >= lu->maxlun) {
        !          4448:                return -1;
        !          4449:        }
        !          4450:        if (lu->lun[lun].type == ISTGT_LU_LUN_TYPE_NONE) {
        !          4451:                return -1;
        !          4452:        }
        !          4453:        if (lu->lun[lun].type != ISTGT_LU_LUN_TYPE_STORAGE) {
        !          4454:                return -1;
        !          4455:        }
        !          4456:        spec = (ISTGT_LU_DISK *) lu->lun[lun].spec;
        !          4457: 
        !          4458: #if 0
        !          4459:        if (spec->lock) {
        !          4460:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "unlock by reset\n");
        !          4461:                spec->lock = 0;
        !          4462:        }
        !          4463: #endif
        !          4464: 
        !          4465:        if (lu->queue_depth != 0) {
        !          4466:                rc = istgt_lu_disk_queue_clear_all(lu, lun);
        !          4467:                if (rc < 0) {
        !          4468:                        ISTGT_ERRLOG("lu_disk_queue_clear_all() failed\n");
        !          4469:                        return -1;
        !          4470:                }
        !          4471:        }
        !          4472: 
        !          4473:        /* re-open file */
        !          4474:        if (!spec->lu->readonly) {
        !          4475:                rc = istgt_lu_disk_sync(spec, 0, spec->size);
        !          4476:                if (rc < 0) {
        !          4477:                        ISTGT_ERRLOG("LU%d: LUN%d: lu_disk_sync() failed\n",
        !          4478:                            lu->num, lun);
        !          4479:                        /* ignore error */
        !          4480:                }
        !          4481:        }
        !          4482:        rc = istgt_lu_disk_close(spec);
        !          4483:        if (rc < 0) {
        !          4484:                ISTGT_ERRLOG("LU%d: LUN%d: lu_disk_close() failed\n",
        !          4485:                    lu->num, lun);
        !          4486:                /* ignore error */
        !          4487:        }
        !          4488:        flags = lu->readonly ? O_RDONLY : O_RDWR;
        !          4489:        rc = istgt_lu_disk_open(spec, flags, 0666);
        !          4490:        if (rc < 0) {
        !          4491:                ISTGT_ERRLOG("LU%d: LUN%d: lu_disk_open() failed\n",
        !          4492:                    lu->num, lun);
        !          4493:                return -1;
        !          4494:        }
        !          4495: 
        !          4496:        return 0;
        !          4497: }
        !          4498: 
        !          4499: static int
        !          4500: istgt_lu_disk_queue_clear_internal(ISTGT_LU_DISK *spec, const char *initiator_port, int all_cmds, uint32_t CmdSN)
        !          4501: {
        !          4502:        ISTGT_LU_TASK_Ptr lu_task;
        !          4503:        ISTGT_QUEUE saved_queue;
        !          4504:        time_t now;
        !          4505:        int rc;
        !          4506: 
        !          4507:        if (spec == NULL)
        !          4508:                return -1;
        !          4509: 
        !          4510:        if (all_cmds != 0) {
        !          4511:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "queue clear by port=%s\n",
        !          4512:                    initiator_port);
        !          4513:        } else {
        !          4514:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "queue clear by port=%s, CmdSN=%u\n",
        !          4515:                    initiator_port, CmdSN);
        !          4516:        }
        !          4517: 
        !          4518:        istgt_queue_init(&saved_queue);
        !          4519: 
        !          4520:        now = time(NULL);
        !          4521:        MTX_LOCK(&spec->cmd_queue_mutex);
        !          4522:        while (1) {
        !          4523:                lu_task = istgt_queue_dequeue(&spec->cmd_queue);
        !          4524:                if (lu_task == NULL)
        !          4525:                        break;
        !          4526:                if (((all_cmds != 0) || (lu_task->lu_cmd.CmdSN == CmdSN))
        !          4527:                    && (strcasecmp(lu_task->initiator_port,
        !          4528:                            initiator_port) == 0)) {
        !          4529:                        ISTGT_LOG("CmdSN(%u), OP=0x%x, ElapsedTime=%u cleared\n",
        !          4530:                            lu_task->lu_cmd.CmdSN,
        !          4531:                            lu_task->lu_cmd.cdb[0],
        !          4532:                            (now - lu_task->create_time));
        !          4533:                        rc = istgt_lu_destroy_task(lu_task);
        !          4534:                        if (rc < 0) {
        !          4535:                                MTX_UNLOCK(&spec->cmd_queue_mutex);
        !          4536:                                ISTGT_ERRLOG("lu_destory_task() failed\n");
        !          4537:                                goto error_return;
        !          4538:                        }
        !          4539:                        continue;
        !          4540:                }
        !          4541:                rc = istgt_queue_enqueue(&saved_queue, lu_task);
        !          4542:                if (rc < 0) {
        !          4543:                        MTX_UNLOCK(&spec->cmd_queue_mutex);
        !          4544:                        ISTGT_ERRLOG("queue_enqueue() failed\n");
        !          4545:                        goto error_return;
        !          4546:                }
        !          4547:        }
        !          4548:        while (1) {
        !          4549:                lu_task = istgt_queue_dequeue(&saved_queue);
        !          4550:                if (lu_task == NULL)
        !          4551:                        break;
        !          4552:                rc = istgt_queue_enqueue(&spec->cmd_queue, lu_task);
        !          4553:                if (rc < 0) {
        !          4554:                        MTX_UNLOCK(&spec->cmd_queue_mutex);
        !          4555:                        ISTGT_ERRLOG("queue_enqueue() failed\n");
        !          4556:                        goto error_return;
        !          4557:                }
        !          4558:        }
        !          4559:        MTX_UNLOCK(&spec->cmd_queue_mutex);
        !          4560: 
        !          4561:        /* check wait task */
        !          4562:        MTX_LOCK(&spec->wait_lu_task_mutex);
        !          4563:        lu_task = spec->wait_lu_task;
        !          4564:        if (lu_task != NULL) {
        !          4565:                if (((all_cmds != 0) || (lu_task->lu_cmd.CmdSN == CmdSN))
        !          4566:                    && (strcasecmp(lu_task->initiator_port,
        !          4567:                            initiator_port) == 0)) {
        !          4568:                        /* conn had gone? */
        !          4569:                        rc = pthread_mutex_trylock(&lu_task->trans_mutex);
        !          4570:                        if (rc == 0) {
        !          4571:                                ISTGT_LOG("CmdSN(%u), OP=0x%x, ElapsedTime=%u aborted\n",
        !          4572:                                    lu_task->lu_cmd.CmdSN,
        !          4573:                                    lu_task->lu_cmd.cdb[0],
        !          4574:                                    (now - lu_task->create_time));
        !          4575:                                /* force error */
        !          4576:                                lu_task->error = 1;
        !          4577:                                lu_task->abort = 1;
        !          4578:                                rc = pthread_cond_broadcast(&lu_task->trans_cond);
        !          4579:                                if (rc != 0) {
        !          4580:                                        /* ignore error */
        !          4581:                                }
        !          4582:                                MTX_UNLOCK(&lu_task->trans_mutex);
        !          4583:                        }
        !          4584:                }
        !          4585:        }
        !          4586:        MTX_UNLOCK(&spec->wait_lu_task_mutex);
        !          4587: 
        !          4588:        rc = istgt_queue_count(&saved_queue);
        !          4589:        if (rc != 0) {
        !          4590:                ISTGT_ERRLOG("temporary queue is not empty\n");
        !          4591:                goto error_return;
        !          4592:        }
        !          4593: 
        !          4594:        istgt_queue_destroy(&saved_queue);
        !          4595:        return 0;
        !          4596: 
        !          4597:  error_return:
        !          4598:        istgt_queue_destroy(&saved_queue);
        !          4599:        return -1;
        !          4600: }
        !          4601: 
        !          4602: static int
        !          4603: istgt_lu_disk_queue_abort_ITL(ISTGT_LU_DISK *spec, const char *initiator_port)
        !          4604: {
        !          4605:        int rc;
        !          4606: 
        !          4607:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "queue abort by port=%s\n",
        !          4608:            initiator_port);
        !          4609: 
        !          4610:        rc = istgt_lu_disk_queue_clear_internal(spec, initiator_port,
        !          4611:            1, 0U); /* ALL, CmdSN=0 */
        !          4612:        return rc;
        !          4613: }
        !          4614: 
        !          4615: int
        !          4616: istgt_lu_disk_queue_clear_IT(CONN_Ptr conn, ISTGT_LU_Ptr lu)
        !          4617: {
        !          4618:        ISTGT_LU_DISK *spec;
        !          4619:        int rc;
        !          4620:        int i;
        !          4621: 
        !          4622:        if (lu == NULL)
        !          4623:                return -1;
        !          4624: 
        !          4625:        for (i = 0; i < lu->maxlun; i++) {
        !          4626:                if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) {
        !          4627: #if 0
        !          4628:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d none\n",
        !          4629:                                                   lu->num, i);
        !          4630: #endif
        !          4631:                        continue;
        !          4632:                }
        !          4633:                if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_STORAGE) {
        !          4634:                        ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
        !          4635:                        return -1;
        !          4636:                }
        !          4637:                spec = (ISTGT_LU_DISK *) lu->lun[i].spec;
        !          4638:                if (spec == NULL) {
        !          4639:                        continue;
        !          4640:                }
        !          4641: 
        !          4642:                rc = istgt_lu_disk_queue_clear_ITL(conn, lu, i);
        !          4643:                if (rc < 0) {
        !          4644:                        return -1;
        !          4645:                }
        !          4646:        }
        !          4647: 
        !          4648:        return 0;
        !          4649: }
        !          4650: 
        !          4651: int
        !          4652: istgt_lu_disk_queue_clear_ITL(CONN_Ptr conn, ISTGT_LU_Ptr lu, int lun)
        !          4653: {
        !          4654:        ISTGT_LU_DISK *spec;
        !          4655:        int rc;
        !          4656: 
        !          4657:        if (lu == NULL)
        !          4658:                return -1;
        !          4659:        if (lun >= lu->maxlun)
        !          4660:                return -1;
        !          4661: 
        !          4662:        spec = (ISTGT_LU_DISK *) lu->lun[lun].spec;
        !          4663:        if (spec == NULL)
        !          4664:                return -1;
        !          4665: 
        !          4666:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "queue clear by name=%s, port=%s\n",
        !          4667:            conn->initiator_name, conn->initiator_port);
        !          4668: 
        !          4669:        rc = istgt_lu_disk_queue_clear_internal(spec, conn->initiator_port,
        !          4670:            1, 0U); /* ALL, CmdSN=0 */
        !          4671:        return rc;
        !          4672: }
        !          4673: 
        !          4674: int
        !          4675: istgt_lu_disk_queue_clear_ITLQ(CONN_Ptr conn, ISTGT_LU_Ptr lu, int lun, uint32_t CmdSN)
        !          4676: {
        !          4677:        ISTGT_LU_DISK *spec;
        !          4678:        int rc;
        !          4679: 
        !          4680:        if (lu == NULL)
        !          4681:                return -1;
        !          4682:        if (lun >= lu->maxlun)
        !          4683:                return -1;
        !          4684: 
        !          4685:        spec = (ISTGT_LU_DISK *) lu->lun[lun].spec;
        !          4686:        if (spec == NULL)
        !          4687:                return -1;
        !          4688: 
        !          4689:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "queue clear by name=%s, port=%s\n",
        !          4690:            conn->initiator_name, conn->initiator_port);
        !          4691: 
        !          4692:        rc = istgt_lu_disk_queue_clear_internal(spec, conn->initiator_port,
        !          4693:            0, CmdSN);
        !          4694:        return rc;
        !          4695: }
        !          4696: 
        !          4697: int
        !          4698: istgt_lu_disk_queue_clear_all(ISTGT_LU_Ptr lu, int lun)
        !          4699: {
        !          4700:        ISTGT_LU_TASK_Ptr lu_task;
        !          4701:        ISTGT_LU_DISK *spec;
        !          4702:        time_t now;
        !          4703:        int rc;
        !          4704: 
        !          4705:        if (lu == NULL)
        !          4706:                return -1;
        !          4707:        if (lun >= lu->maxlun)
        !          4708:                return -1;
        !          4709: 
        !          4710:        if (lu->lun[lun].type == ISTGT_LU_LUN_TYPE_NONE) {
        !          4711:                return -1;
        !          4712:        }
        !          4713:        if (lu->lun[lun].type != ISTGT_LU_LUN_TYPE_STORAGE) {
        !          4714:                return -1;
        !          4715:        }
        !          4716:        spec = (ISTGT_LU_DISK *) lu->lun[lun].spec;
        !          4717:        if (spec == NULL)
        !          4718:                return -1;
        !          4719: 
        !          4720:        now = time(NULL);
        !          4721:        MTX_LOCK(&spec->cmd_queue_mutex);
        !          4722:        while (1) {
        !          4723:                lu_task = istgt_queue_dequeue(&spec->cmd_queue);
        !          4724:                if (lu_task == NULL)
        !          4725:                        break;
        !          4726:                ISTGT_LOG("CmdSN(%u), OP=0x%x, ElapsedTime=%u cleared\n",
        !          4727:                    lu_task->lu_cmd.CmdSN,
        !          4728:                    lu_task->lu_cmd.cdb[0],
        !          4729:                    (now - lu_task->create_time));
        !          4730:                rc = istgt_lu_destroy_task(lu_task);
        !          4731:                if (rc < 0) {
        !          4732:                        MTX_UNLOCK(&spec->cmd_queue_mutex);
        !          4733:                        ISTGT_ERRLOG("lu_destory_task() failed\n");
        !          4734:                        return -1;
        !          4735:                }
        !          4736:        }
        !          4737:        MTX_UNLOCK(&spec->cmd_queue_mutex);
        !          4738: 
        !          4739:        /* check wait task */
        !          4740:        MTX_LOCK(&spec->wait_lu_task_mutex);
        !          4741:        lu_task = spec->wait_lu_task;
        !          4742:        if (lu_task != NULL) {
        !          4743:                /* conn had gone? */
        !          4744:                rc = pthread_mutex_trylock(&lu_task->trans_mutex);
        !          4745:                if (rc == 0) {
        !          4746:                        ISTGT_LOG("CmdSN(%u), OP=0x%x, ElapsedTime=%u aborted\n",
        !          4747:                            lu_task->lu_cmd.CmdSN,
        !          4748:                            lu_task->lu_cmd.cdb[0],
        !          4749:                            (now - lu_task->create_time));
        !          4750:                        /* force error */
        !          4751:                        lu_task->error = 1;
        !          4752:                        lu_task->abort = 1;
        !          4753:                        rc = pthread_cond_broadcast(&lu_task->trans_cond);
        !          4754:                        if (rc != 0) {
        !          4755:                                /* ignore error */
        !          4756:                        }
        !          4757:                        MTX_UNLOCK(&lu_task->trans_mutex);
        !          4758:                }
        !          4759:        }
        !          4760:        MTX_UNLOCK(&spec->wait_lu_task_mutex);
        !          4761: 
        !          4762:        MTX_LOCK(&spec->cmd_queue_mutex);
        !          4763:        rc = istgt_queue_count(&spec->cmd_queue);
        !          4764:        MTX_UNLOCK(&spec->cmd_queue_mutex);
        !          4765:        if (rc != 0) {
        !          4766:                ISTGT_ERRLOG("cmd queue is not empty\n");
        !          4767:                return -1;
        !          4768:        }
        !          4769: 
        !          4770:        return 0;
        !          4771: }
        !          4772: 
        !          4773: int
        !          4774: istgt_lu_disk_queue(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
        !          4775: {
        !          4776:        ISTGT_LU_TASK_Ptr lu_task;
        !          4777:        ISTGT_LU_Ptr lu;
        !          4778:        ISTGT_LU_DISK *spec;
        !          4779:        uint8_t *data;
        !          4780:        uint8_t *cdb;
        !          4781:        uint32_t allocation_len;
        !          4782:        int data_len;
        !          4783:        int data_alloc_len;
        !          4784:        uint8_t *sense_data;
        !          4785:        int *sense_len;
        !          4786:        int lun_i;
        !          4787:        int maxq;
        !          4788:        int qcnt;
        !          4789:        int rc;
        !          4790: 
        !          4791:        if (lu_cmd == NULL)
        !          4792:                return -1;
        !          4793:        lu = lu_cmd->lu;
        !          4794:        if (lu == NULL) {
        !          4795:                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          4796:                return -1;
        !          4797:        }
        !          4798:        spec = NULL;
        !          4799:        cdb = lu_cmd->cdb;
        !          4800:        data = lu_cmd->data;
        !          4801:        data_alloc_len = lu_cmd->alloc_len;
        !          4802:        sense_data = lu_cmd->sense_data;
        !          4803:        sense_len = &lu_cmd->sense_data_len;
        !          4804:        *sense_len = 0;
        !          4805: 
        !          4806:        lun_i = istgt_lu_islun2lun(lu_cmd->lun);
        !          4807:        if (lun_i >= lu->maxlun) {
        !          4808: #ifdef ISTGT_TRACE_DISK
        !          4809:                ISTGT_ERRLOG("LU%d: LUN%4.4"PRIx64" invalid\n",
        !          4810:                    lu->num, lun_i);
        !          4811: #endif /* ISTGT_TRACE_DISK */
        !          4812:                if (cdb[0] == SPC_INQUIRY) {
        !          4813:                        allocation_len = DGET16(&cdb[3]);
        !          4814:                        if (allocation_len > data_alloc_len) {
        !          4815:                                ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
        !          4816:                                    data_alloc_len);
        !          4817:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          4818:                                return -1;
        !          4819:                        }
        !          4820:                        memset(data, 0, allocation_len);
        !          4821:                        /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
        !          4822:                        BDSET8W(&data[0], 0x03, 7, 3);
        !          4823:                        BDADD8W(&data[0], 0x1f, 4, 5);
        !          4824:                        data_len = 96;
        !          4825:                        memset(&data[1], 0, data_len - 1);
        !          4826:                        /* ADDITIONAL LENGTH */
        !          4827:                        data[4] = data_len - 5;
        !          4828:                        lu_cmd->data_len = DMIN32(data_len, lu_cmd->transfer_len);
        !          4829:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          4830:                        return ISTGT_LU_TASK_RESULT_IMMEDIATE;
        !          4831:                } else {
        !          4832:                        /* LOGICAL UNIT NOT SUPPORTED */
        !          4833:                        BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00);
        !          4834:                        lu_cmd->data_len = 0;
        !          4835:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          4836:                        return ISTGT_LU_TASK_RESULT_IMMEDIATE;
        !          4837:                }
        !          4838:        }
        !          4839:        spec = (ISTGT_LU_DISK *) lu->lun[lun_i].spec;
        !          4840:        if (spec == NULL) {
        !          4841:                /* LOGICAL UNIT NOT SUPPORTED */
        !          4842:                BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00);
        !          4843:                lu_cmd->data_len = 0;
        !          4844:                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          4845:                return ISTGT_LU_TASK_RESULT_IMMEDIATE;
        !          4846:        }
        !          4847:        /* ready to enqueue, spec is valid for LUN access */
        !          4848: 
        !          4849:        /* allocate task and copy LU_CMD(PDU) */
        !          4850:        lu_task = xmalloc(sizeof *lu_task);
        !          4851:        memset(lu_task, 0, sizeof *lu_task);
        !          4852:        rc = istgt_lu_create_task(conn, lu_cmd, lu_task, lun_i);
        !          4853:        if (rc < 0) {
        !          4854:                ISTGT_ERRLOG("lu_create_task() failed\n");
        !          4855:                xfree(lu_task);
        !          4856:                return -1;
        !          4857:        }
        !          4858: 
        !          4859:        MTX_LOCK(&lu->queue_mutex);
        !          4860:        /* enqueue SCSI command */
        !          4861:        MTX_LOCK(&spec->cmd_queue_mutex);
        !          4862:        rc = istgt_queue_count(&spec->cmd_queue);
        !          4863:        maxq = spec->queue_depth * lu->istgt->MaxSessions;
        !          4864:        if (rc > maxq) {
        !          4865:                MTX_UNLOCK(&spec->cmd_queue_mutex);
        !          4866:                MTX_UNLOCK(&lu->queue_mutex);
        !          4867:                lu_cmd->data_len = 0;
        !          4868:                lu_cmd->status = ISTGT_SCSI_STATUS_TASK_SET_FULL;
        !          4869:                rc = istgt_lu_destroy_task(lu_task);
        !          4870:                if (rc < 0) {
        !          4871:                        ISTGT_ERRLOG("lu_destroy_task() failed\n");
        !          4872:                        return -1;
        !          4873:                }
        !          4874:                return ISTGT_LU_TASK_RESULT_QUEUE_FULL;
        !          4875:        }
        !          4876:        qcnt = rc;
        !          4877:        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
        !          4878:            "Queue(%d), CmdSN=%u, OP=0x%x, LUN=0x%16.16"PRIx64"\n",
        !          4879:            qcnt, lu_cmd->CmdSN, lu_cmd->cdb[0], lu_cmd->lun);
        !          4880: 
        !          4881:        /* enqueue task to LUN */
        !          4882:        switch (lu_cmd->Attr_bit) {
        !          4883:        case 0x03: /* Head of Queue */
        !          4884:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "insert Head of Queue\n");
        !          4885:                rc = istgt_queue_enqueue_first(&spec->cmd_queue, lu_task);
        !          4886:                break;
        !          4887:        case 0x00: /* Untagged */
        !          4888:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "insert Untagged\n");
        !          4889:                rc = istgt_queue_enqueue(&spec->cmd_queue, lu_task);
        !          4890:                break;
        !          4891:        case 0x01: /* Simple */
        !          4892:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "insert Simple\n");
        !          4893:                rc = istgt_queue_enqueue(&spec->cmd_queue, lu_task);
        !          4894:                break;
        !          4895:        case 0x02: /* Ordered */
        !          4896:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "insert Ordered\n");
        !          4897:                rc = istgt_queue_enqueue(&spec->cmd_queue, lu_task);
        !          4898:                break;
        !          4899:        case 0x04: /* ACA */
        !          4900:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "insert ACA\n");
        !          4901:                rc = istgt_queue_enqueue(&spec->cmd_queue, lu_task);
        !          4902:                break;
        !          4903:        default: /* Reserved */
        !          4904:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "insert Reserved Attribute\n");
        !          4905:                rc = istgt_queue_enqueue(&spec->cmd_queue, lu_task);
        !          4906:                break;
        !          4907:        }
        !          4908:        MTX_UNLOCK(&spec->cmd_queue_mutex);
        !          4909:        if (rc < 0) {
        !          4910:                MTX_UNLOCK(&lu->queue_mutex);
        !          4911:                ISTGT_ERRLOG("queue_enqueue() failed\n");
        !          4912:        error_return:
        !          4913:                rc = istgt_lu_destroy_task(lu_task);
        !          4914:                if (rc < 0) {
        !          4915:                        ISTGT_ERRLOG("lu_destroy_task() failed\n");
        !          4916:                        return -1;
        !          4917:                }
        !          4918:                return -1;
        !          4919:        }
        !          4920: 
        !          4921:        /* notify LUN thread */
        !          4922:        rc = pthread_cond_broadcast(&lu->queue_cond);
        !          4923:        MTX_UNLOCK(&lu->queue_mutex);
        !          4924:        if (rc != 0) {
        !          4925:                ISTGT_ERRLOG("LU%d: cond_broadcast() failed\n", lu->num);
        !          4926:                goto error_return;
        !          4927:        }
        !          4928: 
        !          4929:        return ISTGT_LU_TASK_RESULT_QUEUE_OK;
        !          4930: }
        !          4931: 
        !          4932: int
        !          4933: istgt_lu_disk_queue_count(ISTGT_LU_Ptr lu, int *lun)
        !          4934: {
        !          4935:        ISTGT_LU_DISK *spec;
        !          4936:        int qcnt;
        !          4937:        int luns;
        !          4938:        int i;
        !          4939: 
        !          4940:        if (lun == NULL)
        !          4941:                return -1;
        !          4942: 
        !          4943:        i = *lun;
        !          4944:        if (i >= lu->maxlun) {
        !          4945:                *lun = 0;
        !          4946:                i = 0;
        !          4947:        }
        !          4948: 
        !          4949:        qcnt = 0;
        !          4950:        for (luns = lu->maxlun; luns >= 0 ; luns--) {
        !          4951:                if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) {
        !          4952:                        goto next_lun;
        !          4953:                }
        !          4954:                if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_STORAGE) {
        !          4955:                        ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
        !          4956:                        goto next_lun;
        !          4957:                }
        !          4958:                spec = (ISTGT_LU_DISK *) lu->lun[i].spec;
        !          4959:                if (spec == NULL) {
        !          4960:                        goto next_lun;
        !          4961:                }
        !          4962: 
        !          4963:                MTX_LOCK(&spec->cmd_queue_mutex);
        !          4964:                qcnt = istgt_queue_count(&spec->cmd_queue);
        !          4965:                MTX_UNLOCK(&spec->cmd_queue_mutex);
        !          4966:                if (qcnt > 0) {
        !          4967:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !          4968:                            "LU%d: LUN%d queue(%d)\n",
        !          4969:                            lu->num, i, qcnt);
        !          4970:                        *lun = spec->lun;
        !          4971:                        break;
        !          4972:                }
        !          4973: 
        !          4974:        next_lun:
        !          4975:                i++;
        !          4976:                if (i >= lu->maxlun) {
        !          4977:                        i = 0;
        !          4978:                }
        !          4979:        }
        !          4980:        return qcnt;
        !          4981: }
        !          4982: 
        !          4983: int
        !          4984: istgt_lu_disk_queue_start(ISTGT_LU_Ptr lu, int lun)
        !          4985: {
        !          4986:        ISTGT_Ptr istgt;
        !          4987:        ISTGT_LU_DISK *spec;
        !          4988:        ISTGT_LU_TASK_Ptr lu_task;
        !          4989:        CONN_Ptr conn;
        !          4990:        ISTGT_LU_CMD_Ptr lu_cmd;
        !          4991:        struct timespec abstime;
        !          4992:        time_t now;
        !          4993:        uint8_t *iobuf;
        !          4994:        char tmp[1];
        !          4995:        int abort_task = 0;
        !          4996:        int rc;
        !          4997: 
        !          4998:        if (lun < 0 || lun >= lu->maxlun) {
        !          4999:                return -1;
        !          5000:        }
        !          5001: 
        !          5002:        ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "LU%d: LUN%d queue start\n",
        !          5003:            lu->num, lun);
        !          5004:        spec = (ISTGT_LU_DISK *) lu->lun[lun].spec;
        !          5005:        if (spec == NULL)
        !          5006:                return -1;
        !          5007: 
        !          5008:        MTX_LOCK(&spec->cmd_queue_mutex);
        !          5009:        lu_task = istgt_queue_dequeue(&spec->cmd_queue);
        !          5010:        MTX_UNLOCK(&spec->cmd_queue_mutex);
        !          5011:        if (lu_task == NULL) {
        !          5012:                /* cleared or empty queue */
        !          5013:                return 0;
        !          5014:        }
        !          5015:        lu_task->thread = pthread_self();
        !          5016:        conn = lu_task->conn;
        !          5017:        istgt = conn->istgt;
        !          5018:        lu_cmd = &lu_task->lu_cmd;
        !          5019: 
        !          5020:        /* XXX need pre-allocate? */
        !          5021: #if 0
        !          5022:        /* allocated in istgt_lu_create_task() */
        !          5023:        lu_task->data = xmalloc(lu_cmd->alloc_len);
        !          5024:        lu_task->sense_data = xmalloc(lu_cmd->sense_alloc_len);
        !          5025:        lu_task->iobuf = NULL;
        !          5026: #endif
        !          5027:        lu_cmd->data = lu_task->data;
        !          5028:        lu_cmd->data_len = 0;
        !          5029:        lu_cmd->sense_data = lu_task->sense_data;
        !          5030:        lu_cmd->sense_data_len = 0;
        !          5031: 
        !          5032:        tmp[0] = 'Q';
        !          5033:        if (lu_cmd->W_bit) {
        !          5034:                if (lu_cmd->pdu->data_segment_len >= lu_cmd->transfer_len) {
        !          5035:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !          5036:                            "LU%d: LUN%d Task Write Immediate Start\n",
        !          5037:                            lu->num, lun);
        !          5038: #if 0
        !          5039:                        iobuf = xmalloc(lu_cmd->pdu->data_segment_len);
        !          5040:                        memcpy(iobuf, lu_cmd->pdu->data,
        !          5041:                            lu_cmd->pdu->data_segment_len);
        !          5042:                        lu_task->iobuf = iobuf;
        !          5043: #else
        !          5044:                        iobuf = lu_cmd->pdu->data;
        !          5045:                        lu_task->dup_iobuf = 1;
        !          5046: #endif
        !          5047:                        lu_cmd->iobuf = iobuf;
        !          5048: 
        !          5049:                        MTX_LOCK(&lu_cmd->lu->mutex);
        !          5050:                        rc = istgt_lu_disk_execute(conn, lu_cmd);
        !          5051:                        MTX_UNLOCK(&lu_cmd->lu->mutex);
        !          5052:                        if (rc < 0) {
        !          5053:                                ISTGT_ERRLOG("lu_disk_execute() failed\n");
        !          5054:                        error_return:
        !          5055:                                rc = istgt_lu_destroy_task(lu_task);
        !          5056:                                if (rc < 0) {
        !          5057:                                        ISTGT_ERRLOG("lu_destroy_task() failed\n");
        !          5058:                                        return -1;
        !          5059:                                }
        !          5060:                                return -1;
        !          5061:                        }
        !          5062:                        lu_task->execute = 1;
        !          5063: 
        !          5064:                        /* response */
        !          5065:                        if (conn->use_sender == 0) {
        !          5066:                                MTX_LOCK(&conn->task_queue_mutex);
        !          5067:                                rc = istgt_queue_enqueue(&conn->task_queue, lu_task);
        !          5068:                                MTX_UNLOCK(&conn->task_queue_mutex);
        !          5069:                                if (rc < 0) {
        !          5070:                                        ISTGT_ERRLOG("queue_enqueue() failed\n");
        !          5071:                                        goto error_return;
        !          5072:                                }
        !          5073:                                rc = write(conn->task_pipe[1], tmp, 1);
        !          5074:                                if(rc < 0 || rc != 1) {
        !          5075:                                        ISTGT_ERRLOG("write() failed\n");
        !          5076:                                        goto error_return;
        !          5077:                                }
        !          5078:                        } else {
        !          5079:                                MTX_LOCK(&conn->result_queue_mutex);
        !          5080:                                rc = istgt_queue_enqueue(&conn->result_queue, lu_task);
        !          5081:                                if (rc < 0) {
        !          5082:                                        MTX_UNLOCK(&conn->result_queue_mutex);
        !          5083:                                        ISTGT_ERRLOG("queue_enqueue() failed\n");
        !          5084:                                        goto error_return;
        !          5085:                                }
        !          5086:                                rc = pthread_cond_broadcast(&conn->result_queue_cond);
        !          5087:                                MTX_UNLOCK(&conn->result_queue_mutex);
        !          5088:                                if (rc != 0) {
        !          5089:                                        ISTGT_ERRLOG("cond_broadcast() failed\n");
        !          5090:                                        goto error_return;
        !          5091:                                }
        !          5092:                        }
        !          5093: 
        !          5094: #if 0
        !          5095:                        /* write cache */
        !          5096:                        if (spec->req_write_cache) {
        !          5097:                                MTX_LOCK(&lu->mutex);
        !          5098:                                rc = istgt_lu_disk_write_cache(spec, conn);
        !          5099:                                MTX_UNLOCK(&lu->mutex);
        !          5100:                                if (rc < 0) {
        !          5101:                                        ISTGT_ERRLOG("disk_write_cache() failed\n");
        !          5102:                                        return -1;
        !          5103:                                }
        !          5104:                        }
        !          5105: #endif
        !          5106:                } else {
        !          5107:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !          5108:                            "LU%d: LUN%d Task Write Start\n",
        !          5109:                            lu->num, lun);
        !          5110: 
        !          5111: #if 0
        !          5112:                        MTX_LOCK(&spec->wait_lu_task_mutex);
        !          5113:                        spec->wait_lu_task = NULL;
        !          5114:                        MTX_UNLOCK(&spec->wait_lu_task_mutex);
        !          5115: #endif
        !          5116:                        rc = pthread_mutex_init(&lu_task->trans_mutex, NULL);
        !          5117:                        if (rc != 0) {
        !          5118:                                ISTGT_ERRLOG("mutex_init() failed\n");
        !          5119:                                goto error_return;
        !          5120:                        }
        !          5121:                        rc = pthread_cond_init(&lu_task->trans_cond, NULL);
        !          5122:                        if (rc != 0) {
        !          5123:                                ISTGT_ERRLOG("cond_init() failed\n");
        !          5124:                                goto error_return;
        !          5125:                        }
        !          5126:                        rc = pthread_cond_init(&lu_task->exec_cond, NULL);
        !          5127:                        if (rc != 0) {
        !          5128:                                ISTGT_ERRLOG("cond_init() failed\n");
        !          5129:                                goto error_return;
        !          5130:                        }
        !          5131:                        lu_task->use_cond = 1;
        !          5132: #if 0
        !          5133:                        lu_cmd->iobufsize = lu_cmd->transfer_len + 65536;
        !          5134:                        iobuf = xmalloc(lu_cmd->iobufsize);
        !          5135:                        lu_task->iobuf = iobuf;
        !          5136: #else
        !          5137:                        lu_cmd->iobufsize = lu_task->lu_cmd.iobufsize;
        !          5138:                        iobuf = lu_task->iobuf;
        !          5139: #endif
        !          5140:                        lu_cmd->iobuf = iobuf;
        !          5141:                        lu_task->req_transfer_out = 1;
        !          5142:                        memset(&abstime, 0, sizeof abstime);
        !          5143:                        abstime.tv_sec = 0;
        !          5144:                        abstime.tv_nsec = 0;
        !          5145: 
        !          5146:                        MTX_LOCK(&lu_task->trans_mutex);
        !          5147:                        MTX_LOCK(&conn->task_queue_mutex);
        !          5148:                        rc = istgt_queue_enqueue(&conn->task_queue, lu_task);
        !          5149:                        MTX_UNLOCK(&conn->task_queue_mutex);
        !          5150:                        if (rc < 0) {
        !          5151:                                MTX_UNLOCK(&lu_task->trans_mutex);
        !          5152:                                ISTGT_ERRLOG("queue_enqueue() failed\n");
        !          5153:                                goto error_return;
        !          5154:                        }
        !          5155:                        rc = write(conn->task_pipe[1], tmp, 1);
        !          5156:                        if(rc < 0 || rc != 1) {
        !          5157:                                MTX_UNLOCK(&lu_task->trans_mutex);
        !          5158:                                ISTGT_ERRLOG("write() failed\n");
        !          5159:                                goto error_return;
        !          5160:                        }
        !          5161: 
        !          5162:                        now = time(NULL);
        !          5163:                        abstime.tv_sec = now + (lu_task->condwait / 1000);
        !          5164:                        abstime.tv_nsec = (lu_task->condwait % 1000) * 1000000;
        !          5165: #if 0
        !          5166:                        ISTGT_LOG("wait CmdSN=%u\n", lu_task->lu_cmd.CmdSN);
        !          5167: #endif
        !          5168:                        MTX_LOCK(&spec->wait_lu_task_mutex);
        !          5169:                        spec->wait_lu_task = lu_task;
        !          5170:                        MTX_UNLOCK(&spec->wait_lu_task_mutex);
        !          5171:                        while (lu_task->req_transfer_out == 1) {
        !          5172:                                rc = pthread_cond_timedwait(&lu_task->trans_cond,
        !          5173:                                    &lu_task->trans_mutex,
        !          5174:                                    &abstime);
        !          5175:                                if (rc == ETIMEDOUT) {
        !          5176:                                        if (lu_task->req_transfer_out == 1) {
        !          5177:                                                lu_task->error = 1;
        !          5178:                                                MTX_LOCK(&spec->wait_lu_task_mutex);
        !          5179:                                                spec->wait_lu_task = NULL;
        !          5180:                                                MTX_UNLOCK(&spec->wait_lu_task_mutex);
        !          5181:                                                MTX_UNLOCK(&lu_task->trans_mutex);
        !          5182:                                                ISTGT_ERRLOG("timeout trans_cond CmdSN=%u\n",
        !          5183:                                                    lu_task->lu_cmd.CmdSN);
        !          5184:                                                /* timeout */
        !          5185:                                                return -1;
        !          5186:                                        }
        !          5187:                                        /* OK cond */
        !          5188:                                        rc = 0;
        !          5189:                                        break;
        !          5190:                                }
        !          5191:                                if (lu_task->error != 0) {
        !          5192:                                        rc = -1;
        !          5193:                                        break;
        !          5194:                                }
        !          5195:                                if (rc != 0) {
        !          5196:                                        break;
        !          5197:                                }
        !          5198:                        }
        !          5199:                        MTX_LOCK(&spec->wait_lu_task_mutex);
        !          5200:                        spec->wait_lu_task = NULL;
        !          5201:                        MTX_UNLOCK(&spec->wait_lu_task_mutex);
        !          5202:                        MTX_UNLOCK(&lu_task->trans_mutex);
        !          5203:                        if (rc != 0) {
        !          5204:                                if (rc < 0) {
        !          5205:                                        lu_task->error = 1;
        !          5206:                                        if (lu_task->abort) {
        !          5207:                                                ISTGT_WARNLOG("transfer abort CmdSN=%u\n",
        !          5208:                                                    lu_task->lu_cmd.CmdSN);
        !          5209:                                                return -2;
        !          5210:                                        } else {
        !          5211:                                                ISTGT_ERRLOG("transfer error CmdSN=%u\n",
        !          5212:                                                    lu_task->lu_cmd.CmdSN);
        !          5213:                                                return -1;
        !          5214:                                        }
        !          5215:                                }
        !          5216:                                if (rc == ETIMEDOUT) {
        !          5217:                                        lu_task->error = 1;
        !          5218:                                        ISTGT_ERRLOG("timeout trans_cond CmdSN=%u\n",
        !          5219:                                            lu_task->lu_cmd.CmdSN);
        !          5220:                                        return -1;
        !          5221:                                }
        !          5222:                                lu_task->error = 1;
        !          5223:                                ISTGT_ERRLOG("cond_timedwait rc=%d\n", rc);
        !          5224:                                return -1;
        !          5225:                        }
        !          5226: 
        !          5227:                        if (lu_task->req_execute == 0) {
        !          5228:                                ISTGT_ERRLOG("wrong request\n");
        !          5229:                                goto error_return;
        !          5230:                        }
        !          5231:                        MTX_LOCK(&lu_cmd->lu->mutex);
        !          5232:                        rc = istgt_lu_disk_execute(conn, lu_cmd);
        !          5233:                        MTX_UNLOCK(&lu_cmd->lu->mutex);
        !          5234:                        if (rc < 0) {
        !          5235:                                lu_task->error = 1;
        !          5236:                                ISTGT_ERRLOG("lu_disk_execute() failed\n");
        !          5237:                                goto error_return;
        !          5238:                        }
        !          5239:                        lu_task->execute = 1;
        !          5240: 
        !          5241:                        /* response */
        !          5242:                        if (conn->use_sender == 0) {
        !          5243:                                MTX_LOCK(&conn->task_queue_mutex);
        !          5244:                                rc = istgt_queue_enqueue(&conn->task_queue, lu_task);
        !          5245:                                MTX_UNLOCK(&conn->task_queue_mutex);
        !          5246:                                if (rc < 0) {
        !          5247:                                        ISTGT_ERRLOG("queue_enqueue() failed\n");
        !          5248:                                        goto error_return;
        !          5249:                                }
        !          5250:                                rc = write(conn->task_pipe[1], tmp, 1);
        !          5251:                                if(rc < 0 || rc != 1) {
        !          5252:                                        ISTGT_ERRLOG("write() failed\n");
        !          5253:                                        goto error_return;
        !          5254:                                }
        !          5255:                        } else {
        !          5256:                                MTX_LOCK(&conn->result_queue_mutex);
        !          5257:                                rc = istgt_queue_enqueue(&conn->result_queue, lu_task);
        !          5258:                                if (rc < 0) {
        !          5259:                                        MTX_UNLOCK(&conn->result_queue_mutex);
        !          5260:                                        ISTGT_ERRLOG("queue_enqueue() failed\n");
        !          5261:                                        goto error_return;
        !          5262:                                }
        !          5263:                                rc = pthread_cond_broadcast(&conn->result_queue_cond);
        !          5264:                                MTX_UNLOCK(&conn->result_queue_mutex);
        !          5265:                                if (rc != 0) {
        !          5266:                                        ISTGT_ERRLOG("cond_broadcast() failed\n");
        !          5267:                                        goto error_return;
        !          5268:                                }
        !          5269:                        }
        !          5270: 
        !          5271: #if 0
        !          5272:                        /* write cache */
        !          5273:                        if (spec->req_write_cache) {
        !          5274:                                MTX_LOCK(&lu->mutex);
        !          5275:                                rc = istgt_lu_disk_write_cache(spec, conn);
        !          5276:                                MTX_UNLOCK(&lu->mutex);
        !          5277:                                if (rc < 0) {
        !          5278:                                        ISTGT_ERRLOG("disk_write_cache() failed\n");
        !          5279:                                        return -1;
        !          5280:                                }
        !          5281:                        }
        !          5282: #endif
        !          5283:                }
        !          5284:        } else {
        !          5285:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !          5286:                    "LU%d: LUN%d Task Read Start\n",
        !          5287:                    lu->num, lun);
        !          5288: #if 0
        !          5289:                lu_cmd->iobufsize = lu_cmd->transfer_len + 65536;
        !          5290:                iobuf = xmalloc(lu_cmd->iobufsize);
        !          5291:                lu_task->iobuf = iobuf;
        !          5292: #else
        !          5293:                lu_cmd->iobufsize = lu_task->lu_cmd.iobufsize;
        !          5294:                iobuf = lu_task->iobuf;
        !          5295: #endif
        !          5296:                lu_cmd->iobuf = iobuf;
        !          5297:                MTX_LOCK(&lu_cmd->lu->mutex);
        !          5298:                rc = istgt_lu_disk_execute(conn, lu_cmd);
        !          5299:                MTX_UNLOCK(&lu_cmd->lu->mutex);
        !          5300:                if (rc < 0) {
        !          5301:                        ISTGT_ERRLOG("lu_disk_execute() failed\n");
        !          5302:                        goto error_return;
        !          5303:                }
        !          5304:                lu_task->execute = 1;
        !          5305: 
        !          5306:                /* response */
        !          5307:                if (conn->use_sender == 0) {
        !          5308:                        MTX_LOCK(&conn->task_queue_mutex);
        !          5309:                        rc = istgt_queue_enqueue(&conn->task_queue, lu_task);
        !          5310:                        MTX_UNLOCK(&conn->task_queue_mutex);
        !          5311:                        if (rc < 0) {
        !          5312:                                ISTGT_ERRLOG("queue_enqueue() failed\n");
        !          5313:                                goto error_return;
        !          5314:                        }
        !          5315:                        rc = write(conn->task_pipe[1], tmp, 1);
        !          5316:                        if(rc < 0 || rc != 1) {
        !          5317:                                ISTGT_ERRLOG("write() failed\n");
        !          5318:                                goto error_return;
        !          5319:                        }
        !          5320:                } else {
        !          5321:                        MTX_LOCK(&conn->result_queue_mutex);
        !          5322:                        rc = istgt_queue_enqueue(&conn->result_queue, lu_task);
        !          5323:                        if (rc < 0) {
        !          5324:                                MTX_UNLOCK(&conn->result_queue_mutex);
        !          5325:                                ISTGT_ERRLOG("queue_enqueue() failed\n");
        !          5326:                                goto error_return;
        !          5327:                        }
        !          5328:                        rc = pthread_cond_broadcast(&conn->result_queue_cond);
        !          5329:                        MTX_UNLOCK(&conn->result_queue_mutex);
        !          5330:                        if (rc != 0) {
        !          5331:                                ISTGT_ERRLOG("cond_broadcast() failed\n");
        !          5332:                                goto error_return;
        !          5333:                        }
        !          5334:                }
        !          5335:        }
        !          5336: 
        !          5337:        ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "LU%d: LUN%d queue end\n",
        !          5338:            lu->num, lun);
        !          5339: 
        !          5340:        if (abort_task) {
        !          5341:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Abort Task\n");
        !          5342:                return -1;
        !          5343:        }
        !          5344:        return 0;
        !          5345: }
        !          5346: 
        !          5347: int
        !          5348: istgt_lu_disk_execute(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
        !          5349: {
        !          5350:        ISTGT_LU_Ptr lu;
        !          5351:        ISTGT_LU_DISK *spec;
        !          5352:        uint8_t *data;
        !          5353:        uint8_t *cdb;
        !          5354:        uint32_t allocation_len;
        !          5355:        int data_len;
        !          5356:        int data_alloc_len;
        !          5357:        uint64_t lba;
        !          5358:        uint32_t len;
        !          5359:        uint32_t transfer_len;
        !          5360:        uint32_t parameter_len;
        !          5361:        uint8_t *sense_data;
        !          5362:        int *sense_len;
        !          5363:        int lun_i;
        !          5364:        int rc;
        !          5365: 
        !          5366:        if (lu_cmd == NULL)
        !          5367:                return -1;
        !          5368:        lu = lu_cmd->lu;
        !          5369:        if (lu == NULL) {
        !          5370:                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5371:                return -1;
        !          5372:        }
        !          5373:        spec = NULL;
        !          5374:        cdb = lu_cmd->cdb;
        !          5375:        data = lu_cmd->data;
        !          5376:        data_alloc_len = lu_cmd->alloc_len;
        !          5377:        sense_data = lu_cmd->sense_data;
        !          5378:        sense_len = &lu_cmd->sense_data_len;
        !          5379:        *sense_len = 0;
        !          5380: 
        !          5381:        lun_i = istgt_lu_islun2lun(lu_cmd->lun);
        !          5382:        if (lun_i >= lu->maxlun) {
        !          5383: #ifdef ISTGT_TRACE_DISK
        !          5384:                ISTGT_ERRLOG("LU%d: LUN%4.4"PRIx64" invalid\n",
        !          5385:                    lu->num, lun_i);
        !          5386: #endif /* ISTGT_TRACE_DISK */
        !          5387:                if (cdb[0] == SPC_INQUIRY) {
        !          5388:                        allocation_len = DGET16(&cdb[3]);
        !          5389:                        if (allocation_len > data_alloc_len) {
        !          5390:                                ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
        !          5391:                                    data_alloc_len);
        !          5392:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5393:                                return -1;
        !          5394:                        }
        !          5395:                        memset(data, 0, allocation_len);
        !          5396:                        /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
        !          5397:                        BDSET8W(&data[0], 0x03, 7, 3);
        !          5398:                        BDADD8W(&data[0], 0x1f, 4, 5);
        !          5399:                        data_len = 96;
        !          5400:                        memset(&data[1], 0, data_len - 1);
        !          5401:                        /* ADDITIONAL LENGTH */
        !          5402:                        data[4] = data_len - 5;
        !          5403:                        lu_cmd->data_len = DMIN32(data_len, lu_cmd->transfer_len);
        !          5404:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          5405:                        return 0;
        !          5406:                } else {
        !          5407:                        /* LOGICAL UNIT NOT SUPPORTED */
        !          5408:                        BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00);
        !          5409:                        lu_cmd->data_len = 0;
        !          5410:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5411:                        return 0;
        !          5412:                }
        !          5413:        }
        !          5414:        spec = (ISTGT_LU_DISK *) lu->lun[lun_i].spec;
        !          5415:        if (spec == NULL) {
        !          5416:                /* LOGICAL UNIT NOT SUPPORTED */
        !          5417:                BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00);
        !          5418:                lu_cmd->data_len = 0;
        !          5419:                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5420:                return 0;
        !          5421:        }
        !          5422: 
        !          5423:        if (spec->sense != 0) {
        !          5424:                int sk, asc, ascq;
        !          5425:                if (cdb[0] != SPC_INQUIRY
        !          5426:                    && cdb[0] != SPC_REPORT_LUNS) {
        !          5427:                        sk = (spec->sense >> 16) & 0xffU;
        !          5428:                        asc = (spec->sense >> 8) & 0xffU;
        !          5429:                        ascq = (spec->sense >> 0) & 0xffU;
        !          5430:                        spec->sense = 0;
        !          5431:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !          5432:                            "Generate sk=0x%x, asc=0x%x, ascq=0x%x\n",
        !          5433:                            sk, asc, ascq);
        !          5434:                        *sense_len
        !          5435:                                = istgt_lu_disk_build_sense_data(spec, sense_data,
        !          5436:                                    sk, asc, ascq);
        !          5437:                        lu_cmd->data_len = 0;
        !          5438:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5439:                        return 0;
        !          5440:                }
        !          5441:        }
        !          5442: 
        !          5443:        if (spec->err_write_cache) {
        !          5444:                /* WRITE ERROR - AUTO REALLOCATION FAILED */
        !          5445:                BUILD_SENSE2(MEDIUM_ERROR, 0x0c, 0x02);
        !          5446: #if 0
        !          5447:                /* WRITE ERROR - RECOMMEND REASSIGNMENT */
        !          5448:                BUILD_SENSE2(MEDIUM_ERROR, 0x0c, 0x03);
        !          5449: #endif
        !          5450:                spec->err_write_cache = 0;
        !          5451:                lba = spec->woffset / spec->blocklen;
        !          5452:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
        !          5453:                    "Deferred error (write cache) at %"PRIu64"\n", lba);
        !          5454:                if (lba > 0xffffffffULL) {
        !          5455:                        ISTGT_WARNLOG("lba > 0xffffffff\n");
        !          5456:                }
        !          5457:                /* COMMAND-SPECIFIC INFORMATION */
        !          5458:                DSET32(&sense_data[8], (uint32_t)(lba & 0xffffffffULL));
        !          5459:                lu_cmd->data_len = 0;
        !          5460:                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5461:                return 0;
        !          5462:        }
        !          5463: 
        !          5464:        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
        !          5465:            "SCSI OP=0x%x, LUN=0x%16.16"PRIx64"\n",
        !          5466:            cdb[0], lu_cmd->lun);
        !          5467: #ifdef ISTGT_TRACE_DISK
        !          5468:        if (cdb[0] != SPC_TEST_UNIT_READY) {
        !          5469:                istgt_scsi_dump_cdb(cdb);
        !          5470:        }
        !          5471: #endif /* ISTGT_TRACE_DISK */
        !          5472:        switch (cdb[0]) {
        !          5473:        case SPC_INQUIRY:
        !          5474:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "INQUIRY\n");
        !          5475:                if (lu_cmd->R_bit == 0) {
        !          5476:                        ISTGT_ERRLOG("R_bit == 0\n");
        !          5477:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5478:                        return -1;
        !          5479:                }
        !          5480:                allocation_len = DGET16(&cdb[3]);
        !          5481:                if (allocation_len > data_alloc_len) {
        !          5482:                        ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
        !          5483:                            data_alloc_len);
        !          5484:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5485:                        return -1;
        !          5486:                }
        !          5487:                memset(data, 0, allocation_len);
        !          5488:                data_len = istgt_lu_disk_scsi_inquiry(spec, conn, cdb,
        !          5489:                    data, data_alloc_len);
        !          5490:                if (data_len < 0) {
        !          5491:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5492:                        break;
        !          5493:                }
        !          5494:                ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "INQUIRY", data, data_len);
        !          5495:                lu_cmd->data_len = DMIN32(data_len, lu_cmd->transfer_len);
        !          5496:                lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          5497:                break;
        !          5498: 
        !          5499:        case SPC_REPORT_LUNS:
        !          5500:                {
        !          5501:                        int sel;
        !          5502: 
        !          5503:                        ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "REPORT LUNS\n");
        !          5504:                        if (lu_cmd->R_bit == 0) {
        !          5505:                                ISTGT_ERRLOG("R_bit == 0\n");
        !          5506:                                return -1;
        !          5507:                        }
        !          5508: 
        !          5509:                        sel = cdb[2];
        !          5510:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "sel=%x\n", sel);
        !          5511: 
        !          5512:                        allocation_len = DGET32(&cdb[6]);
        !          5513:                        if (allocation_len > data_alloc_len) {
        !          5514:                                ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
        !          5515:                                                         data_alloc_len);
        !          5516:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5517:                                return -1;
        !          5518:                        }
        !          5519:                        if (allocation_len < 16) {
        !          5520:                                /* INVALID FIELD IN CDB */
        !          5521:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
        !          5522:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5523:                                break;
        !          5524:                        }
        !          5525:                        memset(data, 0, allocation_len);
        !          5526:                        data_len = istgt_lu_disk_scsi_report_luns(lu, conn, cdb, sel,
        !          5527:                            data, data_alloc_len);
        !          5528:                        if (data_len < 0) {
        !          5529:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5530:                                break;
        !          5531:                        }
        !          5532:                        ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "REPORT LUNS", data, data_len);
        !          5533:                        lu_cmd->data_len = DMIN32(data_len, lu_cmd->transfer_len);
        !          5534:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          5535:                }
        !          5536:                break;
        !          5537: 
        !          5538:        case SPC_TEST_UNIT_READY:
        !          5539:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "TEST_UNIT_READY\n");
        !          5540:                lu_cmd->data_len = 0;
        !          5541:                lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          5542:                break;
        !          5543: 
        !          5544:        case SBC_START_STOP_UNIT:
        !          5545:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "START_STOP_UNIT\n");
        !          5546:                {
        !          5547:                        int pc, loej, start;
        !          5548: 
        !          5549:                        pc = BGET8W(&cdb[4], 7, 4);
        !          5550:                        loej = BGET8(&cdb[4], 1);
        !          5551:                        start = BGET8(&cdb[4], 0);
        !          5552: 
        !          5553:                        if (start != 0 || pc != 0) {
        !          5554:                                if (spec->rsv_key) {
        !          5555:                                        rc = istgt_lu_disk_check_pr(spec, conn,
        !          5556:                                            PR_ALLOW(0,0,1,0,0));
        !          5557:                                        if (rc != 0) {
        !          5558:                                                lu_cmd->status
        !          5559:                                                        = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          5560:                                                break;
        !          5561:                                        }
        !          5562:                                }
        !          5563:                        }
        !          5564: 
        !          5565:                        lu_cmd->data_len = 0;
        !          5566:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          5567:                }
        !          5568:                break;
        !          5569: 
        !          5570:        case SBC_READ_CAPACITY_10:
        !          5571:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "READ_CAPACITY_10\n");
        !          5572:                if (lu_cmd->R_bit == 0) {
        !          5573:                        ISTGT_ERRLOG("R_bit == 0\n");
        !          5574:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5575:                        return -1;
        !          5576:                }
        !          5577:                if (spec->blockcnt - 1 > 0xffffffffULL) {
        !          5578:                        DSET32(&data[0], 0xffffffffUL);
        !          5579:                } else {
        !          5580:                        DSET32(&data[0], (uint32_t) (spec->blockcnt - 1));
        !          5581:                }
        !          5582:                DSET32(&data[4], (uint32_t) spec->blocklen);
        !          5583:                data_len = 8;
        !          5584:                lu_cmd->data_len = data_len;
        !          5585:                lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          5586:                ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG,
        !          5587:                    "SBC_READ_CAPACITY_10", data, data_len);
        !          5588:                break;
        !          5589: 
        !          5590:        case SPC_SERVICE_ACTION_IN_16:
        !          5591:                switch (BGET8W(&cdb[1], 4, 5)) { /* SERVICE ACTION */
        !          5592:                case SBC_SAI_READ_CAPACITY_16:
        !          5593:                        ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "READ_CAPACITY_16\n");
        !          5594:                        if (lu_cmd->R_bit == 0) {
        !          5595:                                ISTGT_ERRLOG("R_bit == 0\n");
        !          5596:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5597:                                return -1;
        !          5598:                        }
        !          5599:                        allocation_len = DGET32(&cdb[10]);
        !          5600:                        if (allocation_len > data_alloc_len) {
        !          5601:                                ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
        !          5602:                                    data_alloc_len);
        !          5603:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5604:                                return -1;
        !          5605:                        }
        !          5606:                        memset(data, 0, allocation_len);
        !          5607:                        DSET64(&data[0], spec->blockcnt - 1);
        !          5608:                        DSET32(&data[8], (uint32_t) spec->blocklen);
        !          5609:                        data[12] = 0;                   /* RTO_EN(1) PROT_EN(0) */
        !          5610:                        memset(&data[13], 0, 32 - (8 + 4 + 1));     /* Reserved */
        !          5611:                        data_len = 32;
        !          5612:                        lu_cmd->data_len = DMIN32(data_len, lu_cmd->transfer_len);
        !          5613:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          5614:                        break;
        !          5615:                case SBC_SAI_READ_LONG_16:
        !          5616:                default:
        !          5617:                        /* INVALID COMMAND OPERATION CODE */
        !          5618:                        BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
        !          5619:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5620:                        break;
        !          5621:                }
        !          5622:                break;
        !          5623: 
        !          5624:        case SPC_MODE_SELECT_6:
        !          5625: #if 0
        !          5626:                istgt_scsi_dump_cdb(cdb);
        !          5627: #endif
        !          5628:                {
        !          5629:                        int pf, sp, pllen;
        !          5630:                        int mdlen, mt, dsp, bdlen;
        !          5631: 
        !          5632:                        if (spec->rsv_key) {
        !          5633:                                rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
        !          5634:                                if (rc != 0) {
        !          5635:                                        lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          5636:                                        break;
        !          5637:                                }
        !          5638:                        }
        !          5639: 
        !          5640:                        pf = BGET8(&cdb[1], 4);
        !          5641:                        sp = BGET8(&cdb[1], 0);
        !          5642:                        pllen = cdb[4];             /* Parameter List Length */
        !          5643: 
        !          5644:                        if (pllen == 0) {
        !          5645:                                lu_cmd->data_len = 0;
        !          5646:                                lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          5647:                                break;
        !          5648:                        }
        !          5649:                        /* Data-Out */
        !          5650:                        rc = istgt_lu_disk_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
        !          5651:                            lu_cmd->iobufsize, pllen);
        !          5652:                        if (rc < 0) {
        !          5653:                                ISTGT_ERRLOG("lu_disk_transfer_data() failed\n");
        !          5654:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5655:                                break;
        !          5656:                        }
        !          5657:                        if (pllen < 4) {
        !          5658:                                /* INVALID FIELD IN CDB */
        !          5659:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
        !          5660:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5661:                                break;
        !          5662:                        }
        !          5663: #if 0
        !          5664:                        istgt_dump("MODE SELECT(6)", lu_cmd->iobuf, pllen);
        !          5665: #endif
        !          5666:                        data = lu_cmd->iobuf;
        !          5667:                        mdlen = data[0];            /* Mode Data Length */
        !          5668:                        mt = data[1];               /* Medium Type */
        !          5669:                        dsp = data[2];              /* Device-Specific Parameter */
        !          5670:                        bdlen = data[3];            /* Block Descriptor Length */
        !          5671: 
        !          5672:                        /* Short LBA mode parameter block descriptor */
        !          5673:                        /* data[4]-data[7] Number of Blocks */
        !          5674:                        /* data[8]-data[11] Block Length */
        !          5675: 
        !          5676:                        /* page data */
        !          5677:                        data_len = istgt_lu_disk_scsi_mode_select_page(spec, conn, cdb, pf, sp, &data[4 + bdlen], pllen - (4 + bdlen));
        !          5678:                        if (data_len != 0) {
        !          5679:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5680:                                break;
        !          5681:                        }
        !          5682:                        lu_cmd->data_len = pllen;
        !          5683:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          5684:                        break;
        !          5685:                }
        !          5686: 
        !          5687:        case SPC_MODE_SELECT_10:
        !          5688: #if 0
        !          5689:                istgt_scsi_dump_cdb(cdb);
        !          5690: #endif
        !          5691:                {
        !          5692:                        int pf, sp, pllen;
        !          5693:                        int mdlen, mt, dsp, bdlen;
        !          5694:                        int llba;
        !          5695: 
        !          5696:                        if (spec->rsv_key) {
        !          5697:                                rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
        !          5698:                                if (rc != 0) {
        !          5699:                                        lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          5700:                                        break;
        !          5701:                                }
        !          5702:                        }
        !          5703: 
        !          5704:                        pf = BGET8(&cdb[1], 4);
        !          5705:                        sp = BGET8(&cdb[1], 0);
        !          5706:                        pllen = DGET16(&cdb[7]);    /* Parameter List Length */
        !          5707: 
        !          5708:                        if (pllen == 0) {
        !          5709:                                lu_cmd->data_len = 0;
        !          5710:                                lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          5711:                                break;
        !          5712:                        }
        !          5713:                        /* Data-Out */
        !          5714:                        rc = istgt_lu_disk_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
        !          5715:                            lu_cmd->iobufsize, pllen);
        !          5716:                        if (rc < 0) {
        !          5717:                                ISTGT_ERRLOG("lu_disk_transfer_data() failed\n");
        !          5718:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5719:                                break;
        !          5720:                        }
        !          5721:                        if (pllen < 4) {
        !          5722:                                /* INVALID FIELD IN CDB */
        !          5723:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
        !          5724:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5725:                                break;
        !          5726:                        }
        !          5727: #if 0
        !          5728:                        istgt_dump("MODE SELECT(10)", lu_cmd->iobuf, pllen);
        !          5729: #endif
        !          5730:                        data = lu_cmd->iobuf;
        !          5731:                        mdlen = DGET16(&data[0]);   /* Mode Data Length */
        !          5732:                        mt = data[2];               /* Medium Type */
        !          5733:                        dsp = data[3];              /* Device-Specific Parameter */
        !          5734:                        llba = BGET8(&data[4], 0);  /* Long LBA */
        !          5735:                        bdlen = DGET16(&data[6]);   /* Block Descriptor Length */
        !          5736: 
        !          5737:                        if (llba) {
        !          5738:                                /* Long LBA mode parameter block descriptor */
        !          5739:                                /* data[8]-data[15] Number of Blocks */
        !          5740:                                /* data[16]-data[19] Reserved */
        !          5741:                                /* data[20]-data[23] Block Length */
        !          5742:                        } else {
        !          5743:                                /* Short LBA mode parameter block descriptor */
        !          5744:                                /* data[8]-data[11] Number of Blocks */
        !          5745:                                /* data[12]-data[15] Block Length */
        !          5746:                        }
        !          5747: 
        !          5748:                        /* page data */
        !          5749:                        data_len = istgt_lu_disk_scsi_mode_select_page(spec, conn, cdb, pf, sp, &data[8 + bdlen], pllen - (8 + bdlen));
        !          5750:                        if (data_len != 0) {
        !          5751:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5752:                                break;
        !          5753:                        }
        !          5754:                        lu_cmd->data_len = pllen;
        !          5755:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          5756:                        break;
        !          5757:                }
        !          5758: 
        !          5759:        case SPC_MODE_SENSE_6:
        !          5760: #if 0
        !          5761:                istgt_scsi_dump_cdb(cdb);
        !          5762: #endif
        !          5763:                {
        !          5764:                        int dbd, pc, page, subpage;
        !          5765: 
        !          5766:                        if (spec->rsv_key) {
        !          5767:                                rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
        !          5768:                                if (rc != 0) {
        !          5769:                                        lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          5770:                                        break;
        !          5771:                                }
        !          5772:                        }
        !          5773: 
        !          5774:                        if (lu_cmd->R_bit == 0) {
        !          5775:                                ISTGT_ERRLOG("R_bit == 0\n");
        !          5776:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5777:                                return -1;
        !          5778:                        }
        !          5779: 
        !          5780:                        dbd = BGET8(&cdb[1], 3);
        !          5781:                        pc = BGET8W(&cdb[2], 7, 2);
        !          5782:                        page = BGET8W(&cdb[2], 5, 6);
        !          5783:                        subpage = cdb[3];
        !          5784: 
        !          5785:                        allocation_len = cdb[4];
        !          5786:                        if (allocation_len > data_alloc_len) {
        !          5787:                                ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
        !          5788:                                    data_alloc_len);
        !          5789:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5790:                                return -1;
        !          5791:                        }
        !          5792:                        memset(data, 0, allocation_len);
        !          5793: 
        !          5794:                        data_len = istgt_lu_disk_scsi_mode_sense6(spec, conn, cdb, dbd, pc, page, subpage, data, data_alloc_len);
        !          5795:                        if (data_len < 0) {
        !          5796:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5797:                                break;
        !          5798:                        }
        !          5799: #if 0
        !          5800:                        istgt_dump("MODE SENSE(6)", data, data_len);
        !          5801: #endif
        !          5802:                        lu_cmd->data_len = DMIN32(data_len, lu_cmd->transfer_len);
        !          5803:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          5804:                        break;
        !          5805:                }
        !          5806: 
        !          5807:        case SPC_MODE_SENSE_10:
        !          5808: #if 0
        !          5809:                istgt_scsi_dump_cdb(cdb);
        !          5810: #endif
        !          5811:                {
        !          5812:                        int dbd, pc, page, subpage;
        !          5813:                        int llbaa;
        !          5814: 
        !          5815:                        if (spec->rsv_key) {
        !          5816:                                rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
        !          5817:                                if (rc != 0) {
        !          5818:                                        lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          5819:                                        break;
        !          5820:                                }
        !          5821:                        }
        !          5822: 
        !          5823:                        if (lu_cmd->R_bit == 0) {
        !          5824:                                ISTGT_ERRLOG("R_bit == 0\n");
        !          5825:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5826:                                return -1;
        !          5827:                        }
        !          5828: 
        !          5829:                        llbaa = BGET8(&cdb[1], 4);
        !          5830:                        dbd = BGET8(&cdb[1], 3);
        !          5831:                        pc = BGET8W(&cdb[2], 7, 2);
        !          5832:                        page = BGET8W(&cdb[2], 5, 6);
        !          5833:                        subpage = cdb[3];
        !          5834: 
        !          5835:                        allocation_len = DGET16(&cdb[7]);
        !          5836:                        if (allocation_len > data_alloc_len) {
        !          5837:                                ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
        !          5838:                                    data_alloc_len);
        !          5839:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5840:                                return -1;
        !          5841:                        }
        !          5842:                        memset(data, 0, allocation_len);
        !          5843: 
        !          5844:                        data_len = istgt_lu_disk_scsi_mode_sense10(spec, conn, cdb, llbaa, dbd, pc, page, subpage, data, data_alloc_len);
        !          5845:                        if (data_len < 0) {
        !          5846:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5847:                                break;
        !          5848:                        }
        !          5849: #if 0
        !          5850:                        istgt_dump("MODE SENSE(10)", data, data_len);
        !          5851: #endif
        !          5852:                        lu_cmd->data_len = DMIN32(data_len, lu_cmd->transfer_len);
        !          5853:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          5854:                        break;
        !          5855:                }
        !          5856: 
        !          5857: #if 0
        !          5858:        case SPC_LOG_SELECT:
        !          5859:        case SPC_LOG_SENSE:
        !          5860:                /* INVALID COMMAND OPERATION CODE */
        !          5861:                BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
        !          5862:                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5863:                break;
        !          5864: #endif
        !          5865: 
        !          5866:        case SPC_REQUEST_SENSE:
        !          5867:                {
        !          5868:                        int desc;
        !          5869:                        int sk, asc, ascq;
        !          5870: 
        !          5871:                        if (lu_cmd->R_bit == 0) {
        !          5872:                                ISTGT_ERRLOG("R_bit == 0\n");
        !          5873:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5874:                                return -1;
        !          5875:                        }
        !          5876: 
        !          5877:                        desc = BGET8(&cdb[1], 0);
        !          5878:                        if (desc != 0) {
        !          5879:                                /* INVALID FIELD IN CDB */
        !          5880:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
        !          5881:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5882:                                break;
        !          5883:                        }
        !          5884: 
        !          5885:                        allocation_len = cdb[4];
        !          5886:                        if (allocation_len > data_alloc_len) {
        !          5887:                                ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
        !          5888:                                    data_alloc_len);
        !          5889:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5890:                                return -1;
        !          5891:                        }
        !          5892:                        memset(data, 0, allocation_len);
        !          5893: 
        !          5894:                        if (!spec->sense) {
        !          5895:                                /* NO ADDITIONAL SENSE INFORMATION */
        !          5896:                                sk = ISTGT_SCSI_SENSE_NO_SENSE;
        !          5897:                                asc = 0x00;
        !          5898:                                ascq = 0x00;
        !          5899:                        } else {
        !          5900:                                sk = (spec->sense >> 16) & 0xffU;
        !          5901:                                asc = (spec->sense >> 8) & 0xffU;
        !          5902:                                ascq = spec->sense & 0xffU;
        !          5903:                        }
        !          5904:                        data_len = istgt_lu_disk_build_sense_data(spec, sense_data,
        !          5905:                            sk, asc, ascq);
        !          5906:                        if (data_len < 0 || data_len < 2) {
        !          5907:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5908:                                break;
        !          5909:                        }
        !          5910:                        /* omit SenseLength */
        !          5911:                        data_len -= 2;
        !          5912:                        memcpy(data, sense_data + 2, data_len);
        !          5913: #if 0
        !          5914:                        istgt_dump("REQUEST SENSE", data, data_len);
        !          5915: #endif
        !          5916:                        lu_cmd->data_len = DMIN32(data_len, lu_cmd->transfer_len);
        !          5917:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          5918:                        break;
        !          5919:                }
        !          5920: 
        !          5921:        case SBC_READ_6:
        !          5922:                {
        !          5923:                        if (spec->rsv_key) {
        !          5924:                                rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0));
        !          5925:                                if (rc != 0) {
        !          5926:                                        lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          5927:                                        break;
        !          5928:                                }
        !          5929:                        }
        !          5930: 
        !          5931:                        if (lu_cmd->R_bit == 0) {
        !          5932:                                ISTGT_ERRLOG("R_bit == 0\n");
        !          5933:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5934:                                return -1;
        !          5935:                        }
        !          5936: 
        !          5937:                        lba = (uint64_t) (DGET24(&cdb[1]) & 0x001fffffU);
        !          5938:                        transfer_len = (uint32_t) DGET8(&cdb[4]);
        !          5939:                        if (transfer_len == 0) {
        !          5940:                                transfer_len = 256;
        !          5941:                        }
        !          5942:                        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
        !          5943:                            "READ_6(lba %"PRIu64", len %u blocks)\n",
        !          5944:                            lba, transfer_len);
        !          5945:                        rc = istgt_lu_disk_lbread(spec, conn, lu_cmd, lba, transfer_len);
        !          5946:                        if (rc < 0) {
        !          5947:                                ISTGT_ERRLOG("lu_disk_lbread() failed\n");
        !          5948:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5949:                                break;
        !          5950:                        }
        !          5951:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          5952:                        break;
        !          5953:                }
        !          5954: 
        !          5955:        case SBC_READ_10:
        !          5956:                {
        !          5957:                        int dpo, fua, fua_nv;
        !          5958: 
        !          5959:                        if (spec->rsv_key) {
        !          5960:                                rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0));
        !          5961:                                if (rc != 0) {
        !          5962:                                        lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          5963:                                        break;
        !          5964:                                }
        !          5965:                        }
        !          5966: 
        !          5967:                        if (lu_cmd->R_bit == 0) {
        !          5968:                                ISTGT_ERRLOG("R_bit == 0\n");
        !          5969:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5970:                                return -1;
        !          5971:                        }
        !          5972: 
        !          5973:                        dpo = BGET8(&cdb[1], 4);
        !          5974:                        fua = BGET8(&cdb[1], 3);
        !          5975:                        fua_nv = BGET8(&cdb[1], 1);
        !          5976:                        lba = (uint64_t) DGET32(&cdb[2]);
        !          5977:                        transfer_len = (uint32_t) DGET16(&cdb[7]);
        !          5978:                        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
        !          5979:                            "READ_10(lba %"PRIu64", len %u blocks)\n",
        !          5980:                            lba, transfer_len);
        !          5981:                        rc = istgt_lu_disk_lbread(spec, conn, lu_cmd, lba, transfer_len);
        !          5982:                        if (rc < 0) {
        !          5983:                                ISTGT_ERRLOG("lu_disk_lbread() failed\n");
        !          5984:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          5985:                                break;
        !          5986:                        }
        !          5987:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          5988:                        break;
        !          5989:                }
        !          5990: 
        !          5991:        case SBC_READ_12:
        !          5992:                {
        !          5993:                        int dpo, fua, fua_nv;
        !          5994: 
        !          5995:                        if (spec->rsv_key) {
        !          5996:                                rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0));
        !          5997:                                if (rc != 0) {
        !          5998:                                        lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          5999:                                        break;
        !          6000:                                }
        !          6001:                        }
        !          6002: 
        !          6003:                        if (lu_cmd->R_bit == 0) {
        !          6004:                                ISTGT_ERRLOG("R_bit == 0\n");
        !          6005:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6006:                                return -1;
        !          6007:                        }
        !          6008: 
        !          6009:                        dpo = BGET8(&cdb[1], 4);
        !          6010:                        fua = BGET8(&cdb[1], 3);
        !          6011:                        fua_nv = BGET8(&cdb[1], 1);
        !          6012:                        lba = (uint64_t) DGET32(&cdb[2]);
        !          6013:                        transfer_len = (uint32_t) DGET32(&cdb[6]);
        !          6014:                        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
        !          6015:                            "READ_12(lba %"PRIu64", len %u blocks)\n",
        !          6016:                            lba, transfer_len);
        !          6017:                        rc = istgt_lu_disk_lbread(spec, conn, lu_cmd, lba, transfer_len);
        !          6018:                        if (rc < 0) {
        !          6019:                                ISTGT_ERRLOG("lu_disk_lbread() failed\n");
        !          6020:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6021:                                break;
        !          6022:                        }
        !          6023:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          6024:                        break;
        !          6025:                }
        !          6026: 
        !          6027:        case SBC_READ_16:
        !          6028:                {
        !          6029:                        int dpo, fua, fua_nv;
        !          6030: 
        !          6031:                        if (spec->rsv_key) {
        !          6032:                                rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0));
        !          6033:                                if (rc != 0) {
        !          6034:                                        lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          6035:                                        break;
        !          6036:                                }
        !          6037:                        }
        !          6038: 
        !          6039:                        if (lu_cmd->R_bit == 0) {
        !          6040:                                ISTGT_ERRLOG("R_bit == 0\n");
        !          6041:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6042:                                return -1;
        !          6043:                        }
        !          6044: 
        !          6045:                        dpo = BGET8(&cdb[1], 4);
        !          6046:                        fua = BGET8(&cdb[1], 3);
        !          6047:                        fua_nv = BGET8(&cdb[1], 1);
        !          6048:                        lba = (uint64_t) DGET64(&cdb[2]);
        !          6049:                        transfer_len = (uint32_t) DGET32(&cdb[10]);
        !          6050:                        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
        !          6051:                            "READ_16(lba %"PRIu64", len %u blocks)\n",
        !          6052:                            lba, transfer_len);
        !          6053:                        rc = istgt_lu_disk_lbread(spec, conn, lu_cmd, lba, transfer_len);
        !          6054:                        if (rc < 0) {
        !          6055:                                ISTGT_ERRLOG("lu_disk_lbread() failed\n");
        !          6056:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6057:                                break;
        !          6058:                        }
        !          6059:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          6060:                        break;
        !          6061:                }
        !          6062: 
        !          6063:        case SBC_WRITE_6:
        !          6064:                {
        !          6065:                        if (spec->rsv_key) {
        !          6066:                                rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
        !          6067:                                if (rc != 0) {
        !          6068:                                        lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          6069:                                        break;
        !          6070:                                }
        !          6071:                        }
        !          6072: 
        !          6073:                        if (lu_cmd->W_bit == 0) {
        !          6074:                                ISTGT_ERRLOG("W_bit == 0\n");
        !          6075:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6076:                                return -1;
        !          6077:                        }
        !          6078: 
        !          6079:                        lba = (uint64_t) (DGET24(&cdb[1]) & 0x001fffffU);
        !          6080:                        transfer_len = (uint32_t) DGET8(&cdb[4]);
        !          6081:                        if (transfer_len == 0) {
        !          6082:                                transfer_len = 256;
        !          6083:                        }
        !          6084:                        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
        !          6085:                            "WRITE_6(lba %"PRIu64", len %u blocks)\n",
        !          6086:                            lba, transfer_len);
        !          6087:                        rc = istgt_lu_disk_lbwrite(spec, conn, lu_cmd, lba, transfer_len);
        !          6088:                        if (rc < 0) {
        !          6089:                                ISTGT_ERRLOG("lu_disk_lbwrite() failed\n");
        !          6090:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6091:                                break;
        !          6092:                        }
        !          6093:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          6094:                        break;
        !          6095:                }
        !          6096: 
        !          6097:        case SBC_WRITE_10:
        !          6098:        case SBC_WRITE_AND_VERIFY_10:
        !          6099:                {
        !          6100:                        int dpo, fua, fua_nv;
        !          6101: 
        !          6102:                        if (spec->rsv_key) {
        !          6103:                                rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
        !          6104:                                if (rc != 0) {
        !          6105:                                        lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          6106:                                        break;
        !          6107:                                }
        !          6108:                        }
        !          6109: 
        !          6110:                        if (lu_cmd->W_bit == 0) {
        !          6111:                                ISTGT_ERRLOG("W_bit == 0\n");
        !          6112:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6113:                                return -1;
        !          6114:                        }
        !          6115: 
        !          6116:                        dpo = BGET8(&cdb[1], 4);
        !          6117:                        fua = BGET8(&cdb[1], 3);
        !          6118:                        fua_nv = BGET8(&cdb[1], 1);
        !          6119:                        lba = (uint64_t) DGET32(&cdb[2]);
        !          6120:                        transfer_len = (uint32_t) DGET16(&cdb[7]);
        !          6121:                        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
        !          6122:                            "WRITE_10(lba %"PRIu64", len %u blocks)\n",
        !          6123:                            lba, transfer_len);
        !          6124:                        rc = istgt_lu_disk_lbwrite(spec, conn, lu_cmd, lba, transfer_len);
        !          6125:                        if (rc < 0) {
        !          6126:                                ISTGT_ERRLOG("lu_disk_lbwrite() failed\n");
        !          6127:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6128:                                break;
        !          6129:                        }
        !          6130:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          6131:                        break;
        !          6132:                }
        !          6133: 
        !          6134:        case SBC_WRITE_12:
        !          6135:        case SBC_WRITE_AND_VERIFY_12:
        !          6136:                {
        !          6137:                        int dpo, fua, fua_nv;
        !          6138: 
        !          6139:                        if (spec->rsv_key) {
        !          6140:                                rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
        !          6141:                                if (rc != 0) {
        !          6142:                                        lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          6143:                                        break;
        !          6144:                                }
        !          6145:                        }
        !          6146: 
        !          6147:                        if (lu_cmd->W_bit == 0) {
        !          6148:                                ISTGT_ERRLOG("W_bit == 0\n");
        !          6149:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6150:                                return -1;
        !          6151:                        }
        !          6152: 
        !          6153:                        dpo = BGET8(&cdb[1], 4);
        !          6154:                        fua = BGET8(&cdb[1], 3);
        !          6155:                        fua_nv = BGET8(&cdb[1], 1);
        !          6156:                        lba = (uint64_t) DGET32(&cdb[2]);
        !          6157:                        transfer_len = (uint32_t) DGET32(&cdb[6]);
        !          6158:                        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
        !          6159:                            "WRITE_12(lba %"PRIu64", len %u blocks)\n",
        !          6160:                            lba, transfer_len);
        !          6161:                        rc = istgt_lu_disk_lbwrite(spec, conn, lu_cmd, lba, transfer_len);
        !          6162:                        if (rc < 0) {
        !          6163:                                ISTGT_ERRLOG("lu_disk_lbwrite() failed\n");
        !          6164:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6165:                                break;
        !          6166:                        }
        !          6167:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          6168:                        break;
        !          6169:                }
        !          6170: 
        !          6171:        case SBC_WRITE_16:
        !          6172:        case SBC_WRITE_AND_VERIFY_16:
        !          6173:                {
        !          6174:                        int dpo, fua, fua_nv;
        !          6175: 
        !          6176:                        if (spec->rsv_key) {
        !          6177:                                rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
        !          6178:                                if (rc != 0) {
        !          6179:                                        lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          6180:                                        break;
        !          6181:                                }
        !          6182:                        }
        !          6183: 
        !          6184:                        if (lu_cmd->W_bit == 0) {
        !          6185:                                ISTGT_ERRLOG("W_bit == 0\n");
        !          6186:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6187:                                return -1;
        !          6188:                        }
        !          6189: 
        !          6190:                        dpo = BGET8(&cdb[1], 4);
        !          6191:                        fua = BGET8(&cdb[1], 3);
        !          6192:                        fua_nv = BGET8(&cdb[1], 1);
        !          6193:                        lba = (uint64_t) DGET64(&cdb[2]);
        !          6194:                        transfer_len = (uint32_t) DGET32(&cdb[10]);
        !          6195:                        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
        !          6196:                            "WRITE_16(lba %"PRIu64", len %u blocks)\n",
        !          6197:                            lba, transfer_len);
        !          6198:                        rc = istgt_lu_disk_lbwrite(spec, conn, lu_cmd, lba, transfer_len);
        !          6199:                        if (rc < 0) {
        !          6200:                                ISTGT_ERRLOG("lu_disk_lbwrite() failed\n");
        !          6201:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6202:                                break;
        !          6203:                        }
        !          6204:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          6205:                        break;
        !          6206:                }
        !          6207: 
        !          6208:        case SBC_VERIFY_10:
        !          6209:                {
        !          6210:                        int dpo, bytchk;
        !          6211: 
        !          6212:                        if (spec->rsv_key) {
        !          6213:                                rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0));
        !          6214:                                if (rc != 0) {
        !          6215:                                        lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          6216:                                        break;
        !          6217:                                }
        !          6218:                        }
        !          6219: 
        !          6220:                        dpo = BGET8(&cdb[1], 4);
        !          6221:                        bytchk = BGET8(&cdb[1], 1);
        !          6222:                        lba = (uint64_t) DGET32(&cdb[2]);
        !          6223:                        len = (uint32_t) DGET16(&cdb[7]);
        !          6224:                        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
        !          6225:                            "VERIFY_10(lba %"PRIu64", len %u blocks)\n",
        !          6226:                            lba, len);
        !          6227:                        lu_cmd->data_len = 0;
        !          6228:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          6229:                        break;
        !          6230:                }
        !          6231: 
        !          6232:        case SBC_VERIFY_12:
        !          6233:                {
        !          6234:                        int dpo, bytchk;
        !          6235: 
        !          6236:                        if (spec->rsv_key) {
        !          6237:                                rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0));
        !          6238:                                if (rc != 0) {
        !          6239:                                        lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          6240:                                        break;
        !          6241:                                }
        !          6242:                        }
        !          6243: 
        !          6244:                        dpo = BGET8(&cdb[1], 4);
        !          6245:                        bytchk = BGET8(&cdb[1], 1);
        !          6246:                        lba = (uint64_t) DGET32(&cdb[2]);
        !          6247:                        len = (uint32_t) DGET32(&cdb[6]);
        !          6248:                        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
        !          6249:                            "VERIFY_12(lba %"PRIu64", len %u blocks)\n",
        !          6250:                            lba, len);
        !          6251:                        lu_cmd->data_len = 0;
        !          6252:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          6253:                        break;
        !          6254:                }
        !          6255: 
        !          6256:        case SBC_VERIFY_16:
        !          6257:                {
        !          6258:                        int dpo, bytchk;
        !          6259: 
        !          6260:                        if (spec->rsv_key) {
        !          6261:                                rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(1,0,1,1,0));
        !          6262:                                if (rc != 0) {
        !          6263:                                        lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          6264:                                        break;
        !          6265:                                }
        !          6266:                        }
        !          6267: 
        !          6268:                        dpo = BGET8(&cdb[1], 4);
        !          6269:                        bytchk = BGET8(&cdb[1], 1);
        !          6270:                        lba = (uint64_t) DGET64(&cdb[2]);
        !          6271:                        len = (uint32_t) DGET32(&cdb[10]);
        !          6272:                        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
        !          6273:                            "VERIFY_16(lba %"PRIu64", len %u blocks)\n",
        !          6274:                            lba, len);
        !          6275:                        lu_cmd->data_len = 0;
        !          6276:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          6277:                        break;
        !          6278:                }
        !          6279: 
        !          6280:        case SBC_WRITE_SAME_10:
        !          6281:                {
        !          6282:                        int wprotect, pbdata, lbdata, group_no;
        !          6283: 
        !          6284:                        if (spec->rsv_key) {
        !          6285:                                rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
        !          6286:                                if (rc != 0) {
        !          6287:                                        lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          6288:                                        break;
        !          6289:                                }
        !          6290:                        }
        !          6291: 
        !          6292:                        if (lu_cmd->W_bit == 0) {
        !          6293:                                ISTGT_ERRLOG("W_bit == 0\n");
        !          6294:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6295:                                return -1;
        !          6296:                        }
        !          6297: 
        !          6298:                        wprotect = BGET8W(&cdb[1], 7, 3);
        !          6299:                        pbdata = BGET8(&cdb[1], 2);
        !          6300:                        lbdata = BGET8(&cdb[1], 1);
        !          6301:                        lba = (uint64_t) DGET32(&cdb[2]);
        !          6302:                        transfer_len = (uint32_t) DGET16(&cdb[7]);
        !          6303:                        group_no = BGET8W(&cdb[6], 4, 5);
        !          6304: 
        !          6305:                        /* only PBDATA=0 and LBDATA=0 support */
        !          6306:                        if (pbdata || lbdata) {
        !          6307:                                /* INVALID FIELD IN CDB */
        !          6308:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
        !          6309:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6310:                                break;
        !          6311:                        }
        !          6312: 
        !          6313:                        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
        !          6314:                            "WRITE_SAME_10(lba %"PRIu64", len %u blocks)\n",
        !          6315:                            lba, transfer_len);
        !          6316:                        rc = istgt_lu_disk_lbwrite_same(spec, conn, lu_cmd, lba, transfer_len);
        !          6317:                        if (rc < 0) {
        !          6318:                                ISTGT_ERRLOG("lu_disk_lbwrite_same() failed\n");
        !          6319:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6320:                                break;
        !          6321:                        }
        !          6322:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          6323:                        break;
        !          6324:                }
        !          6325: 
        !          6326:        case SBC_WRITE_SAME_16:
        !          6327:                {
        !          6328:                        int wprotect, anchor, unmap, pbdata, lbdata, group_no;
        !          6329: 
        !          6330: #if 0
        !          6331:                        istgt_scsi_dump_cdb(cdb);
        !          6332: #endif
        !          6333:                        if (spec->rsv_key) {
        !          6334:                                rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
        !          6335:                                if (rc != 0) {
        !          6336:                                        lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          6337:                                        break;
        !          6338:                                }
        !          6339:                        }
        !          6340: 
        !          6341:                        if (lu_cmd->W_bit == 0) {
        !          6342:                                ISTGT_ERRLOG("W_bit == 0\n");
        !          6343:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6344:                                return -1;
        !          6345:                        }
        !          6346: 
        !          6347:                        wprotect = BGET8W(&cdb[1], 7, 3);
        !          6348:                        anchor = BGET8(&cdb[1], 4);
        !          6349:                        unmap = BGET8(&cdb[1], 3);
        !          6350:                        pbdata = BGET8(&cdb[1], 2);
        !          6351:                        lbdata = BGET8(&cdb[1], 1);
        !          6352:                        lba = (uint64_t) DGET64(&cdb[2]);
        !          6353:                        transfer_len = (uint32_t) DGET32(&cdb[10]);
        !          6354:                        group_no = BGET8W(&cdb[14], 4, 5);
        !          6355: 
        !          6356:                        /* only PBDATA=0 and LBDATA=0 support */
        !          6357:                        if (pbdata || lbdata) {
        !          6358:                                /* INVALID FIELD IN CDB */
        !          6359:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
        !          6360:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6361:                                break;
        !          6362:                        }
        !          6363:                        if (anchor) {
        !          6364:                                /* INVALID FIELD IN CDB */
        !          6365:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
        !          6366:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6367:                                break;
        !          6368:                        }
        !          6369: 
        !          6370:                        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
        !          6371:                            "WRITE_SAME_16(lba %"PRIu64", len %u blocks)\n",
        !          6372:                            lba, transfer_len);
        !          6373:                        rc = istgt_lu_disk_lbwrite_same(spec, conn, lu_cmd, lba, transfer_len);
        !          6374:                        if (rc < 0) {
        !          6375:                                ISTGT_ERRLOG("lu_disk_lbwrite_same() failed\n");
        !          6376:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6377:                                break;
        !          6378:                        }
        !          6379:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          6380:                        break;
        !          6381:                }
        !          6382: 
        !          6383:        case SBC_COMPARE_AND_WRITE:
        !          6384:                {
        !          6385:                        int64_t maxlen;
        !          6386:                        int wprotect, dpo, fua, fua_nv, group_no;
        !          6387: 
        !          6388: #if 0
        !          6389:                        istgt_scsi_dump_cdb(cdb);
        !          6390: #endif
        !          6391:                        if (spec->lu->istgt->swmode == ISTGT_SWMODE_TRADITIONAL) {
        !          6392:                                /* INVALID COMMAND OPERATION CODE */
        !          6393:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
        !          6394:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6395:                                break;
        !          6396:                        }
        !          6397:                        if (spec->rsv_key) {
        !          6398:                                rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
        !          6399:                                if (rc != 0) {
        !          6400:                                        lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          6401:                                        break;
        !          6402:                                }
        !          6403:                        }
        !          6404: 
        !          6405:                        if (lu_cmd->W_bit == 0) {
        !          6406:                                ISTGT_ERRLOG("W_bit == 0\n");
        !          6407:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6408:                                return -1;
        !          6409:                        }
        !          6410: 
        !          6411:                        wprotect = BGET8W(&cdb[1], 7, 3);
        !          6412:                        dpo = BGET8(&cdb[1], 4);
        !          6413:                        fua = BGET8(&cdb[1], 3);
        !          6414:                        fua_nv = BGET8(&cdb[1], 1);
        !          6415:                        lba = (uint64_t) DGET64(&cdb[2]);
        !          6416:                        transfer_len = (uint32_t) DGET8(&cdb[13]);
        !          6417:                        group_no = BGET8W(&cdb[14], 4, 5);
        !          6418: 
        !          6419:                        maxlen = ISTGT_LU_WORK_BLOCK_SIZE / spec->blocklen;
        !          6420:                        if (maxlen > 0xff) {
        !          6421:                                maxlen = 0xff;
        !          6422:                        }
        !          6423:                        if (transfer_len > maxlen) {
        !          6424:                                /* INVALID FIELD IN CDB */
        !          6425:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
        !          6426:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6427:                                break;
        !          6428:                        }
        !          6429: 
        !          6430:                        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
        !          6431:                            "COMPARE_AND_WRITE(lba %"PRIu64", len %u blocks)\n",
        !          6432:                            lba, transfer_len);
        !          6433:                        rc = istgt_lu_disk_lbwrite_ats(spec, conn, lu_cmd, lba, transfer_len);
        !          6434:                        if (rc < 0) {
        !          6435:                                //ISTGT_ERRLOG("lu_disk_lbwrite_ats() failed\n");
        !          6436:                                /* sense data build by function */
        !          6437:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6438:                                break;
        !          6439:                        }
        !          6440:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          6441:                        break;
        !          6442:                }
        !          6443: 
        !          6444:        case SBC_SYNCHRONIZE_CACHE_10:
        !          6445:                {
        !          6446:                        int sync_nv, immed;
        !          6447: 
        !          6448:                        if (spec->rsv_key) {
        !          6449:                                rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
        !          6450:                                if (rc != 0) {
        !          6451:                                        lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          6452:                                        break;
        !          6453:                                }
        !          6454:                        }
        !          6455: 
        !          6456:                        sync_nv = BGET8(&cdb[1], 2);
        !          6457:                        immed = BGET8(&cdb[1], 1);
        !          6458:                        lba = (uint64_t) DGET32(&cdb[2]);
        !          6459:                        len = (uint32_t) DGET16(&cdb[7]);
        !          6460:                        if (len == 0) {
        !          6461:                                len = spec->blockcnt;
        !          6462:                        }
        !          6463:                        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
        !          6464:                            "SYNCHRONIZE_CACHE_10(lba %"PRIu64
        !          6465:                            ", len %u blocks)\n",
        !          6466:                            lba, len);
        !          6467:                        rc = istgt_lu_disk_lbsync(spec, conn, lu_cmd, lba, len);
        !          6468:                        if (rc < 0) {
        !          6469:                                ISTGT_ERRLOG("lu_disk_lbsync() failed\n");
        !          6470:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6471:                                break;
        !          6472:                        }
        !          6473:                        lu_cmd->data_len = 0;
        !          6474:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          6475:                        break;
        !          6476:                }
        !          6477: 
        !          6478:        case SBC_SYNCHRONIZE_CACHE_16:
        !          6479:                {
        !          6480:                        int sync_nv, immed;
        !          6481: 
        !          6482:                        if (spec->rsv_key) {
        !          6483:                                rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
        !          6484:                                if (rc != 0) {
        !          6485:                                        lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          6486:                                        break;
        !          6487:                                }
        !          6488:                        }
        !          6489: 
        !          6490:                        sync_nv = BGET8(&cdb[1], 2);
        !          6491:                        immed = BGET8(&cdb[1], 1);
        !          6492:                        lba = (uint64_t) DGET64(&cdb[2]);
        !          6493:                        len = (uint32_t) DGET32(&cdb[10]);
        !          6494:                        if (len == 0) {
        !          6495:                                len = spec->blockcnt;
        !          6496:                        }
        !          6497:                        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
        !          6498:                            "SYNCHRONIZE_CACHE_10(lba %"PRIu64
        !          6499:                            ", len %u blocks)\n",
        !          6500:                            lba, len);
        !          6501:                        rc = istgt_lu_disk_lbsync(spec, conn, lu_cmd, lba, len);
        !          6502:                        if (rc < 0) {
        !          6503:                                ISTGT_ERRLOG("lu_disk_lbsync() failed\n");
        !          6504:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6505:                                break;
        !          6506:                        }
        !          6507:                        lu_cmd->data_len = 0;
        !          6508:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          6509:                        break;
        !          6510:                }
        !          6511: 
        !          6512:        case SCC_MAINTENANCE_IN:
        !          6513:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MAINTENANCE_IN\n");
        !          6514:                switch (BGET8W(&cdb[1], 4, 5)) { /* SERVICE ACTION */
        !          6515:                case SPC_MI_REPORT_TARGET_PORT_GROUPS:
        !          6516:                        ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "REPORT_TARGET_PORT_GROUPS\n");
        !          6517:                        if (lu_cmd->R_bit == 0) {
        !          6518:                                ISTGT_ERRLOG("R_bit == 0\n");
        !          6519:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6520:                                return -1;
        !          6521:                        }
        !          6522:                        allocation_len = DGET32(&cdb[6]);
        !          6523:                        if (allocation_len > data_alloc_len) {
        !          6524:                                ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
        !          6525:                                    data_alloc_len);
        !          6526:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6527:                                return -1;
        !          6528:                        }
        !          6529:                        memset(data, 0, allocation_len);
        !          6530:                        data_len = istgt_lu_disk_scsi_report_target_port_groups(spec, conn, cdb, data, data_alloc_len);
        !          6531:                        if (data_len < 0) {
        !          6532:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6533:                                break;
        !          6534:                        }
        !          6535:                        ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG,
        !          6536:                            "REPORT_TARGET_PORT_GROUPS", data, data_len);
        !          6537:                        lu_cmd->data_len = DMIN32(data_len, lu_cmd->transfer_len);
        !          6538:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          6539:                        break;
        !          6540:                default:
        !          6541:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "SA=0x%2.2x\n",
        !          6542:                            BGET8W(&cdb[1], 4, 5));
        !          6543:                        /* INVALID COMMAND OPERATION CODE */
        !          6544:                        BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
        !          6545:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6546:                        break;
        !          6547:                }
        !          6548:                break;
        !          6549: 
        !          6550:        case SCC_MAINTENANCE_OUT:
        !          6551:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MAINTENANCE_OUT\n");
        !          6552:                switch (BGET8W(&cdb[1], 4, 5)) { /* SERVICE ACTION */
        !          6553:                case SPC_MO_SET_TARGET_PORT_GROUPS:
        !          6554:                        ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "SET_TARGET_PORT_GROUPS\n");
        !          6555:                        if (spec->rsv_key) {
        !          6556:                                rc = istgt_lu_disk_check_pr(spec, conn, PR_ALLOW(0,0,1,0,0));
        !          6557:                                if (rc != 0) {
        !          6558:                                        lu_cmd->status = ISTGT_SCSI_STATUS_RESERVATION_CONFLICT;
        !          6559:                                        break;
        !          6560:                                }
        !          6561:                        }
        !          6562:                        if (lu_cmd->W_bit == 0) {
        !          6563:                                ISTGT_ERRLOG("W_bit == 0\n");
        !          6564:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6565:                                return -1;
        !          6566:                        }
        !          6567:                        parameter_len = DGET32(&cdb[6]);
        !          6568:                        if (parameter_len == 0) {
        !          6569:                                lu_cmd->data_len = 0;
        !          6570:                                lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          6571:                                break;
        !          6572:                        }
        !          6573:                        /* Data-Out */
        !          6574:                        rc = istgt_lu_disk_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
        !          6575:                            lu_cmd->iobufsize, parameter_len);
        !          6576:                        if (rc < 0) {
        !          6577:                                ISTGT_ERRLOG("lu_disk_transfer_data() failed\n");
        !          6578:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6579:                                break;
        !          6580:                        }
        !          6581:                        if (parameter_len < 4) {
        !          6582:                                /* INVALID FIELD IN CDB */
        !          6583:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
        !          6584:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6585:                                break;
        !          6586:                        }
        !          6587:                        ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG,
        !          6588:                            "SET_TARGET_PORT_GROUPS",
        !          6589:                            lu_cmd->iobuf, parameter_len);
        !          6590:                        data = lu_cmd->iobuf;
        !          6591:                        /* data[0]-data[3] Reserved */
        !          6592:                        /* Set target port group descriptor(s) */
        !          6593:                        data_len = istgt_lu_disk_scsi_set_target_port_groups(spec, conn, cdb, &data[4], parameter_len - 4);
        !          6594:                        if (data_len < 0) {
        !          6595:                                /* INVALID FIELD IN PARAMETER LIST */
        !          6596:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00);
        !          6597:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6598:                                break;
        !          6599:                        }
        !          6600:                        lu_cmd->data_len = parameter_len;
        !          6601:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          6602:                        break;
        !          6603:                default:
        !          6604:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "SA=0x%2.2x\n",
        !          6605:                            BGET8W(&cdb[1], 4, 5));
        !          6606:                        /* INVALID COMMAND OPERATION CODE */
        !          6607:                        BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
        !          6608:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6609:                        break;
        !          6610:                }
        !          6611:                break;
        !          6612: 
        !          6613:        case SPC_PERSISTENT_RESERVE_IN:
        !          6614:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "PERSISTENT_RESERVE_IN\n");
        !          6615:                {
        !          6616:                        int sa;
        !          6617: 
        !          6618:                        if (lu_cmd->R_bit == 0) {
        !          6619:                                ISTGT_ERRLOG("R_bit == 0\n");
        !          6620:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6621:                                return -1;
        !          6622:                        }
        !          6623: 
        !          6624:                        sa = BGET8W(&cdb[1], 4, 5);
        !          6625:                        allocation_len = DGET16(&cdb[7]);
        !          6626:                        if (allocation_len > data_alloc_len) {
        !          6627:                                ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
        !          6628:                                    data_alloc_len);
        !          6629:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6630:                                return -1;
        !          6631:                        }
        !          6632:                        memset(data, 0, allocation_len);
        !          6633: 
        !          6634:                        data_len = istgt_lu_disk_scsi_persistent_reserve_in(spec, conn, lu_cmd, sa, data, allocation_len);
        !          6635:                        if (data_len < 0) {
        !          6636:                                /* status build by function */
        !          6637:                                break;
        !          6638:                        }
        !          6639:                        ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG,
        !          6640:                            "PERSISTENT_RESERVE_IN", data, data_len);
        !          6641:                        lu_cmd->data_len = DMIN32(data_len, lu_cmd->transfer_len);
        !          6642:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          6643:                }
        !          6644:                break;
        !          6645: 
        !          6646:        case SPC_PERSISTENT_RESERVE_OUT:
        !          6647:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "PERSISTENT_RESERVE_OUT\n");
        !          6648:                {
        !          6649:                        int sa, scope, type;
        !          6650: 
        !          6651:                        if (lu_cmd->W_bit == 0) {
        !          6652:                                ISTGT_ERRLOG("W_bit == 0\n");
        !          6653:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6654:                                return -1;
        !          6655:                        }
        !          6656: 
        !          6657:                        sa = BGET8W(&cdb[1], 4, 5);
        !          6658:                        scope = BGET8W(&cdb[2], 7, 4);
        !          6659:                        type = BGET8W(&cdb[2], 3, 4);
        !          6660:                        parameter_len = DGET32(&cdb[5]);
        !          6661: 
        !          6662:                        /* Data-Out */
        !          6663:                        rc = istgt_lu_disk_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
        !          6664:                            lu_cmd->iobufsize, parameter_len);
        !          6665:                        if (rc < 0) {
        !          6666:                                ISTGT_ERRLOG("lu_disk_transfer_data() failed\n");
        !          6667:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6668:                                break;
        !          6669:                        }
        !          6670:                        if (parameter_len < 24) {
        !          6671:                                /* INVALID FIELD IN CDB */
        !          6672:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
        !          6673:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6674:                                break;
        !          6675:                        }
        !          6676: 
        !          6677:                        ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG,
        !          6678:                            "PERSISTENT_RESERVE_OUT",
        !          6679:                            lu_cmd->iobuf, parameter_len);
        !          6680:                        data = lu_cmd->iobuf;
        !          6681: 
        !          6682:                        data_len = istgt_lu_disk_scsi_persistent_reserve_out(spec, conn, lu_cmd, sa, scope, type, &data[0], parameter_len);
        !          6683:                        if (data_len < 0) {
        !          6684:                                /* status build by function */
        !          6685:                                break;
        !          6686:                        }
        !          6687:                        lu_cmd->data_len = parameter_len;
        !          6688:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          6689:                }
        !          6690:                break;
        !          6691: 
        !          6692:        /* XXX TODO: fix */
        !          6693:        case SPC_EXTENDED_COPY:
        !          6694:                /* INVALID COMMAND OPERATION CODE */
        !          6695:                BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
        !          6696:                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6697:                break;
        !          6698:        case SPC2_RELEASE_6:
        !          6699:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RELEASE_6\n");
        !          6700:                rc = istgt_lu_disk_scsi_release(spec, conn, lu_cmd);
        !          6701:                if (rc < 0) {
        !          6702:                        /* build by function */
        !          6703:                        break;
        !          6704:                }
        !          6705:                lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          6706:                break;
        !          6707:        case SPC2_RELEASE_10:
        !          6708:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RELEASE_10\n");
        !          6709:                rc = istgt_lu_disk_scsi_release(spec, conn, lu_cmd);
        !          6710:                if (rc < 0) {
        !          6711:                        /* build by function */
        !          6712:                        break;
        !          6713:                }
        !          6714:                lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          6715:                break;
        !          6716:        case SPC2_RESERVE_6:
        !          6717:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RESERVE_6\n");
        !          6718:                rc = istgt_lu_disk_scsi_reserve(spec, conn, lu_cmd);
        !          6719:                if (rc < 0) {
        !          6720:                        /* build by function */
        !          6721:                        break;
        !          6722:                }
        !          6723:                lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          6724:                break;
        !          6725:        case SPC2_RESERVE_10:
        !          6726:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RESERVE_10\n");
        !          6727:                rc = istgt_lu_disk_scsi_reserve(spec, conn, lu_cmd);
        !          6728:                if (rc < 0) {
        !          6729:                        /* build by function */
        !          6730:                        break;
        !          6731:                }
        !          6732:                lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
        !          6733:                break;
        !          6734: 
        !          6735:        default:
        !          6736:                ISTGT_ERRLOG("unsupported SCSI OP=0x%x\n", cdb[0]);
        !          6737:                /* INVALID COMMAND OPERATION CODE */
        !          6738:                BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
        !          6739:                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
        !          6740:                break;
        !          6741:        }
        !          6742: 
        !          6743:        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
        !          6744:            "SCSI OP=0x%x, LUN=0x%16.16"PRIx64" status=0x%x,"
        !          6745:            " complete\n",
        !          6746:            cdb[0], lu_cmd->lun, lu_cmd->status);
        !          6747:        return 0;
        !          6748: }

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