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

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

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