Annotation of embedaddon/istgt/src/istgt_lu_disk.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2008-2011 Daisuke Aoyama <aoyama@peach.ne.jp>.
                      3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms, with or without
                      6:  * modification, are permitted provided that the following conditions
                      7:  * are met:
                      8:  * 1. Redistributions of source code must retain the above copyright
                      9:  *    notice, this list of conditions and the following disclaimer.
                     10:  * 2. Redistributions in binary form must reproduce the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer in the
                     12:  *    documentation and/or other materials provided with the distribution.
                     13:  *
                     14:  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     15:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     16:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     17:  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
                     18:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     19:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     20:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     21:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     22:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     23:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     24:  * SUCH DAMAGE.
                     25:  *
                     26:  */
                     27: 
                     28: #ifdef HAVE_CONFIG_H
                     29: #include "config.h"
                     30: #endif
                     31: 
                     32: #include <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>