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