Annotation of embedaddon/istgt/src/istgt_lu_dvd.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 <sys/types.h>
                     40: #include <sys/stat.h>
                     41: 
                     42: #include <fcntl.h>
                     43: #include <unistd.h>
                     44: 
                     45: #ifdef HAVE_UUID_H
                     46: #include <uuid.h>
                     47: #endif
                     48: 
                     49: #include "istgt.h"
                     50: #include "istgt_ver.h"
                     51: #include "istgt_log.h"
                     52: #include "istgt_conf.h"
                     53: #include "istgt_sock.h"
                     54: #include "istgt_misc.h"
                     55: #include "istgt_iscsi.h"
                     56: #include "istgt_lu.h"
                     57: #include "istgt_proto.h"
                     58: #include "istgt_scsi.h"
                     59: 
1.1.1.2 ! misho      60: #if !defined(__GNUC__)
        !            61: #undef __attribute__
        !            62: #define __attribute__(x)
        !            63: #endif
        !            64: 
1.1       misho      65: //#define ISTGT_TRACE_DVD
                     66: 
                     67: #define DEFAULT_DVD_BLOCKLEN 2048
                     68: #define DEFAULT_DVD_PROFILE MM_PROF_DVDROM
                     69: 
                     70: enum {
                     71:        MM_PROF_CDROM = 0x0008,
                     72:        MM_PROF_DVDROM = 0x0010,
                     73: } ISTGT_LU_MM_PROF;
                     74: 
                     75: typedef struct istgt_lu_dvd_t {
                     76:        ISTGT_LU_Ptr lu;
                     77:        int num;
                     78:        int lun;
                     79: 
                     80:        int fd;
                     81:        const char *file;
                     82:        uint64_t size;
                     83:        uint64_t blocklen;
                     84:        uint64_t blockcnt;
                     85: 
                     86: #ifdef HAVE_UUID_H
                     87:        uuid_t uuid;
                     88: #endif /* HAVE_UUID_H */
                     89: 
                     90:        /* cache flags */
                     91:        int read_cache;
                     92:        int write_cache;
                     93: 
                     94:        /* flags */
                     95:        int mflags;
                     96:        /* current DVD/CD profile */
                     97:        int profile;
                     98: 
                     99:        /* media state */
                    100:        volatile int mload;
                    101:        volatile int mchanged;
                    102:        volatile int mwait;
                    103: 
                    104:        /* mode flags */
                    105:        volatile int lock;
                    106: 
                    107:        /* SCSI sense code */
                    108:        volatile int sense;
                    109: } ISTGT_LU_DVD;
                    110: 
1.1.1.2 ! misho     111: #define BUILD_SENSE(SK,ASC,ASCQ)                                       \
        !           112:        do {                                                            \
        !           113:                *sense_len =                                            \
        !           114:                        istgt_lu_dvd_build_sense_data(spec, sense_data, \
        !           115:                            ISTGT_SCSI_SENSE_ ## SK,                    \
        !           116:                            (ASC), (ASCQ));                             \
1.1       misho     117:        } while (0)
                    118: 
                    119: static int istgt_lu_dvd_build_sense_data(ISTGT_LU_DVD *spec, uint8_t *data, int sk, int asc, int ascq);
                    120: 
                    121: static int
                    122: istgt_lu_dvd_open(ISTGT_LU_DVD *spec, int flags, int mode)
                    123: {
                    124:        int rc;
                    125: 
                    126:        rc = open(spec->file, flags, mode);
                    127:        if (rc < 0) {
                    128:                return -1;
                    129:        }
                    130:        spec->fd = rc;
                    131:        return 0;
                    132: }
                    133: 
                    134: static int
                    135: istgt_lu_dvd_close(ISTGT_LU_DVD *spec)
                    136: {
                    137:        int rc;
                    138: 
                    139:        if (spec->fd == -1)
                    140:                return 0;
                    141:        rc = close(spec->fd);
                    142:        if (rc < 0) {
                    143:                return -1;
                    144:        }
                    145:        spec->fd = -1;
                    146:        return 0;
                    147: }
                    148: 
                    149: static int64_t
                    150: istgt_lu_dvd_seek(ISTGT_LU_DVD *spec, uint64_t offset)
                    151: {
                    152:        off_t rc;
                    153: 
                    154:        rc = lseek(spec->fd, (off_t) offset, SEEK_SET);
                    155:        if (rc < 0) {
                    156:                return -1;
                    157:        }
                    158:        return 0;
                    159: }
                    160: 
                    161: static int64_t
                    162: istgt_lu_dvd_read(ISTGT_LU_DVD *spec, void *buf, uint64_t nbytes)
                    163: {
                    164:        int64_t rc;
                    165: 
                    166:        rc = (int64_t) read(spec->fd, buf, (size_t) nbytes);
                    167:        if (rc < 0) {
                    168:                return -1;
                    169:        }
                    170:        return rc;
                    171: }
                    172: 
                    173: static int64_t
                    174: istgt_lu_dvd_write(ISTGT_LU_DVD *spec, const void *buf, uint64_t nbytes)
                    175: {
                    176:        int64_t rc;
                    177: 
                    178:        rc = (int64_t) write(spec->fd, buf, (size_t) nbytes);
                    179:        if (rc < 0) {
                    180:                return -1;
                    181:        }
                    182:        return rc;
                    183: }
                    184: 
                    185: static int64_t
1.1.1.2 ! misho     186: istgt_lu_dvd_sync(ISTGT_LU_DVD *spec, uint64_t offset __attribute__((__unused__)), uint64_t nbytes __attribute__((__unused__)))
1.1       misho     187: {
                    188:        int64_t rc;
                    189: 
                    190:        rc = (int64_t) fsync(spec->fd);
                    191:        if (rc < 0) {
                    192:                return -1;
                    193:        }
                    194:        return rc;
                    195: }
                    196: 
                    197: int
                    198: istgt_lu_dvd_media_present(ISTGT_LU_DVD *spec)
                    199: {
                    200:        if (spec->mload) {
                    201:                return 1;
                    202:        }
                    203:        return 0;
                    204: }
                    205: 
                    206: int
                    207: istgt_lu_dvd_media_lock(ISTGT_LU_DVD *spec)
                    208: {
                    209:        if (spec->lock) {
                    210:                return 1;
                    211:        }
                    212:        return 0;
                    213: }
                    214: 
                    215: static int istgt_lu_dvd_allocate(ISTGT_LU_DVD *spec);
                    216: 
                    217: int
                    218: istgt_lu_dvd_load_media(ISTGT_LU_DVD *spec)
                    219: {
                    220:        ISTGT_LU_Ptr lu;
                    221:        int flags;
                    222:        int newfile;
                    223:        int rc;
                    224: 
                    225:        if (istgt_lu_dvd_media_present(spec)) {
                    226:                /* media present */
                    227:                return -1;
                    228:        }
                    229:        if (spec->mchanged) {
                    230:                /* changed soon */
                    231:                return -1;
                    232:        }
                    233: 
                    234:        lu = spec->lu;
                    235:        if (lu->lun[spec->lun].type != ISTGT_LU_LUN_TYPE_REMOVABLE) {
                    236:                ISTGT_ERRLOG("LU%d: not removable\n", lu->num);
                    237:                return -1;
                    238:        }
                    239:        if (strcasecmp(lu->lun[spec->lun].u.removable.file,
                    240:                                   "/dev/null") == 0) {
                    241:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: empty\n", lu->num);
                    242:                spec->file = NULL;
                    243:                spec->size = 0;
                    244:                spec->mflags = 0;
                    245:                spec->blocklen = DEFAULT_DVD_BLOCKLEN;
                    246:                spec->blockcnt = spec->size / spec->blocklen;
                    247:                spec->profile = DEFAULT_DVD_PROFILE;
                    248:                return 0;
                    249:        }
                    250:        spec->file = lu->lun[spec->lun].u.removable.file;
                    251:        spec->size = lu->lun[spec->lun].u.removable.size;
                    252:        spec->mflags = lu->lun[spec->lun].u.removable.flags;
                    253:        //spec->blocklen = lu->blocklen;
                    254:        spec->blocklen = DEFAULT_DVD_BLOCKLEN;
                    255:        spec->blockcnt = spec->size / spec->blocklen;
                    256:        spec->profile = DEFAULT_DVD_PROFILE;
                    257: 
                    258:        spec->mload = 0;
                    259:        spec->mchanged = 1;
                    260:        spec->mwait = 3;
                    261: 
                    262:        if (access(spec->file, W_OK) != 0) {
                    263:                if (errno != ENOENT) {
                    264:                        spec->mflags |= ISTGT_LU_FLAG_MEDIA_READONLY;
                    265:                }
                    266:        } else {
                    267:                struct stat st;
                    268:                rc = stat(spec->file, &st);
                    269:                if (rc != 0 || !S_ISREG(st.st_mode)) {
                    270:                        spec->mflags |= ISTGT_LU_FLAG_MEDIA_READONLY;
                    271:                } else {
                    272:                        if ((st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0) {
                    273:                                spec->mflags |= ISTGT_LU_FLAG_MEDIA_READONLY;
                    274:                        }
                    275:                }
                    276:        }
                    277:        if (lu->readonly
                    278:                || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
                    279:                flags = O_RDONLY;
                    280:        } else {
                    281:                flags = O_RDWR;
                    282:        }
                    283:        newfile = 0;
                    284:        rc = istgt_lu_dvd_open(spec, flags, 0666);
                    285:        if (rc < 0) {
                    286:                newfile = 1;
                    287:                if (lu->readonly
                    288:                        || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
                    289:                        flags = O_RDONLY;
                    290:                } else {
                    291:                        flags = (O_CREAT | O_EXCL | O_RDWR);
                    292:                }
                    293:                rc = istgt_lu_dvd_open(spec, flags, 0666);
                    294:                if (rc < 0) {
1.1.1.2 ! misho     295:                        ISTGT_ERRLOG("LU%d: LUN%d: open error(errno=%d)\n",
        !           296:                            lu->num, spec->lun, errno);
1.1       misho     297:                        return -1;
                    298:                }
                    299:                if (lu->lun[spec->lun].u.removable.size < ISTGT_LU_MEDIA_SIZE_MIN) {
                    300:                        lu->lun[spec->lun].u.removable.size = ISTGT_LU_MEDIA_SIZE_MIN;
                    301:                }
                    302:        }
                    303:        if (lu->readonly
                    304:                || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
                    305:                /* readonly */
                    306:        } else {
                    307:                if (newfile == 0) {
                    308:                        /* XXX TODO: existing file check */
                    309:                }
                    310:                rc = istgt_lu_dvd_allocate(spec);
                    311:                if (rc < 0) {
                    312:                        ISTGT_ERRLOG("LU%d: LUN%d: allocate error\n", lu->num, spec->lun);
                    313:                        return -1;
                    314:                }
                    315:        }
                    316:        return 0;
                    317: }
                    318: 
                    319: int
                    320: istgt_lu_dvd_unload_media(ISTGT_LU_DVD *spec)
                    321: {
                    322:        int64_t rc;
                    323: 
                    324:        if (!istgt_lu_dvd_media_present(spec)
                    325:                && !spec->mchanged) {
                    326:                /* media absent */
                    327:                return 0;
                    328:        }
                    329:        if (istgt_lu_dvd_media_lock(spec)) {
                    330:                return -1;
                    331:        }
                    332: 
                    333:        if (!spec->lu->readonly
                    334:                && !(spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
                    335:                rc = istgt_lu_dvd_sync(spec, 0, spec->size);
                    336:                if (rc < 0) {
                    337:                        ISTGT_ERRLOG("lu_dvd_sync() failed\n");
                    338:                        return -1;
                    339:                }
                    340:        }
                    341:        rc = (int64_t) istgt_lu_dvd_close(spec);
                    342:        if (rc < 0) {
                    343:                ISTGT_ERRLOG("lu_dvd_close() failed\n");
                    344:                return -1;
                    345:        }
                    346: 
                    347:        spec->file = NULL;
                    348:        spec->size = 0;
                    349:        spec->mflags = 0;
                    350:        spec->blocklen = DEFAULT_DVD_BLOCKLEN;
                    351:        spec->blockcnt = spec->size / spec->blocklen;
                    352:        spec->profile = DEFAULT_DVD_PROFILE;
                    353: 
                    354:        spec->mload = 0;
                    355:        spec->mchanged = 0;
                    356:        spec->mwait = 3;
                    357:        return 0;
                    358: }
                    359: 
                    360: int
                    361: istgt_lu_dvd_change_media(ISTGT_LU_DVD *spec, char *type, char *flags, char *file, char *size)
                    362: {
                    363:        ISTGT_LU_Ptr lu;
                    364:        char *mfile;
                    365:        uint64_t msize;
                    366:        int mflags;
                    367:        int rc;
                    368: 
                    369:        if (istgt_lu_dvd_media_lock(spec)) {
                    370:                return -1;
                    371:        }
                    372: 
                    373:        lu = spec->lu;
                    374:        if (lu->lun[spec->lun].type != ISTGT_LU_LUN_TYPE_REMOVABLE) {
                    375:                ISTGT_ERRLOG("LU%d: not removable\n", lu->num);
                    376:                return -1;
                    377:        }
                    378: 
                    379:        if (strcmp(type, "-") == 0) {
                    380:                /* use ISO image */
                    381:                ;
                    382:        } else {
                    383:                ISTGT_ERRLOG("unsupported media type\n");
                    384:                return -1;
                    385:        }
                    386: 
                    387:        mfile = xstrdup(file);
                    388:        mflags = istgt_lu_parse_media_flags(flags);
                    389:        msize = istgt_lu_parse_media_size(file, size, &mflags);
                    390: 
                    391:        rc = istgt_lu_dvd_unload_media(spec);
                    392:        if (rc < 0) {
                    393:                return -1;
                    394:        }
                    395: 
                    396:        /* replace */
                    397:        xfree(lu->lun[spec->lun].u.removable.file);
                    398:        lu->lun[spec->lun].u.removable.file = mfile;
                    399:        lu->lun[spec->lun].u.removable.size = msize;
                    400:        lu->lun[spec->lun].u.removable.flags = mflags;
                    401: 
                    402:        /* reload */
                    403:        rc = istgt_lu_dvd_load_media(spec);
                    404:        if (rc < 0) {
                    405:                (void) istgt_lu_dvd_unload_media(spec);
                    406:        }
                    407:        if (spec->file == NULL) {
                    408:                (void) istgt_lu_dvd_unload_media(spec);
                    409:        }
                    410:        spec->mwait = 5;
                    411:        return rc;
                    412: }
                    413: 
                    414: static int
                    415: istgt_lu_dvd_allocate(ISTGT_LU_DVD *spec)
                    416: {
                    417:        uint8_t *data;
                    418:        uint64_t fsize;
                    419:        uint64_t size;
                    420:        uint64_t blocklen;
                    421:        uint64_t offset;
                    422:        uint64_t nbytes;
                    423:        int64_t rc;
                    424: 
                    425:        size = spec->size;
                    426:        blocklen = spec->blocklen;
                    427:        nbytes = blocklen;
                    428:        data = xmalloc(nbytes);
                    429:        memset(data, 0, nbytes);
                    430: 
                    431:        fsize = istgt_lu_get_filesize(spec->file);
                    432:        if (fsize > size) {
                    433:                xfree(data);
                    434:                return 0;
                    435:        }
                    436: 
                    437:        offset = size - nbytes;
                    438:        rc = istgt_lu_dvd_seek(spec, offset);
                    439:        if (rc == -1) {
                    440:                ISTGT_ERRLOG("lu_dvd_seek() failed\n");
                    441:                xfree(data);
                    442:                return -1;
                    443:        }
                    444:        rc = istgt_lu_dvd_read(spec, data, nbytes);
                    445:        /* EOF is OK */
                    446:        if (rc == -1) {
                    447:                ISTGT_ERRLOG("lu_dvd_read() failed\n");
                    448:                xfree(data);
                    449:                return -1;
                    450:        }
                    451:        rc = istgt_lu_dvd_seek(spec, offset);
                    452:        if (rc == -1) {
                    453:                ISTGT_ERRLOG("lu_dvd_seek() failed\n");
                    454:                xfree(data);
                    455:                return -1;
                    456:        }
                    457:        rc = istgt_lu_dvd_write(spec, data, nbytes);
1.1.1.2 ! misho     458:        if (rc == -1 || (uint64_t) rc != nbytes) {
1.1       misho     459:                ISTGT_ERRLOG("lu_dvd_write() failed\n");
                    460:                xfree(data);
                    461:                return -1;
                    462:        }
                    463: 
                    464:        xfree(data);
                    465:        return 0;
                    466: }
                    467: 
                    468: int
1.1.1.2 ! misho     469: istgt_lu_dvd_init(ISTGT_Ptr istgt __attribute__((__unused__)), ISTGT_LU_Ptr lu)
1.1       misho     470: {
                    471:        ISTGT_LU_DVD *spec;
                    472:        uint64_t gb_size;
                    473:        uint64_t mb_size;
                    474: #ifdef HAVE_UUID_H
                    475:        uint32_t status;
                    476: #endif /* HAVE_UUID_H */
                    477:        int mb_digit;
                    478:        int ro;
                    479:        int rc;
                    480:        int i;
                    481: 
                    482:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_dvd_init\n");
                    483: 
                    484:        printf("LU%d DVD UNIT\n", lu->num);
                    485:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d TargetName=%s\n",
                    486:                                   lu->num, lu->name);
                    487:        for (i = 0; i < lu->maxlun; i++) {
                    488:                if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) {
                    489:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d none\n",
1.1.1.2 ! misho     490:                            lu->num, i);
1.1       misho     491:                        lu->lun[i].spec = NULL;
                    492:                        continue;
                    493:                }
                    494:                if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_REMOVABLE) {
                    495:                        ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
                    496:                        return -1;
                    497:                }
                    498:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d removable\n",
1.1.1.2 ! misho     499:                    lu->num, i);
1.1       misho     500: 
                    501:                spec = xmalloc(sizeof *spec);
                    502:                memset(spec, 0, sizeof *spec);
                    503:                spec->lu = lu;
                    504:                spec->num = lu->num;
                    505:                spec->lun = i;
                    506:                spec->fd = -1;
                    507:                spec->read_cache = 1;
                    508:                spec->write_cache = 1;
                    509: 
                    510: #ifdef HAVE_UUID_H
                    511:                uuid_create(&spec->uuid, &status);
                    512:                if (status != uuid_s_ok) {
                    513:                        ISTGT_ERRLOG("LU%d: LUN%d: uuid_create() failed\n", lu->num, i);
                    514:                        xfree(spec);
                    515:                        return -1;
                    516:                }
                    517: #endif /* HAVE_UUID_H */
                    518: 
                    519:                spec->mload = 0;
                    520:                spec->mchanged = 0;
                    521:                spec->mwait = 0;
                    522:                rc = istgt_lu_dvd_load_media(spec);
                    523:                if (rc < 0) {
                    524:                        ISTGT_ERRLOG("lu_dvd_load_media() failed\n");
                    525:                        xfree(spec);
                    526:                        return -1;
                    527:                }
                    528: 
                    529:                if (spec->file != NULL) {
                    530:                        /* initial state */
                    531:                        spec->mload = 1;
                    532:                        spec->mchanged = 0;
                    533:                        spec->mwait = 0;
                    534: 
                    535:                        if (spec->lu->readonly
1.1.1.2 ! misho     536:                            || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
1.1       misho     537:                                ro = 1;
                    538:                        } else {
                    539:                                ro = 0;
                    540:                        }
                    541: 
                    542:                        printf("LU%d: LUN%d file=%s, size=%"PRIu64", flag=%s\n",
1.1.1.2 ! misho     543:                            lu->num, i, spec->file, spec->size, ro ? "ro" : "rw");
1.1       misho     544:                        printf("LU%d: LUN%d %"PRIu64" blocks, %"PRIu64" bytes/block\n",
1.1.1.2 ! misho     545:                            lu->num, i, spec->blockcnt, spec->blocklen);
1.1       misho     546: 
                    547:                        gb_size = spec->size / ISTGT_LU_1GB;
                    548:                        mb_size = (spec->size % ISTGT_LU_1GB) / ISTGT_LU_1MB;
                    549:                        if (gb_size > 0) {
                    550:                                mb_digit = (int) (((mb_size * 100) / 1024) / 10);
                    551:                                printf("LU%d: LUN%d %"PRIu64".%dGB %sstorage for %s\n",
1.1.1.2 ! misho     552:                                    lu->num, i, gb_size, mb_digit,
        !           553:                                    lu->readonly ? "readonly " : "", lu->name);
1.1       misho     554:                        } else {
                    555:                                printf("LU%d: LUN%d %"PRIu64"MB %sstorage for %s\n",
1.1.1.2 ! misho     556:                                    lu->num, i, mb_size,
        !           557:                                    lu->readonly ? "readonly " : "", lu->name);
1.1       misho     558:                        }
                    559:                } else {
                    560:                        /* initial state */
                    561:                        spec->mload = 0;
                    562:                        spec->mchanged = 0;
                    563:                        spec->mwait = 0;
                    564: 
                    565:                        printf("LU%d: LUN%d empty slot\n",
1.1.1.2 ! misho     566:                            lu->num, i);
1.1       misho     567:                }
                    568: 
                    569:                lu->lun[i].spec = spec;
                    570:        }
                    571: 
                    572:        return 0;
                    573: }
                    574: 
                    575: int
1.1.1.2 ! misho     576: istgt_lu_dvd_shutdown(ISTGT_Ptr istgt __attribute__((__unused__)), ISTGT_LU_Ptr lu)
1.1       misho     577: {
                    578:        ISTGT_LU_DVD *spec;
                    579:        int rc;
                    580:        int i;
                    581: 
                    582:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_dvd_shutdown\n");
                    583: 
                    584:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d TargetName=%s\n",
                    585:                                   lu->num, lu->name);
                    586:        for (i = 0; i < lu->maxlun; i++) {
                    587:                if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) {
                    588:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d none\n",
1.1.1.2 ! misho     589:                            lu->num, i);
1.1       misho     590:                        continue;
                    591:                }
                    592:                if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_REMOVABLE) {
                    593:                        ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
                    594:                        return -1;
                    595:                }
                    596:                spec = (ISTGT_LU_DVD *) lu->lun[i].spec;
                    597: 
                    598:                if (!spec->lu->readonly
                    599:                        && !(spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
                    600:                        rc = istgt_lu_dvd_sync(spec, 0, spec->size);
                    601:                        if (rc < 0) {
                    602:                                //ISTGT_ERRLOG("LU%d: lu_dvd_sync() failed\n", lu->num);
                    603:                                /* ignore error */
                    604:                        }
                    605:                }
                    606:                rc = istgt_lu_dvd_close(spec);
                    607:                if (rc < 0) {
                    608:                        //ISTGT_ERRLOG("LU%d: lu_dvd_close() failed\n", lu->num);
                    609:                        /* ignore error */
                    610:                }
                    611:                xfree(spec);
                    612:                lu->lun[i].spec = NULL;
                    613:        }
                    614: 
                    615:        return 0;
                    616: }
                    617: 
                    618: static int
1.1.1.2 ! misho     619: istgt_lu_dvd_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     620: {
                    621:        uint64_t fmt_lun, lun, method;
                    622:        int hlen = 0, len = 0;
                    623:        int i;
                    624: 
                    625:        if (alloc_len < 8) {
                    626:                return -1;
                    627:        }
                    628: 
                    629:        if (sel == 0x00) {
                    630:                /* logical unit with addressing method */
                    631:        } else if (sel == 0x01) {
                    632:                /* well known logical unit */
                    633:        } else if (sel == 0x02) {
                    634:                /* logical unit */
                    635:        } else {
                    636:                return -1;
                    637:        }
                    638: 
                    639:        /* LUN LIST LENGTH */
                    640:        DSET32(&data[0], 0);
                    641:        /* Reserved */
                    642:        DSET32(&data[4], 0);
                    643:        hlen = 8;
                    644: 
                    645:        for (i = 0; i < lu->maxlun; i++) {
                    646:                if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) {
                    647: #if 0
                    648:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d none\n",
1.1.1.2 ! misho     649:                            lu->num, i);
1.1       misho     650: #endif
                    651:                        continue;
                    652:                }
                    653:                if (alloc_len - (hlen + len) < 8) {
                    654:                        return -1;
                    655:                }
                    656:                lun = (uint64_t) i;
                    657:                if (lu->maxlun <= 0x0100) {
                    658:                        /* below 256 */
                    659:                        method = 0x00U;
                    660:                        fmt_lun = (method & 0x03U) << 62;
                    661:                        fmt_lun |= (lun & 0x00ffU) << 48;
1.1.1.2 ! misho     662:                } else if (lu->maxlun <= 0x4000) {
1.1       misho     663:                        /* below 16384 */
                    664:                        method = 0x01U;
                    665:                        fmt_lun = (method & 0x03U) << 62;
                    666:                        fmt_lun |= (lun & 0x3fffU) << 48;
                    667:                } else {
                    668:                        /* XXX */
                    669:                        fmt_lun = 0;
                    670:                }
                    671:                /* LUN */
                    672:                DSET64(&data[hlen + len], fmt_lun);
                    673:                len += 8;
                    674:        }
                    675:        /* LUN LIST LENGTH */
                    676:        DSET32(&data[0], len);
                    677:        return hlen + len;
                    678: }
                    679: 
                    680: static int
                    681: istgt_lu_dvd_scsi_inquiry(ISTGT_LU_DVD *spec, CONN_Ptr conn, uint8_t *cdb, uint8_t *data, int alloc_len)
                    682: {
                    683:        uint64_t LUI;
                    684:        uint8_t *cp, *cp2;
                    685:        int hlen = 0, len = 0, plen, plen2;
                    686:        int pc;
                    687:        int pq, pd;
                    688:        int rmb;
                    689:        int evpd;
                    690:        int pg_tag;
                    691:        int i, j;
                    692: 
                    693:        if (alloc_len < 0xff) {
                    694:                return -1;
                    695:        }
                    696: 
                    697:        pq = 0x00;
                    698:        pd = SPC_PERIPHERAL_DEVICE_TYPE_DVD;
                    699:        rmb = 1;
                    700: 
                    701:        LUI = istgt_get_lui(spec->lu->name, spec->lun & 0xffffU);
                    702: 
                    703:        pc = cdb[2];
                    704:        evpd = BGET8(&cdb[1], 0);
                    705:        if (evpd) {
                    706:                /* Vital product data */
                    707:                switch (pc) {
                    708:                case SPC_VPD_SUPPORTED_VPD_PAGES:
                    709:                        /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
                    710:                        BDSET8W(&data[0], pq, 7, 3);
                    711:                        BDADD8W(&data[0], pd, 4, 5);
                    712:                        /* PAGE CODE */
                    713:                        data[1] = pc;
                    714:                        /* Reserved */
                    715:                        data[2] = 0;
                    716:                        /* PAGE LENGTH */
                    717:                        data[3] = 0;
                    718:                        hlen = 4;
                    719: 
                    720:                        data[4] = SPC_VPD_SUPPORTED_VPD_PAGES;      /* 0x00 */
                    721:                        data[5] = SPC_VPD_UNIT_SERIAL_NUMBER;       /* 0x80 */
                    722:                        data[6] = SPC_VPD_DEVICE_IDENTIFICATION;    /* 0x83 */
                    723:                        data[7] = SPC_VPD_MANAGEMENT_NETWORK_ADDRESSES; /* 0x85 */
                    724:                        data[8] = SPC_VPD_EXTENDED_INQUIRY_DATA;    /* 0x86 */
                    725:                        data[9] = SPC_VPD_MODE_PAGE_POLICY;         /* 0x87 */
                    726:                        data[10]= SPC_VPD_SCSI_PORTS;               /* 0x88 */
                    727:                        len = 11 - hlen;
                    728: 
                    729:                        /* PAGE LENGTH */
                    730:                        data[3] = len;
                    731:                        break;
                    732: 
                    733:                case SPC_VPD_UNIT_SERIAL_NUMBER:
                    734:                        /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
                    735:                        BDSET8W(&data[0], pq, 7, 3);
                    736:                        BDADD8W(&data[0], pd, 4, 5);
                    737:                        /* PAGE CODE */
                    738:                        data[1] = pc;
                    739:                        /* Reserved */
                    740:                        data[2] = 0;
                    741:                        /* PAGE LENGTH */
                    742:                        data[3] = 0;
                    743:                        hlen = 4;
                    744: 
                    745:                        /* PRODUCT SERIAL NUMBER */
                    746:                        len = strlen(spec->lu->inq_serial);
                    747:                        if (len > MAX_LU_SERIAL_STRING) {
                    748:                                len = MAX_LU_SERIAL_STRING;
                    749:                        }
                    750:                        istgt_strcpy_pad(&data[4], len, spec->lu->inq_serial, ' ');
                    751: 
                    752:                        /* PAGE LENGTH */
                    753:                        data[3] = len;
                    754:                        break;
                    755: 
                    756:                case SPC_VPD_DEVICE_IDENTIFICATION:
                    757:                        /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
                    758:                        BDSET8W(&data[0], pq, 7, 3);
                    759:                        BDADD8W(&data[0], pd, 4, 5);
                    760:                        /* PAGE CODE */
                    761:                        data[1] = pc;
                    762:                        /* PAGE LENGTH */
                    763:                        DSET16(&data[2], 0);
                    764:                        hlen = 4;
                    765: 
                    766:                        /* Identification descriptor 1 */
                    767:                        /* Logical Unit */
                    768:                        cp = &data[hlen + len];
                    769: 
                    770:                        /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
                    771:                        BDSET8W(&cp[0], 0, 7, 4);
                    772:                        BDADD8W(&cp[0], SPC_VPD_CODE_SET_BINARY, 3, 4);
                    773:                        /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
                    774:                        BDSET8W(&cp[1], 0, 7, 1); /* PIV=0 */
                    775:                        BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_LOGICAL_UNIT, 5, 2);
                    776:                        BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_NAA, 3, 4);
                    777:                        /* Reserved */
                    778:                        cp[2] = 0;
                    779:                        /* IDENTIFIER LENGTH */
                    780:                        cp[3] = 0;
                    781: 
                    782:                        /* IDENTIFIER */
                    783: #if 0
                    784:                        /* 16bytes ID */
                    785:                        plen = istgt_lu_set_extid(&cp[4], 0, LUI);
                    786: #else
                    787:                        plen = istgt_lu_set_lid(&cp[4], LUI);
                    788: #endif
                    789: 
                    790:                        cp[3] = plen;
                    791:                        len += 4 + plen;
                    792: 
                    793:                        /* Identification descriptor 2 */
                    794:                        /* T10 VENDOR IDENTIFICATION */
                    795:                        cp = &data[hlen + len];
                    796: 
                    797:                        /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
                    798:                        BDSET8W(&cp[0], 0, 7, 4);
                    799:                        BDADD8W(&cp[0], SPC_VPD_CODE_SET_UTF8, 3, 4);
                    800:                        /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
                    801:                        BDSET8W(&cp[1], 0, 7, 1); /* PIV=0 */
                    802:                        BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_LOGICAL_UNIT, 5, 2);
                    803:                        BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_T10_VENDOR_ID, 3, 4);
                    804:                        /* Reserved */
                    805:                        cp[2] = 0;
                    806:                        /* IDENTIFIER LENGTH */
                    807:                        cp[3] = 0;
                    808: 
                    809:                        /* IDENTIFIER */
                    810:                        /* T10 VENDOR IDENTIFICATION */
                    811:                        istgt_strcpy_pad(&cp[4], 8, spec->lu->inq_vendor, ' ');
                    812:                        plen = 8;
                    813:                        /* VENDOR SPECIFIC IDENTIFIER */
                    814:                        /* PRODUCT IDENTIFICATION */
                    815:                        istgt_strcpy_pad(&cp[12], 16, spec->lu->inq_product, ' ');
                    816:                        /* PRODUCT SERIAL NUMBER */
                    817:                        istgt_strcpy_pad(&cp[28], MAX_LU_SERIAL_STRING,
1.1.1.2 ! misho     818:                            spec->lu->inq_serial, ' ');
1.1       misho     819:                        plen += 16 + MAX_LU_SERIAL_STRING;
                    820: 
                    821:                        cp[3] = plen;
                    822:                        len += 4 + plen;
                    823: 
                    824:                        /* Identification descriptor 3 */
                    825:                        /* Target Device */
                    826:                        cp = &data[hlen + len];
                    827: 
                    828:                        /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
                    829:                        BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4);
                    830:                        BDADD8W(&cp[0], SPC_VPD_CODE_SET_UTF8, 3, 4);
                    831:                        /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
                    832:                        BDSET8W(&cp[1], 1, 7, 1); /* PIV */
                    833:                        BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_TARGET_DEVICE, 5, 2);
                    834:                        BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_SCSI_NAME, 3, 4);
                    835:                        /* Reserved */
                    836:                        cp[2] = 0;
                    837:                        /* IDENTIFIER LENGTH */
                    838:                        cp[3] = 0;
                    839: 
                    840:                        /* IDENTIFIER */
                    841:                        plen = snprintf((char *) &cp[4], MAX_TARGET_NAME,
1.1.1.2 ! misho     842:                            "%s", spec->lu->name);
1.1       misho     843:                        cp[3] = plen;
                    844:                        len += 4 + plen;
                    845: 
                    846:                        /* Identification descriptor 4 */
                    847:                        /* Target Port */
                    848:                        cp = &data[hlen + len];
                    849: 
                    850:                        /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
                    851:                        BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4);
                    852:                        BDADD8W(&cp[0], SPC_VPD_CODE_SET_UTF8, 3, 4);
                    853:                        /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
                    854:                        BDSET8W(&cp[1], 1, 7, 1); /* PIV */
                    855:                        BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_TARGET_PORT, 5, 2);
                    856:                        BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_SCSI_NAME, 3, 4);
                    857:                        /* Reserved */
                    858:                        cp[2] = 0;
                    859:                        /* IDENTIFIER LENGTH */
                    860:                        cp[3] = 0;
                    861: 
                    862:                        /* IDENTIFIER */
                    863:                        plen = snprintf((char *) &cp[4], MAX_TARGET_NAME,
1.1.1.2 ! misho     864:                            "%s"",t,0x""%4.4x", spec->lu->name, conn->portal.tag);
1.1       misho     865:                        cp[3] = plen;
                    866:                        len += 4 + plen;
                    867: 
                    868:                        /* Identification descriptor 5 */
                    869:                        /* Relative Target Port */
                    870:                        cp = &data[hlen + len];
                    871: 
                    872:                        /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
                    873:                        BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4);
                    874:                        BDADD8W(&cp[0], SPC_VPD_CODE_SET_BINARY, 3, 4);
                    875:                        /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
                    876:                        BDSET8W(&cp[1], 1, 7, 1); /* PIV */
                    877:                        BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_TARGET_PORT, 5, 2);
                    878:                        BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_RELATIVE_TARGET_PORT,
                    879:                                        3, 4);
                    880:                        /* Reserved */
                    881:                        cp[2] = 0;
                    882:                        /* IDENTIFIER LENGTH */
                    883:                        cp[3] = 0;
                    884: 
                    885:                        /* IDENTIFIER */
                    886:                        /* Obsolete */
                    887:                        DSET16(&cp[4], 0);
                    888:                        /* Relative Target Port Identifier */
                    889:                        //DSET16(&cp[6], 1); /* port1 as port A */
                    890:                        //DSET16(&cp[6], 2); /* port2 as port B */
                    891:                        DSET16(&cp[6], (uint16_t) (1 + conn->portal.idx));
                    892:                        plen = 4;
                    893: 
                    894:                        cp[3] = plen;
                    895:                        len += 4 + plen;
                    896: 
                    897:                        /* Identification descriptor 6 */
                    898:                        /* Target port group */
                    899:                        cp = &data[hlen + len];
                    900: 
                    901:                        /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
                    902:                        BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4);
                    903:                        BDADD8W(&cp[0], SPC_VPD_CODE_SET_BINARY, 3, 4);
                    904:                        /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
                    905:                        BDSET8W(&cp[1], 1, 7, 1); /* PIV */
                    906:                        BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_TARGET_PORT, 5, 2);
                    907:                        BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_TARGET_PORT_GROUP,
                    908:                                        3, 4);
                    909:                        /* Reserved */
                    910:                        cp[2] = 0;
                    911:                        /* IDENTIFIER LENGTH */
                    912:                        cp[3] = 0;
                    913: 
                    914:                        /* IDENTIFIER */
                    915:                        /* Reserved */
                    916:                        DSET16(&cp[4], 0);
                    917:                        /* TARGET PORT GROUP */
                    918:                        DSET16(&cp[6], (uint16_t) (conn->portal.tag));
                    919:                        plen = 4;
                    920: 
                    921:                        cp[3] = plen;
                    922:                        len += 4 + plen;
                    923: 
                    924:                        /* Identification descriptor 7 */
                    925:                        /* Logical unit group */
                    926:                        cp = &data[hlen + len];
                    927: 
                    928:                        /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
                    929:                        BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4);
                    930:                        BDADD8W(&cp[0], SPC_VPD_CODE_SET_BINARY, 3, 4);
                    931:                        /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
                    932:                        BDSET8W(&cp[1], 1, 7, 1); /* PIV */
                    933:                        BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_TARGET_PORT, 5, 2);
                    934:                        BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_LOGICAL_UNIT_GROUP,
1.1.1.2 ! misho     935:                            3, 4);
1.1       misho     936:                        /* Reserved */
                    937:                        cp[2] = 0;
                    938:                        /* IDENTIFIER LENGTH */
                    939:                        cp[3] = 0;
                    940: 
                    941:                        /* IDENTIFIER */
                    942:                        /* Reserved */
                    943:                        DSET16(&cp[4], 0);
                    944:                        /* LOGICAL UNIT GROUP */
                    945:                        DSET16(&cp[6], (uint16_t) (spec->lu->num));
                    946:                        plen = 4;
                    947: 
                    948:                        cp[3] = plen;
                    949:                        len += 4 + plen;
                    950: 
                    951:                        /* PAGE LENGTH */
                    952:                        if (len > 0xffff) {
                    953:                                len = 0xffff;
                    954:                        }
                    955:                        DSET16(&data[2], len);
                    956:                        break;
                    957: 
                    958:                case SPC_VPD_EXTENDED_INQUIRY_DATA:
                    959:                        /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
                    960:                        BDSET8W(&data[0], pq, 7, 3);
                    961:                        BDADD8W(&data[0], pd, 4, 5);
                    962:                        /* PAGE CODE */
                    963:                        data[1] = pc;
                    964:                        /* Reserved */
                    965:                        data[2] = 0;
                    966:                        /* PAGE LENGTH */
                    967:                        data[3] = 0;
                    968:                        hlen = 4;
                    969: 
                    970:                        /* RTO(3) GRD_CHK(2) APP_CHK(1) REF_CHK(0) */
                    971:                        data[4] = 0;
                    972:                        /* GROUP_SUP(4) PRIOR_SUP(3) HEADSUP(2) ORDSUP(1) SIMPSUP(0) */
                    973:                        data[5] = 0;
                    974:                        /* NV_SUP(1) V_SUP(0) */
                    975:                        data[6] = 0;
                    976:                        /* Reserved[7-63] */
                    977:                        memset(&data[7], 0, (64 - 7));
                    978:                        len = 64 - hlen;
                    979: 
                    980:                        /* PAGE LENGTH */
                    981:                        data[3] = len;
                    982:                        break;
                    983: 
                    984:                case SPC_VPD_MANAGEMENT_NETWORK_ADDRESSES:
                    985:                        /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
                    986:                        BDSET8W(&data[0], pq, 7, 3);
                    987:                        BDADD8W(&data[0], pd, 4, 5);
                    988:                        /* PAGE CODE */
                    989:                        data[1] = pc;
                    990:                        /* PAGE LENGTH */
                    991:                        DSET16(&data[2], 0);
                    992:                        hlen = 4;
                    993: 
                    994: #if 0
                    995:                        /* Network services descriptor N */
                    996:                        cp = &data[hlen + len];
                    997: 
                    998:                        /* ASSOCIATION(6-5) SERVICE TYPE(4-0) */
                    999:                        BDSET8W(&cp[0], 0x00, 6, 2);
                   1000:                        BDADD8W(&cp[0], 0x00, 4, 5);
                   1001:                        /* Reserved */
                   1002:                        cp[1] = 0;
                   1003:                        /* NETWORK ADDRESS LENGTH */
                   1004:                        DSET16(&cp[2], 0);
                   1005:                        /* NETWORK ADDRESS */
                   1006:                        cp[4] = 0;
                   1007:                        /* ... */
                   1008:                        plen = 0;
                   1009:                        DSET16(&cp[2], plen);
                   1010:                        len += 4 + plen;
                   1011: #endif
                   1012: 
                   1013:                        /* PAGE LENGTH */
                   1014:                        if (len > 0xffff) {
                   1015:                                len = 0xffff;
                   1016:                        }
                   1017:                        DSET16(&data[2], len);
                   1018:                        break;
                   1019: 
                   1020:                case SPC_VPD_MODE_PAGE_POLICY:
                   1021:                        /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
                   1022:                        BDSET8W(&data[0], pq, 7, 3);
                   1023:                        BDADD8W(&data[0], pd, 4, 5);
                   1024:                        /* PAGE CODE */
                   1025:                        data[1] = pc;
                   1026:                        /* PAGE LENGTH */
                   1027:                        DSET16(&data[2], 0);
                   1028:                        hlen = 4;
                   1029: 
                   1030:                        /* Mode page policy descriptor 1 */
                   1031:                        cp = &data[hlen + len];
                   1032: 
                   1033:                        /* POLICY PAGE CODE(5-0) */
                   1034:                        BDSET8W(&cp[0], 0x3f, 5, 6);    /* all page code */
                   1035:                        /* POLICY SUBPAGE CODE */
                   1036:                        cp[1] = 0xff;                   /* all sub page */
                   1037:                        /* MLUS(7) MODE PAGE POLICY(1-0) */
                   1038:                        //BDSET8(&cp[2], 1, 7); /* multiple logical units share */
                   1039:                        BDSET8(&cp[2], 0, 7); /* own copy */
                   1040:                        BDADD8W(&cp[2], 0x00, 1, 2); /* Shared */
                   1041:                        //BDADD8W(&cp[2], 0x01, 1, 2); /* Per target port */
                   1042:                        //BDADD8W(&cp[2], 0x02, 1, 2); /* Per initiator port */
                   1043:                        //BDADD8W(&cp[2], 0x03, 1, 2); /* Per I_T nexus */
                   1044:                        /* Reserved */
                   1045:                        cp[3] = 0;
                   1046:                        len += 4;
                   1047: 
                   1048:                        /* PAGE LENGTH */
                   1049:                        if (len > 0xffff) {
                   1050:                                len = 0xffff;
                   1051:                        }
                   1052:                        DSET16(&data[2], len);
                   1053:                        break;
                   1054: 
                   1055:                case SPC_VPD_SCSI_PORTS:
                   1056:                        /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
                   1057:                        BDSET8W(&data[0], pq, 7, 3);
                   1058:                        BDADD8W(&data[0], pd, 4, 5);
                   1059:                        /* PAGE CODE */
                   1060:                        data[1] = pc;
                   1061:                        /* PAGE LENGTH */
                   1062:                        DSET16(&data[2], 0);
                   1063:                        hlen = 4;
                   1064: 
                   1065:                        /* Identification descriptor list */
                   1066:                        for (i = 0; i < spec->lu->maxmap; i++) {
                   1067:                                pg_tag = spec->lu->map[i].pg_tag;
                   1068:                                /* skip same pg_tag */
                   1069:                                for (j = 0; j < i; j++) {
                   1070:                                        if (spec->lu->map[j].pg_tag == pg_tag) {
                   1071:                                                goto skip_pg_tag;
                   1072:                                        }
                   1073:                                }
                   1074: 
                   1075:                                /* Identification descriptor N */
                   1076:                                cp = &data[hlen + len];
                   1077: 
                   1078:                                /* Reserved */
                   1079:                                DSET16(&cp[0], 0);
                   1080:                                /* RELATIVE PORT IDENTIFIER */
                   1081:                                DSET16(&cp[2], (uint16_t) (1 + pg_tag));
                   1082:                                /* Reserved */
                   1083:                                DSET16(&cp[4], 0);
                   1084:                                /* INITIATOR PORT TRANSPORTID LENGTH */
                   1085:                                DSET16(&cp[6], 0);
                   1086:                                /* Reserved */
                   1087:                                DSET16(&cp[8], 0);
                   1088:                                /* TARGET PORT DESCRIPTORS LENGTH */
                   1089:                                DSET16(&cp[10], 0);
                   1090:                                len += 12;
                   1091: 
                   1092:                                plen2 = 0;
                   1093:                                /* Target port descriptor 1 */
                   1094:                                cp2 = &data[hlen + len + plen2];
                   1095: 
                   1096:                                /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
                   1097:                                BDSET8W(&cp2[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4);
                   1098:                                BDADD8W(&cp2[0], SPC_VPD_CODE_SET_UTF8, 3, 4);
                   1099:                                /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
                   1100:                                BDSET8W(&cp2[1], 1, 7, 1); /* PIV */
                   1101:                                BDADD8W(&cp2[1], SPC_VPD_ASSOCIATION_TARGET_PORT, 5, 2);
                   1102:                                BDADD8W(&cp2[1], SPC_VPD_IDENTIFIER_TYPE_SCSI_NAME, 3, 4);
                   1103:                                /* Reserved */
                   1104:                                cp2[2] = 0;
                   1105:                                /* IDENTIFIER LENGTH */
                   1106:                                cp2[3] = 0;
                   1107: 
                   1108:                                /* IDENTIFIER */
                   1109:                                plen = snprintf((char *) &cp2[4], MAX_TARGET_NAME,
1.1.1.2 ! misho    1110:                                    "%s"",t,0x""%4.4x", spec->lu->name, pg_tag);
1.1       misho    1111:                                cp2[3] = plen;
                   1112:                                plen2 += 4 + plen;
                   1113: 
                   1114:                                /* TARGET PORT DESCRIPTORS LENGTH */
                   1115:                                DSET16(&cp[10], plen2);
                   1116:                                len += plen2;
                   1117:                        skip_pg_tag:
                   1118:                                ;
                   1119:                        }
                   1120: 
                   1121:                        /* PAGE LENGTH */
                   1122:                        if (len > 0xffff) {
                   1123:                                len = 0xffff;
                   1124:                        }
                   1125:                        DSET16(&data[2], len);
                   1126:                        break;
                   1127: 
                   1128:                default:
                   1129:                        if (pc >= 0xc0 && pc <= 0xff) {
                   1130:                                ISTGT_WARNLOG("Vendor specific INQUIRY VPD page 0x%x\n", pc);
                   1131:                        } else {
                   1132:                                ISTGT_ERRLOG("unsupported INQUIRY VPD page 0x%x\n", pc);
                   1133:                        }
                   1134:                        return -1;
                   1135:                }
                   1136:        } else {
                   1137:                /* Standard INQUIRY data */
                   1138:                /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
                   1139:                BDSET8W(&data[0], pq, 7, 3);
                   1140:                BDADD8W(&data[0], pd, 4, 5);
                   1141:                /* RMB(7) */
                   1142:                BDSET8W(&data[1], rmb, 7, 1);
                   1143:                /* VERSION */
                   1144:                /* See SPC3/SBC2/MMC4/SAM2 for more details */
                   1145:                data[2] = SPC_VERSION_SPC3;
                   1146:                /* NORMACA(5) HISUP(4) RESPONSE DATA FORMAT(3-0) */
                   1147:                BDSET8W(&data[3], 2, 3, 4);             /* format 2 */
                   1148:                BDADD8(&data[1], 1, 4);         /* hierarchical support */
                   1149:                /* ADDITIONAL LENGTH */
                   1150:                data[4] = 0;
                   1151:                hlen = 5;
                   1152: 
                   1153:                /* SCCS(7) ACC(6) TPGS(5-4) 3PC(3) PROTECT(0) */
                   1154:                data[5] = 0;
                   1155:                /* BQUE(7) ENCSERV(6) VS(5) MULTIP(4) MCHNGR(3) ADDR16(0) */
                   1156:                data[6] = 0;
                   1157:                /* WBUS16(5) SYNC(4) LINKED(3) CMDQUE(1) VS(0) */
                   1158:                data[7] = 0;
                   1159:                /* T10 VENDOR IDENTIFICATION */
                   1160:                istgt_strcpy_pad(&data[8], 8, spec->lu->inq_vendor, ' ');
                   1161:                /* PRODUCT IDENTIFICATION */
                   1162:                istgt_strcpy_pad(&data[16], 16, spec->lu->inq_product, ' ');
                   1163:                /* PRODUCT REVISION LEVEL */
                   1164:                istgt_strcpy_pad(&data[32], 4, spec->lu->inq_revision, ' ');
                   1165:                /* Vendor specific */
                   1166:                memset(&data[36], 0x20, 20);
                   1167:                /* CLOCKING(3-2) QAS(1) IUS(0) */
                   1168:                data[56] = 0;
                   1169:                /* Reserved */
                   1170:                data[57] = 0;
                   1171:                /* VERSION DESCRIPTOR 1-8 */
                   1172:                DSET16(&data[58], 0x0960); /* iSCSI (no version claimed) */
                   1173:                DSET16(&data[60], 0x0300); /* SPC-3 (no version claimed) */
                   1174:                DSET16(&data[62], 0x03a0); /* MMC-4 (no version claimed) */
                   1175:                DSET16(&data[64], 0x0040); /* SAM-2 (no version claimed) */
                   1176:                DSET16(&data[66], 0x0000);
                   1177:                DSET16(&data[68], 0x0000);
                   1178:                DSET16(&data[70], 0x0000);
                   1179:                DSET16(&data[72], 0x0000);
                   1180:                /* Reserved[74-95] */
                   1181:                memset(&data[74], 0, (96 - 74));
                   1182:                /* Vendor specific parameters[96-n] */
                   1183:                //data[96] = 0;
                   1184:                len = 96 - hlen;
                   1185: 
                   1186:                /* ADDITIONAL LENGTH */
                   1187:                data[4] = len;
                   1188:        }
                   1189: 
                   1190:        return hlen + len;
                   1191: }
                   1192: 
1.1.1.2 ! misho    1193: #define MODE_SENSE_PAGE_INIT(B,L,P,SP)                                 \
        !          1194:        do {                                                            \
        !          1195:                memset((B), 0, (L));                                    \
        !          1196:                if ((SP) != 0x00) {                                     \
        !          1197:                        (B)[0] = (P) | 0x40; /* PAGE + SPF=1 */         \
        !          1198:                        (B)[1] = (SP);                                  \
        !          1199:                        DSET16(&(B)[2], (L) - 4);                       \
        !          1200:                } else {                                                \
        !          1201:                        (B)[0] = (P);                                   \
        !          1202:                        (B)[1] = (L) - 2;                               \
        !          1203:                }                                                       \
1.1       misho    1204:        } while (0)
                   1205: 
                   1206: static int
                   1207: istgt_lu_dvd_scsi_mode_sense_page(ISTGT_LU_DVD *spec, CONN_Ptr conn, uint8_t *cdb, int pc, int page, int subpage, uint8_t *data, int alloc_len)
                   1208: {
                   1209:        uint8_t *cp;
                   1210:        int len = 0;
                   1211:        int plen;
                   1212:        int i;
                   1213: 
                   1214: #if 0
                   1215:        printf("SENSE pc=%d, page=%2.2x, subpage=%2.2x\n", pc, page, subpage);
                   1216: #endif
                   1217:        ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE: pc=%d, page=%2.2x, subpage=%2.2x\n", pc, page, subpage);
                   1218: 
                   1219:        if (pc == 0x00) {
                   1220:                /* Current values */
                   1221:        } else if (pc == 0x01) {
                   1222:                /* Changeable values */
                   1223:                if (page != 0x08) {
                   1224:                        /* not supported */
1.1.1.2 ! misho    1225:                        return -1;
1.1       misho    1226:                }
                   1227:        } else if (pc == 0x02) {
                   1228:                /* Default values */
                   1229:        } else {
                   1230:                /* Saved values */
                   1231:        }
                   1232: 
                   1233:        cp = &data[len];
                   1234:        switch (page) {
                   1235:        case 0x00:
                   1236:                /* Vendor specific */
                   1237:                break;
                   1238:        case 0x01:
                   1239:                /* Read-Write Error Recovery */
                   1240:                break;
                   1241:        case 0x02:
                   1242:                /* Reserved */
                   1243:                break;
                   1244:        case 0x03:
                   1245:                /* MRW */
                   1246:                break;
                   1247:        case 0x04:
                   1248:                /* Reserved */
                   1249:                break;
                   1250:        case 0x05:
                   1251:                /* Write Parameter */
                   1252:                break;
                   1253:        case 0x06:
                   1254:                /* Reserved */
                   1255:                break;
                   1256:        case 0x07:
                   1257:                /* Verify Error Recovery */
                   1258:                break;
                   1259:        case 0x08:
                   1260:                /* Caching */
                   1261:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Caching\n");
                   1262:                if (subpage != 0x00)
                   1263:                        break;
                   1264: 
                   1265:                plen = 0x12 + 2;
                   1266:                MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
                   1267:                BDADD8(&cp[0], 1, 7); /* PS */
                   1268:                BDADD8(&cp[2], 1, 2); /* WCE */
                   1269:                //BDADD8(&cp[2], 1, 0); /* RCD */
                   1270:                if (spec->write_cache == 1) {
                   1271:                        BDADD8(&cp[2], 1, 2); /* WCE=1 */
                   1272:                } else {
                   1273:                        BDADD8(&cp[2], 0, 2); /* WCE=0 */
                   1274:                }
                   1275:                if (spec->read_cache == 0) {
                   1276:                        BDADD8(&cp[2], 1, 0); /* RCD=1 */
                   1277:                } else {
                   1278:                        BDADD8(&cp[2], 0, 0); /* RCD=0 */
                   1279:                }
                   1280:                len += plen;
                   1281:                break;
                   1282:        case 0x09:
                   1283:        case 0x0a:
                   1284:                /* Reserved */
                   1285:                break;
                   1286:        case 0x0b:
                   1287:                /* Medium Types Supported */
                   1288:                break;
                   1289:        case 0x0c:
                   1290:                /* Reserved */
                   1291:                break;
                   1292:        case 0x0d:
                   1293:                /* CD Device Parameters */
                   1294:                break;
                   1295:        case 0x0e:
                   1296:                /* CD Audio Control */
                   1297:                break;
                   1298:        case 0x0f:
                   1299:        case 0x10:
                   1300:        case 0x11:
                   1301:        case 0x12:
                   1302:        case 0x13:
                   1303:        case 0x14:
                   1304:        case 0x15:
                   1305:        case 0x16:
                   1306:        case 0x17:
                   1307:        case 0x18:
                   1308:        case 0x19:
                   1309:                /* Reserved */
                   1310:                break;
                   1311:        case 0x1a:
                   1312:                /* Power Condition */
                   1313:                break;
                   1314:        case 0x1b:
                   1315:                /* Reserved */
                   1316:                break;
                   1317:        case 0x1c:
                   1318:                /* Informational Exceptions Control */
                   1319:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Informational Exceptions Control\n");
                   1320:                if (subpage != 0x00)
                   1321:                        break;
                   1322: 
                   1323:                plen = 0x0a + 2;
                   1324:                MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
                   1325:                len += plen;
                   1326:                break;
                   1327:        case 0x1d:
                   1328:                /* Time-out & Protect */
                   1329:                break;
                   1330:        case 0x1e:
                   1331:        case 0x1f:
                   1332:                /* Reserved */
                   1333:                break;
                   1334:        case 0x20:
                   1335:        case 0x21:
                   1336:        case 0x22:
                   1337:        case 0x23:
                   1338:        case 0x24:
                   1339:        case 0x25:
                   1340:        case 0x26:
                   1341:        case 0x27:
                   1342:        case 0x28:
                   1343:        case 0x29:
                   1344:                /* Vendor-specific */
                   1345:                break;
                   1346:        case 0x2a:
                   1347:                /* MM Capabilities & Mechanical Status */
                   1348:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE MM Capabilities & Mechanical Status\n");
                   1349:                if (subpage != 0x00)
                   1350:                        break;
                   1351: 
                   1352:                plen = 28 + 2;
                   1353:                MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
                   1354: 
                   1355:                BDADD8(&cp[2], 1, 3); /* DVD-ROM read */
                   1356: 
                   1357:                len += plen;
                   1358:                break;
                   1359:        case 0x2b:
                   1360:                /* Reserved */
                   1361:                break;
                   1362:        case 0x2c:
                   1363:        case 0x2d:
                   1364:        case 0x2e:
                   1365:        case 0x2f:
                   1366:        case 0x30:
                   1367:        case 0x31:
                   1368:        case 0x32:
                   1369:        case 0x33:
                   1370:        case 0x34:
                   1371:        case 0x35:
                   1372:        case 0x36:
                   1373:        case 0x37:
                   1374:        case 0x38:
                   1375:        case 0x39:
                   1376:        case 0x3a:
                   1377:        case 0x3b:
                   1378:        case 0x3c:
                   1379:        case 0x3d:
                   1380:        case 0x3e:
                   1381:                /* Vendor-specific */
                   1382:                break;
                   1383:        case 0x3f:
                   1384:                switch (subpage) {
                   1385:                case 0x00:
                   1386:                        /* All mode pages */
                   1387:                        for (i = 0x00; i < 0x3e; i ++) {
                   1388:                                len += istgt_lu_dvd_scsi_mode_sense_page(spec, conn, cdb, pc, i, 0x00, &cp[len], alloc_len);
                   1389:                        }
                   1390:                        break;
                   1391:                case 0xff:
                   1392:                        /* All mode pages and subpages */
                   1393:                        for (i = 0x00; i < 0x3e; i ++) {
                   1394:                                len += istgt_lu_dvd_scsi_mode_sense_page(spec, conn, cdb, pc, i, 0x00, &cp[len], alloc_len);
                   1395:                        }
                   1396:                        for (i = 0x00; i < 0x3e; i ++) {
                   1397:                                len += istgt_lu_dvd_scsi_mode_sense_page(spec, conn, cdb, pc, i, 0xff, &cp[len], alloc_len);
                   1398:                        }
                   1399:                        break;
                   1400:                default:
                   1401:                        /* 0x01-0x3e: Reserved */
                   1402:                        break;
                   1403:                }
                   1404:        }
                   1405: 
                   1406:        return len;
                   1407: }
                   1408: 
                   1409: static int
                   1410: istgt_lu_dvd_scsi_mode_sense6(ISTGT_LU_DVD *spec, CONN_Ptr conn, uint8_t *cdb, int dbd, int pc, int page, int subpage, uint8_t *data, int alloc_len)
                   1411: {
                   1412:        uint8_t *cp;
                   1413:        int hlen = 0, len = 0, plen;
                   1414:        int total;
                   1415:        int llbaa = 0;
                   1416: 
                   1417:        data[0] = 0;                    /* Mode Data Length */
                   1418:        if (spec->mload) {
1.1.1.2 ! misho    1419:                data[1] = 0;            /* Medium Type */
        !          1420:                data[2] = 0;            /* Device-Specific Parameter */
1.1       misho    1421:                if (spec->lu->readonly
1.1.1.2 ! misho    1422:                    || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
1.1       misho    1423:                        BDADD8(&data[2], 1, 7);     /* WP */
                   1424:                }
                   1425:        } else {
1.1.1.2 ! misho    1426:                data[1] = 0;            /* Medium Type */
        !          1427:                data[2] = 0;            /* Device-Specific Parameter */
1.1       misho    1428:        }
                   1429:        data[3] = 0;                    /* Block Descripter Length */
                   1430:        hlen = 4;
                   1431: 
                   1432:        cp = &data[4];
                   1433:        if (dbd) {                      /* Disable Block Descripters */
                   1434:                len = 0;
                   1435:        } else {
                   1436:                if (llbaa) {
                   1437:                        if (spec->mload) {
                   1438:                                /* Number of Blocks */
                   1439:                                DSET64(&cp[0], spec->blockcnt);
                   1440:                                /* Reserved */
                   1441:                                DSET32(&cp[8], 0);
                   1442:                                /* Block Length */
                   1443:                                DSET32(&cp[12], (uint32_t) spec->blocklen);
                   1444:                        } else {
                   1445:                                /* Number of Blocks */
                   1446:                                DSET64(&cp[0], 0ULL);
                   1447:                                /* Reserved */
                   1448:                                DSET32(&cp[8], 0);
                   1449:                                /* Block Length */
                   1450:                                DSET32(&cp[12], 0);
                   1451:                        }
                   1452:                        len = 16;
                   1453:                } else {
                   1454:                        if (spec->mload) {
                   1455:                                /* Number of Blocks */
                   1456:                                if (spec->blockcnt > 0xffffffffULL) {
                   1457:                                        DSET32(&cp[0], 0xffffffffUL);
                   1458:                                } else {
                   1459:                                        DSET32(&cp[0], (uint32_t) spec->blockcnt);
                   1460:                                }
                   1461:                                /* Block Length */
                   1462:                                DSET32(&cp[4], (uint32_t) spec->blocklen);
                   1463:                        } else {
                   1464:                                /* Number of Blocks */
                   1465:                                DSET32(&cp[0], 0);
                   1466:                                /* Block Length */
                   1467:                                DSET32(&cp[4], 0);
                   1468:                        }
                   1469:                        len = 8;
                   1470:                }
                   1471:                cp += len;
                   1472:        }
                   1473:        data[3] = len;                  /* Block Descripter Length */
                   1474: 
                   1475:        plen = istgt_lu_dvd_scsi_mode_sense_page(spec, conn, cdb, pc, page, subpage, &cp[0], alloc_len);
1.1.1.2 ! misho    1476:        if (plen < 0) {
        !          1477:                return -1;
        !          1478:        }
1.1       misho    1479:        cp += plen;
                   1480: 
                   1481:        total = hlen + len + plen;
                   1482:        data[0] = total - 1;            /* Mode Data Length */
                   1483: 
                   1484:        return total;
                   1485: }
                   1486: 
                   1487: static int
                   1488: istgt_lu_dvd_scsi_mode_sense10(ISTGT_LU_DVD *spec, CONN_Ptr conn, uint8_t *cdb, int dbd, int llbaa, int pc, int page, int subpage, uint8_t *data, int alloc_len)
                   1489: {
                   1490:        uint8_t *cp;
                   1491:        int hlen = 0, len = 0, plen;
                   1492:        int total;
                   1493: 
                   1494:        DSET16(&data[0], 0);            /* Mode Data Length */
                   1495:        if (spec->mload) {
1.1.1.2 ! misho    1496:                data[2] = 0;            /* Medium Type */
        !          1497:                data[3] = 0;            /* Device-Specific Parameter */
1.1       misho    1498:                if (spec->lu->readonly
1.1.1.2 ! misho    1499:                    || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
1.1       misho    1500:                        BDADD8(&data[3], 1, 7);     /* WP */
                   1501:                }
                   1502:        } else {
1.1.1.2 ! misho    1503:                data[2] = 0;            /* Medium Type */
        !          1504:                data[3] = 0;            /* Device-Specific Parameter */
1.1       misho    1505:        }
                   1506:        if (llbaa) {
                   1507:                BDSET8(&data[4], 1, 1);      /* Long LBA */
                   1508:        } else {
                   1509:                BDSET8(&data[4], 0, 1);      /* Short LBA */
                   1510:        }
                   1511:        data[5] = 0;                    /* Reserved */
1.1.1.2 ! misho    1512:        DSET16(&data[6], 0);            /* Block Descripter Length */
1.1       misho    1513:        hlen = 8;
                   1514: 
                   1515:        cp = &data[8];
                   1516:        if (dbd) {                      /* Disable Block Descripters */
                   1517:                len = 0;
                   1518:        } else {
                   1519:                if (llbaa) {
                   1520:                        if (spec->mload) {
                   1521:                                /* Number of Blocks */
                   1522:                                DSET64(&cp[0], spec->blockcnt);
                   1523:                                /* Reserved */
                   1524:                                DSET32(&cp[8], 0);
                   1525:                                /* Block Length */
                   1526:                                DSET32(&cp[12], (uint32_t) spec->blocklen);
                   1527:                        } else {
                   1528:                                /* Number of Blocks */
                   1529:                                DSET64(&cp[0], 0ULL);
                   1530:                                /* Reserved */
                   1531:                                DSET32(&cp[8], 0);
                   1532:                                /* Block Length */
                   1533:                                DSET32(&cp[12], 0);
                   1534:                        }
                   1535:                        len = 16;
                   1536:                } else {
                   1537:                        if (spec->mload) {
                   1538:                                /* Number of Blocks */
                   1539:                                if (spec->blockcnt > 0xffffffffULL) {
                   1540:                                        DSET32(&cp[0], 0xffffffffUL);
                   1541:                                } else {
                   1542:                                        DSET32(&cp[0], (uint32_t) spec->blockcnt);
                   1543:                                }
                   1544:                                /* Block Length */
                   1545:                                DSET32(&cp[4], (uint32_t) spec->blocklen);
                   1546:                        } else {
                   1547:                                /* Number of Blocks */
                   1548:                                DSET32(&cp[0], 0);
                   1549:                                /* Block Length */
                   1550:                                DSET32(&cp[4], 0);
                   1551:                        }
                   1552:                        len = 8;
                   1553:                }
                   1554:                cp += len;
                   1555:        }
                   1556:        DSET16(&data[6], len);          /* Block Descripter Length */
                   1557: 
                   1558:        plen = istgt_lu_dvd_scsi_mode_sense_page(spec, conn, cdb, pc, page, subpage, &cp[0], alloc_len);
1.1.1.2 ! misho    1559:        if (plen < 0) {
        !          1560:                return -1;
        !          1561:        }
1.1       misho    1562:        cp += plen;
                   1563: 
                   1564:        total = hlen + len + plen;
                   1565:        DSET16(&data[0], total - 2);    /* Mode Data Length */
                   1566: 
                   1567:        return total;
                   1568: }
                   1569: 
                   1570: static int
                   1571: istgt_lu_dvd_transfer_data(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint8_t *buf, size_t bufsize, size_t len)
                   1572: {
                   1573:        int rc;
                   1574: 
                   1575:        if (len > bufsize) {
1.1.1.2 ! misho    1576:                ISTGT_ERRLOG("bufsize(%zd) too small\n", bufsize);
1.1       misho    1577:                return -1;
                   1578:        }
                   1579:        rc = istgt_iscsi_transfer_out(conn, lu_cmd, buf, bufsize, len);
                   1580:        if (rc < 0) {
                   1581:                ISTGT_ERRLOG("iscsi_transfer_out()\n");
                   1582:                return -1;
                   1583:        }
                   1584:        return 0;
                   1585: }
                   1586: 
                   1587: static int
                   1588: istgt_lu_dvd_scsi_mode_select_page(ISTGT_LU_DVD *spec, CONN_Ptr conn, uint8_t *cdb, int pf, int sp, uint8_t *data, size_t len)
                   1589: {
1.1.1.2 ! misho    1590:        size_t hlen, plen;
1.1       misho    1591:        int ps, spf, page, subpage;
                   1592:        int rc;
                   1593: 
                   1594:        if (pf == 0) {
                   1595:                /* vendor specific */
                   1596:                return 0;
                   1597:        }
                   1598: 
                   1599:        if (len < 1)
                   1600:                return 0;
                   1601:        ps = BGET8(&data[0], 7);
                   1602:        spf = BGET8(&data[0], 6);
                   1603:        page = data[0] & 0x3f;
                   1604:        if (spf) {
                   1605:                /* Sub_page mode page format */
                   1606:                hlen = 4;
                   1607:                if (len < hlen)
                   1608:                        return 0;
                   1609:                subpage = data[1];
                   1610: 
                   1611:                plen = DGET16(&data[2]);
                   1612:        } else {
                   1613:                /* Page_0 mode page format */
                   1614:                hlen = 2;
                   1615:                if (len < hlen)
                   1616:                        return 0;
                   1617:                subpage = 0;
                   1618:                plen = data[1];
                   1619:        }
                   1620:        plen += hlen;
                   1621:        if (len < plen)
                   1622:                return 0;
                   1623: 
                   1624: #if 0
                   1625:        printf("ps=%d, page=%2.2x, subpage=%2.2x\n", ps, page, subpage);
                   1626: #endif
                   1627:        switch (page) {
                   1628:        case 0x08:
                   1629:                /* Caching */
                   1630:                {
                   1631:                        int wce, rcd;
                   1632: 
                   1633:                        ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SELECT Caching\n");
                   1634:                        if (subpage != 0x00)
                   1635:                                break;
                   1636:                        if (plen != 0x12 + hlen) {
                   1637:                                /* unknown format */
                   1638:                                break;
                   1639:                        }
                   1640:                        wce = BGET8(&data[2], 2); /* WCE */
                   1641:                        rcd = BGET8(&data[2], 0); /* RCD */
                   1642: 
                   1643:                        if (wce) {
                   1644:                                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SELECT Writeback cache enable\n");
                   1645:                                spec->write_cache = 1;
                   1646:                        } else {
                   1647:                                spec->write_cache = 0;
                   1648:                        }
                   1649:                        if (rcd) {
                   1650:                                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SELECT Read cache disable\n");
                   1651:                                spec->read_cache = 0;
                   1652:                        } else {
                   1653:                                spec->read_cache = 1;
                   1654:                        }
                   1655:                }
                   1656:                break;
                   1657:        default:
                   1658:                /* not supported */
                   1659:                break;
                   1660:        }
                   1661: 
                   1662:        len -= plen;
                   1663:        if (len != 0) {
                   1664:                rc = istgt_lu_dvd_scsi_mode_select_page(spec, conn, cdb,  pf, sp, &data[plen], len);
                   1665:                if (rc < 0) {
                   1666:                        return rc;
                   1667:                }
                   1668:        }
                   1669:        return 0;
                   1670: }
                   1671: 
1.1.1.2 ! misho    1672: #define FEATURE_DESCRIPTOR_INIT(B,L,FC)                                        \
        !          1673:        do {                                                            \
1.1       misho    1674:                memset((B), 0, (L));                                    \
                   1675:                DSET16(&(B)[0], (FC));                                  \
1.1.1.2 ! misho    1676:                (B)[3] = (L) - 4;                                       \
1.1       misho    1677:        } while (0)
                   1678: 
                   1679: static int
1.1.1.2 ! misho    1680: istgt_lu_dvd_get_feature_descriptor(ISTGT_LU_DVD *spec, CONN_Ptr conn __attribute__((__unused__)), uint8_t *cdb __attribute__((__unused__)), int fc, uint8_t *data)
1.1       misho    1681: {
                   1682:        uint8_t *cp;
                   1683:        int hlen = 0, len = 0, plen;
                   1684: 
                   1685:        switch (fc) {
                   1686:        case 0x0000:
                   1687:                /* Profile List */
                   1688:                plen = 2 * 4 + 4;
                   1689:                FEATURE_DESCRIPTOR_INIT(data, plen, fc);
                   1690:                /* Version(5-2) Persistent(1) Current(0) */
                   1691:                BDSET8W(&data[2], 0, 5, 4);
                   1692:                BSET8(&data[2], 1);                     /* Persistent=1 */
                   1693:                BSET8(&data[2], 0);                     /* Current=1 */
                   1694:                hlen = 4;
                   1695: 
                   1696:                /* Profile Descriptor */
                   1697:                cp = &data[hlen + len];
                   1698:                /* Profile 1 (CDROM) */
                   1699:                DSET16(&cp[0], 0x0008);
                   1700:                if (spec->profile == MM_PROF_CDROM) {
                   1701:                        BSET8(&cp[2], 0);               /* CurrentP(0)=1 */
                   1702:                }
                   1703:                plen = 4;
                   1704:                len += plen;
                   1705: 
                   1706:                cp = &data[hlen + len];
                   1707:                /* Profile 2 (DVDROM) */
                   1708:                DSET16(&cp[0], 0x0010);
                   1709:                if (spec->profile == MM_PROF_DVDROM) {
                   1710:                        BSET8(&cp[2], 0);               /* CurrentP(0)=1 */
                   1711:                }
                   1712:                plen = 4;
                   1713:                len += plen;
                   1714:                break;
                   1715: 
                   1716:        case 0x0001:
                   1717:                /* Core Feature */
                   1718:                /* GET CONFIGURATION/GET EVENT STATUS NOTIFICATION/INQUIRY */
                   1719:                /* MODE SELECT (10)/MODE SENSE (10)/REQUEST SENSE/TEST UNIT READY */
                   1720:                plen = 8 + 4;
                   1721:                FEATURE_DESCRIPTOR_INIT(data, plen, fc);
                   1722:                /* Version(5-2) Persistent(1) Current(0) */
1.1.1.2 ! misho    1723:                BDSET8W(&data[2], 0x01, 5, 4);          /* MMC4 */
1.1       misho    1724:                BSET8(&data[2], 1);                     /* Persistent=1 */
                   1725:                BSET8(&data[2], 0);                     /* Current=1 */
                   1726:                hlen = 4;
                   1727: 
                   1728:                /* Physical Interface Standard */
1.1.1.2 ! misho    1729:                DSET32(&data[4], 0x00000000);           /* Unspecified */
1.1       misho    1730:                /* DBE(0) */
                   1731:                BCLR8(&data[8], 0);                     /* DBE=0*/
                   1732:                len = 8;
                   1733:                break;
                   1734: 
                   1735:        case 0x0003:
                   1736:                /* Removable Medium */
                   1737:                /* MECHANISM STATUS/PREVENT ALLOW MEDIUM REMOVAL/START STOP UNIT */
                   1738:                plen = 0x04 + 4;
                   1739:                FEATURE_DESCRIPTOR_INIT(data, plen, fc);
                   1740:                /* Version(5-2) Persistent(1) Current(0) */
                   1741:                BDSET8W(&data[2], 0x01, 5, 4);
                   1742:                BSET8(&data[2], 1);                     /* Persistent=1 */
                   1743:                BSET8(&data[2], 0);                     /* Current=1 */
                   1744:                hlen = 4;
                   1745: 
                   1746:                /* Loading Mechanism Type(7-5) Eject(3) Pvnt Jmpr(2) Lock(0) */
                   1747:                BDSET8W(&data[4], 0x01, 7, 3); /* Tray type loading mechanism */
                   1748:                BSET8(&data[4], 3);                     /* eject via START/STOP YES */
                   1749:                BSET8(&data[4], 0);                     /* locking YES */
                   1750:                len = 8;
                   1751:                break;
                   1752: 
                   1753:        case 0x0010:
                   1754:                /* Random Readable */
                   1755:                /* READ CAPACITY/READ (10) */
                   1756:                plen = 4 + 4;
                   1757:                FEATURE_DESCRIPTOR_INIT(data, plen, fc);
                   1758:                /* Version(5-2) Persistent(1) Current(0) */
                   1759:                BDSET8W(&data[2], 0x00, 5, 4);
                   1760:                BSET8(&data[2], 1);                     /* Persistent=1 */
                   1761:                BSET8(&data[2], 0);                     /* Current=1 */
                   1762:                hlen = 4;
                   1763: 
                   1764:                /* Logical Block Size */
                   1765:                DSET32(&data[4], (uint32_t) spec->blocklen);
                   1766:                /* Blocking */
                   1767:                DSET16(&data[8], 1);
                   1768:                /* PP(0) */
1.1.1.2 ! misho    1769:                BCLR8(&data[10], 0);                    /* PP=0 */
1.1       misho    1770:                len = 4;
                   1771:                break;
                   1772: 
                   1773:        case 0x001d:
                   1774:                /* Multi-Read Feature */
                   1775:                /* READ (10)/READ CD/READ DISC INFORMATION/READ TRACK INFORMATION */
                   1776:                plen = 4;
                   1777:                FEATURE_DESCRIPTOR_INIT(data, plen, fc);
                   1778:                /* Version(5-2) Persistent(1) Current(0) */
                   1779:                BDSET8W(&data[2], 0x00, 5, 4);
                   1780:                BSET8(&data[2], 1);                     /* Persistent=1 */
                   1781:                BSET8(&data[2], 0);                     /* Current=1 */
                   1782:                hlen = 4;
                   1783:                len = 0;
                   1784:                break;
                   1785: 
                   1786:        case 0x001e:
                   1787:                /* CD Read */
                   1788:                /* READ CD/READ CD MSF/READ TOC/PMA/ATIP */
                   1789:                plen = 4 + 4;
                   1790:                FEATURE_DESCRIPTOR_INIT(data, plen, fc);
                   1791:                /* Version(5-2) Persistent(1) Current(0) */
                   1792:                BDSET8W(&data[2], 0x02, 5, 4); /* MMC4 */
                   1793:                BCLR8(&data[2], 1);                     /* Persistent=0 */
                   1794:                if (spec->profile == MM_PROF_CDROM) {
                   1795:                        BSET8(&data[2], 0);             /* Current=1 */
                   1796:                } else {
                   1797:                        BCLR8(&data[2], 0);             /* Current=0 */
                   1798:                }
                   1799:                hlen = 4;
                   1800: 
                   1801:                /* DAP(7) C2 Flags(1) CD-Text(0) */
                   1802:                BCLR8(&data[4], 7);             /* not support DAP */
                   1803:                BCLR8(&data[4], 1);             /* not support C2 */
                   1804:                BCLR8(&data[4], 0);             /* not support CD-Text */
                   1805:                len = 4;
                   1806:                break;
                   1807: 
                   1808:        case 0x001f:
                   1809:                /* DVD Read */
                   1810:                /* READ (10)/READ (12)/READ DVD STRUCTURE/READ TOC/PMA/ATIP */
                   1811:                plen = 4;
                   1812:                FEATURE_DESCRIPTOR_INIT(data, plen, fc);
                   1813:                /* Version(5-2) Persistent(1) Current(0) */
                   1814:                BDSET8W(&data[2], 0x00, 5, 4);
                   1815:                BCLR8(&data[2], 1);                     /* Persistent=0 */
                   1816:                if (spec->profile == MM_PROF_DVDROM) {
                   1817:                        BSET8(&data[2], 0);             /* Current=1 */
                   1818:                } else {
                   1819:                        BCLR8(&data[2], 0);             /* Current=0 */
                   1820:                }
                   1821:                hlen = 4;
                   1822:                len = 0;
                   1823:                break;
                   1824: 
                   1825:        default:
                   1826:                /* not supported */
                   1827:                break;
                   1828:        }
                   1829: 
                   1830:        return hlen + len;
                   1831: }
                   1832: 
                   1833: static int
                   1834: istgt_lu_dvd_scsi_get_configuration(ISTGT_LU_DVD *spec, CONN_Ptr conn, uint8_t *cdb, int rt, int sfn, uint8_t *data)
                   1835: {
                   1836:        uint8_t *cp;
                   1837:        int hlen = 0, len = 0, plen;
                   1838:        int fc;
                   1839: 
                   1840:        /* Feature Header */
                   1841:        /* Data Length */
                   1842:        DSET32(&data[0], 0);
                   1843:        /* Reserved */
                   1844:        data[4] = 0;
                   1845:        /* Reserved */
                   1846:        data[5] = 0;
                   1847:        /* Current Profile */
                   1848:        DSET16(&data[6], spec->profile);
                   1849:        hlen = 8;
                   1850: 
                   1851:        cp = &data[hlen];
                   1852:        switch (rt) {
                   1853:        case 0x00:
                   1854:                /* all of features */
                   1855:                for (fc = sfn; fc < 0xffff; fc++) {
                   1856:                        plen = istgt_lu_dvd_get_feature_descriptor(spec, conn, cdb, fc, &cp[len]);
                   1857:                        len += plen;
                   1858:                }
                   1859:                break;
                   1860: 
                   1861:        case 0x01:
                   1862:                /* current of features */
                   1863:                for (fc = sfn; fc < 0xffff; fc++) {
                   1864:                        plen = istgt_lu_dvd_get_feature_descriptor(spec, conn, cdb, fc, &cp[len]);
                   1865:                        if (BGET8(&cp[2], 0) == 1) {
                   1866:                                len += plen;
                   1867:                        } else {
                   1868:                                /* drop non active descriptors */
                   1869:                        }
                   1870:                }
                   1871:                break;
                   1872: 
                   1873:        case 0x02:
                   1874:                /* specified feature */
                   1875:                fc = sfn;
                   1876:                plen = istgt_lu_dvd_get_feature_descriptor(spec, conn, cdb, fc, &cp[len]);
                   1877:                len += plen;
                   1878:                break;
                   1879: 
                   1880:        default:
                   1881:                /* not supported */
                   1882:                break;
                   1883:        }
                   1884: 
                   1885:        /* Data Length */
                   1886:        DSET32(&data[0], len);
                   1887: 
                   1888:        return hlen + len;
                   1889: }
                   1890: 
                   1891: static int
1.1.1.2 ! misho    1892: istgt_lu_dvd_scsi_get_event_status_notification(ISTGT_LU_DVD *spec, CONN_Ptr conn __attribute__((__unused__)), uint8_t *cdb __attribute__((__unused__)), int keep __attribute__((__unused__)), int ncr, uint8_t *data)
1.1       misho    1893: {
                   1894:        uint8_t *cp;
                   1895:        int hlen = 0, len = 0;
                   1896: 
                   1897:        /* Event Descriptor Length */
                   1898:        DSET16(&data[0], 0);
                   1899:        /* NEA(7) Notification Class(2-0) */
                   1900:        data[2] = 0;
                   1901:        /* Supported Event Classes */
                   1902:        data[3] = 0x7e;
                   1903:        hlen = 4;
                   1904: 
                   1905:        cp = &data[hlen];
                   1906:        /* Lowest class number has highest priority */
                   1907:        if (ncr & (1 << 0)) {
                   1908:                /* Reserved */
                   1909:                len = 0;
                   1910:        }
                   1911:        if (ncr & (1 << 1)) {
                   1912:                /* Operational Change */
1.1.1.2 ! misho    1913:                BDSET8W(&data[2], 0x01, 2, 3);          /* Notification Class */
1.1       misho    1914:                /* Event Code */
1.1.1.2 ! misho    1915:                BDSET8W(&cp[0], 0x00, 3, 4);            /* NoChg */
1.1       misho    1916:                /* Persistent Prevented(7) Operational Status(3-0) */
                   1917:                BDSET8(&cp[1], 0, 7);                   /* not prevented */
                   1918:                BDADD8W(&cp[1], 0, 3, 4);
                   1919:                /* Operational Change */
                   1920:                DSET16(&cp[2], 0x00);                   /* NoChg */
                   1921:                len = 4;
                   1922:                goto event_available;
                   1923:        }
                   1924:        if (ncr & (1 << 2)) {
                   1925:                /* Power Management */
1.1.1.2 ! misho    1926:                BDSET8W(&data[2], 0x02, 2, 3);          /* Notification Class */
1.1       misho    1927:                /* Event Code */
1.1.1.2 ! misho    1928:                BDSET8W(&cp[0], 0x00, 3, 4);            /* NoChg */
1.1       misho    1929:                /* Power Status */
1.1.1.2 ! misho    1930:                cp[1] = 0x01;                           /* Active */
1.1       misho    1931:                /* Reserved */
                   1932:                cp[2] = 0;
                   1933:                /* Reserved */
                   1934:                cp[3] = 0;
                   1935:                len = 4;
                   1936:                goto event_available;
                   1937:        }
                   1938:        if (ncr & (1 << 3)) {
                   1939:                /* External Request */
1.1.1.2 ! misho    1940:                BDSET8W(&data[2], 0x03, 2, 3);          /* Notification Class */
1.1       misho    1941:                /* Event Code */
1.1.1.2 ! misho    1942:                BDSET8W(&cp[0], 0x00, 3, 4);            /* NoChg */
1.1       misho    1943:                /* Persistent Prevented(7) External Request Status(3-0) */
                   1944:                BDSET8(&cp[1], 0, 7);                   /* not prevented */
                   1945:                BDADD8W(&cp[1], 0, 3, 4);               /* Ready */
                   1946:                /* External Request */
                   1947:                DSET16(&cp[2], 0x00);                   /* No Request */
                   1948:                len = 4;
                   1949:                goto event_available;
                   1950:        }
                   1951:        if (ncr & (1 << 4)) {
                   1952:                /* Media */
1.1.1.2 ! misho    1953:                BDSET8W(&data[2], 0x04, 2, 3);          /* Notification Class */
1.1       misho    1954:                if (spec->mchanged) {
                   1955:                        if (spec->mwait > 0) {
                   1956:                                spec->mwait--;
                   1957:                        } else {
                   1958:                                spec->mchanged = 0;
                   1959:                                spec->mload = 1;
                   1960:                        }
                   1961:                        if (spec->mload) {
                   1962:                                /* Event Code */
                   1963:                                BDSET8W(&cp[0], 0x02, 3, 4);    /* NewMedia */
                   1964:                                /* Media Status */
                   1965:                                /* Media Present(1) Door or Tray open(0) */
1.1.1.2 ! misho    1966:                                BDSET8(&cp[1], 1, 1);           /* media present */
        !          1967:                                BDADD8(&cp[1], 0, 0);           /* tray close */
1.1       misho    1968:                        } else {
                   1969:                                /* Event Code */
                   1970:                                BDSET8W(&cp[0], 0x03, 3, 4);    /* MediaRemoval */
                   1971:                                /* Media Status */
                   1972:                                /* Media Present(1) Door or Tray open(0) */
1.1.1.2 ! misho    1973:                                BDSET8(&cp[1], 0, 1);           /* media absent */
        !          1974:                                BDADD8(&cp[1], 1, 0);           /* tray open */
1.1       misho    1975:                        }
                   1976:                } else {
                   1977:                        if (spec->mwait > 0) {
                   1978:                                spec->mwait--;
                   1979:                                /* Event Code */
                   1980:                                BDSET8W(&cp[0], 0x01, 3, 4);    /* EjectRequest */
                   1981:                                /* Media Status */
                   1982:                                /* Media Present(1) Door or Tray open(0) */
1.1.1.2 ! misho    1983:                                BDSET8(&cp[1], 0, 1);           /* media absent */
        !          1984:                                BDADD8(&cp[1], 1, 0);           /* tray open */
1.1       misho    1985:                        } else {
                   1986:                                if (spec->mload) {
                   1987:                                        /* Event Code */
                   1988:                                        BDSET8W(&cp[0], 0x00, 3, 4);    /* NoChg */
                   1989:                                        /* Media Status */
                   1990:                                        /* Media Present(1) Door or Tray open(0) */
1.1.1.2 ! misho    1991:                                        BDSET8(&cp[1], 1, 1);   /* media present */
        !          1992:                                        BDADD8(&cp[1], 0, 0);   /* tray close */
1.1       misho    1993:                                } else {
                   1994:                                        /* Event Code */
                   1995:                                        BDSET8W(&cp[0], 0x00, 3, 4);    /* NoChg */
                   1996:                                        /* Media Status */
                   1997:                                        /* Media Present(1) Door or Tray open(0) */
1.1.1.2 ! misho    1998:                                        BDSET8(&cp[1], 0, 1);   /* media absent */
        !          1999:                                        BDADD8(&cp[1], 0, 0);   /* tray close */
1.1       misho    2000:                                }
                   2001:                        }
                   2002:                }
                   2003:                /* Start Slot */
                   2004:                cp[2] = 0;
                   2005:                /* End Slot */
                   2006:                cp[3] = 0;
                   2007:                len = 4;
                   2008:                goto event_available;
                   2009:        }
                   2010:        if (ncr & (1 << 5)) {
                   2011:                /* Multi-Initiator */
1.1.1.2 ! misho    2012:                BDSET8W(&data[2], 0x05, 2, 3);          /* Notification Class */
1.1       misho    2013:                /* Event Code */
1.1.1.2 ! misho    2014:                BDSET8W(&cp[0], 0x00, 3, 4);            /* NoChg */
1.1       misho    2015:                /* Persistent Prevented(7) Multiple Initiator Status(3-0) */
                   2016:                BDSET8(&cp[1], 0, 7);                   /* not prevented */
                   2017:                BDADD8W(&cp[1], 0, 3, 4);               /* Ready */
                   2018:                /* Multiple Initiator Priority */
                   2019:                DSET16(&cp[2], 0x00);                   /* No Request */
                   2020:                len = 4;
                   2021:                goto event_available;
                   2022:        }
                   2023:        if (ncr & (1 << 6)) {
                   2024:                /* Device Busy */
1.1.1.2 ! misho    2025:                BDSET8W(&data[2], 0x06, 2, 3);          /* Notification Class */
1.1       misho    2026:                /* Event Code */
1.1.1.2 ! misho    2027:                BDSET8W(&cp[0], 0x00, 3, 4);            /* NoChg */
1.1       misho    2028:                /* Media Status */
                   2029:                /* Device Busy Status */
1.1.1.2 ! misho    2030:                cp[1] = 0;                              /* Not Busy */
1.1       misho    2031:                /* Time */
                   2032:                DSET16(&cp[2], 0);
                   2033:                len = 4;
                   2034:                goto event_available;
                   2035:        }
                   2036:        if (ncr & (1 << 7)) {
                   2037:                /* Reserved */
                   2038:                len = 0;
                   2039:        }
                   2040: 
                   2041:        if (len == 0) {
                   2042:                /* No Event Available */
                   2043:                BDSET8(&data[2], 0, 7);                 /* NEA=1 */
                   2044:        }
                   2045: 
                   2046: event_available:
                   2047:        /* Event Descriptor Length */
                   2048:        DSET16(&data[0], len + (hlen - 2));
                   2049: 
                   2050:        return hlen + len;
                   2051: }
                   2052: 
                   2053: static int
1.1.1.2 ! misho    2054: istgt_lu_dvd_scsi_mechanism_status(ISTGT_LU_DVD *spec, CONN_Ptr conn __attribute__((__unused__)), uint8_t *cdb __attribute__((__unused__)), uint8_t *data)
1.1       misho    2055: {
                   2056:        uint8_t *cp;
                   2057:        int hlen = 0, len = 0, plen;
                   2058:        int selected_slot = 0, max_slots = 1;
                   2059: 
                   2060:        /* Mechanism Status Header */
                   2061:        /* Fault(7) Changer State(6-5) Current Slot(4-0) */
                   2062:        BDSET8(&data[0], 0, 7);
1.1.1.2 ! misho    2063:        BDADD8W(&data[0], 0x00, 6, 2);                  /* Ready */
1.1       misho    2064:        BDADD8W(&data[0], (selected_slot & 0x1f), 4, 5); /* slot low bits */
                   2065:        /* Mechanism State(7-5) Door open(4) Current Slot(2-0) */
                   2066:        BDSET8W(&data[1], 0x00, 7, 3);          /* Idle */
                   2067:        BDADD8W(&data[1], (selected_slot & 0xe0) >> 5, 2, 3); /* slot high bits */
                   2068:        /* Current LBA (Legacy) */
                   2069:        DSET24(&data[2], 0);
                   2070:        /* Number of Slots Available */
                   2071:        data[5] = max_slots;
                   2072:        /* Length of Slot Tables */
                   2073:        DSET16(&data[6], 0);
                   2074:        hlen = 8;
                   2075: 
                   2076:        /* Slot Tables */
                   2077:        /* Slot 0 */
                   2078:        cp = &data[hlen + len];
                   2079: 
                   2080:        if (spec->mchanged) {
                   2081:                if (spec->mload) {
                   2082:                        /* Disc Present(7) Change(0) */
1.1.1.2 ! misho    2083:                        BDSET8(&cp[0], 1, 7);           /* disc in slot */
1.1       misho    2084:                } else {
                   2085:                        /* Disc Present(7) Change(0) */
1.1.1.2 ! misho    2086:                        BDSET8(&cp[0], 0, 7);           /* no disc in slot */
1.1       misho    2087:                }
1.1.1.2 ! misho    2088:                BDADD8(&cp[0], 1, 0);                   /* disc changed */
1.1       misho    2089:        } else {
                   2090:                if (spec->mload) {
                   2091:                        /* Disc Present(7) Change(0) */
1.1.1.2 ! misho    2092:                        BDSET8(&cp[0], 1, 7);           /* disc in slot */
1.1       misho    2093:                } else {
                   2094:                        /* Disc Present(7) Change(0) */
1.1.1.2 ! misho    2095:                        BDSET8(&cp[0], 0, 7);           /* no disc in slot */
1.1       misho    2096:                }
1.1.1.2 ! misho    2097:                BDADD8(&cp[0], 0, 0);                   /* disc not changed */
1.1       misho    2098:        }
                   2099:        /* CWP_V(1) CWP(0) */
                   2100:        BDSET8(&cp[1], 0, 1);                           /* non Cartridge Write Protection */
                   2101:        BDADD8(&cp[1], 0, 0);                           /* CWP=0 */
                   2102:        /* Reserved */
                   2103:        cp[2] = 0;
                   2104:        /* Reserved */
                   2105:        cp[3] = 0;
                   2106:        plen = 4;
                   2107:        len += plen;
                   2108: 
                   2109:        /* Length of Slot Tables */
                   2110:        DSET16(&data[6], len);
                   2111: 
                   2112:        return hlen + len;
                   2113: }
                   2114: 
                   2115: static int
1.1.1.2 ! misho    2116: istgt_lu_dvd_scsi_read_toc(ISTGT_LU_DVD *spec, CONN_Ptr conn __attribute__((__unused__)), uint8_t *cdb __attribute__((__unused__)), int msf, int format, int track __attribute__((__unused__)), uint8_t *data)
1.1       misho    2117: {
                   2118:        uint8_t *cp;
                   2119:        int hlen = 0, len = 0, plen;
                   2120: 
                   2121:        switch (format) {
                   2122:        case 0x00: /* Formatted TOC */
                   2123:                /* TOC Data Length */
                   2124:                DSET16(&data[0], 0);
                   2125:                /* First Track Number */
                   2126:                data[2] = 1;
                   2127:                /* Last Track Number */
                   2128:                data[3] = 1;
                   2129:                hlen = 4;
                   2130: 
                   2131:                /* TOC Track Descriptor */
                   2132:                /* Track 1 Descriptor */
                   2133:                cp = &data[hlen + len];
                   2134: 
                   2135:                /* Reserved */
                   2136:                cp[0] = 0;
                   2137:                /* ADR(7-4) CONTROL(3-0) */
                   2138:                cp[1] = 0x14;
                   2139:                /* Track Number */
                   2140:                cp[2] = 1;
                   2141:                /* Reserved */
                   2142:                cp[3] = 0;
                   2143:                /* Track Start Address */
                   2144:                if (msf) {
                   2145:                        DSET32(&cp[4], istgt_lba2msf(0));
                   2146:                } else {
                   2147:                        DSET32(&cp[4], 0);
                   2148:                }
                   2149:                plen = 8;
                   2150:                len += plen;
                   2151: 
                   2152:                /* Track AAh (Lead-out) Descriptor */
                   2153:                cp = &data[hlen + len];
                   2154: 
                   2155:                /* Reserved */
                   2156:                cp[0] = 0;
                   2157:                /* ADR(7-4) CONTROL(3-0) */
                   2158:                cp[1] = 0x14;
                   2159:                /* Track Number */
                   2160:                cp[2] = 0xaa;
                   2161:                /* Reserved */
                   2162:                cp[3] = 0;
                   2163:                /* Track Start Address */
                   2164:                if (msf) {
                   2165:                        DSET32(&cp[4], istgt_lba2msf(spec->blockcnt));
                   2166:                } else {
                   2167:                        DSET32(&cp[4], spec->blockcnt);
                   2168:                }
                   2169:                plen = 8;
                   2170:                len += plen;
                   2171: 
                   2172:                /* TOC Data Length */
                   2173:                DSET16(&data[0], hlen + len - 2);
                   2174:                break;
                   2175: 
                   2176:        case 0x01: /* Multi-session Information */
                   2177:                /* TOC Data Length */
                   2178:                DSET16(&data[0], 0);
                   2179:                /* First Complete Session Number */
                   2180:                data[2] = 1;
                   2181:                /* Last Complete Session Number */
                   2182:                data[3] = 1;
                   2183:                hlen = 4;
                   2184: 
                   2185:                /* TOC Track Descriptor */
                   2186:                cp = &data[hlen + len];
                   2187: 
                   2188:                /* Reserved */
                   2189:                cp[0] = 0;
                   2190:                /* ADR(7-4) CONTROL(3-0) */
                   2191:                cp[1] = 0x14;
                   2192:                /* First Track Number In Last Complete Session */
                   2193:                cp[2] = 1;
                   2194:                /* Reserved */
                   2195:                cp[3] = 0;
                   2196:                /* Start Address of First Track in Last Session */
                   2197:                if (msf) {
                   2198:                        DSET32(&cp[4], istgt_lba2msf(0));
                   2199:                } else {
                   2200:                        DSET32(&cp[4], 0);
                   2201:                }
                   2202:                len = 8;
                   2203: 
                   2204:                /* TOC Data Length */
                   2205:                DSET16(&data[0], hlen + len - 2);
                   2206:                break;
                   2207: 
                   2208:        case 0x02: /* Raw TOC */
                   2209:                /* TOC Data Length */
                   2210:                DSET16(&data[0], 0);
                   2211:                /* First Complete Session Number */
                   2212:                data[2] = 1;
                   2213:                /* Last Complete Session Number */
                   2214:                data[3] = 1;
                   2215:                hlen = 4;
                   2216: 
                   2217:                /* TOC Track Descriptor */
                   2218:                /* First Track number in the program area */
                   2219:                cp = &data[hlen + len];
                   2220: 
                   2221:                /* Session Number */
                   2222:                cp[0] = 1;
                   2223:                /* ADR(7-4) CONTROL(3-0) */
                   2224:                cp[1] = 0x14;
                   2225:                /* TNO */
                   2226:                cp[2] = 0;
                   2227:                /* POINT */
                   2228:                cp[3] = 0xa0;
                   2229:                /* Min */
                   2230:                cp[4] = 0;
                   2231:                /* Sec */
                   2232:                cp[5] = 0;
                   2233:                /* Frame */
                   2234:                cp[6] = 0;
                   2235:                /* Zero */
                   2236:                cp[7] = 0;
                   2237:                /* PMIN / First Track Number */
                   2238:                cp[8] = 1;
                   2239:                /* PSEC / Disc Type */
                   2240:                cp[9] = 0x00; /* CD-DA or CD Data with first track in Mode 1 */
                   2241:                /* PFRAME */
                   2242:                cp[10] = 0;
                   2243:                plen = 11;
                   2244:                len += plen;
                   2245: 
                   2246:                /* Last Track number in the program area */
                   2247:                cp = &data[hlen + len];
                   2248: 
                   2249:                /* Session Number */
                   2250:                cp[0] = 1;
                   2251:                /* ADR(7-4) CONTROL(3-0) */
                   2252:                cp[1] = 0x14;
                   2253:                /* TNO */
                   2254:                cp[2] = 0;
                   2255:                /* POINT */
                   2256:                cp[3] = 0xa1;
                   2257:                /* Min */
                   2258:                cp[4] = 0;
                   2259:                /* Sec */
                   2260:                cp[5] = 0;
                   2261:                /* Frame */
                   2262:                cp[6] = 0;
                   2263:                /* Zero */
                   2264:                cp[7] = 0;
                   2265:                /* PMIN / Last Track Number */
                   2266:                cp[8] = 1;
                   2267:                /* PSEC */
                   2268:                cp[9] = 0;
                   2269:                /* PFRAME */
                   2270:                cp[10] = 0;
                   2271:                plen = 11;
                   2272:                len += plen;
                   2273: 
                   2274:                /* Start location of the Lead-out area */
                   2275:                cp = &data[hlen + len];
                   2276: 
                   2277:                /* Session Number */
                   2278:                cp[0] = 1;
                   2279:                /* ADR(7-4) CONTROL(3-0) */
                   2280:                cp[1] = 0x14;
                   2281:                /* TNO */
                   2282:                cp[2] = 0;
                   2283:                /* POINT */
                   2284:                cp[3] = 0xa2;
                   2285:                /* Min */
                   2286:                cp[4] = 0;
                   2287:                /* Sec */
                   2288:                cp[5] = 0;
                   2289:                /* Frame */
                   2290:                cp[6] = 0;
                   2291:                /* Zero */
                   2292:                cp[7] = 0;
                   2293:                /* PMIN / Start position of Lead-out */
                   2294:                /* PSEC / Start position of Lead-out */
                   2295:                /* PFRAME / Start position of Lead-out */
                   2296:                if (msf) {
                   2297:                        DSET24(&cp[8], istgt_lba2msf(spec->blockcnt));
                   2298:                } else {
                   2299:                        DSET24(&cp[8], spec->blockcnt);
                   2300:                }
                   2301:                plen = 11;
                   2302:                len += plen;
                   2303: 
                   2304:                /* Track data */
                   2305:                cp = &data[hlen + len];
                   2306: 
                   2307:                /* Session Number */
                   2308:                cp[0] = 1;
                   2309:                /* ADR(7-4) CONTROL(3-0) */
                   2310:                cp[1] = 0x14;
                   2311:                /* TNO */
                   2312:                cp[2] = 0;
                   2313:                /* POINT */
                   2314:                cp[3] = 1;
                   2315:                /* Min */
                   2316:                cp[4] = 0;
                   2317:                /* Sec */
                   2318:                cp[5] = 0;
                   2319:                /* Frame */
                   2320:                cp[6] = 0;
                   2321:                /* Zero */
                   2322:                cp[7] = 0;
                   2323:                /* PMIN / Start position of Lead-out */
                   2324:                /* PSEC / Start position of Lead-out */
                   2325:                /* PFRAME / Start position of Lead-out */
                   2326:                if (msf) {
                   2327:                        DSET24(&cp[8], istgt_lba2msf(0));
                   2328:                } else {
                   2329:                        DSET24(&cp[8], 0);
                   2330:                }
                   2331:                plen = 11;
                   2332:                len += plen;
                   2333: 
                   2334:                /* TOC Data Length */
                   2335:                DSET16(&data[0], hlen + len - 2);
                   2336:                break;
                   2337: 
                   2338:        default:
                   2339:                ISTGT_ERRLOG("unsupported format 0x%x\n", format);
                   2340:                return -1;
                   2341:        }
                   2342: 
                   2343:        return hlen + len;
                   2344: }
                   2345: 
                   2346: static int
1.1.1.2 ! misho    2347: istgt_lu_dvd_scsi_read_disc_information(ISTGT_LU_DVD *spec __attribute__((__unused__)), CONN_Ptr conn __attribute__((__unused__)), uint8_t *cdb __attribute__((__unused__)), int datatype, uint8_t *data)
1.1       misho    2348: {
                   2349:        int hlen = 0, len = 0;
                   2350: 
                   2351:        switch (datatype) {
                   2352:        case 0x00: /* Disc Information Block */
                   2353:                /* Disc Information Length */
                   2354:                DSET16(&data[0], 0);
                   2355:                hlen = 2;
                   2356: 
                   2357:                /* Disc Information Data Type(7-5) Erasable(4) */
                   2358:                /* State of last Session(3-2) Disc Status(1-0) */
                   2359:                BDSET8W(&data[2], datatype, 7, 3);
                   2360:                BDADD8W(&data[2], 0, 4, 1);
1.1.1.2 ! misho    2361:                BDADD8W(&data[2], 0x03, 3, 2);          /* Complete Session */
        !          2362:                BDADD8W(&data[2], 0x02, 1, 2);          /* Finalized Disc */
1.1       misho    2363:                /* Number of First Track on Disc */
                   2364:                data[3] = 1;
                   2365:                /* Number of Sessions (Least Significant Byte) */
                   2366:                data[4] = (1) & 0xff;
                   2367:                /* First Track Number in Last Session (Least Significant Byte) */
                   2368:                data[5] = (1) & 0xff;
                   2369:                /* Last Track Number in Last Session (Least Significant Byte) */
                   2370:                data[6] = (1) & 0xff;
                   2371:                /* DID_V(7) DBC_V(6) URU(5) DAC_V(4) BG Format Status(1-0) */
                   2372:                BDSET8(&data[7], 0, 7);                 /* Disc ID Valid */
                   2373:                BDADD8(&data[7], 0, 6);                 /* Disc Bar Code Valid */
                   2374:                BDADD8(&data[7], 1, 5);                 /* Unrestricted Use Disc */
                   2375:                BDADD8(&data[7], 0, 4);                 /* Disc Application Code Valid */
                   2376:                BDADD8W(&data[7], 0, 1, 2);             /* BG Format Status */
                   2377:                /* Disc Type */
1.1.1.2 ! misho    2378:                data[8] = 0x00;                         /* CD-DA or CD-ROM Disc */
1.1       misho    2379:                /* Number of Sessions (Most Significant Byte) */
                   2380:                data[9] = (1 >> 8) & 0xff;
                   2381:                /* First Track Number in Last Session (Most Significant Byte) */
                   2382:                data[10] = (1 >> 8) & 0xff;
                   2383:                /* Last Track Number in Last Session (Most Significant Byte) */
                   2384:                data[11] = (1 >> 8) & 0xff;
                   2385:                /* Disc Identification */
                   2386:                DSET32(&data[12], 0);
                   2387:                /* Last Session Lead-in Start Address */
                   2388:                DSET32(&data[16], 0);
                   2389:                /* Last Possible Lead-out Start Address */
                   2390:                DSET32(&data[20], 0);
                   2391:                /* Disc Bar Code */
                   2392:                memset(&data[24], 0, 8);
                   2393:                /* Disc Application Code */
                   2394:                data[32] = 0;
                   2395:                /* Number of OPC Tables */
                   2396:                data[33] = 0;
                   2397:                /* OPC Table Entries */
                   2398:                //data[34] = 0;
                   2399:                len = 34 - hlen;
                   2400: 
                   2401:                /* Disc Information Length */
                   2402:                DSET16(&data[0], len);
                   2403:                break;
                   2404: 
                   2405:        case 0x01: /* Track Resources Information Block */
                   2406:                /* Disc Information Length */
                   2407:                DSET16(&data[0], 0);
                   2408:                hlen = 2;
                   2409: 
                   2410:                /* Disc Information Data Type(7-5) */
                   2411:                BDSET8W(&data[2], datatype, 7, 3);
                   2412:                /* Reserved */
                   2413:                data[3] = 0;
                   2414:                /* Maximum possible number of the Tracks on the disc */
                   2415:                DSET16(&data[4], 99);
                   2416:                /* Number of the assigned Tracks on the disc */
                   2417:                DSET16(&data[6], 1);
                   2418:                /* Maximum possible number of appendable Tracks on the disc */
                   2419:                DSET16(&data[8], 99);
                   2420:                /* Current number of appendable Tracks on the disc */
                   2421:                DSET16(&data[10], 99);
                   2422:                len = 12 - hlen;
                   2423: 
                   2424:                /* Disc Information Length */
                   2425:                DSET16(&data[0], len);
                   2426:                break;
                   2427: 
                   2428:        case 0x02: /* POW Resources Information Block */
                   2429:                /* Disc Information Length */
                   2430:                DSET16(&data[0], 0);
                   2431:                hlen = 2;
                   2432: 
                   2433:                /* Disc Information Data Type(7-5) */
                   2434:                BDSET8W(&data[2], datatype, 7, 3);
                   2435:                /* Reserved */
                   2436:                data[3] = 0;
                   2437:                /* Remaining POW Replacements */
                   2438:                DSET32(&data[4], 0);
                   2439:                /* Remaining POW Reallocation Map Entries */
                   2440:                DSET32(&data[8], 0);
                   2441:                /* Number of Remaining POW Updates */
                   2442:                DSET32(&data[12], 0);
                   2443:                len = 16 - hlen;
                   2444: 
                   2445:                /* Disc Information Length */
                   2446:                DSET16(&data[0], len);
                   2447:                break;
                   2448: 
                   2449:        default:
                   2450:                ISTGT_ERRLOG("unsupported datatype 0x%x\n", datatype);
                   2451:                return -1;
                   2452:        }
                   2453: 
                   2454:        return hlen + len;
                   2455: }
                   2456: 
                   2457: static int
1.1.1.2 ! misho    2458: istgt_lu_dvd_scsi_read_disc_structure(ISTGT_LU_DVD *spec, CONN_Ptr conn __attribute__((__unused__)), uint8_t *cdb __attribute__((__unused__)), int mediatype, int layernumber __attribute__((__unused__)), int format, int agid __attribute__((__unused__)), uint8_t *data)
1.1       misho    2459: {
                   2460:        uint8_t *cp;
                   2461:        int hlen = 0, len = 0;
                   2462: 
                   2463:        if (mediatype == 0x00) {
                   2464:                /* DVD and HD DVD types */
                   2465:        } else if (mediatype == 0x01) {
                   2466:                /* BD */
                   2467:        } else {
                   2468:                /* Reserved */
                   2469:        }
                   2470: 
                   2471:        switch (format) {
                   2472:        case 0x00: /* Physical Format Information */
                   2473:                /* Disc Structure Data Length */
                   2474:                DSET16(&data[0], 0);
                   2475:                /* Reserved */
                   2476:                data[2] = 0;
                   2477:                /* Reserved */
                   2478:                data[3] = 0;
                   2479:                hlen = 4;
                   2480: 
                   2481:                /* Physical Format Information */
                   2482:                cp = &data[hlen + len];
                   2483: 
                   2484:                /* Disk Category(7-4) Part Version(3-0) */
1.1.1.2 ! misho    2485:                BDSET8W(&cp[0], 0x00, 7, 4);            /* DVD-ROM */
        !          2486:                BDADD8W(&cp[0], 0x01, 3, 4);            /* part 1 */
1.1       misho    2487:                /* Disc Size(7-4) Maximum Rate(0-3) */
1.1.1.2 ! misho    2488:                BDSET8W(&cp[1], 0x00, 7, 4);            /* 120mm */
        !          2489:                BDADD8W(&cp[1], 0x0f, 3, 4);            /* Not Specified */
1.1       misho    2490:                /* Number of Layers(6-5) Track(4) Layer Type(3-0) */
1.1.1.2 ! misho    2491:                BDSET8W(&cp[2], 0x00, 6, 2);            /* one layer */
        !          2492:                BDADD8W(&cp[2], 0x00, 4, 1);            /* Parallel Track Path */
        !          2493:                BDADD8W(&cp[2], 0x00, 3, 4);            /* embossed data */
1.1       misho    2494:                /* Linear Density(7-4) Track Density(3-0) */
1.1.1.2 ! misho    2495:                BDSET8W(&cp[3], 0x00, 7, 4);            /* 0.267 um/bit */
        !          2496:                BDADD8W(&cp[3], 0x00, 3, 4);            /* 0.74 um/track */
1.1       misho    2497:                /* Starting Physical Sector Number of Data Area */
                   2498:                DSET32(&cp[4], 0);
                   2499:                /* End Physical Sector Number of Data Area */
                   2500:                DSET32(&cp[8], spec->blockcnt - 1);
                   2501:                /* End Physical Sector Number in Layer 0 */
                   2502:                DSET32(&cp[12], spec->blockcnt - 1);
                   2503:                /* BCA(7) */
                   2504:                BDSET8(&cp[16], 0, 7);
                   2505:                /* Media Specific */
                   2506:                memset(&cp[17], 0, 2048 - 16);
                   2507:                len = 2048;
                   2508: 
                   2509:                /* Disc Information Length */
                   2510:                DSET16(&data[0], hlen + len - 2);
                   2511:                break;
                   2512: 
                   2513:        case 0x01: /* DVD Copyright Information */
                   2514:                /* Disc Structure Data Length */
                   2515:                DSET16(&data[0], 0);
                   2516:                /* Reserved */
                   2517:                data[2] = 0;
                   2518:                /* Reserved */
                   2519:                data[3] = 0;
                   2520:                hlen = 4;
                   2521: 
                   2522:                /* DVD Copyright Information */
                   2523:                cp = &data[hlen + len];
                   2524: 
                   2525:                /* Copyright Protection System Type */
                   2526:                cp[0] = 0x00;
1.1.1.2 ! misho    2527:                //cp[0] = 0x01;                         /* CSS/CPPM */
1.1       misho    2528:                /* Region Management Information */
                   2529:                cp[1] = 0x00;
                   2530:                //cp[1] = 0xff & ~(1 << (2 - 1));       /* 2=Japan */
                   2531:                /* Reserved */
                   2532:                cp[2] = 0;
                   2533:                /* Reserved */
                   2534:                cp[3] = 0;
                   2535:                len = 4;
                   2536: 
                   2537:                /* Disc Information Length */
                   2538:                DSET16(&data[0], hlen + len - 2);
                   2539:                break;
                   2540: 
                   2541:        default:
                   2542:                ISTGT_ERRLOG("unsupported format 0x%x\n", format);
                   2543:                return -1;
                   2544:        }
                   2545: 
                   2546:        return hlen + len;
                   2547: }
                   2548: 
                   2549: static int
1.1.1.2 ! misho    2550: istgt_lu_dvd_scsi_report_key(ISTGT_LU_DVD *spec __attribute__((__unused__)), CONN_Ptr conn __attribute__((__unused__)), uint8_t *cdb __attribute__((__unused__)), int keyclass, int agid __attribute__((__unused__)), int keyformat, uint8_t *data)
1.1       misho    2551: {
                   2552:        uint8_t *cp;
                   2553:        int hlen = 0, len = 0;
                   2554: 
                   2555:        if (keyclass == 0x00) {
                   2556:                /* DVD CSS/CPPM or CPRM */
                   2557:        } else {
                   2558:                return -1;
                   2559:        }
                   2560: 
                   2561:        switch (keyformat) {
                   2562:        case 0x08: /* Report Drive region settings */
                   2563:                /* REPORT KEY Data Length */
                   2564:                DSET16(&data[0], 6);
                   2565:                /* Reserved */
                   2566:                data[2] = 0;
                   2567:                /* Reserved */
                   2568:                data[3] = 0;
                   2569:                hlen = 4;
                   2570: 
                   2571:                /* RPC State */
                   2572:                cp = &data[hlen + len];
                   2573: 
                   2574:                /* Type Code(7-6) # of Vendor Resets Available(5-3) */
                   2575:                /* # of User Controlled Changes Available(2-0) */
                   2576:                BDSET8W(&cp[0], 0x00, 7, 2);    /* No Drive region setting */
                   2577:                //BDSET8W(&cp[0], 0x01, 7, 2);  /* Drive region is set */
                   2578:                BDADD8W(&cp[0], 4, 5, 3);               /* # of vendor */
                   2579:                BDADD8W(&cp[0], 5, 2, 3);               /* # of user */
                   2580:                /* Region Mask */
                   2581:                cp[1] = 0;
                   2582:                //cp[1] = 0xff & ~(1 << (2 - 1));       /* 2=Japan */
                   2583:                /* RPC Scheme */
                   2584:                cp[2] = 0;
                   2585:                //cp[2] = 0x01; /* RPC Phase II */
                   2586:                /* Reserved */
                   2587:                cp[3] = 0;
                   2588:                len = 4;
                   2589: 
                   2590:                /* REPORT KEY Data Length */
                   2591:                DSET16(&data[0], hlen + len - 2);
                   2592:                break;
                   2593: 
                   2594:        case 0x00: /* AGID for CSS/CPPM */
                   2595:        case 0x01: /* Challenge Key */
                   2596:        case 0x02: /* KEY1 */
                   2597:        case 0x04: /* TITLE KEY */
                   2598:        case 0x05: /* ASF */
                   2599:        case 0x11: /* AGID for CPRM */
                   2600:                /* not supported */
                   2601:                return -1;
                   2602: 
                   2603:        default:
                   2604:                ISTGT_ERRLOG("unsupported keyformat 0x%x\n", keyformat);
                   2605:                return -1;
                   2606:        }
                   2607: 
                   2608:        return hlen + len;
                   2609: }
                   2610: 
                   2611: static int
1.1.1.2 ! misho    2612: istgt_lu_dvd_lbread(ISTGT_LU_DVD *spec, CONN_Ptr conn __attribute__((__unused__)), ISTGT_LU_CMD_Ptr lu_cmd, uint64_t lba, uint32_t len)
1.1       misho    2613: {
                   2614:        uint8_t *data;
                   2615:        uint64_t maxlba;
                   2616:        uint64_t llen;
                   2617:        uint64_t blen;
                   2618:        uint64_t offset;
                   2619:        uint64_t nbytes;
                   2620:        int64_t rc;
                   2621: 
                   2622:        if (len == 0) {
                   2623:                lu_cmd->data = NULL;
                   2624:                lu_cmd->data_len = 0;
                   2625:                return 0;
                   2626:        }
                   2627: 
                   2628:        maxlba = spec->blockcnt;
                   2629:        llen = (uint64_t) len;
                   2630:        blen = spec->blocklen;
                   2631:        offset = lba * blen;
                   2632:        nbytes = llen * blen;
                   2633: 
                   2634:        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
1.1.1.2 ! misho    2635:            "Read: max=%"PRIu64", lba=%"PRIu64", len=%u\n",
        !          2636:            maxlba, lba, len);
1.1       misho    2637: 
                   2638:        if (lba >= maxlba || llen > maxlba || lba > (maxlba - llen)) {
                   2639:                ISTGT_ERRLOG("end of media\n");
                   2640:                return -1;
                   2641:        }
                   2642: 
                   2643:        if (nbytes > lu_cmd->iobufsize) {
1.1.1.2 ! misho    2644:                ISTGT_ERRLOG("nbytes(%zu) > iobufsize(%zu)\n",
        !          2645:                    (size_t) nbytes, lu_cmd->iobufsize);
1.1       misho    2646:                return -1;
                   2647:        }
                   2648:        data = lu_cmd->iobuf;
                   2649: 
                   2650:        rc = istgt_lu_dvd_seek(spec, offset);
                   2651:        if (rc < 0) {
                   2652:                ISTGT_ERRLOG("lu_dvd_seek() failed\n");
                   2653:                return -1;
                   2654:        }
                   2655: 
                   2656:        rc = istgt_lu_dvd_read(spec, data, nbytes);
                   2657:        if (rc < 0) {
                   2658:                ISTGT_ERRLOG("lu_dvd_read() failed\n");
                   2659:                return -1;
                   2660:        }
                   2661:        ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "Read %"PRId64"/%"PRIu64" bytes\n",
1.1.1.2 ! misho    2662:            rc, nbytes);
1.1       misho    2663: 
                   2664:        lu_cmd->data = data;
                   2665:        lu_cmd->data_len = rc;
                   2666: 
                   2667:        return 0;
                   2668: }
                   2669: 
                   2670: #if 0
                   2671: static int
                   2672: istgt_lu_dvd_lbwrite(ISTGT_LU_DVD *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint64_t lba, uint32_t len)
                   2673: {
                   2674:        uint8_t *data;
                   2675:        uint64_t maxlba;
                   2676:        uint64_t llen;
                   2677:        uint64_t blen;
                   2678:        uint64_t offset;
                   2679:        uint64_t nbytes;
                   2680:        int64_t rc;
                   2681: 
                   2682:        if (len == 0) {
                   2683:                lu_cmd->data_len = 0;
                   2684:                return 0;
                   2685:        }
                   2686: 
                   2687:        maxlba = spec->blockcnt;
                   2688:        llen = (uint64_t) len;
                   2689:        blen = spec->blocklen;
                   2690:        offset = lba * blen;
                   2691:        nbytes = llen * blen;
                   2692: 
                   2693:        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
1.1.1.2 ! misho    2694:            "Write: max=%"PRIu64", lba=%"PRIu64", len=%u\n",
        !          2695:            maxlba, lba, len);
1.1       misho    2696: 
                   2697:        if (lba >= maxlba || llen > maxlba || lba > (maxlba - llen)) {
                   2698:                ISTGT_ERRLOG("end of media\n");
                   2699:                return -1;
                   2700:        }
                   2701: 
                   2702:        if (nbytes > lu_cmd->iobufsize) {
                   2703:                ISTGT_ERRLOG("nbytes(%u) > iobufsize(%u)\n",
1.1.1.2 ! misho    2704:                    nbytes, lu_cmd->iobufsize);
1.1       misho    2705:                return -1;
                   2706:        }
                   2707:        data = lu_cmd->iobuf;
                   2708: 
                   2709:        rc = istgt_lu_dvd_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
1.1.1.2 ! misho    2710:            lu_cmd->iobufsize, nbytes);
1.1       misho    2711:        if (rc < 0) {
                   2712:                ISTGT_ERRLOG("lu_dvd_transfer_data() failed\n");
                   2713:                return -1;
                   2714:        }
                   2715: 
                   2716:        if (spec->lu->readonly) {
                   2717:                ISTGT_ERRLOG("LU%d: readonly unit\n", spec->lu->num);
                   2718:                return -1;
                   2719:        }
                   2720:        if (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY) {
                   2721:                ISTGT_ERRLOG("LU%d: readonly media\n", spec->lu->num);
                   2722:                return -1;
                   2723:        }
                   2724: 
                   2725:        rc = istgt_lu_dvd_seek(spec, offset);
                   2726:        if (rc < 0) {
                   2727:                ISTGT_ERRLOG("lu_dvd_seek() failed\n");
                   2728:                return -1;
                   2729:        }
                   2730: 
                   2731:        rc = istgt_lu_dvd_write(spec, data, nbytes);
                   2732:        if (rc < 0 || rc != nbytes) {
                   2733:                ISTGT_ERRLOG("lu_dvd_write() failed\n");
                   2734:                return -1;
                   2735:        }
                   2736:        ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "Wrote %"PRId64"/%"PRIu64" bytes\n",
1.1.1.2 ! misho    2737:            rc, nbytes);
1.1       misho    2738: 
                   2739:        lu_cmd->data_len = rc;
                   2740: 
                   2741:        return 0;
                   2742: }
                   2743: 
                   2744: static int
                   2745: istgt_lu_dvd_lbsync(ISTGT_LU_DVD *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint64_t lba, uint32_t len)
                   2746: {
                   2747:        uint64_t maxlba;
                   2748:        uint64_t llen;
                   2749:        uint64_t blen;
                   2750:        uint64_t offset;
                   2751:        uint64_t nbytes;
                   2752:        int64_t rc;
                   2753: 
                   2754:        if (len == 0) {
                   2755:                return 0;
                   2756:        }
                   2757: 
                   2758:        maxlba = spec->blockcnt;
                   2759:        llen = (uint64_t) len;
                   2760:        blen = spec->blocklen;
                   2761:        offset = lba * blen;
                   2762:        nbytes = llen * blen;
                   2763: 
                   2764:        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
1.1.1.2 ! misho    2765:            "Sync: max=%"PRIu64", lba=%"PRIu64", len=%u\n",
        !          2766:            maxlba, lba, len);
1.1       misho    2767: 
                   2768:        if (lba >= maxlba || llen > maxlba || lba > (maxlba - llen)) {
                   2769:                ISTGT_ERRLOG("end of media\n");
                   2770:                return -1;
                   2771:        }
                   2772: 
                   2773:        rc = istgt_lu_dvd_sync(spec, offset, nbytes);
                   2774:        if (rc < 0) {
                   2775:                ISTGT_ERRLOG("lu_dvd_sync() failed\n");
                   2776:                return -1;
                   2777:        }
                   2778: 
                   2779:        return 0;
                   2780: }
                   2781: #endif
                   2782: 
                   2783: static int
1.1.1.2 ! misho    2784: istgt_lu_dvd_build_sense_data(ISTGT_LU_DVD *spec __attribute__((__unused__)), uint8_t *data, int sk, int asc, int ascq)
1.1       misho    2785: {
                   2786:        int rc;
                   2787: 
                   2788:        rc = istgt_lu_scsi_build_sense_data(data, sk, asc, ascq);
                   2789:        if (rc < 0) {
                   2790:                return -1;
                   2791:        }
                   2792:        return rc;
                   2793: }
                   2794: 
                   2795: static int
                   2796: istgt_lu_dvd_build_sense_media(ISTGT_LU_DVD *spec, uint8_t *data)
                   2797: {
                   2798:        uint8_t *sense_data;
                   2799:        int *sense_len;
                   2800:        int data_len;
                   2801: 
                   2802:        sense_data = data;
                   2803:        sense_len = &data_len;
                   2804:        *sense_len = 0;
                   2805: 
                   2806:        if (!spec->mload && !spec->mchanged) {
                   2807:                /* MEDIUM NOT PRESENT */
                   2808:                BUILD_SENSE(NOT_READY, 0x3a, 0x00);
                   2809:                return data_len;
                   2810:        }
                   2811:        if (spec->mchanged) {
                   2812:                /* MEDIUM NOT PRESENT */
                   2813:                BUILD_SENSE(NOT_READY, 0x3a, 0x00);
                   2814:                return data_len;
                   2815: #if 0
                   2816:                /* LOGICAL UNIT NOT READY, CAUSE NOT REPORTABLE */
                   2817:                BUILD_SENSE(NOT_READY, 0x04, 0x00);
                   2818:                return data_len;
                   2819:                /* LOGICAL UNIT IS IN PROCESS OF BECOMING READY */
                   2820:                BUILD_SENSE(NOT_READY, 0x04, 0x01);
                   2821:                return data_len;
                   2822: #endif
                   2823:        }
                   2824:        return 0;
                   2825: }
                   2826: 
                   2827: int
                   2828: istgt_lu_dvd_reset(ISTGT_LU_Ptr lu, int lun)
                   2829: {
                   2830:        ISTGT_LU_DVD *spec;
                   2831:        int flags;
                   2832:        int rc;
                   2833: 
                   2834:        if (lu == NULL) {
                   2835:                return -1;
                   2836:        }
                   2837:        if (lun >= lu->maxlun) {
                   2838:                return -1;
                   2839:        }
                   2840:        if (lu->lun[lun].type == ISTGT_LU_LUN_TYPE_NONE) {
                   2841:                return -1;
                   2842:        }
                   2843:        if (lu->lun[lun].type != ISTGT_LU_LUN_TYPE_REMOVABLE) {
                   2844:                return -1;
                   2845:        }
                   2846:        spec = (ISTGT_LU_DVD *) lu->lun[lun].spec;
                   2847: 
                   2848:        if (spec->lock) {
                   2849:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "unlock by reset\n");
                   2850:                spec->lock = 0;
                   2851:        }
                   2852: 
                   2853:        /* re-open file */
                   2854:        if (!spec->lu->readonly
                   2855:            && !(spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
                   2856:                rc = istgt_lu_dvd_sync(spec, 0, spec->size);
                   2857:                if (rc < 0) {
                   2858:                        ISTGT_ERRLOG("LU%d: LUN%d: lu_dvd_sync() failed\n",
                   2859:                            lu->num, lun);
                   2860:                        /* ignore error */
                   2861:                }
                   2862:        }
                   2863:        rc = istgt_lu_dvd_close(spec);
                   2864:        if (rc < 0) {
                   2865:                ISTGT_ERRLOG("LU%d: LUN%d: lu_dvd_close() failed\n",
                   2866:                    lu->num, lun);
                   2867:                /* ignore error */
                   2868:        }
                   2869:        flags = (lu->readonly || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY))
                   2870:                ? O_RDONLY : O_RDWR;
                   2871:        rc = istgt_lu_dvd_open(spec, flags, 0666);
                   2872:        if (rc < 0) {
                   2873:                ISTGT_ERRLOG("LU%d: LUN%d: lu_dvd_open() failed\n",
                   2874:                    lu->num, lun);
                   2875:                return -1;
                   2876:        }
                   2877: 
                   2878:        return 0;
                   2879: }
                   2880: 
                   2881: int
                   2882: istgt_lu_dvd_execute(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
                   2883: {
                   2884:        ISTGT_LU_Ptr lu;
                   2885:        ISTGT_LU_DVD *spec;
                   2886:        uint8_t *data;
                   2887:        uint8_t *cdb;
                   2888:        uint64_t fmt_lun;
                   2889:        uint64_t lun;
                   2890:        uint64_t method;
                   2891:        uint32_t allocation_len;
                   2892:        int data_len;
                   2893:        int data_alloc_len;
                   2894:        uint64_t lba;
                   2895:        uint32_t transfer_len;
                   2896:        uint8_t *sense_data;
1.1.1.2 ! misho    2897:        size_t *sense_len;
1.1       misho    2898:        int rc;
                   2899: 
                   2900:        if (lu_cmd == NULL)
                   2901:                return -1;
                   2902:        lu = lu_cmd->lu;
                   2903:        if (lu == NULL) {
                   2904:                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   2905:                return -1;
                   2906:        }
                   2907:        spec = NULL;
                   2908:        cdb = lu_cmd->cdb;
                   2909:        data = lu_cmd->data;
                   2910:        data_alloc_len = lu_cmd->alloc_len;
                   2911:        sense_data = lu_cmd->sense_data;
                   2912:        sense_len = &lu_cmd->sense_data_len;
                   2913:        *sense_len = 0;
                   2914: 
                   2915:        fmt_lun = lu_cmd->lun;
                   2916:        method = (fmt_lun >> 62) & 0x03U;
                   2917:        fmt_lun = fmt_lun >> 48;
                   2918:        if (method == 0x00U) {
                   2919:                lun = fmt_lun & 0x00ffU;
                   2920:        } else if (method == 0x01U) {
                   2921:                lun = fmt_lun & 0x3fffU;
                   2922:        } else {
                   2923:                lun = 0xffffU;
                   2924:        }
1.1.1.2 ! misho    2925:        if (lun >= (uint64_t) lu->maxlun) {
1.1       misho    2926: #ifdef ISTGT_TRACE_DVD
                   2927:                ISTGT_ERRLOG("LU%d: LUN%4.4"PRIx64" invalid\n",
                   2928:                                         lu->num, lun);
                   2929: #endif /* ISTGT_TRACE_DVD */
                   2930:                if (cdb[0] == SPC_INQUIRY) {
                   2931:                        allocation_len = DGET16(&cdb[3]);
1.1.1.2 ! misho    2932:                        if (allocation_len > (size_t) data_alloc_len) {
1.1       misho    2933:                                ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1.1.1.2 ! misho    2934:                                    data_alloc_len);
1.1       misho    2935:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   2936:                                return -1;
                   2937:                        }
                   2938:                        memset(data, 0, allocation_len);
                   2939:                        /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
                   2940:                        BDSET8W(&data[0], 0x03, 7, 3);
                   2941:                        BDADD8W(&data[0], 0x1f, 4, 5);
                   2942:                        data_len = 96;
                   2943:                        memset(&data[1], 0, data_len - 1);
                   2944:                        /* ADDITIONAL LENGTH */
                   2945:                        data[4] = data_len - 5;
1.1.1.2 ! misho    2946:                        lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1       misho    2947:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   2948:                        return 0;
                   2949:                } else {
                   2950:                        /* LOGICAL UNIT NOT SUPPORTED */
                   2951:                        BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00);
                   2952:                        lu_cmd->data_len = 0;
                   2953:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   2954:                        return 0;
                   2955:                }
                   2956:        }
                   2957:        spec = (ISTGT_LU_DVD *) lu->lun[lun].spec;
                   2958:        if (spec == NULL) {
                   2959:                /* LOGICAL UNIT NOT SUPPORTED */
                   2960:                BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00);
                   2961:                lu_cmd->data_len = 0;
                   2962:                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   2963:                return 0;
                   2964:        }
                   2965: 
                   2966:        ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "SCSI OP=0x%x, LUN=0x%16.16"PRIx64"\n",
1.1.1.2 ! misho    2967:            cdb[0], lu_cmd->lun);
1.1       misho    2968: #ifdef ISTGT_TRACE_DVD
                   2969:        if (cdb[0] != SPC_TEST_UNIT_READY
                   2970:                && cdb[0] != MMC_GET_EVENT_STATUS_NOTIFICATION) {
                   2971:                istgt_scsi_dump_cdb(cdb);
                   2972:        } else {
                   2973:                istgt_scsi_dump_cdb(cdb);
                   2974:        }
                   2975:        ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "mload=%d, mchanged=%d, mwait=%d\n", spec->mload, spec->mchanged, spec->mwait);
                   2976: #endif /* ISTGT_TRACE_DVD */
                   2977:        switch (cdb[0]) {
                   2978:        case SPC_INQUIRY:
                   2979:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "INQUIRY\n");
                   2980:                if (lu_cmd->R_bit == 0) {
                   2981:                        ISTGT_ERRLOG("R_bit == 0\n");
                   2982:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   2983:                        return -1;
                   2984:                }
                   2985:                allocation_len = DGET16(&cdb[3]);
1.1.1.2 ! misho    2986:                if (allocation_len > (size_t) data_alloc_len) {
1.1       misho    2987:                        ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1.1.1.2 ! misho    2988:                            data_alloc_len);
1.1       misho    2989:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   2990:                        return -1;
                   2991:                }
                   2992:                memset(data, 0, allocation_len);
                   2993:                data_len = istgt_lu_dvd_scsi_inquiry(spec, conn, cdb,
1.1.1.2 ! misho    2994:                    data, data_alloc_len);
1.1       misho    2995:                if (data_len < 0) {
                   2996:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   2997:                        break;
                   2998:                }
                   2999:                ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "INQUIRY", data, data_len);
1.1.1.2 ! misho    3000:                lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1       misho    3001:                lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   3002:                break;
                   3003: 
                   3004:        case SPC_REPORT_LUNS:
                   3005:                {
                   3006:                        int sel;
                   3007: 
                   3008:                        ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "REPORT LUNS\n");
                   3009:                        if (lu_cmd->R_bit == 0) {
                   3010:                                ISTGT_ERRLOG("R_bit == 0\n");
                   3011:                                return -1;
                   3012:                        }
                   3013: 
                   3014:                        sel = cdb[2];
                   3015:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "sel=%x\n", sel);
                   3016: 
                   3017:                        allocation_len = DGET32(&cdb[6]);
1.1.1.2 ! misho    3018:                        if (allocation_len > (size_t) data_alloc_len) {
1.1       misho    3019:                                ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1.1.1.2 ! misho    3020:                                    data_alloc_len);
1.1       misho    3021:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3022:                                return -1;
                   3023:                        }
                   3024:                        if (allocation_len < 16) {
                   3025:                                /* INVALID FIELD IN CDB */
                   3026:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
                   3027:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3028:                                break;
                   3029:                        }
                   3030:                        memset(data, 0, allocation_len);
                   3031:                        data_len = istgt_lu_dvd_scsi_report_luns(lu, conn, cdb, sel,
                   3032:                                                                                                         data, data_alloc_len);
                   3033:                        if (data_len < 0) {
                   3034:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3035:                                break;
                   3036:                        }
                   3037:                        ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "REPORT LUNS", data, data_len);
1.1.1.2 ! misho    3038:                        lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1       misho    3039:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   3040:                }
                   3041:                break;
                   3042: 
                   3043:        case SPC_TEST_UNIT_READY:
                   3044:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "TEST_UNIT_READY\n");
                   3045:                {
                   3046:                        data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
                   3047: 
                   3048:                        /* media state change? */
                   3049:                        if (spec->mchanged) {
                   3050:                                /* wait OS polling */
                   3051:                                if (spec->mwait > 0) {
                   3052:                                        spec->mwait--;
                   3053:                                } else {
                   3054:                                        /* load new media */
                   3055:                                        spec->mchanged = 0;
                   3056:                                        spec->mload = 1;
                   3057:                                }
                   3058:                        }
                   3059: 
                   3060:                        if (data_len != 0) {
                   3061:                                *sense_len = data_len;
                   3062:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3063:                                break;
                   3064:                        }
                   3065: 
                   3066:                        /* OK media present */
                   3067:                        lu_cmd->data_len = 0;
                   3068:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   3069:                        break;
                   3070:                }
                   3071: 
                   3072:        case MMC_START_STOP_UNIT:
                   3073:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "START_STOP_UNIT\n");
                   3074:                {
                   3075:                        int pc, fl, loej, start;
                   3076: 
                   3077:                        pc = BGET8W(&cdb[4], 7, 4);
                   3078:                        fl = BGET8(&cdb[4], 2);
                   3079:                        loej = BGET8(&cdb[4], 1);
                   3080:                        start = BGET8(&cdb[4], 0);
                   3081: 
                   3082:                        data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
                   3083:                        if (data_len != 0) {
                   3084:                                *sense_len = data_len;
                   3085:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3086:                                break;
                   3087:                        }
                   3088: 
                   3089:                        if (!loej) {
                   3090:                                if (start) {
                   3091:                                        /* start */
                   3092:                                } else {
                   3093:                                        /* stop */
                   3094:                                }
                   3095:                                lu_cmd->data_len = 0;
                   3096:                                lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   3097:                                break;
                   3098:                        }
                   3099: 
                   3100:                        /* loej=1 */
                   3101:                        if (start) {
                   3102:                                /* load disc */
                   3103:                                if (!spec->mload) {
                   3104:                                        if (istgt_lu_dvd_load_media(spec) < 0) {
                   3105:                                                ISTGT_ERRLOG("lu_dvd_load_media() failed\n");
                   3106:                                                /* INTERNAL TARGET FAILURE */
                   3107:                                                BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
                   3108:                                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3109:                                                break;
                   3110:                                        }
                   3111:                                        /* OK load */
                   3112:                                }
                   3113:                        } else {
                   3114:                                /* eject */
                   3115:                                if (!spec->lock) {
                   3116:                                        if (spec->mload) {
                   3117:                                                if (istgt_lu_dvd_unload_media(spec) < 0) {
                   3118:                                                        ISTGT_ERRLOG("lu_dvd_unload_media() failed\n");
                   3119:                                                        /* INTERNAL TARGET FAILURE */
                   3120:                                                        BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
                   3121:                                                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3122:                                                        break;
                   3123:                                                }
                   3124:                                                /* OK unload */
                   3125:                                        }
                   3126:                                } else {
                   3127:                                        /* MEDIUM REMOVAL PREVENTED */
                   3128:                                        BUILD_SENSE(ILLEGAL_REQUEST, 0x53, 0x02);
                   3129:                                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3130:                                        break;
                   3131:                                }
                   3132:                        }
                   3133: 
                   3134:                        lu_cmd->data_len = 0;
                   3135:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   3136:                        break;
                   3137:                }
                   3138: 
                   3139:        case SPC_PREVENT_ALLOW_MEDIUM_REMOVAL:
                   3140:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "PREVENT_ALLOW_MEDIUM_REMOVAL\n");
                   3141:                {
                   3142:                        int persistent, prevent;
                   3143: 
                   3144:                        persistent = BGET8(&cdb[4], 1);
                   3145:                        prevent = BGET8(&cdb[4], 0);
                   3146: 
                   3147:                        data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
                   3148:                        if (data_len != 0) {
                   3149:                                *sense_len = data_len;
                   3150:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3151:                                break;
                   3152:                        }
                   3153: 
                   3154:                        if (persistent) {
                   3155:                                if (prevent) {
                   3156:                                        /* Persistent Prevent */
                   3157:                                } else {
                   3158:                                        /* Persistent Allow */
                   3159:                                }
                   3160:                        } else {
                   3161:                                if (prevent) {
                   3162:                                        /* Locked */
                   3163:                                        spec->lock = 1;
                   3164:                                } else {
                   3165:                                        /* Unlocked */
                   3166:                                        spec->lock = 0;
                   3167:                                }
                   3168:                        }
                   3169: 
                   3170:                        lu_cmd->data_len = 0;
                   3171:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   3172:                        break;
                   3173:                }
                   3174: 
                   3175:        case MMC_READ_CAPACITY:
                   3176:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "READ_CAPACITY\n");
                   3177:                if (lu_cmd->R_bit == 0) {
                   3178:                        ISTGT_ERRLOG("R_bit == 0\n");
                   3179:                        return -1;
                   3180:                }
                   3181: 
                   3182:                data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
                   3183:                if (data_len != 0) {
                   3184:                        *sense_len = data_len;
                   3185:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3186:                        break;
                   3187:                }
                   3188: 
                   3189:                if (spec->blockcnt - 1 > 0xffffffffULL) {
                   3190:                        DSET32(&data[0], 0xffffffffUL);
                   3191:                } else {
                   3192:                        DSET32(&data[0], (uint32_t) (spec->blockcnt - 1));
                   3193:                }
                   3194:                DSET32(&data[4], (uint32_t) spec->blocklen);
                   3195:                data_len = 8;
                   3196:                lu_cmd->data_len = data_len;
                   3197:                lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   3198:                break;
                   3199: 
                   3200:        case SPC_MODE_SELECT_6:
                   3201:                {
                   3202:                        int pf, sp, pllen;
                   3203:                        int mdlen, mt, dsp, bdlen;
                   3204: 
                   3205:                        pf = BGET8(&cdb[1], 4);
                   3206:                        sp = BGET8(&cdb[1], 0);
                   3207:                        pllen = cdb[4];             /* Parameter List Length */
                   3208: 
                   3209:                        /* Data-Out */
                   3210:                        rc = istgt_lu_dvd_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
1.1.1.2 ! misho    3211:                            lu_cmd->iobufsize, pllen);
1.1       misho    3212:                        if (rc < 0) {
                   3213:                                ISTGT_ERRLOG("lu_dvd_transfer_data() failed\n");
                   3214:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3215:                                break;
                   3216:                        }
                   3217: #if 0
                   3218:                        istgt_dump("MODE SELECT(6)", lu_cmd->iobuf, pllen);
                   3219: #endif
                   3220:                        data = lu_cmd->iobuf;
                   3221:                        mdlen = data[0];            /* Mode Data Length */
                   3222:                        mt = data[1];               /* Medium Type */
                   3223:                        dsp = data[2];              /* Device-Specific Parameter */
                   3224:                        bdlen = data[3];            /* Block Descriptor Length */
                   3225: 
                   3226:                        /* Short LBA mode parameter block descriptor */
                   3227:                        /* data[4]-data[7] Number of Blocks */
                   3228:                        /* data[8]-data[11] Block Length */
                   3229: 
                   3230:                        /* page data */
                   3231:                        data_len = istgt_lu_dvd_scsi_mode_select_page(spec, conn, cdb, pf, sp, &data[4 + bdlen], pllen - (4 + bdlen));
                   3232:                        if (data_len != 0) {
                   3233:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3234:                                break;
                   3235:                        }
                   3236:                        lu_cmd->data_len = pllen;
                   3237:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   3238:                        break;
                   3239:                }
                   3240: 
                   3241:        case SPC_MODE_SELECT_10:
                   3242:                {
                   3243:                        int pf, sp, pllen;
                   3244:                        int mdlen, mt, dsp, bdlen;
                   3245:                        int llba;
                   3246: 
                   3247:                        pf = BGET8(&cdb[1], 4);
                   3248:                        sp = BGET8(&cdb[1], 0);
                   3249:                        pllen = DGET16(&cdb[7]);    /* Parameter List Length */
                   3250: 
                   3251:                        /* Data-Out */
                   3252:                        rc = istgt_lu_dvd_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
1.1.1.2 ! misho    3253:                            lu_cmd->iobufsize, pllen);
1.1       misho    3254:                        if (rc < 0) {
                   3255:                                ISTGT_ERRLOG("lu_dvd_transfer_data() failed\n");
                   3256:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3257:                                break;
                   3258:                        }
                   3259: #if 0
                   3260:                        istgt_dump("MODE SELECT(10)", lu_cmd->iobuf, pllen);
                   3261: #endif
                   3262:                        data = lu_cmd->iobuf;
                   3263:                        mdlen = DGET16(&data[0]);   /* Mode Data Length */
                   3264:                        mt = data[2];               /* Medium Type */
                   3265:                        dsp = data[3];              /* Device-Specific Parameter */
                   3266:                        llba = BGET8(&data[4], 0);  /* Long LBA */
                   3267:                        bdlen = DGET16(&data[6]);   /* Block Descriptor Length */
                   3268: 
                   3269:                        if (llba) {
                   3270:                                /* Long LBA mode parameter block descriptor */
                   3271:                                /* data[8]-data[15] Number of Blocks */
                   3272:                                /* data[16]-data[19] Reserved */
                   3273:                                /* data[20]-data[23] Block Length */
                   3274:                        } else {
                   3275:                                /* Short LBA mode parameter block descriptor */
                   3276:                                /* data[8]-data[11] Number of Blocks */
                   3277:                                /* data[12]-data[15] Block Length */
                   3278:                        }
                   3279: 
                   3280:                        /* page data */
                   3281:                        data_len = istgt_lu_dvd_scsi_mode_select_page(spec, conn, cdb, pf, sp, &data[8 + bdlen], pllen - (8 + bdlen));
                   3282:                        if (data_len != 0) {
                   3283:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3284:                                break;
                   3285:                        }
                   3286:                        lu_cmd->data_len = pllen;
                   3287:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   3288:                        break;
                   3289:                }
                   3290: 
                   3291:        case SPC_MODE_SENSE_6:
                   3292:                {
                   3293:                        int dbd, pc, page, subpage;
                   3294: 
                   3295:                        if (lu_cmd->R_bit == 0) {
                   3296:                                ISTGT_ERRLOG("R_bit == 0\n");
                   3297:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3298:                                return -1;
                   3299:                        }
                   3300: 
                   3301:                        dbd = BGET8(&cdb[1], 3);
                   3302:                        pc = BGET8W(&cdb[2], 7, 2);
                   3303:                        page = BGET8W(&cdb[2], 5, 6);
                   3304:                        subpage = cdb[3];
                   3305: 
                   3306:                        allocation_len = cdb[4];
1.1.1.2 ! misho    3307:                        if (allocation_len > (size_t) data_alloc_len) {
1.1       misho    3308:                                ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1.1.1.2 ! misho    3309:                                    data_alloc_len);
1.1       misho    3310:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3311:                                return -1;
                   3312:                        }
                   3313:                        memset(data, 0, allocation_len);
                   3314: 
                   3315:                        data_len = istgt_lu_dvd_scsi_mode_sense6(spec, conn, cdb, dbd, pc, page, subpage, data, data_alloc_len);
                   3316:                        if (data_len < 0) {
1.1.1.2 ! misho    3317:                                /* INVALID FIELD IN CDB */
        !          3318:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
1.1       misho    3319:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3320:                                break;
                   3321:                        }
                   3322: #if 0
                   3323:                        istgt_dump("MODE SENSE(6)", data, data_len);
                   3324: #endif
1.1.1.2 ! misho    3325:                        lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1       misho    3326:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   3327:                        break;
                   3328:                }
                   3329: 
                   3330:        case SPC_MODE_SENSE_10:
                   3331:                {
                   3332:                        int dbd, pc, page, subpage;
                   3333:                        int llbaa;
                   3334: 
                   3335:                        if (lu_cmd->R_bit == 0) {
                   3336:                                ISTGT_ERRLOG("R_bit == 0\n");
                   3337:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3338:                                return -1;
                   3339:                        }
                   3340: 
                   3341:                        llbaa = BGET8(&cdb[1], 4);
                   3342:                        dbd = BGET8(&cdb[1], 3);
                   3343:                        pc = BGET8W(&cdb[2], 7, 2);
                   3344:                        page = BGET8W(&cdb[2], 5, 6);
                   3345:                        subpage = cdb[3];
                   3346: 
                   3347:                        allocation_len = DGET16(&cdb[7]);
1.1.1.2 ! misho    3348:                        if (allocation_len > (size_t) data_alloc_len) {
1.1       misho    3349:                                ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1.1.1.2 ! misho    3350:                                    data_alloc_len);
1.1       misho    3351:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3352:                                return -1;
                   3353:                        }
                   3354:                        memset(data, 0, allocation_len);
                   3355: 
                   3356:                        data_len = istgt_lu_dvd_scsi_mode_sense10(spec, conn, cdb, llbaa, dbd, pc, page, subpage, data, data_alloc_len);
                   3357:                        if (data_len < 0) {
1.1.1.2 ! misho    3358:                                /* INVALID FIELD IN CDB */
        !          3359:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
1.1       misho    3360:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3361:                                break;
                   3362:                        }
                   3363: #if 0
                   3364:                        istgt_dump("MODE SENSE(10)", data, data_len);
                   3365: #endif
1.1.1.2 ! misho    3366:                        lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1       misho    3367:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   3368:                        break;
                   3369:                }
                   3370: 
                   3371:        case SPC_LOG_SELECT:
                   3372:        case SPC_LOG_SENSE:
                   3373:                /* INVALID COMMAND OPERATION CODE */
                   3374:                BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
                   3375:                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3376:                break;
                   3377: 
                   3378:        case SPC_REQUEST_SENSE:
                   3379:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "REQUEST_SENSE\n");
                   3380:                {
                   3381:                        int desc;
                   3382:                        int sk, asc, ascq;
                   3383: 
                   3384:                        if (lu_cmd->R_bit == 0) {
                   3385:                                ISTGT_ERRLOG("R_bit == 0\n");
                   3386:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3387:                                return -1;
                   3388:                        }
                   3389: 
                   3390:                        desc = BGET8(&cdb[1], 0);
                   3391:                        if (desc != 0) {
                   3392:                                /* INVALID FIELD IN CDB */
                   3393:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
                   3394:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3395:                                break;
                   3396:                        }
                   3397: 
                   3398:                        data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
                   3399: 
                   3400:                        /* media state change? */
                   3401:                        if (spec->mchanged) {
                   3402:                                /* wait OS polling */
                   3403:                                if (spec->mwait > 0) {
                   3404:                                        spec->mwait--;
                   3405:                                } else {
                   3406:                                        /* load new media */
                   3407:                                        spec->mchanged = 0;
                   3408:                                        spec->mload = 1;
                   3409:                                }
                   3410:                        }
                   3411: 
                   3412:                        if (data_len != 0) {
                   3413:                                *sense_len = data_len;
                   3414:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3415:                                break;
                   3416:                        }
                   3417: 
                   3418:                        allocation_len = cdb[4];
1.1.1.2 ! misho    3419:                        if (allocation_len > (size_t) data_alloc_len) {
1.1       misho    3420:                                ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1.1.1.2 ! misho    3421:                                    data_alloc_len);
1.1       misho    3422:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3423:                                return -1;
                   3424:                        }
                   3425:                        memset(data, 0, allocation_len);
                   3426: 
                   3427:                        if (!spec->sense) {
                   3428:                                /* NO ADDITIONAL SENSE INFORMATION */
                   3429:                                sk = ISTGT_SCSI_SENSE_NO_SENSE;
                   3430:                                asc = 0x00;
                   3431:                                ascq = 0x00;
                   3432:                        } else {
                   3433:                                sk = (spec->sense >> 16) & 0xffU;
                   3434:                                asc = (spec->sense >> 8) & 0xffU;
                   3435:                                ascq = spec->sense & 0xffU;
                   3436:                        }
                   3437:                        data_len = istgt_lu_dvd_build_sense_data(spec, sense_data,
                   3438:                                                                                                         sk, asc, ascq);
                   3439:                        if (data_len < 0 || data_len < 2) {
                   3440:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3441:                                break;
                   3442:                        }
                   3443:                        /* omit SenseLength */
                   3444:                        data_len -= 2;
                   3445:                        memcpy(data, sense_data + 2, data_len);
                   3446: 
1.1.1.2 ! misho    3447:                        lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1       misho    3448:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   3449:                        break;
                   3450:                }
                   3451: 
                   3452:        case MMC_GET_CONFIGURATION:
                   3453:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "GET_CONFIGURATION\n");
                   3454:                {
                   3455:                        int rt, sfn;
                   3456: 
                   3457:                        if (lu_cmd->R_bit == 0) {
                   3458:                                ISTGT_ERRLOG("R_bit == 0\n");
                   3459:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3460:                                return -1;
                   3461:                        }
                   3462: 
                   3463:                        rt = BGET8W(&cdb[1], 1, 2);
                   3464:                        sfn = DGET16(&cdb[2]);
                   3465: 
                   3466:                        data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
                   3467:                        if (data_len != 0) {
                   3468:                                *sense_len = data_len;
                   3469:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3470:                                break;
                   3471:                        }
                   3472: 
                   3473:                        allocation_len = DGET16(&cdb[7]);
1.1.1.2 ! misho    3474:                        if (allocation_len > (size_t) data_alloc_len) {
1.1       misho    3475:                                ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1.1.1.2 ! misho    3476:                                    data_alloc_len);
1.1       misho    3477:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3478:                                return -1;
                   3479:                        }
                   3480:                        memset(data, 0, allocation_len);
                   3481: 
                   3482:                        data_len = istgt_lu_dvd_scsi_get_configuration(spec, conn, cdb, rt, sfn, data);
                   3483:                        if (data_len < 0) {
                   3484:                                /* INVALID FIELD IN CDB */
                   3485:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
                   3486:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3487:                                break;
                   3488:                        }
1.1.1.2 ! misho    3489:                        lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1       misho    3490:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   3491:                        break;
                   3492:                }
                   3493: 
                   3494:        case MMC_GET_EVENT_STATUS_NOTIFICATION:
                   3495:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "GET_EVENT_STATUS_NOTIFICATION\n");
                   3496:                {
                   3497:                        int polled, ncr;
                   3498:                        int keep = 0;
                   3499: 
                   3500:                        if (lu_cmd->R_bit == 0) {
                   3501:                                ISTGT_ERRLOG("R_bit == 0\n");
                   3502:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3503:                                return -1;
                   3504:                        }
                   3505: 
                   3506:                        polled = BGET8(&cdb[1], 0);
                   3507:                        ncr = cdb[4];
                   3508: 
                   3509:                        allocation_len = DGET16(&cdb[7]);
1.1.1.2 ! misho    3510:                        if (allocation_len > (size_t) data_alloc_len) {
1.1       misho    3511:                                ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1.1.1.2 ! misho    3512:                                    data_alloc_len);
1.1       misho    3513:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3514:                                return -1;
                   3515:                        }
                   3516:                        memset(data, 0, allocation_len);
                   3517: 
                   3518:                        if (!polled) {
                   3519:                                /* asynchronous operation */
                   3520:                                /* INVALID FIELD IN CDB */
                   3521:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
                   3522:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3523:                                break;
                   3524:                        }
                   3525:                        if (allocation_len <= 4) {
                   3526:                                /* shall not clear any event */
                   3527:                                keep = 1;
                   3528:                        }
                   3529:                        data_len = istgt_lu_dvd_scsi_get_event_status_notification(spec, conn, cdb, keep, ncr, data);
                   3530:                        if (data_len < 0) {
                   3531:                                /* INVALID FIELD IN CDB */
                   3532:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
                   3533:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3534:                                break;
                   3535:                        }
                   3536:                        ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "EVENT", data, data_len);
1.1.1.2 ! misho    3537:                        lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1       misho    3538:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   3539:                        break;
                   3540:                }
                   3541: 
                   3542:        case MMC_GET_PERFORMANCE:
                   3543:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "GET_PERFORMANCE\n");
                   3544:                {
                   3545:                        int dt, mnd, type;
                   3546: 
                   3547:                        data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
                   3548:                        if (data_len != 0) {
                   3549:                                *sense_len = data_len;
                   3550:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3551:                                break;
                   3552:                        }
                   3553: 
                   3554:                        dt = BGET8W(&cdb[1], 4, 5);
                   3555:                        lba = DGET32(&cdb[2]);
                   3556:                        mnd = DGET16(&cdb[8]);
                   3557:                        type = cdb[10];
                   3558: 
                   3559:                        /* INVALID COMMAND OPERATION CODE */
                   3560:                        BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
                   3561:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3562:                        break;
                   3563:                }
                   3564: 
                   3565:        case MMC_MECHANISM_STATUS:
                   3566:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MECHANISM_STATUS\n");
                   3567:                {
                   3568:                        if (lu_cmd->R_bit == 0) {
                   3569:                                ISTGT_ERRLOG("R_bit == 0\n");
                   3570:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3571:                                return -1;
                   3572:                        }
                   3573: 
                   3574:                        allocation_len = DGET16(&cdb[8]);
1.1.1.2 ! misho    3575:                        if (allocation_len > (size_t) data_alloc_len) {
1.1       misho    3576:                                ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1.1.1.2 ! misho    3577:                                    data_alloc_len);
1.1       misho    3578:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3579:                                return -1;
                   3580:                        }
                   3581:                        memset(data, 0, allocation_len);
                   3582: 
                   3583:                        data_len = istgt_lu_dvd_scsi_mechanism_status(spec, conn, cdb, data);
                   3584:                        if (data_len < 0) {
                   3585:                                /* INVALID FIELD IN CDB */
                   3586:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
                   3587:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3588:                                break;
                   3589:                        }
1.1.1.2 ! misho    3590:                        lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1       misho    3591:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   3592:                        break;
                   3593:                }
                   3594: 
                   3595:        case MMC_READ_TOC_PMA_ATIP:
                   3596:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "READ_TOC_PMA_ATIP\n");
                   3597:                {
                   3598:                        int msf, format, track;
                   3599: 
                   3600:                        if (lu_cmd->R_bit == 0) {
                   3601:                                ISTGT_ERRLOG("R_bit == 0\n");
                   3602:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3603:                                return -1;
                   3604:                        }
                   3605: 
                   3606:                        data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
                   3607:                        if (data_len != 0) {
                   3608:                                *sense_len = data_len;
                   3609:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3610:                                break;
                   3611:                        }
                   3612: 
                   3613:                        msf = BGET8(&cdb[1], 1);
                   3614:                        format = BGET8W(&cdb[2], 3, 4);
                   3615:                        track = cdb[6];
                   3616: 
                   3617:                        allocation_len = DGET16(&cdb[7]);
1.1.1.2 ! misho    3618:                        if (allocation_len > (size_t) data_alloc_len) {
1.1       misho    3619:                                ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1.1.1.2 ! misho    3620:                                    data_alloc_len);
1.1       misho    3621:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3622:                                return -1;
                   3623:                        }
                   3624:                        memset(data, 0, allocation_len);
                   3625: 
                   3626:                        data_len = istgt_lu_dvd_scsi_read_toc(spec, conn, cdb, msf, format, track, data);
                   3627:                        if (data_len < 0) {
                   3628:                                /* INVALID FIELD IN CDB */
                   3629:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
                   3630:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3631:                                break;
                   3632:                        }
1.1.1.2 ! misho    3633:                        lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1       misho    3634:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   3635:                        break;
                   3636:                }
                   3637: 
                   3638:        case MMC_READ_DISC_INFORMATION:
                   3639:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "READ_DISC_INFORMATION\n");
                   3640:                {
                   3641:                        int datatype;
                   3642: 
                   3643:                        if (lu_cmd->R_bit == 0) {
                   3644:                                ISTGT_ERRLOG("R_bit == 0\n");
                   3645:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3646:                                return -1;
                   3647:                        }
                   3648: 
                   3649:                        data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
                   3650:                        if (data_len != 0) {
                   3651:                                *sense_len = data_len;
                   3652:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3653:                                break;
                   3654:                        }
                   3655: 
                   3656:                        datatype = BGET8W(&cdb[1], 2, 3);
                   3657: 
                   3658:                        allocation_len = DGET16(&cdb[7]);
1.1.1.2 ! misho    3659:                        if (allocation_len > (size_t) data_alloc_len) {
1.1       misho    3660:                                ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1.1.1.2 ! misho    3661:                                    data_alloc_len);
1.1       misho    3662:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3663:                                return -1;
                   3664:                        }
                   3665:                        memset(data, 0, allocation_len);
                   3666: 
                   3667:                        data_len = istgt_lu_dvd_scsi_read_disc_information(spec, conn, cdb, datatype, data);
                   3668:                        if (data_len < 0) {
                   3669:                                /* INVALID FIELD IN CDB */
                   3670:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
                   3671:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3672:                                break;
                   3673:                        }
1.1.1.2 ! misho    3674:                        lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1       misho    3675:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   3676:                        break;
                   3677:                }
                   3678: 
                   3679:        case MMC_READ_DISC_STRUCTURE:
                   3680:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "READ_DISC_STRUCTURE\n");
                   3681:                {
                   3682:                        int mediatype, layernumber, format, agid;
                   3683: 
                   3684:                        if (lu_cmd->R_bit == 0) {
                   3685:                                ISTGT_ERRLOG("R_bit == 0\n");
                   3686:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3687:                                return -1;
                   3688:                        }
                   3689: 
                   3690:                        data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
                   3691:                        if (data_len != 0) {
                   3692:                                *sense_len = data_len;
                   3693:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3694:                                break;
                   3695:                        }
                   3696: 
                   3697:                        mediatype = BGET8W(&cdb[1], 3, 4);
                   3698:                        layernumber = cdb[6];
                   3699:                        format = cdb[7];
                   3700:                        agid = BGET8W(&cdb[10], 7, 2);
                   3701: 
                   3702:                        allocation_len = DGET16(&cdb[8]);
1.1.1.2 ! misho    3703:                        if (allocation_len > (size_t) data_alloc_len) {
1.1       misho    3704:                                ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1.1.1.2 ! misho    3705:                                    data_alloc_len);
1.1       misho    3706:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3707:                                return -1;
                   3708:                        }
                   3709:                        memset(data, 0, allocation_len);
                   3710: 
                   3711:                        data_len = istgt_lu_dvd_scsi_read_disc_structure(spec, conn, cdb, mediatype, layernumber, format, agid, data);
                   3712:                        if (data_len < 0) {
                   3713:                                /* INVALID FIELD IN CDB */
                   3714:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
                   3715:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3716:                                break;
                   3717:                        }
1.1.1.2 ! misho    3718:                        lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1       misho    3719:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   3720:                        break;
                   3721:                }
                   3722: 
                   3723:        case MMC_READ_SUB_CHANNEL:
                   3724:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "READ_SUB_CHANNEL\n");
                   3725:                {
                   3726:                        data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
                   3727:                        if (data_len != 0) {
                   3728:                                *sense_len = data_len;
                   3729:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3730:                                break;
                   3731:                        }
                   3732: 
                   3733:                        /* INVALID COMMAND OPERATION CODE */
                   3734:                        BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
                   3735:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3736:                        break;
                   3737:                }
                   3738: 
                   3739:        case MMC_REPORT_KEY:
                   3740:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "REPORT_KEY\n");
                   3741:                {
                   3742:                        int keyclass, agid, keyformat;
                   3743: 
                   3744:                        if (lu_cmd->R_bit == 0) {
                   3745:                                ISTGT_ERRLOG("R_bit == 0\n");
                   3746:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3747:                                return -1;
                   3748:                        }
                   3749: 
                   3750:                        data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
                   3751:                        if (data_len != 0) {
                   3752:                                *sense_len = data_len;
                   3753:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3754:                                break;
                   3755:                        }
                   3756: 
                   3757:                        keyclass = cdb[7];
                   3758:                        agid = BGET8W(&cdb[10], 7, 2);
                   3759:                        keyformat = BGET8W(&cdb[10], 5, 6);
                   3760: 
                   3761:                        allocation_len = DGET16(&cdb[8]);
1.1.1.2 ! misho    3762:                        if (allocation_len > (size_t) data_alloc_len) {
1.1       misho    3763:                                ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1.1.1.2 ! misho    3764:                                    data_alloc_len);
1.1       misho    3765:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3766:                                return -1;
                   3767:                        }
                   3768:                        memset(data, 0, allocation_len);
                   3769: 
                   3770:                        data_len = istgt_lu_dvd_scsi_report_key(spec, conn, cdb, keyclass, agid, keyformat, data);
                   3771:                        if (data_len < 0) {
                   3772:                                /* INVALID FIELD IN CDB */
                   3773:                                BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
                   3774:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3775:                                break;
                   3776:                        }
1.1.1.2 ! misho    3777:                        lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1       misho    3778:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   3779:                        break;
                   3780:                }
                   3781: 
                   3782:        case MMC_SEND_KEY:
                   3783:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "SEND_KEY\n");
                   3784:                {
                   3785:                        data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
                   3786:                        if (data_len != 0) {
                   3787:                                *sense_len = data_len;
                   3788:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3789:                                break;
                   3790:                        }
                   3791: 
                   3792:                        /* INVALID COMMAND OPERATION CODE */
                   3793:                        BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
                   3794:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3795:                        break;
                   3796:                }
                   3797: 
                   3798:        case MMC_READ_10:
                   3799:                {
                   3800:                        int dpo, fua;
                   3801: 
                   3802:                        if (lu_cmd->R_bit == 0) {
                   3803:                                ISTGT_ERRLOG("R_bit == 0\n");
                   3804:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3805:                                return -1;
                   3806:                        }
                   3807: 
                   3808:                        data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
                   3809:                        if (data_len != 0) {
                   3810:                                *sense_len = data_len;
                   3811:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3812:                                break;
                   3813:                        }
                   3814: 
                   3815:                        dpo = BGET8(&cdb[1], 4);
                   3816:                        fua = BGET8(&cdb[1], 3);
                   3817:                        lba = (uint64_t) DGET32(&cdb[2]);
                   3818:                        transfer_len = (uint32_t) DGET16(&cdb[7]);
                   3819:                        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
1.1.1.2 ! misho    3820:                            "READ_10(lba %"PRIu64", len %u blocks)\n",
        !          3821:                            lba, transfer_len);
1.1       misho    3822:                        rc = istgt_lu_dvd_lbread(spec, conn, lu_cmd, lba, transfer_len);
                   3823:                        if (rc < 0) {
                   3824:                                ISTGT_ERRLOG("lu_dvd_lbread() failed\n");
                   3825:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3826:                                break;
                   3827:                        }
                   3828:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   3829:                        break;
                   3830:                }
                   3831: 
                   3832:        case MMC_READ_12:
                   3833:                {
                   3834:                        int dpo, fua;
                   3835: 
                   3836:                        if (lu_cmd->R_bit == 0) {
                   3837:                                ISTGT_ERRLOG("R_bit == 0\n");
                   3838:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3839:                                return -1;
                   3840:                        }
                   3841: 
                   3842:                        data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
                   3843:                        if (data_len != 0) {
                   3844:                                *sense_len = data_len;
                   3845:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3846:                                break;
                   3847:                        }
                   3848: 
                   3849:                        dpo = BGET8(&cdb[1], 4);
                   3850:                        fua = BGET8(&cdb[1], 3);
                   3851:                        lba = (uint64_t) DGET32(&cdb[2]);
                   3852:                        transfer_len = (uint32_t) DGET32(&cdb[6]);
                   3853:                        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
1.1.1.2 ! misho    3854:                            "READ_12(lba %"PRIu64", len %u blocks)\n",
        !          3855:                            lba, transfer_len);
1.1       misho    3856:                        rc = istgt_lu_dvd_lbread(spec, conn, lu_cmd, lba, transfer_len);
                   3857:                        if (rc < 0) {
                   3858:                                ISTGT_ERRLOG("lu_dvd_lbread() failed\n");
                   3859:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3860:                                break;
                   3861:                        }
                   3862:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   3863:                        break;
                   3864:                }
                   3865: 
                   3866: #if 0
                   3867:        case MMC_WRITE_10:
                   3868:        case MMC_WRITE_AND_VERIFY_10:
                   3869:        case MMC_WRITE_12:
                   3870:        case MMC_VERIFY_10:
                   3871:        case MMC_SYNCHRONIZE_CACHE:
                   3872:                /* INVALID COMMAND OPERATION CODE */
                   3873:                BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
                   3874:                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3875:                break;
                   3876: #endif
                   3877: 
                   3878:        /* XXX TODO: fix */
                   3879:        case SPC2_RELEASE_6:
                   3880:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RELEASE_6\n");
                   3881:                lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   3882:                break;
                   3883:        case SPC2_RELEASE_10:
                   3884:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RELEASE_10\n");
                   3885:                lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   3886:                break;
                   3887:        case SPC2_RESERVE_6:
                   3888:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RESERVE_6\n");
                   3889:                lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   3890:                break;
                   3891:        case SPC2_RESERVE_10:
                   3892:                ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RESERVE_10\n");
                   3893:                lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   3894:                break;
                   3895: 
                   3896:        default:
                   3897:                ISTGT_ERRLOG("unsupported SCSI OP=0x%x\n", cdb[0]);
                   3898:                /* INVALID COMMAND OPERATION CODE */
                   3899:                BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
                   3900:                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   3901:                break;
                   3902:        }
                   3903: 
                   3904:        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
1.1.1.2 ! misho    3905:            "SCSI OP=0x%x, LUN=0x%16.16"PRIx64" status=0x%x,"
        !          3906:            " complete\n",
        !          3907:            cdb[0], lu_cmd->lun, lu_cmd->status);
1.1       misho    3908:        return 0;
                   3909: }

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