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

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

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