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