Annotation of embedaddon/istgt/src/istgt_lu_dvd.c, revision 1.1.1.3
1.1 misho 1: /*
1.1.1.2 misho 2: * Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
1.1 misho 3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: *
14: * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17: * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
18: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24: * SUCH DAMAGE.
25: *
26: */
27:
28: #ifdef HAVE_CONFIG_H
29: #include "config.h"
30: #endif
31:
32: #include <inttypes.h>
33: #include <stdint.h>
34:
35: #include <errno.h>
36: #include <stdio.h>
37: #include <string.h>
38: #include <pthread.h>
39: #include <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 */
1.1.1.3 ! misho 1268: if (pc == 0x01) {
! 1269: // Changeable values
! 1270: BDADD8(&cp[2], 1, 2); /* WCE */
! 1271: BDADD8(&cp[2], 1, 0); /* RCD */
! 1272: len += plen;
! 1273: break;
! 1274: }
1.1 misho 1275: BDADD8(&cp[2], 1, 2); /* WCE */
1276: //BDADD8(&cp[2], 1, 0); /* RCD */
1277: if (spec->write_cache == 1) {
1278: BDADD8(&cp[2], 1, 2); /* WCE=1 */
1279: } else {
1280: BDADD8(&cp[2], 0, 2); /* WCE=0 */
1281: }
1282: if (spec->read_cache == 0) {
1283: BDADD8(&cp[2], 1, 0); /* RCD=1 */
1284: } else {
1285: BDADD8(&cp[2], 0, 0); /* RCD=0 */
1286: }
1287: len += plen;
1288: break;
1289: case 0x09:
1290: case 0x0a:
1291: /* Reserved */
1292: break;
1293: case 0x0b:
1294: /* Medium Types Supported */
1295: break;
1296: case 0x0c:
1297: /* Reserved */
1298: break;
1299: case 0x0d:
1300: /* CD Device Parameters */
1301: break;
1302: case 0x0e:
1303: /* CD Audio Control */
1304: break;
1305: case 0x0f:
1306: case 0x10:
1307: case 0x11:
1308: case 0x12:
1309: case 0x13:
1310: case 0x14:
1311: case 0x15:
1312: case 0x16:
1313: case 0x17:
1314: case 0x18:
1315: case 0x19:
1316: /* Reserved */
1317: break;
1318: case 0x1a:
1319: /* Power Condition */
1320: break;
1321: case 0x1b:
1322: /* Reserved */
1323: break;
1324: case 0x1c:
1325: /* Informational Exceptions Control */
1326: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Informational Exceptions Control\n");
1327: if (subpage != 0x00)
1328: break;
1329:
1330: plen = 0x0a + 2;
1331: MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
1332: len += plen;
1333: break;
1334: case 0x1d:
1335: /* Time-out & Protect */
1336: break;
1337: case 0x1e:
1338: case 0x1f:
1339: /* Reserved */
1340: break;
1341: case 0x20:
1342: case 0x21:
1343: case 0x22:
1344: case 0x23:
1345: case 0x24:
1346: case 0x25:
1347: case 0x26:
1348: case 0x27:
1349: case 0x28:
1350: case 0x29:
1351: /* Vendor-specific */
1352: break;
1353: case 0x2a:
1354: /* MM Capabilities & Mechanical Status */
1355: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE MM Capabilities & Mechanical Status\n");
1356: if (subpage != 0x00)
1357: break;
1358:
1359: plen = 28 + 2;
1360: MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
1361:
1362: BDADD8(&cp[2], 1, 3); /* DVD-ROM read */
1363:
1364: len += plen;
1365: break;
1366: case 0x2b:
1367: /* Reserved */
1368: break;
1369: case 0x2c:
1370: case 0x2d:
1371: case 0x2e:
1372: case 0x2f:
1373: case 0x30:
1374: case 0x31:
1375: case 0x32:
1376: case 0x33:
1377: case 0x34:
1378: case 0x35:
1379: case 0x36:
1380: case 0x37:
1381: case 0x38:
1382: case 0x39:
1383: case 0x3a:
1384: case 0x3b:
1385: case 0x3c:
1386: case 0x3d:
1387: case 0x3e:
1388: /* Vendor-specific */
1389: break;
1390: case 0x3f:
1391: switch (subpage) {
1392: case 0x00:
1393: /* All mode pages */
1394: for (i = 0x00; i < 0x3e; i ++) {
1395: len += istgt_lu_dvd_scsi_mode_sense_page(spec, conn, cdb, pc, i, 0x00, &cp[len], alloc_len);
1396: }
1397: break;
1398: case 0xff:
1399: /* All mode pages and subpages */
1400: for (i = 0x00; i < 0x3e; i ++) {
1401: len += istgt_lu_dvd_scsi_mode_sense_page(spec, conn, cdb, pc, i, 0x00, &cp[len], alloc_len);
1402: }
1403: for (i = 0x00; i < 0x3e; i ++) {
1404: len += istgt_lu_dvd_scsi_mode_sense_page(spec, conn, cdb, pc, i, 0xff, &cp[len], alloc_len);
1405: }
1406: break;
1407: default:
1408: /* 0x01-0x3e: Reserved */
1409: break;
1410: }
1411: }
1412:
1413: return len;
1414: }
1415:
1416: static int
1417: 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)
1418: {
1419: uint8_t *cp;
1420: int hlen = 0, len = 0, plen;
1421: int total;
1422: int llbaa = 0;
1423:
1424: data[0] = 0; /* Mode Data Length */
1425: if (spec->mload) {
1.1.1.2 misho 1426: data[1] = 0; /* Medium Type */
1427: data[2] = 0; /* Device-Specific Parameter */
1.1 misho 1428: if (spec->lu->readonly
1.1.1.2 misho 1429: || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
1.1 misho 1430: BDADD8(&data[2], 1, 7); /* WP */
1431: }
1432: } else {
1.1.1.2 misho 1433: data[1] = 0; /* Medium Type */
1434: data[2] = 0; /* Device-Specific Parameter */
1.1 misho 1435: }
1436: data[3] = 0; /* Block Descripter Length */
1437: hlen = 4;
1438:
1439: cp = &data[4];
1440: if (dbd) { /* Disable Block Descripters */
1441: len = 0;
1442: } else {
1443: if (llbaa) {
1444: if (spec->mload) {
1445: /* Number of Blocks */
1446: DSET64(&cp[0], spec->blockcnt);
1447: /* Reserved */
1448: DSET32(&cp[8], 0);
1449: /* Block Length */
1450: DSET32(&cp[12], (uint32_t) spec->blocklen);
1451: } else {
1452: /* Number of Blocks */
1453: DSET64(&cp[0], 0ULL);
1454: /* Reserved */
1455: DSET32(&cp[8], 0);
1456: /* Block Length */
1457: DSET32(&cp[12], 0);
1458: }
1459: len = 16;
1460: } else {
1461: if (spec->mload) {
1462: /* Number of Blocks */
1463: if (spec->blockcnt > 0xffffffffULL) {
1464: DSET32(&cp[0], 0xffffffffUL);
1465: } else {
1466: DSET32(&cp[0], (uint32_t) spec->blockcnt);
1467: }
1468: /* Block Length */
1469: DSET32(&cp[4], (uint32_t) spec->blocklen);
1470: } else {
1471: /* Number of Blocks */
1472: DSET32(&cp[0], 0);
1473: /* Block Length */
1474: DSET32(&cp[4], 0);
1475: }
1476: len = 8;
1477: }
1478: cp += len;
1479: }
1480: data[3] = len; /* Block Descripter Length */
1481:
1482: plen = istgt_lu_dvd_scsi_mode_sense_page(spec, conn, cdb, pc, page, subpage, &cp[0], alloc_len);
1.1.1.2 misho 1483: if (plen < 0) {
1484: return -1;
1485: }
1.1 misho 1486: cp += plen;
1487:
1488: total = hlen + len + plen;
1489: data[0] = total - 1; /* Mode Data Length */
1490:
1491: return total;
1492: }
1493:
1494: static int
1495: 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)
1496: {
1497: uint8_t *cp;
1498: int hlen = 0, len = 0, plen;
1499: int total;
1500:
1501: DSET16(&data[0], 0); /* Mode Data Length */
1502: if (spec->mload) {
1.1.1.2 misho 1503: data[2] = 0; /* Medium Type */
1504: data[3] = 0; /* Device-Specific Parameter */
1.1 misho 1505: if (spec->lu->readonly
1.1.1.2 misho 1506: || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
1.1 misho 1507: BDADD8(&data[3], 1, 7); /* WP */
1508: }
1509: } else {
1.1.1.2 misho 1510: data[2] = 0; /* Medium Type */
1511: data[3] = 0; /* Device-Specific Parameter */
1.1 misho 1512: }
1513: if (llbaa) {
1514: BDSET8(&data[4], 1, 1); /* Long LBA */
1515: } else {
1516: BDSET8(&data[4], 0, 1); /* Short LBA */
1517: }
1518: data[5] = 0; /* Reserved */
1.1.1.2 misho 1519: DSET16(&data[6], 0); /* Block Descripter Length */
1.1 misho 1520: hlen = 8;
1521:
1522: cp = &data[8];
1523: if (dbd) { /* Disable Block Descripters */
1524: len = 0;
1525: } else {
1526: if (llbaa) {
1527: if (spec->mload) {
1528: /* Number of Blocks */
1529: DSET64(&cp[0], spec->blockcnt);
1530: /* Reserved */
1531: DSET32(&cp[8], 0);
1532: /* Block Length */
1533: DSET32(&cp[12], (uint32_t) spec->blocklen);
1534: } else {
1535: /* Number of Blocks */
1536: DSET64(&cp[0], 0ULL);
1537: /* Reserved */
1538: DSET32(&cp[8], 0);
1539: /* Block Length */
1540: DSET32(&cp[12], 0);
1541: }
1542: len = 16;
1543: } else {
1544: if (spec->mload) {
1545: /* Number of Blocks */
1546: if (spec->blockcnt > 0xffffffffULL) {
1547: DSET32(&cp[0], 0xffffffffUL);
1548: } else {
1549: DSET32(&cp[0], (uint32_t) spec->blockcnt);
1550: }
1551: /* Block Length */
1552: DSET32(&cp[4], (uint32_t) spec->blocklen);
1553: } else {
1554: /* Number of Blocks */
1555: DSET32(&cp[0], 0);
1556: /* Block Length */
1557: DSET32(&cp[4], 0);
1558: }
1559: len = 8;
1560: }
1561: cp += len;
1562: }
1563: DSET16(&data[6], len); /* Block Descripter Length */
1564:
1565: plen = istgt_lu_dvd_scsi_mode_sense_page(spec, conn, cdb, pc, page, subpage, &cp[0], alloc_len);
1.1.1.2 misho 1566: if (plen < 0) {
1567: return -1;
1568: }
1.1 misho 1569: cp += plen;
1570:
1571: total = hlen + len + plen;
1572: DSET16(&data[0], total - 2); /* Mode Data Length */
1573:
1574: return total;
1575: }
1576:
1577: static int
1578: istgt_lu_dvd_transfer_data(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint8_t *buf, size_t bufsize, size_t len)
1579: {
1580: int rc;
1581:
1582: if (len > bufsize) {
1.1.1.2 misho 1583: ISTGT_ERRLOG("bufsize(%zd) too small\n", bufsize);
1.1 misho 1584: return -1;
1585: }
1586: rc = istgt_iscsi_transfer_out(conn, lu_cmd, buf, bufsize, len);
1587: if (rc < 0) {
1588: ISTGT_ERRLOG("iscsi_transfer_out()\n");
1589: return -1;
1590: }
1591: return 0;
1592: }
1593:
1594: static int
1595: 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)
1596: {
1.1.1.2 misho 1597: size_t hlen, plen;
1.1 misho 1598: int ps, spf, page, subpage;
1599: int rc;
1600:
1601: if (pf == 0) {
1602: /* vendor specific */
1603: return 0;
1604: }
1605:
1606: if (len < 1)
1607: return 0;
1608: ps = BGET8(&data[0], 7);
1609: spf = BGET8(&data[0], 6);
1610: page = data[0] & 0x3f;
1611: if (spf) {
1612: /* Sub_page mode page format */
1613: hlen = 4;
1614: if (len < hlen)
1615: return 0;
1616: subpage = data[1];
1617:
1618: plen = DGET16(&data[2]);
1619: } else {
1620: /* Page_0 mode page format */
1621: hlen = 2;
1622: if (len < hlen)
1623: return 0;
1624: subpage = 0;
1625: plen = data[1];
1626: }
1627: plen += hlen;
1628: if (len < plen)
1629: return 0;
1630:
1631: #if 0
1632: printf("ps=%d, page=%2.2x, subpage=%2.2x\n", ps, page, subpage);
1633: #endif
1634: switch (page) {
1635: case 0x08:
1636: /* Caching */
1637: {
1638: int wce, rcd;
1639:
1640: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SELECT Caching\n");
1641: if (subpage != 0x00)
1642: break;
1643: if (plen != 0x12 + hlen) {
1644: /* unknown format */
1645: break;
1646: }
1647: wce = BGET8(&data[2], 2); /* WCE */
1648: rcd = BGET8(&data[2], 0); /* RCD */
1649:
1650: if (wce) {
1651: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SELECT Writeback cache enable\n");
1652: spec->write_cache = 1;
1653: } else {
1654: spec->write_cache = 0;
1655: }
1656: if (rcd) {
1657: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SELECT Read cache disable\n");
1658: spec->read_cache = 0;
1659: } else {
1660: spec->read_cache = 1;
1661: }
1662: }
1663: break;
1664: default:
1665: /* not supported */
1666: break;
1667: }
1668:
1669: len -= plen;
1670: if (len != 0) {
1671: rc = istgt_lu_dvd_scsi_mode_select_page(spec, conn, cdb, pf, sp, &data[plen], len);
1672: if (rc < 0) {
1673: return rc;
1674: }
1675: }
1676: return 0;
1677: }
1678:
1.1.1.2 misho 1679: #define FEATURE_DESCRIPTOR_INIT(B,L,FC) \
1680: do { \
1.1 misho 1681: memset((B), 0, (L)); \
1682: DSET16(&(B)[0], (FC)); \
1.1.1.2 misho 1683: (B)[3] = (L) - 4; \
1.1 misho 1684: } while (0)
1685:
1686: static int
1.1.1.2 misho 1687: 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 1688: {
1689: uint8_t *cp;
1690: int hlen = 0, len = 0, plen;
1691:
1692: switch (fc) {
1693: case 0x0000:
1694: /* Profile List */
1695: plen = 2 * 4 + 4;
1696: FEATURE_DESCRIPTOR_INIT(data, plen, fc);
1697: /* Version(5-2) Persistent(1) Current(0) */
1698: BDSET8W(&data[2], 0, 5, 4);
1699: BSET8(&data[2], 1); /* Persistent=1 */
1700: BSET8(&data[2], 0); /* Current=1 */
1701: hlen = 4;
1702:
1703: /* Profile Descriptor */
1704: cp = &data[hlen + len];
1705: /* Profile 1 (CDROM) */
1706: DSET16(&cp[0], 0x0008);
1707: if (spec->profile == MM_PROF_CDROM) {
1708: BSET8(&cp[2], 0); /* CurrentP(0)=1 */
1709: }
1710: plen = 4;
1711: len += plen;
1712:
1713: cp = &data[hlen + len];
1714: /* Profile 2 (DVDROM) */
1715: DSET16(&cp[0], 0x0010);
1716: if (spec->profile == MM_PROF_DVDROM) {
1717: BSET8(&cp[2], 0); /* CurrentP(0)=1 */
1718: }
1719: plen = 4;
1720: len += plen;
1721: break;
1722:
1723: case 0x0001:
1724: /* Core Feature */
1725: /* GET CONFIGURATION/GET EVENT STATUS NOTIFICATION/INQUIRY */
1726: /* MODE SELECT (10)/MODE SENSE (10)/REQUEST SENSE/TEST UNIT READY */
1727: plen = 8 + 4;
1728: FEATURE_DESCRIPTOR_INIT(data, plen, fc);
1729: /* Version(5-2) Persistent(1) Current(0) */
1.1.1.2 misho 1730: BDSET8W(&data[2], 0x01, 5, 4); /* MMC4 */
1.1 misho 1731: BSET8(&data[2], 1); /* Persistent=1 */
1732: BSET8(&data[2], 0); /* Current=1 */
1733: hlen = 4;
1734:
1735: /* Physical Interface Standard */
1.1.1.2 misho 1736: DSET32(&data[4], 0x00000000); /* Unspecified */
1.1 misho 1737: /* DBE(0) */
1738: BCLR8(&data[8], 0); /* DBE=0*/
1739: len = 8;
1740: break;
1741:
1742: case 0x0003:
1743: /* Removable Medium */
1744: /* MECHANISM STATUS/PREVENT ALLOW MEDIUM REMOVAL/START STOP UNIT */
1745: plen = 0x04 + 4;
1746: FEATURE_DESCRIPTOR_INIT(data, plen, fc);
1747: /* Version(5-2) Persistent(1) Current(0) */
1748: BDSET8W(&data[2], 0x01, 5, 4);
1749: BSET8(&data[2], 1); /* Persistent=1 */
1750: BSET8(&data[2], 0); /* Current=1 */
1751: hlen = 4;
1752:
1753: /* Loading Mechanism Type(7-5) Eject(3) Pvnt Jmpr(2) Lock(0) */
1754: BDSET8W(&data[4], 0x01, 7, 3); /* Tray type loading mechanism */
1755: BSET8(&data[4], 3); /* eject via START/STOP YES */
1756: BSET8(&data[4], 0); /* locking YES */
1757: len = 8;
1758: break;
1759:
1760: case 0x0010:
1761: /* Random Readable */
1762: /* READ CAPACITY/READ (10) */
1763: plen = 4 + 4;
1764: FEATURE_DESCRIPTOR_INIT(data, plen, fc);
1765: /* Version(5-2) Persistent(1) Current(0) */
1766: BDSET8W(&data[2], 0x00, 5, 4);
1767: BSET8(&data[2], 1); /* Persistent=1 */
1768: BSET8(&data[2], 0); /* Current=1 */
1769: hlen = 4;
1770:
1771: /* Logical Block Size */
1772: DSET32(&data[4], (uint32_t) spec->blocklen);
1773: /* Blocking */
1774: DSET16(&data[8], 1);
1775: /* PP(0) */
1.1.1.2 misho 1776: BCLR8(&data[10], 0); /* PP=0 */
1.1 misho 1777: len = 4;
1778: break;
1779:
1780: case 0x001d:
1781: /* Multi-Read Feature */
1782: /* READ (10)/READ CD/READ DISC INFORMATION/READ TRACK INFORMATION */
1783: plen = 4;
1784: FEATURE_DESCRIPTOR_INIT(data, plen, fc);
1785: /* Version(5-2) Persistent(1) Current(0) */
1786: BDSET8W(&data[2], 0x00, 5, 4);
1787: BSET8(&data[2], 1); /* Persistent=1 */
1788: BSET8(&data[2], 0); /* Current=1 */
1789: hlen = 4;
1790: len = 0;
1791: break;
1792:
1793: case 0x001e:
1794: /* CD Read */
1795: /* READ CD/READ CD MSF/READ TOC/PMA/ATIP */
1796: plen = 4 + 4;
1797: FEATURE_DESCRIPTOR_INIT(data, plen, fc);
1798: /* Version(5-2) Persistent(1) Current(0) */
1799: BDSET8W(&data[2], 0x02, 5, 4); /* MMC4 */
1800: BCLR8(&data[2], 1); /* Persistent=0 */
1801: if (spec->profile == MM_PROF_CDROM) {
1802: BSET8(&data[2], 0); /* Current=1 */
1803: } else {
1804: BCLR8(&data[2], 0); /* Current=0 */
1805: }
1806: hlen = 4;
1807:
1808: /* DAP(7) C2 Flags(1) CD-Text(0) */
1809: BCLR8(&data[4], 7); /* not support DAP */
1810: BCLR8(&data[4], 1); /* not support C2 */
1811: BCLR8(&data[4], 0); /* not support CD-Text */
1812: len = 4;
1813: break;
1814:
1815: case 0x001f:
1816: /* DVD Read */
1817: /* READ (10)/READ (12)/READ DVD STRUCTURE/READ TOC/PMA/ATIP */
1818: plen = 4;
1819: FEATURE_DESCRIPTOR_INIT(data, plen, fc);
1820: /* Version(5-2) Persistent(1) Current(0) */
1821: BDSET8W(&data[2], 0x00, 5, 4);
1822: BCLR8(&data[2], 1); /* Persistent=0 */
1823: if (spec->profile == MM_PROF_DVDROM) {
1824: BSET8(&data[2], 0); /* Current=1 */
1825: } else {
1826: BCLR8(&data[2], 0); /* Current=0 */
1827: }
1828: hlen = 4;
1829: len = 0;
1830: break;
1831:
1832: default:
1833: /* not supported */
1834: break;
1835: }
1836:
1837: return hlen + len;
1838: }
1839:
1840: static int
1841: istgt_lu_dvd_scsi_get_configuration(ISTGT_LU_DVD *spec, CONN_Ptr conn, uint8_t *cdb, int rt, int sfn, uint8_t *data)
1842: {
1843: uint8_t *cp;
1844: int hlen = 0, len = 0, plen;
1845: int fc;
1846:
1847: /* Feature Header */
1848: /* Data Length */
1849: DSET32(&data[0], 0);
1850: /* Reserved */
1851: data[4] = 0;
1852: /* Reserved */
1853: data[5] = 0;
1854: /* Current Profile */
1855: DSET16(&data[6], spec->profile);
1856: hlen = 8;
1857:
1858: cp = &data[hlen];
1859: switch (rt) {
1860: case 0x00:
1861: /* all of features */
1862: for (fc = sfn; fc < 0xffff; fc++) {
1863: plen = istgt_lu_dvd_get_feature_descriptor(spec, conn, cdb, fc, &cp[len]);
1864: len += plen;
1865: }
1866: break;
1867:
1868: case 0x01:
1869: /* current of features */
1870: for (fc = sfn; fc < 0xffff; fc++) {
1871: plen = istgt_lu_dvd_get_feature_descriptor(spec, conn, cdb, fc, &cp[len]);
1872: if (BGET8(&cp[2], 0) == 1) {
1873: len += plen;
1874: } else {
1875: /* drop non active descriptors */
1876: }
1877: }
1878: break;
1879:
1880: case 0x02:
1881: /* specified feature */
1882: fc = sfn;
1883: plen = istgt_lu_dvd_get_feature_descriptor(spec, conn, cdb, fc, &cp[len]);
1884: len += plen;
1885: break;
1886:
1887: default:
1888: /* not supported */
1889: break;
1890: }
1891:
1892: /* Data Length */
1893: DSET32(&data[0], len);
1894:
1895: return hlen + len;
1896: }
1897:
1898: static int
1.1.1.2 misho 1899: 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 1900: {
1901: uint8_t *cp;
1902: int hlen = 0, len = 0;
1903:
1904: /* Event Descriptor Length */
1905: DSET16(&data[0], 0);
1906: /* NEA(7) Notification Class(2-0) */
1907: data[2] = 0;
1908: /* Supported Event Classes */
1909: data[3] = 0x7e;
1910: hlen = 4;
1911:
1912: cp = &data[hlen];
1913: /* Lowest class number has highest priority */
1914: if (ncr & (1 << 0)) {
1915: /* Reserved */
1916: len = 0;
1917: }
1918: if (ncr & (1 << 1)) {
1919: /* Operational Change */
1.1.1.2 misho 1920: BDSET8W(&data[2], 0x01, 2, 3); /* Notification Class */
1.1 misho 1921: /* Event Code */
1.1.1.2 misho 1922: BDSET8W(&cp[0], 0x00, 3, 4); /* NoChg */
1.1 misho 1923: /* Persistent Prevented(7) Operational Status(3-0) */
1924: BDSET8(&cp[1], 0, 7); /* not prevented */
1925: BDADD8W(&cp[1], 0, 3, 4);
1926: /* Operational Change */
1927: DSET16(&cp[2], 0x00); /* NoChg */
1928: len = 4;
1929: goto event_available;
1930: }
1931: if (ncr & (1 << 2)) {
1932: /* Power Management */
1.1.1.2 misho 1933: BDSET8W(&data[2], 0x02, 2, 3); /* Notification Class */
1.1 misho 1934: /* Event Code */
1.1.1.2 misho 1935: BDSET8W(&cp[0], 0x00, 3, 4); /* NoChg */
1.1 misho 1936: /* Power Status */
1.1.1.2 misho 1937: cp[1] = 0x01; /* Active */
1.1 misho 1938: /* Reserved */
1939: cp[2] = 0;
1940: /* Reserved */
1941: cp[3] = 0;
1942: len = 4;
1943: goto event_available;
1944: }
1945: if (ncr & (1 << 3)) {
1946: /* External Request */
1.1.1.2 misho 1947: BDSET8W(&data[2], 0x03, 2, 3); /* Notification Class */
1.1 misho 1948: /* Event Code */
1.1.1.2 misho 1949: BDSET8W(&cp[0], 0x00, 3, 4); /* NoChg */
1.1 misho 1950: /* Persistent Prevented(7) External Request Status(3-0) */
1951: BDSET8(&cp[1], 0, 7); /* not prevented */
1952: BDADD8W(&cp[1], 0, 3, 4); /* Ready */
1953: /* External Request */
1954: DSET16(&cp[2], 0x00); /* No Request */
1955: len = 4;
1956: goto event_available;
1957: }
1958: if (ncr & (1 << 4)) {
1959: /* Media */
1.1.1.2 misho 1960: BDSET8W(&data[2], 0x04, 2, 3); /* Notification Class */
1.1 misho 1961: if (spec->mchanged) {
1962: if (spec->mwait > 0) {
1963: spec->mwait--;
1964: } else {
1965: spec->mchanged = 0;
1966: spec->mload = 1;
1967: }
1968: if (spec->mload) {
1969: /* Event Code */
1970: BDSET8W(&cp[0], 0x02, 3, 4); /* NewMedia */
1971: /* Media Status */
1972: /* Media Present(1) Door or Tray open(0) */
1.1.1.2 misho 1973: BDSET8(&cp[1], 1, 1); /* media present */
1974: BDADD8(&cp[1], 0, 0); /* tray close */
1.1 misho 1975: } else {
1976: /* Event Code */
1977: BDSET8W(&cp[0], 0x03, 3, 4); /* MediaRemoval */
1978: /* Media Status */
1979: /* Media Present(1) Door or Tray open(0) */
1.1.1.2 misho 1980: BDSET8(&cp[1], 0, 1); /* media absent */
1981: BDADD8(&cp[1], 1, 0); /* tray open */
1.1 misho 1982: }
1983: } else {
1984: if (spec->mwait > 0) {
1985: spec->mwait--;
1986: /* Event Code */
1987: BDSET8W(&cp[0], 0x01, 3, 4); /* EjectRequest */
1988: /* Media Status */
1989: /* Media Present(1) Door or Tray open(0) */
1.1.1.2 misho 1990: BDSET8(&cp[1], 0, 1); /* media absent */
1991: BDADD8(&cp[1], 1, 0); /* tray open */
1.1 misho 1992: } else {
1993: if (spec->mload) {
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], 1, 1); /* media present */
1999: BDADD8(&cp[1], 0, 0); /* tray close */
1.1 misho 2000: } else {
2001: /* Event Code */
2002: BDSET8W(&cp[0], 0x00, 3, 4); /* NoChg */
2003: /* Media Status */
2004: /* Media Present(1) Door or Tray open(0) */
1.1.1.2 misho 2005: BDSET8(&cp[1], 0, 1); /* media absent */
2006: BDADD8(&cp[1], 0, 0); /* tray close */
1.1 misho 2007: }
2008: }
2009: }
2010: /* Start Slot */
2011: cp[2] = 0;
2012: /* End Slot */
2013: cp[3] = 0;
2014: len = 4;
2015: goto event_available;
2016: }
2017: if (ncr & (1 << 5)) {
2018: /* Multi-Initiator */
1.1.1.2 misho 2019: BDSET8W(&data[2], 0x05, 2, 3); /* Notification Class */
1.1 misho 2020: /* Event Code */
1.1.1.2 misho 2021: BDSET8W(&cp[0], 0x00, 3, 4); /* NoChg */
1.1 misho 2022: /* Persistent Prevented(7) Multiple Initiator Status(3-0) */
2023: BDSET8(&cp[1], 0, 7); /* not prevented */
2024: BDADD8W(&cp[1], 0, 3, 4); /* Ready */
2025: /* Multiple Initiator Priority */
2026: DSET16(&cp[2], 0x00); /* No Request */
2027: len = 4;
2028: goto event_available;
2029: }
2030: if (ncr & (1 << 6)) {
2031: /* Device Busy */
1.1.1.2 misho 2032: BDSET8W(&data[2], 0x06, 2, 3); /* Notification Class */
1.1 misho 2033: /* Event Code */
1.1.1.2 misho 2034: BDSET8W(&cp[0], 0x00, 3, 4); /* NoChg */
1.1 misho 2035: /* Media Status */
2036: /* Device Busy Status */
1.1.1.2 misho 2037: cp[1] = 0; /* Not Busy */
1.1 misho 2038: /* Time */
2039: DSET16(&cp[2], 0);
2040: len = 4;
2041: goto event_available;
2042: }
2043: if (ncr & (1 << 7)) {
2044: /* Reserved */
2045: len = 0;
2046: }
2047:
2048: if (len == 0) {
2049: /* No Event Available */
2050: BDSET8(&data[2], 0, 7); /* NEA=1 */
2051: }
2052:
2053: event_available:
2054: /* Event Descriptor Length */
2055: DSET16(&data[0], len + (hlen - 2));
2056:
2057: return hlen + len;
2058: }
2059:
2060: static int
1.1.1.2 misho 2061: 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 2062: {
2063: uint8_t *cp;
2064: int hlen = 0, len = 0, plen;
2065: int selected_slot = 0, max_slots = 1;
2066:
2067: /* Mechanism Status Header */
2068: /* Fault(7) Changer State(6-5) Current Slot(4-0) */
2069: BDSET8(&data[0], 0, 7);
1.1.1.2 misho 2070: BDADD8W(&data[0], 0x00, 6, 2); /* Ready */
1.1 misho 2071: BDADD8W(&data[0], (selected_slot & 0x1f), 4, 5); /* slot low bits */
2072: /* Mechanism State(7-5) Door open(4) Current Slot(2-0) */
2073: BDSET8W(&data[1], 0x00, 7, 3); /* Idle */
2074: BDADD8W(&data[1], (selected_slot & 0xe0) >> 5, 2, 3); /* slot high bits */
2075: /* Current LBA (Legacy) */
2076: DSET24(&data[2], 0);
2077: /* Number of Slots Available */
2078: data[5] = max_slots;
2079: /* Length of Slot Tables */
2080: DSET16(&data[6], 0);
2081: hlen = 8;
2082:
2083: /* Slot Tables */
2084: /* Slot 0 */
2085: cp = &data[hlen + len];
2086:
2087: if (spec->mchanged) {
2088: if (spec->mload) {
2089: /* Disc Present(7) Change(0) */
1.1.1.2 misho 2090: BDSET8(&cp[0], 1, 7); /* disc in slot */
1.1 misho 2091: } else {
2092: /* Disc Present(7) Change(0) */
1.1.1.2 misho 2093: BDSET8(&cp[0], 0, 7); /* no disc in slot */
1.1 misho 2094: }
1.1.1.2 misho 2095: BDADD8(&cp[0], 1, 0); /* disc changed */
1.1 misho 2096: } else {
2097: if (spec->mload) {
2098: /* Disc Present(7) Change(0) */
1.1.1.2 misho 2099: BDSET8(&cp[0], 1, 7); /* disc in slot */
1.1 misho 2100: } else {
2101: /* Disc Present(7) Change(0) */
1.1.1.2 misho 2102: BDSET8(&cp[0], 0, 7); /* no disc in slot */
1.1 misho 2103: }
1.1.1.2 misho 2104: BDADD8(&cp[0], 0, 0); /* disc not changed */
1.1 misho 2105: }
2106: /* CWP_V(1) CWP(0) */
2107: BDSET8(&cp[1], 0, 1); /* non Cartridge Write Protection */
2108: BDADD8(&cp[1], 0, 0); /* CWP=0 */
2109: /* Reserved */
2110: cp[2] = 0;
2111: /* Reserved */
2112: cp[3] = 0;
2113: plen = 4;
2114: len += plen;
2115:
2116: /* Length of Slot Tables */
2117: DSET16(&data[6], len);
2118:
2119: return hlen + len;
2120: }
2121:
2122: static int
1.1.1.2 misho 2123: 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 2124: {
2125: uint8_t *cp;
2126: int hlen = 0, len = 0, plen;
2127:
2128: switch (format) {
2129: case 0x00: /* Formatted TOC */
2130: /* TOC Data Length */
2131: DSET16(&data[0], 0);
2132: /* First Track Number */
2133: data[2] = 1;
2134: /* Last Track Number */
2135: data[3] = 1;
2136: hlen = 4;
2137:
2138: /* TOC Track Descriptor */
2139: /* Track 1 Descriptor */
2140: cp = &data[hlen + len];
2141:
2142: /* Reserved */
2143: cp[0] = 0;
2144: /* ADR(7-4) CONTROL(3-0) */
2145: cp[1] = 0x14;
2146: /* Track Number */
2147: cp[2] = 1;
2148: /* Reserved */
2149: cp[3] = 0;
2150: /* Track Start Address */
2151: if (msf) {
2152: DSET32(&cp[4], istgt_lba2msf(0));
2153: } else {
2154: DSET32(&cp[4], 0);
2155: }
2156: plen = 8;
2157: len += plen;
2158:
2159: /* Track AAh (Lead-out) Descriptor */
2160: cp = &data[hlen + len];
2161:
2162: /* Reserved */
2163: cp[0] = 0;
2164: /* ADR(7-4) CONTROL(3-0) */
2165: cp[1] = 0x14;
2166: /* Track Number */
2167: cp[2] = 0xaa;
2168: /* Reserved */
2169: cp[3] = 0;
2170: /* Track Start Address */
2171: if (msf) {
2172: DSET32(&cp[4], istgt_lba2msf(spec->blockcnt));
2173: } else {
2174: DSET32(&cp[4], spec->blockcnt);
2175: }
2176: plen = 8;
2177: len += plen;
2178:
2179: /* TOC Data Length */
2180: DSET16(&data[0], hlen + len - 2);
2181: break;
2182:
2183: case 0x01: /* Multi-session Information */
2184: /* TOC Data Length */
2185: DSET16(&data[0], 0);
2186: /* First Complete Session Number */
2187: data[2] = 1;
2188: /* Last Complete Session Number */
2189: data[3] = 1;
2190: hlen = 4;
2191:
2192: /* TOC Track Descriptor */
2193: cp = &data[hlen + len];
2194:
2195: /* Reserved */
2196: cp[0] = 0;
2197: /* ADR(7-4) CONTROL(3-0) */
2198: cp[1] = 0x14;
2199: /* First Track Number In Last Complete Session */
2200: cp[2] = 1;
2201: /* Reserved */
2202: cp[3] = 0;
2203: /* Start Address of First Track in Last Session */
2204: if (msf) {
2205: DSET32(&cp[4], istgt_lba2msf(0));
2206: } else {
2207: DSET32(&cp[4], 0);
2208: }
2209: len = 8;
2210:
2211: /* TOC Data Length */
2212: DSET16(&data[0], hlen + len - 2);
2213: break;
2214:
2215: case 0x02: /* Raw TOC */
2216: /* TOC Data Length */
2217: DSET16(&data[0], 0);
2218: /* First Complete Session Number */
2219: data[2] = 1;
2220: /* Last Complete Session Number */
2221: data[3] = 1;
2222: hlen = 4;
2223:
2224: /* TOC Track Descriptor */
2225: /* First Track number in the program area */
2226: cp = &data[hlen + len];
2227:
2228: /* Session Number */
2229: cp[0] = 1;
2230: /* ADR(7-4) CONTROL(3-0) */
2231: cp[1] = 0x14;
2232: /* TNO */
2233: cp[2] = 0;
2234: /* POINT */
2235: cp[3] = 0xa0;
2236: /* Min */
2237: cp[4] = 0;
2238: /* Sec */
2239: cp[5] = 0;
2240: /* Frame */
2241: cp[6] = 0;
2242: /* Zero */
2243: cp[7] = 0;
2244: /* PMIN / First Track Number */
2245: cp[8] = 1;
2246: /* PSEC / Disc Type */
2247: cp[9] = 0x00; /* CD-DA or CD Data with first track in Mode 1 */
2248: /* PFRAME */
2249: cp[10] = 0;
2250: plen = 11;
2251: len += plen;
2252:
2253: /* Last Track number in the program area */
2254: cp = &data[hlen + len];
2255:
2256: /* Session Number */
2257: cp[0] = 1;
2258: /* ADR(7-4) CONTROL(3-0) */
2259: cp[1] = 0x14;
2260: /* TNO */
2261: cp[2] = 0;
2262: /* POINT */
2263: cp[3] = 0xa1;
2264: /* Min */
2265: cp[4] = 0;
2266: /* Sec */
2267: cp[5] = 0;
2268: /* Frame */
2269: cp[6] = 0;
2270: /* Zero */
2271: cp[7] = 0;
2272: /* PMIN / Last Track Number */
2273: cp[8] = 1;
2274: /* PSEC */
2275: cp[9] = 0;
2276: /* PFRAME */
2277: cp[10] = 0;
2278: plen = 11;
2279: len += plen;
2280:
2281: /* Start location of the Lead-out area */
2282: cp = &data[hlen + len];
2283:
2284: /* Session Number */
2285: cp[0] = 1;
2286: /* ADR(7-4) CONTROL(3-0) */
2287: cp[1] = 0x14;
2288: /* TNO */
2289: cp[2] = 0;
2290: /* POINT */
2291: cp[3] = 0xa2;
2292: /* Min */
2293: cp[4] = 0;
2294: /* Sec */
2295: cp[5] = 0;
2296: /* Frame */
2297: cp[6] = 0;
2298: /* Zero */
2299: cp[7] = 0;
2300: /* PMIN / Start position of Lead-out */
2301: /* PSEC / Start position of Lead-out */
2302: /* PFRAME / Start position of Lead-out */
2303: if (msf) {
2304: DSET24(&cp[8], istgt_lba2msf(spec->blockcnt));
2305: } else {
2306: DSET24(&cp[8], spec->blockcnt);
2307: }
2308: plen = 11;
2309: len += plen;
2310:
2311: /* Track data */
2312: cp = &data[hlen + len];
2313:
2314: /* Session Number */
2315: cp[0] = 1;
2316: /* ADR(7-4) CONTROL(3-0) */
2317: cp[1] = 0x14;
2318: /* TNO */
2319: cp[2] = 0;
2320: /* POINT */
2321: cp[3] = 1;
2322: /* Min */
2323: cp[4] = 0;
2324: /* Sec */
2325: cp[5] = 0;
2326: /* Frame */
2327: cp[6] = 0;
2328: /* Zero */
2329: cp[7] = 0;
2330: /* PMIN / Start position of Lead-out */
2331: /* PSEC / Start position of Lead-out */
2332: /* PFRAME / Start position of Lead-out */
2333: if (msf) {
2334: DSET24(&cp[8], istgt_lba2msf(0));
2335: } else {
2336: DSET24(&cp[8], 0);
2337: }
2338: plen = 11;
2339: len += plen;
2340:
2341: /* TOC Data Length */
2342: DSET16(&data[0], hlen + len - 2);
2343: break;
2344:
2345: default:
2346: ISTGT_ERRLOG("unsupported format 0x%x\n", format);
2347: return -1;
2348: }
2349:
2350: return hlen + len;
2351: }
2352:
2353: static int
1.1.1.2 misho 2354: 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 2355: {
2356: int hlen = 0, len = 0;
2357:
2358: switch (datatype) {
2359: case 0x00: /* Disc Information Block */
2360: /* Disc Information Length */
2361: DSET16(&data[0], 0);
2362: hlen = 2;
2363:
2364: /* Disc Information Data Type(7-5) Erasable(4) */
2365: /* State of last Session(3-2) Disc Status(1-0) */
2366: BDSET8W(&data[2], datatype, 7, 3);
2367: BDADD8W(&data[2], 0, 4, 1);
1.1.1.2 misho 2368: BDADD8W(&data[2], 0x03, 3, 2); /* Complete Session */
2369: BDADD8W(&data[2], 0x02, 1, 2); /* Finalized Disc */
1.1 misho 2370: /* Number of First Track on Disc */
2371: data[3] = 1;
2372: /* Number of Sessions (Least Significant Byte) */
2373: data[4] = (1) & 0xff;
2374: /* First Track Number in Last Session (Least Significant Byte) */
2375: data[5] = (1) & 0xff;
2376: /* Last Track Number in Last Session (Least Significant Byte) */
2377: data[6] = (1) & 0xff;
2378: /* DID_V(7) DBC_V(6) URU(5) DAC_V(4) BG Format Status(1-0) */
2379: BDSET8(&data[7], 0, 7); /* Disc ID Valid */
2380: BDADD8(&data[7], 0, 6); /* Disc Bar Code Valid */
2381: BDADD8(&data[7], 1, 5); /* Unrestricted Use Disc */
2382: BDADD8(&data[7], 0, 4); /* Disc Application Code Valid */
2383: BDADD8W(&data[7], 0, 1, 2); /* BG Format Status */
2384: /* Disc Type */
1.1.1.2 misho 2385: data[8] = 0x00; /* CD-DA or CD-ROM Disc */
1.1 misho 2386: /* Number of Sessions (Most Significant Byte) */
2387: data[9] = (1 >> 8) & 0xff;
2388: /* First Track Number in Last Session (Most Significant Byte) */
2389: data[10] = (1 >> 8) & 0xff;
2390: /* Last Track Number in Last Session (Most Significant Byte) */
2391: data[11] = (1 >> 8) & 0xff;
2392: /* Disc Identification */
2393: DSET32(&data[12], 0);
2394: /* Last Session Lead-in Start Address */
2395: DSET32(&data[16], 0);
2396: /* Last Possible Lead-out Start Address */
2397: DSET32(&data[20], 0);
2398: /* Disc Bar Code */
2399: memset(&data[24], 0, 8);
2400: /* Disc Application Code */
2401: data[32] = 0;
2402: /* Number of OPC Tables */
2403: data[33] = 0;
2404: /* OPC Table Entries */
2405: //data[34] = 0;
2406: len = 34 - hlen;
2407:
2408: /* Disc Information Length */
2409: DSET16(&data[0], len);
2410: break;
2411:
2412: case 0x01: /* Track Resources Information Block */
2413: /* Disc Information Length */
2414: DSET16(&data[0], 0);
2415: hlen = 2;
2416:
2417: /* Disc Information Data Type(7-5) */
2418: BDSET8W(&data[2], datatype, 7, 3);
2419: /* Reserved */
2420: data[3] = 0;
2421: /* Maximum possible number of the Tracks on the disc */
2422: DSET16(&data[4], 99);
2423: /* Number of the assigned Tracks on the disc */
2424: DSET16(&data[6], 1);
2425: /* Maximum possible number of appendable Tracks on the disc */
2426: DSET16(&data[8], 99);
2427: /* Current number of appendable Tracks on the disc */
2428: DSET16(&data[10], 99);
2429: len = 12 - hlen;
2430:
2431: /* Disc Information Length */
2432: DSET16(&data[0], len);
2433: break;
2434:
2435: case 0x02: /* POW Resources Information Block */
2436: /* Disc Information Length */
2437: DSET16(&data[0], 0);
2438: hlen = 2;
2439:
2440: /* Disc Information Data Type(7-5) */
2441: BDSET8W(&data[2], datatype, 7, 3);
2442: /* Reserved */
2443: data[3] = 0;
2444: /* Remaining POW Replacements */
2445: DSET32(&data[4], 0);
2446: /* Remaining POW Reallocation Map Entries */
2447: DSET32(&data[8], 0);
2448: /* Number of Remaining POW Updates */
2449: DSET32(&data[12], 0);
2450: len = 16 - hlen;
2451:
2452: /* Disc Information Length */
2453: DSET16(&data[0], len);
2454: break;
2455:
2456: default:
2457: ISTGT_ERRLOG("unsupported datatype 0x%x\n", datatype);
2458: return -1;
2459: }
2460:
2461: return hlen + len;
2462: }
2463:
2464: static int
1.1.1.2 misho 2465: 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 2466: {
2467: uint8_t *cp;
2468: int hlen = 0, len = 0;
2469:
2470: if (mediatype == 0x00) {
2471: /* DVD and HD DVD types */
2472: } else if (mediatype == 0x01) {
2473: /* BD */
2474: } else {
2475: /* Reserved */
2476: }
2477:
2478: switch (format) {
2479: case 0x00: /* Physical Format Information */
2480: /* Disc Structure Data Length */
2481: DSET16(&data[0], 0);
2482: /* Reserved */
2483: data[2] = 0;
2484: /* Reserved */
2485: data[3] = 0;
2486: hlen = 4;
2487:
2488: /* Physical Format Information */
2489: cp = &data[hlen + len];
2490:
2491: /* Disk Category(7-4) Part Version(3-0) */
1.1.1.2 misho 2492: BDSET8W(&cp[0], 0x00, 7, 4); /* DVD-ROM */
2493: BDADD8W(&cp[0], 0x01, 3, 4); /* part 1 */
1.1 misho 2494: /* Disc Size(7-4) Maximum Rate(0-3) */
1.1.1.2 misho 2495: BDSET8W(&cp[1], 0x00, 7, 4); /* 120mm */
2496: BDADD8W(&cp[1], 0x0f, 3, 4); /* Not Specified */
1.1 misho 2497: /* Number of Layers(6-5) Track(4) Layer Type(3-0) */
1.1.1.2 misho 2498: BDSET8W(&cp[2], 0x00, 6, 2); /* one layer */
2499: BDADD8W(&cp[2], 0x00, 4, 1); /* Parallel Track Path */
2500: BDADD8W(&cp[2], 0x00, 3, 4); /* embossed data */
1.1 misho 2501: /* Linear Density(7-4) Track Density(3-0) */
1.1.1.2 misho 2502: BDSET8W(&cp[3], 0x00, 7, 4); /* 0.267 um/bit */
2503: BDADD8W(&cp[3], 0x00, 3, 4); /* 0.74 um/track */
1.1 misho 2504: /* Starting Physical Sector Number of Data Area */
2505: DSET32(&cp[4], 0);
2506: /* End Physical Sector Number of Data Area */
2507: DSET32(&cp[8], spec->blockcnt - 1);
2508: /* End Physical Sector Number in Layer 0 */
2509: DSET32(&cp[12], spec->blockcnt - 1);
2510: /* BCA(7) */
2511: BDSET8(&cp[16], 0, 7);
2512: /* Media Specific */
2513: memset(&cp[17], 0, 2048 - 16);
2514: len = 2048;
2515:
2516: /* Disc Information Length */
2517: DSET16(&data[0], hlen + len - 2);
2518: break;
2519:
2520: case 0x01: /* DVD Copyright Information */
2521: /* Disc Structure Data Length */
2522: DSET16(&data[0], 0);
2523: /* Reserved */
2524: data[2] = 0;
2525: /* Reserved */
2526: data[3] = 0;
2527: hlen = 4;
2528:
2529: /* DVD Copyright Information */
2530: cp = &data[hlen + len];
2531:
2532: /* Copyright Protection System Type */
2533: cp[0] = 0x00;
1.1.1.2 misho 2534: //cp[0] = 0x01; /* CSS/CPPM */
1.1 misho 2535: /* Region Management Information */
2536: cp[1] = 0x00;
2537: //cp[1] = 0xff & ~(1 << (2 - 1)); /* 2=Japan */
2538: /* Reserved */
2539: cp[2] = 0;
2540: /* Reserved */
2541: cp[3] = 0;
2542: len = 4;
2543:
2544: /* Disc Information Length */
2545: DSET16(&data[0], hlen + len - 2);
2546: break;
2547:
2548: default:
2549: ISTGT_ERRLOG("unsupported format 0x%x\n", format);
2550: return -1;
2551: }
2552:
2553: return hlen + len;
2554: }
2555:
2556: static int
1.1.1.2 misho 2557: 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 2558: {
2559: uint8_t *cp;
2560: int hlen = 0, len = 0;
2561:
2562: if (keyclass == 0x00) {
2563: /* DVD CSS/CPPM or CPRM */
2564: } else {
2565: return -1;
2566: }
2567:
2568: switch (keyformat) {
2569: case 0x08: /* Report Drive region settings */
2570: /* REPORT KEY Data Length */
2571: DSET16(&data[0], 6);
2572: /* Reserved */
2573: data[2] = 0;
2574: /* Reserved */
2575: data[3] = 0;
2576: hlen = 4;
2577:
2578: /* RPC State */
2579: cp = &data[hlen + len];
2580:
2581: /* Type Code(7-6) # of Vendor Resets Available(5-3) */
2582: /* # of User Controlled Changes Available(2-0) */
2583: BDSET8W(&cp[0], 0x00, 7, 2); /* No Drive region setting */
2584: //BDSET8W(&cp[0], 0x01, 7, 2); /* Drive region is set */
2585: BDADD8W(&cp[0], 4, 5, 3); /* # of vendor */
2586: BDADD8W(&cp[0], 5, 2, 3); /* # of user */
2587: /* Region Mask */
2588: cp[1] = 0;
2589: //cp[1] = 0xff & ~(1 << (2 - 1)); /* 2=Japan */
2590: /* RPC Scheme */
2591: cp[2] = 0;
2592: //cp[2] = 0x01; /* RPC Phase II */
2593: /* Reserved */
2594: cp[3] = 0;
2595: len = 4;
2596:
2597: /* REPORT KEY Data Length */
2598: DSET16(&data[0], hlen + len - 2);
2599: break;
2600:
2601: case 0x00: /* AGID for CSS/CPPM */
2602: case 0x01: /* Challenge Key */
2603: case 0x02: /* KEY1 */
2604: case 0x04: /* TITLE KEY */
2605: case 0x05: /* ASF */
2606: case 0x11: /* AGID for CPRM */
2607: /* not supported */
2608: return -1;
2609:
2610: default:
2611: ISTGT_ERRLOG("unsupported keyformat 0x%x\n", keyformat);
2612: return -1;
2613: }
2614:
2615: return hlen + len;
2616: }
2617:
2618: static int
1.1.1.2 misho 2619: 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 2620: {
2621: uint8_t *data;
2622: uint64_t maxlba;
2623: uint64_t llen;
2624: uint64_t blen;
2625: uint64_t offset;
2626: uint64_t nbytes;
2627: int64_t rc;
2628:
2629: if (len == 0) {
2630: lu_cmd->data = NULL;
2631: lu_cmd->data_len = 0;
2632: return 0;
2633: }
2634:
2635: maxlba = spec->blockcnt;
2636: llen = (uint64_t) len;
2637: blen = spec->blocklen;
2638: offset = lba * blen;
2639: nbytes = llen * blen;
2640:
2641: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
1.1.1.2 misho 2642: "Read: max=%"PRIu64", lba=%"PRIu64", len=%u\n",
2643: maxlba, lba, len);
1.1 misho 2644:
2645: if (lba >= maxlba || llen > maxlba || lba > (maxlba - llen)) {
2646: ISTGT_ERRLOG("end of media\n");
2647: return -1;
2648: }
2649:
2650: if (nbytes > lu_cmd->iobufsize) {
1.1.1.2 misho 2651: ISTGT_ERRLOG("nbytes(%zu) > iobufsize(%zu)\n",
2652: (size_t) nbytes, lu_cmd->iobufsize);
1.1 misho 2653: return -1;
2654: }
2655: data = lu_cmd->iobuf;
2656:
2657: rc = istgt_lu_dvd_seek(spec, offset);
2658: if (rc < 0) {
2659: ISTGT_ERRLOG("lu_dvd_seek() failed\n");
2660: return -1;
2661: }
2662:
2663: rc = istgt_lu_dvd_read(spec, data, nbytes);
2664: if (rc < 0) {
2665: ISTGT_ERRLOG("lu_dvd_read() failed\n");
2666: return -1;
2667: }
2668: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "Read %"PRId64"/%"PRIu64" bytes\n",
1.1.1.2 misho 2669: rc, nbytes);
1.1 misho 2670:
2671: lu_cmd->data = data;
2672: lu_cmd->data_len = rc;
2673:
2674: return 0;
2675: }
2676:
2677: #if 0
2678: static int
2679: istgt_lu_dvd_lbwrite(ISTGT_LU_DVD *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint64_t lba, uint32_t len)
2680: {
2681: uint8_t *data;
2682: uint64_t maxlba;
2683: uint64_t llen;
2684: uint64_t blen;
2685: uint64_t offset;
2686: uint64_t nbytes;
2687: int64_t rc;
2688:
2689: if (len == 0) {
2690: lu_cmd->data_len = 0;
2691: return 0;
2692: }
2693:
2694: maxlba = spec->blockcnt;
2695: llen = (uint64_t) len;
2696: blen = spec->blocklen;
2697: offset = lba * blen;
2698: nbytes = llen * blen;
2699:
2700: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
1.1.1.2 misho 2701: "Write: max=%"PRIu64", lba=%"PRIu64", len=%u\n",
2702: maxlba, lba, len);
1.1 misho 2703:
2704: if (lba >= maxlba || llen > maxlba || lba > (maxlba - llen)) {
2705: ISTGT_ERRLOG("end of media\n");
2706: return -1;
2707: }
2708:
2709: if (nbytes > lu_cmd->iobufsize) {
2710: ISTGT_ERRLOG("nbytes(%u) > iobufsize(%u)\n",
1.1.1.2 misho 2711: nbytes, lu_cmd->iobufsize);
1.1 misho 2712: return -1;
2713: }
2714: data = lu_cmd->iobuf;
2715:
2716: rc = istgt_lu_dvd_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
1.1.1.2 misho 2717: lu_cmd->iobufsize, nbytes);
1.1 misho 2718: if (rc < 0) {
2719: ISTGT_ERRLOG("lu_dvd_transfer_data() failed\n");
2720: return -1;
2721: }
2722:
2723: if (spec->lu->readonly) {
2724: ISTGT_ERRLOG("LU%d: readonly unit\n", spec->lu->num);
2725: return -1;
2726: }
2727: if (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY) {
2728: ISTGT_ERRLOG("LU%d: readonly media\n", spec->lu->num);
2729: return -1;
2730: }
2731:
2732: rc = istgt_lu_dvd_seek(spec, offset);
2733: if (rc < 0) {
2734: ISTGT_ERRLOG("lu_dvd_seek() failed\n");
2735: return -1;
2736: }
2737:
2738: rc = istgt_lu_dvd_write(spec, data, nbytes);
2739: if (rc < 0 || rc != nbytes) {
2740: ISTGT_ERRLOG("lu_dvd_write() failed\n");
2741: return -1;
2742: }
2743: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "Wrote %"PRId64"/%"PRIu64" bytes\n",
1.1.1.2 misho 2744: rc, nbytes);
1.1 misho 2745:
2746: lu_cmd->data_len = rc;
2747:
2748: return 0;
2749: }
2750:
2751: static int
2752: istgt_lu_dvd_lbsync(ISTGT_LU_DVD *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint64_t lba, uint32_t len)
2753: {
2754: uint64_t maxlba;
2755: uint64_t llen;
2756: uint64_t blen;
2757: uint64_t offset;
2758: uint64_t nbytes;
2759: int64_t rc;
2760:
2761: if (len == 0) {
2762: return 0;
2763: }
2764:
2765: maxlba = spec->blockcnt;
2766: llen = (uint64_t) len;
2767: blen = spec->blocklen;
2768: offset = lba * blen;
2769: nbytes = llen * blen;
2770:
2771: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
1.1.1.2 misho 2772: "Sync: max=%"PRIu64", lba=%"PRIu64", len=%u\n",
2773: maxlba, lba, len);
1.1 misho 2774:
2775: if (lba >= maxlba || llen > maxlba || lba > (maxlba - llen)) {
2776: ISTGT_ERRLOG("end of media\n");
2777: return -1;
2778: }
2779:
2780: rc = istgt_lu_dvd_sync(spec, offset, nbytes);
2781: if (rc < 0) {
2782: ISTGT_ERRLOG("lu_dvd_sync() failed\n");
2783: return -1;
2784: }
2785:
2786: return 0;
2787: }
2788: #endif
2789:
2790: static int
1.1.1.2 misho 2791: istgt_lu_dvd_build_sense_data(ISTGT_LU_DVD *spec __attribute__((__unused__)), uint8_t *data, int sk, int asc, int ascq)
1.1 misho 2792: {
2793: int rc;
2794:
2795: rc = istgt_lu_scsi_build_sense_data(data, sk, asc, ascq);
2796: if (rc < 0) {
2797: return -1;
2798: }
2799: return rc;
2800: }
2801:
2802: static int
2803: istgt_lu_dvd_build_sense_media(ISTGT_LU_DVD *spec, uint8_t *data)
2804: {
2805: uint8_t *sense_data;
2806: int *sense_len;
2807: int data_len;
2808:
2809: sense_data = data;
2810: sense_len = &data_len;
2811: *sense_len = 0;
2812:
2813: if (!spec->mload && !spec->mchanged) {
2814: /* MEDIUM NOT PRESENT */
2815: BUILD_SENSE(NOT_READY, 0x3a, 0x00);
2816: return data_len;
2817: }
2818: if (spec->mchanged) {
2819: /* MEDIUM NOT PRESENT */
2820: BUILD_SENSE(NOT_READY, 0x3a, 0x00);
2821: return data_len;
2822: #if 0
2823: /* LOGICAL UNIT NOT READY, CAUSE NOT REPORTABLE */
2824: BUILD_SENSE(NOT_READY, 0x04, 0x00);
2825: return data_len;
2826: /* LOGICAL UNIT IS IN PROCESS OF BECOMING READY */
2827: BUILD_SENSE(NOT_READY, 0x04, 0x01);
2828: return data_len;
2829: #endif
2830: }
2831: return 0;
2832: }
2833:
2834: int
2835: istgt_lu_dvd_reset(ISTGT_LU_Ptr lu, int lun)
2836: {
2837: ISTGT_LU_DVD *spec;
2838: int flags;
2839: int rc;
2840:
2841: if (lu == NULL) {
2842: return -1;
2843: }
2844: if (lun >= lu->maxlun) {
2845: return -1;
2846: }
2847: if (lu->lun[lun].type == ISTGT_LU_LUN_TYPE_NONE) {
2848: return -1;
2849: }
2850: if (lu->lun[lun].type != ISTGT_LU_LUN_TYPE_REMOVABLE) {
2851: return -1;
2852: }
2853: spec = (ISTGT_LU_DVD *) lu->lun[lun].spec;
2854:
2855: if (spec->lock) {
2856: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "unlock by reset\n");
2857: spec->lock = 0;
2858: }
2859:
2860: /* re-open file */
2861: if (!spec->lu->readonly
2862: && !(spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
2863: rc = istgt_lu_dvd_sync(spec, 0, spec->size);
2864: if (rc < 0) {
2865: ISTGT_ERRLOG("LU%d: LUN%d: lu_dvd_sync() failed\n",
2866: lu->num, lun);
2867: /* ignore error */
2868: }
2869: }
2870: rc = istgt_lu_dvd_close(spec);
2871: if (rc < 0) {
2872: ISTGT_ERRLOG("LU%d: LUN%d: lu_dvd_close() failed\n",
2873: lu->num, lun);
2874: /* ignore error */
2875: }
2876: flags = (lu->readonly || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY))
2877: ? O_RDONLY : O_RDWR;
2878: rc = istgt_lu_dvd_open(spec, flags, 0666);
2879: if (rc < 0) {
2880: ISTGT_ERRLOG("LU%d: LUN%d: lu_dvd_open() failed\n",
2881: lu->num, lun);
2882: return -1;
2883: }
2884:
2885: return 0;
2886: }
2887:
2888: int
2889: istgt_lu_dvd_execute(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
2890: {
2891: ISTGT_LU_Ptr lu;
2892: ISTGT_LU_DVD *spec;
2893: uint8_t *data;
2894: uint8_t *cdb;
2895: uint64_t fmt_lun;
2896: uint64_t lun;
2897: uint64_t method;
2898: uint32_t allocation_len;
2899: int data_len;
2900: int data_alloc_len;
2901: uint64_t lba;
2902: uint32_t transfer_len;
2903: uint8_t *sense_data;
1.1.1.2 misho 2904: size_t *sense_len;
1.1 misho 2905: int rc;
2906:
2907: if (lu_cmd == NULL)
2908: return -1;
2909: lu = lu_cmd->lu;
2910: if (lu == NULL) {
2911: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
2912: return -1;
2913: }
2914: spec = NULL;
2915: cdb = lu_cmd->cdb;
2916: data = lu_cmd->data;
2917: data_alloc_len = lu_cmd->alloc_len;
2918: sense_data = lu_cmd->sense_data;
2919: sense_len = &lu_cmd->sense_data_len;
2920: *sense_len = 0;
2921:
2922: fmt_lun = lu_cmd->lun;
2923: method = (fmt_lun >> 62) & 0x03U;
2924: fmt_lun = fmt_lun >> 48;
2925: if (method == 0x00U) {
2926: lun = fmt_lun & 0x00ffU;
2927: } else if (method == 0x01U) {
2928: lun = fmt_lun & 0x3fffU;
2929: } else {
2930: lun = 0xffffU;
2931: }
1.1.1.2 misho 2932: if (lun >= (uint64_t) lu->maxlun) {
1.1 misho 2933: #ifdef ISTGT_TRACE_DVD
2934: ISTGT_ERRLOG("LU%d: LUN%4.4"PRIx64" invalid\n",
2935: lu->num, lun);
2936: #endif /* ISTGT_TRACE_DVD */
2937: if (cdb[0] == SPC_INQUIRY) {
2938: allocation_len = DGET16(&cdb[3]);
1.1.1.2 misho 2939: if (allocation_len > (size_t) data_alloc_len) {
1.1 misho 2940: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1.1.1.2 misho 2941: data_alloc_len);
1.1 misho 2942: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
2943: return -1;
2944: }
2945: memset(data, 0, allocation_len);
2946: /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
2947: BDSET8W(&data[0], 0x03, 7, 3);
2948: BDADD8W(&data[0], 0x1f, 4, 5);
2949: data_len = 96;
2950: memset(&data[1], 0, data_len - 1);
2951: /* ADDITIONAL LENGTH */
2952: data[4] = data_len - 5;
1.1.1.2 misho 2953: lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1 misho 2954: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
2955: return 0;
2956: } else {
2957: /* LOGICAL UNIT NOT SUPPORTED */
2958: BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00);
2959: lu_cmd->data_len = 0;
2960: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
2961: return 0;
2962: }
2963: }
2964: spec = (ISTGT_LU_DVD *) lu->lun[lun].spec;
2965: if (spec == NULL) {
2966: /* LOGICAL UNIT NOT SUPPORTED */
2967: BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00);
2968: lu_cmd->data_len = 0;
2969: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
2970: return 0;
2971: }
2972:
2973: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "SCSI OP=0x%x, LUN=0x%16.16"PRIx64"\n",
1.1.1.2 misho 2974: cdb[0], lu_cmd->lun);
1.1 misho 2975: #ifdef ISTGT_TRACE_DVD
2976: if (cdb[0] != SPC_TEST_UNIT_READY
2977: && cdb[0] != MMC_GET_EVENT_STATUS_NOTIFICATION) {
2978: istgt_scsi_dump_cdb(cdb);
2979: } else {
2980: istgt_scsi_dump_cdb(cdb);
2981: }
2982: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "mload=%d, mchanged=%d, mwait=%d\n", spec->mload, spec->mchanged, spec->mwait);
2983: #endif /* ISTGT_TRACE_DVD */
2984: switch (cdb[0]) {
2985: case SPC_INQUIRY:
2986: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "INQUIRY\n");
2987: if (lu_cmd->R_bit == 0) {
2988: ISTGT_ERRLOG("R_bit == 0\n");
2989: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
2990: return -1;
2991: }
2992: allocation_len = DGET16(&cdb[3]);
1.1.1.2 misho 2993: if (allocation_len > (size_t) data_alloc_len) {
1.1 misho 2994: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1.1.1.2 misho 2995: data_alloc_len);
1.1 misho 2996: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
2997: return -1;
2998: }
2999: memset(data, 0, allocation_len);
3000: data_len = istgt_lu_dvd_scsi_inquiry(spec, conn, cdb,
1.1.1.2 misho 3001: data, data_alloc_len);
1.1 misho 3002: if (data_len < 0) {
3003: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3004: break;
3005: }
3006: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "INQUIRY", data, data_len);
1.1.1.2 misho 3007: lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1 misho 3008: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3009: break;
3010:
3011: case SPC_REPORT_LUNS:
3012: {
3013: int sel;
3014:
3015: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "REPORT LUNS\n");
3016: if (lu_cmd->R_bit == 0) {
3017: ISTGT_ERRLOG("R_bit == 0\n");
3018: return -1;
3019: }
3020:
3021: sel = cdb[2];
3022: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "sel=%x\n", sel);
3023:
3024: allocation_len = DGET32(&cdb[6]);
1.1.1.2 misho 3025: if (allocation_len > (size_t) data_alloc_len) {
1.1 misho 3026: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1.1.1.2 misho 3027: data_alloc_len);
1.1 misho 3028: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3029: return -1;
3030: }
3031: if (allocation_len < 16) {
3032: /* INVALID FIELD IN CDB */
3033: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3034: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3035: break;
3036: }
3037: memset(data, 0, allocation_len);
3038: data_len = istgt_lu_dvd_scsi_report_luns(lu, conn, cdb, sel,
3039: data, data_alloc_len);
3040: if (data_len < 0) {
3041: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3042: break;
3043: }
3044: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "REPORT LUNS", data, data_len);
1.1.1.2 misho 3045: lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1 misho 3046: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3047: }
3048: break;
3049:
3050: case SPC_TEST_UNIT_READY:
3051: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "TEST_UNIT_READY\n");
3052: {
3053: data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
3054:
3055: /* media state change? */
3056: if (spec->mchanged) {
3057: /* wait OS polling */
3058: if (spec->mwait > 0) {
3059: spec->mwait--;
3060: } else {
3061: /* load new media */
3062: spec->mchanged = 0;
3063: spec->mload = 1;
3064: }
3065: }
3066:
3067: if (data_len != 0) {
3068: *sense_len = data_len;
3069: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3070: break;
3071: }
3072:
3073: /* OK media present */
3074: lu_cmd->data_len = 0;
3075: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3076: break;
3077: }
3078:
3079: case MMC_START_STOP_UNIT:
3080: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "START_STOP_UNIT\n");
3081: {
3082: int pc, fl, loej, start;
3083:
3084: pc = BGET8W(&cdb[4], 7, 4);
3085: fl = BGET8(&cdb[4], 2);
3086: loej = BGET8(&cdb[4], 1);
3087: start = BGET8(&cdb[4], 0);
3088:
3089: data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
3090: if (data_len != 0) {
3091: *sense_len = data_len;
3092: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3093: break;
3094: }
3095:
3096: if (!loej) {
3097: if (start) {
3098: /* start */
3099: } else {
3100: /* stop */
3101: }
3102: lu_cmd->data_len = 0;
3103: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3104: break;
3105: }
3106:
3107: /* loej=1 */
3108: if (start) {
3109: /* load disc */
3110: if (!spec->mload) {
3111: if (istgt_lu_dvd_load_media(spec) < 0) {
3112: ISTGT_ERRLOG("lu_dvd_load_media() failed\n");
3113: /* INTERNAL TARGET FAILURE */
3114: BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
3115: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3116: break;
3117: }
3118: /* OK load */
3119: }
3120: } else {
3121: /* eject */
3122: if (!spec->lock) {
3123: if (spec->mload) {
3124: if (istgt_lu_dvd_unload_media(spec) < 0) {
3125: ISTGT_ERRLOG("lu_dvd_unload_media() failed\n");
3126: /* INTERNAL TARGET FAILURE */
3127: BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
3128: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3129: break;
3130: }
3131: /* OK unload */
3132: }
3133: } else {
3134: /* MEDIUM REMOVAL PREVENTED */
3135: BUILD_SENSE(ILLEGAL_REQUEST, 0x53, 0x02);
3136: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3137: break;
3138: }
3139: }
3140:
3141: lu_cmd->data_len = 0;
3142: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3143: break;
3144: }
3145:
3146: case SPC_PREVENT_ALLOW_MEDIUM_REMOVAL:
3147: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "PREVENT_ALLOW_MEDIUM_REMOVAL\n");
3148: {
3149: int persistent, prevent;
3150:
3151: persistent = BGET8(&cdb[4], 1);
3152: prevent = BGET8(&cdb[4], 0);
3153:
3154: data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
3155: if (data_len != 0) {
3156: *sense_len = data_len;
3157: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3158: break;
3159: }
3160:
3161: if (persistent) {
3162: if (prevent) {
3163: /* Persistent Prevent */
3164: } else {
3165: /* Persistent Allow */
3166: }
3167: } else {
3168: if (prevent) {
3169: /* Locked */
3170: spec->lock = 1;
3171: } else {
3172: /* Unlocked */
3173: spec->lock = 0;
3174: }
3175: }
3176:
3177: lu_cmd->data_len = 0;
3178: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3179: break;
3180: }
3181:
3182: case MMC_READ_CAPACITY:
3183: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "READ_CAPACITY\n");
3184: if (lu_cmd->R_bit == 0) {
3185: ISTGT_ERRLOG("R_bit == 0\n");
3186: return -1;
3187: }
3188:
3189: data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
3190: if (data_len != 0) {
3191: *sense_len = data_len;
3192: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3193: break;
3194: }
3195:
3196: if (spec->blockcnt - 1 > 0xffffffffULL) {
3197: DSET32(&data[0], 0xffffffffUL);
3198: } else {
3199: DSET32(&data[0], (uint32_t) (spec->blockcnt - 1));
3200: }
3201: DSET32(&data[4], (uint32_t) spec->blocklen);
3202: data_len = 8;
3203: lu_cmd->data_len = data_len;
3204: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3205: break;
3206:
3207: case SPC_MODE_SELECT_6:
3208: {
3209: int pf, sp, pllen;
3210: int mdlen, mt, dsp, bdlen;
3211:
3212: pf = BGET8(&cdb[1], 4);
3213: sp = BGET8(&cdb[1], 0);
3214: pllen = cdb[4]; /* Parameter List Length */
3215:
3216: /* Data-Out */
3217: rc = istgt_lu_dvd_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
1.1.1.2 misho 3218: lu_cmd->iobufsize, pllen);
1.1 misho 3219: if (rc < 0) {
3220: ISTGT_ERRLOG("lu_dvd_transfer_data() failed\n");
3221: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3222: break;
3223: }
3224: #if 0
3225: istgt_dump("MODE SELECT(6)", lu_cmd->iobuf, pllen);
3226: #endif
3227: data = lu_cmd->iobuf;
3228: mdlen = data[0]; /* Mode Data Length */
3229: mt = data[1]; /* Medium Type */
3230: dsp = data[2]; /* Device-Specific Parameter */
3231: bdlen = data[3]; /* Block Descriptor Length */
3232:
3233: /* Short LBA mode parameter block descriptor */
3234: /* data[4]-data[7] Number of Blocks */
3235: /* data[8]-data[11] Block Length */
3236:
3237: /* page data */
3238: data_len = istgt_lu_dvd_scsi_mode_select_page(spec, conn, cdb, pf, sp, &data[4 + bdlen], pllen - (4 + bdlen));
3239: if (data_len != 0) {
3240: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3241: break;
3242: }
3243: lu_cmd->data_len = pllen;
3244: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3245: break;
3246: }
3247:
3248: case SPC_MODE_SELECT_10:
3249: {
3250: int pf, sp, pllen;
3251: int mdlen, mt, dsp, bdlen;
3252: int llba;
3253:
3254: pf = BGET8(&cdb[1], 4);
3255: sp = BGET8(&cdb[1], 0);
3256: pllen = DGET16(&cdb[7]); /* Parameter List Length */
3257:
3258: /* Data-Out */
3259: rc = istgt_lu_dvd_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
1.1.1.2 misho 3260: lu_cmd->iobufsize, pllen);
1.1 misho 3261: if (rc < 0) {
3262: ISTGT_ERRLOG("lu_dvd_transfer_data() failed\n");
3263: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3264: break;
3265: }
3266: #if 0
3267: istgt_dump("MODE SELECT(10)", lu_cmd->iobuf, pllen);
3268: #endif
3269: data = lu_cmd->iobuf;
3270: mdlen = DGET16(&data[0]); /* Mode Data Length */
3271: mt = data[2]; /* Medium Type */
3272: dsp = data[3]; /* Device-Specific Parameter */
3273: llba = BGET8(&data[4], 0); /* Long LBA */
3274: bdlen = DGET16(&data[6]); /* Block Descriptor Length */
3275:
3276: if (llba) {
3277: /* Long LBA mode parameter block descriptor */
3278: /* data[8]-data[15] Number of Blocks */
3279: /* data[16]-data[19] Reserved */
3280: /* data[20]-data[23] Block Length */
3281: } else {
3282: /* Short LBA mode parameter block descriptor */
3283: /* data[8]-data[11] Number of Blocks */
3284: /* data[12]-data[15] Block Length */
3285: }
3286:
3287: /* page data */
3288: data_len = istgt_lu_dvd_scsi_mode_select_page(spec, conn, cdb, pf, sp, &data[8 + bdlen], pllen - (8 + bdlen));
3289: if (data_len != 0) {
3290: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3291: break;
3292: }
3293: lu_cmd->data_len = pllen;
3294: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3295: break;
3296: }
3297:
3298: case SPC_MODE_SENSE_6:
3299: {
3300: int dbd, pc, page, subpage;
3301:
3302: if (lu_cmd->R_bit == 0) {
3303: ISTGT_ERRLOG("R_bit == 0\n");
3304: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3305: return -1;
3306: }
3307:
3308: dbd = BGET8(&cdb[1], 3);
3309: pc = BGET8W(&cdb[2], 7, 2);
3310: page = BGET8W(&cdb[2], 5, 6);
3311: subpage = cdb[3];
3312:
3313: allocation_len = cdb[4];
1.1.1.2 misho 3314: if (allocation_len > (size_t) data_alloc_len) {
1.1 misho 3315: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1.1.1.2 misho 3316: data_alloc_len);
1.1 misho 3317: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3318: return -1;
3319: }
3320: memset(data, 0, allocation_len);
3321:
3322: data_len = istgt_lu_dvd_scsi_mode_sense6(spec, conn, cdb, dbd, pc, page, subpage, data, data_alloc_len);
3323: if (data_len < 0) {
1.1.1.2 misho 3324: /* INVALID FIELD IN CDB */
3325: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
1.1 misho 3326: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3327: break;
3328: }
3329: #if 0
3330: istgt_dump("MODE SENSE(6)", data, data_len);
3331: #endif
1.1.1.2 misho 3332: lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1 misho 3333: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3334: break;
3335: }
3336:
3337: case SPC_MODE_SENSE_10:
3338: {
3339: int dbd, pc, page, subpage;
3340: int llbaa;
3341:
3342: if (lu_cmd->R_bit == 0) {
3343: ISTGT_ERRLOG("R_bit == 0\n");
3344: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3345: return -1;
3346: }
3347:
3348: llbaa = BGET8(&cdb[1], 4);
3349: dbd = BGET8(&cdb[1], 3);
3350: pc = BGET8W(&cdb[2], 7, 2);
3351: page = BGET8W(&cdb[2], 5, 6);
3352: subpage = cdb[3];
3353:
3354: allocation_len = DGET16(&cdb[7]);
1.1.1.2 misho 3355: if (allocation_len > (size_t) data_alloc_len) {
1.1 misho 3356: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1.1.1.2 misho 3357: data_alloc_len);
1.1 misho 3358: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3359: return -1;
3360: }
3361: memset(data, 0, allocation_len);
3362:
3363: data_len = istgt_lu_dvd_scsi_mode_sense10(spec, conn, cdb, llbaa, dbd, pc, page, subpage, data, data_alloc_len);
3364: if (data_len < 0) {
1.1.1.2 misho 3365: /* INVALID FIELD IN CDB */
3366: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
1.1 misho 3367: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3368: break;
3369: }
3370: #if 0
3371: istgt_dump("MODE SENSE(10)", data, data_len);
3372: #endif
1.1.1.2 misho 3373: lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1 misho 3374: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3375: break;
3376: }
3377:
3378: case SPC_LOG_SELECT:
3379: case SPC_LOG_SENSE:
3380: /* INVALID COMMAND OPERATION CODE */
3381: BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
3382: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3383: break;
3384:
3385: case SPC_REQUEST_SENSE:
3386: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "REQUEST_SENSE\n");
3387: {
3388: int desc;
3389: int sk, asc, ascq;
3390:
3391: if (lu_cmd->R_bit == 0) {
3392: ISTGT_ERRLOG("R_bit == 0\n");
3393: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3394: return -1;
3395: }
3396:
3397: desc = BGET8(&cdb[1], 0);
3398: if (desc != 0) {
3399: /* INVALID FIELD IN CDB */
3400: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3401: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3402: break;
3403: }
3404:
3405: data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
3406:
3407: /* media state change? */
3408: if (spec->mchanged) {
3409: /* wait OS polling */
3410: if (spec->mwait > 0) {
3411: spec->mwait--;
3412: } else {
3413: /* load new media */
3414: spec->mchanged = 0;
3415: spec->mload = 1;
3416: }
3417: }
3418:
3419: if (data_len != 0) {
3420: *sense_len = data_len;
3421: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3422: break;
3423: }
3424:
3425: allocation_len = cdb[4];
1.1.1.2 misho 3426: if (allocation_len > (size_t) data_alloc_len) {
1.1 misho 3427: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1.1.1.2 misho 3428: data_alloc_len);
1.1 misho 3429: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3430: return -1;
3431: }
3432: memset(data, 0, allocation_len);
3433:
3434: if (!spec->sense) {
3435: /* NO ADDITIONAL SENSE INFORMATION */
3436: sk = ISTGT_SCSI_SENSE_NO_SENSE;
3437: asc = 0x00;
3438: ascq = 0x00;
3439: } else {
3440: sk = (spec->sense >> 16) & 0xffU;
3441: asc = (spec->sense >> 8) & 0xffU;
3442: ascq = spec->sense & 0xffU;
3443: }
3444: data_len = istgt_lu_dvd_build_sense_data(spec, sense_data,
3445: sk, asc, ascq);
3446: if (data_len < 0 || data_len < 2) {
3447: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3448: break;
3449: }
3450: /* omit SenseLength */
3451: data_len -= 2;
3452: memcpy(data, sense_data + 2, data_len);
3453:
1.1.1.2 misho 3454: lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1 misho 3455: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3456: break;
3457: }
3458:
3459: case MMC_GET_CONFIGURATION:
3460: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "GET_CONFIGURATION\n");
3461: {
3462: int rt, sfn;
3463:
3464: if (lu_cmd->R_bit == 0) {
3465: ISTGT_ERRLOG("R_bit == 0\n");
3466: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3467: return -1;
3468: }
3469:
3470: rt = BGET8W(&cdb[1], 1, 2);
3471: sfn = DGET16(&cdb[2]);
3472:
3473: data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
3474: if (data_len != 0) {
3475: *sense_len = data_len;
3476: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3477: break;
3478: }
3479:
3480: allocation_len = DGET16(&cdb[7]);
1.1.1.2 misho 3481: if (allocation_len > (size_t) data_alloc_len) {
1.1 misho 3482: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1.1.1.2 misho 3483: data_alloc_len);
1.1 misho 3484: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3485: return -1;
3486: }
3487: memset(data, 0, allocation_len);
3488:
3489: data_len = istgt_lu_dvd_scsi_get_configuration(spec, conn, cdb, rt, sfn, data);
3490: if (data_len < 0) {
3491: /* INVALID FIELD IN CDB */
3492: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3493: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3494: break;
3495: }
1.1.1.2 misho 3496: lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1 misho 3497: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3498: break;
3499: }
3500:
3501: case MMC_GET_EVENT_STATUS_NOTIFICATION:
3502: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "GET_EVENT_STATUS_NOTIFICATION\n");
3503: {
3504: int polled, ncr;
3505: int keep = 0;
3506:
3507: if (lu_cmd->R_bit == 0) {
3508: ISTGT_ERRLOG("R_bit == 0\n");
3509: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3510: return -1;
3511: }
3512:
3513: polled = BGET8(&cdb[1], 0);
3514: ncr = cdb[4];
3515:
3516: allocation_len = DGET16(&cdb[7]);
1.1.1.2 misho 3517: if (allocation_len > (size_t) data_alloc_len) {
1.1 misho 3518: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1.1.1.2 misho 3519: data_alloc_len);
1.1 misho 3520: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3521: return -1;
3522: }
3523: memset(data, 0, allocation_len);
3524:
3525: if (!polled) {
3526: /* asynchronous operation */
3527: /* INVALID FIELD IN CDB */
3528: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3529: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3530: break;
3531: }
3532: if (allocation_len <= 4) {
3533: /* shall not clear any event */
3534: keep = 1;
3535: }
3536: data_len = istgt_lu_dvd_scsi_get_event_status_notification(spec, conn, cdb, keep, ncr, data);
3537: if (data_len < 0) {
3538: /* INVALID FIELD IN CDB */
3539: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3540: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3541: break;
3542: }
3543: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "EVENT", data, data_len);
1.1.1.2 misho 3544: lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1 misho 3545: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3546: break;
3547: }
3548:
3549: case MMC_GET_PERFORMANCE:
3550: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "GET_PERFORMANCE\n");
3551: {
3552: int dt, mnd, type;
3553:
3554: data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
3555: if (data_len != 0) {
3556: *sense_len = data_len;
3557: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3558: break;
3559: }
3560:
3561: dt = BGET8W(&cdb[1], 4, 5);
3562: lba = DGET32(&cdb[2]);
3563: mnd = DGET16(&cdb[8]);
3564: type = cdb[10];
3565:
3566: /* INVALID COMMAND OPERATION CODE */
3567: BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
3568: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3569: break;
3570: }
3571:
3572: case MMC_MECHANISM_STATUS:
3573: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MECHANISM_STATUS\n");
3574: {
3575: if (lu_cmd->R_bit == 0) {
3576: ISTGT_ERRLOG("R_bit == 0\n");
3577: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3578: return -1;
3579: }
3580:
3581: allocation_len = DGET16(&cdb[8]);
1.1.1.2 misho 3582: if (allocation_len > (size_t) data_alloc_len) {
1.1 misho 3583: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1.1.1.2 misho 3584: data_alloc_len);
1.1 misho 3585: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3586: return -1;
3587: }
3588: memset(data, 0, allocation_len);
3589:
3590: data_len = istgt_lu_dvd_scsi_mechanism_status(spec, conn, cdb, data);
3591: if (data_len < 0) {
3592: /* INVALID FIELD IN CDB */
3593: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3594: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3595: break;
3596: }
1.1.1.2 misho 3597: lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1 misho 3598: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3599: break;
3600: }
3601:
3602: case MMC_READ_TOC_PMA_ATIP:
3603: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "READ_TOC_PMA_ATIP\n");
3604: {
3605: int msf, format, track;
3606:
3607: if (lu_cmd->R_bit == 0) {
3608: ISTGT_ERRLOG("R_bit == 0\n");
3609: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3610: return -1;
3611: }
3612:
3613: data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
3614: if (data_len != 0) {
3615: *sense_len = data_len;
3616: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3617: break;
3618: }
3619:
3620: msf = BGET8(&cdb[1], 1);
3621: format = BGET8W(&cdb[2], 3, 4);
3622: track = cdb[6];
3623:
3624: allocation_len = DGET16(&cdb[7]);
1.1.1.2 misho 3625: if (allocation_len > (size_t) data_alloc_len) {
1.1 misho 3626: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1.1.1.2 misho 3627: data_alloc_len);
1.1 misho 3628: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3629: return -1;
3630: }
3631: memset(data, 0, allocation_len);
3632:
3633: data_len = istgt_lu_dvd_scsi_read_toc(spec, conn, cdb, msf, format, track, data);
3634: if (data_len < 0) {
3635: /* INVALID FIELD IN CDB */
3636: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3637: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3638: break;
3639: }
1.1.1.2 misho 3640: lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1 misho 3641: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3642: break;
3643: }
3644:
3645: case MMC_READ_DISC_INFORMATION:
3646: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "READ_DISC_INFORMATION\n");
3647: {
3648: int datatype;
3649:
3650: if (lu_cmd->R_bit == 0) {
3651: ISTGT_ERRLOG("R_bit == 0\n");
3652: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3653: return -1;
3654: }
3655:
3656: data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
3657: if (data_len != 0) {
3658: *sense_len = data_len;
3659: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3660: break;
3661: }
3662:
3663: datatype = BGET8W(&cdb[1], 2, 3);
3664:
3665: allocation_len = DGET16(&cdb[7]);
1.1.1.2 misho 3666: if (allocation_len > (size_t) data_alloc_len) {
1.1 misho 3667: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1.1.1.2 misho 3668: data_alloc_len);
1.1 misho 3669: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3670: return -1;
3671: }
3672: memset(data, 0, allocation_len);
3673:
3674: data_len = istgt_lu_dvd_scsi_read_disc_information(spec, conn, cdb, datatype, data);
3675: if (data_len < 0) {
3676: /* INVALID FIELD IN CDB */
3677: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3678: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3679: break;
3680: }
1.1.1.2 misho 3681: lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1 misho 3682: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3683: break;
3684: }
3685:
3686: case MMC_READ_DISC_STRUCTURE:
3687: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "READ_DISC_STRUCTURE\n");
3688: {
3689: int mediatype, layernumber, format, agid;
3690:
3691: if (lu_cmd->R_bit == 0) {
3692: ISTGT_ERRLOG("R_bit == 0\n");
3693: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3694: return -1;
3695: }
3696:
3697: data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
3698: if (data_len != 0) {
3699: *sense_len = data_len;
3700: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3701: break;
3702: }
3703:
3704: mediatype = BGET8W(&cdb[1], 3, 4);
3705: layernumber = cdb[6];
3706: format = cdb[7];
3707: agid = BGET8W(&cdb[10], 7, 2);
3708:
3709: allocation_len = DGET16(&cdb[8]);
1.1.1.2 misho 3710: if (allocation_len > (size_t) data_alloc_len) {
1.1 misho 3711: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1.1.1.2 misho 3712: data_alloc_len);
1.1 misho 3713: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3714: return -1;
3715: }
3716: memset(data, 0, allocation_len);
3717:
3718: data_len = istgt_lu_dvd_scsi_read_disc_structure(spec, conn, cdb, mediatype, layernumber, format, agid, data);
3719: if (data_len < 0) {
3720: /* INVALID FIELD IN CDB */
3721: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3722: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3723: break;
3724: }
1.1.1.2 misho 3725: lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1 misho 3726: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3727: break;
3728: }
3729:
3730: case MMC_READ_SUB_CHANNEL:
3731: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "READ_SUB_CHANNEL\n");
3732: {
3733: data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
3734: if (data_len != 0) {
3735: *sense_len = data_len;
3736: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3737: break;
3738: }
3739:
3740: /* INVALID COMMAND OPERATION CODE */
3741: BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
3742: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3743: break;
3744: }
3745:
3746: case MMC_REPORT_KEY:
3747: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "REPORT_KEY\n");
3748: {
3749: int keyclass, agid, keyformat;
3750:
3751: if (lu_cmd->R_bit == 0) {
3752: ISTGT_ERRLOG("R_bit == 0\n");
3753: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3754: return -1;
3755: }
3756:
3757: data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
3758: if (data_len != 0) {
3759: *sense_len = data_len;
3760: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3761: break;
3762: }
3763:
3764: keyclass = cdb[7];
3765: agid = BGET8W(&cdb[10], 7, 2);
3766: keyformat = BGET8W(&cdb[10], 5, 6);
3767:
3768: allocation_len = DGET16(&cdb[8]);
1.1.1.2 misho 3769: if (allocation_len > (size_t) data_alloc_len) {
1.1 misho 3770: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
1.1.1.2 misho 3771: data_alloc_len);
1.1 misho 3772: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3773: return -1;
3774: }
3775: memset(data, 0, allocation_len);
3776:
3777: data_len = istgt_lu_dvd_scsi_report_key(spec, conn, cdb, keyclass, agid, keyformat, data);
3778: if (data_len < 0) {
3779: /* INVALID FIELD IN CDB */
3780: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
3781: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3782: break;
3783: }
1.1.1.2 misho 3784: lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
1.1 misho 3785: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3786: break;
3787: }
3788:
3789: case MMC_SEND_KEY:
3790: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "SEND_KEY\n");
3791: {
3792: data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
3793: if (data_len != 0) {
3794: *sense_len = data_len;
3795: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3796: break;
3797: }
3798:
3799: /* INVALID COMMAND OPERATION CODE */
3800: BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
3801: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3802: break;
3803: }
3804:
3805: case MMC_READ_10:
3806: {
3807: int dpo, fua;
3808:
3809: if (lu_cmd->R_bit == 0) {
3810: ISTGT_ERRLOG("R_bit == 0\n");
3811: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3812: return -1;
3813: }
3814:
3815: data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
3816: if (data_len != 0) {
3817: *sense_len = data_len;
3818: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3819: break;
3820: }
3821:
3822: dpo = BGET8(&cdb[1], 4);
3823: fua = BGET8(&cdb[1], 3);
3824: lba = (uint64_t) DGET32(&cdb[2]);
3825: transfer_len = (uint32_t) DGET16(&cdb[7]);
3826: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
1.1.1.2 misho 3827: "READ_10(lba %"PRIu64", len %u blocks)\n",
3828: lba, transfer_len);
1.1 misho 3829: rc = istgt_lu_dvd_lbread(spec, conn, lu_cmd, lba, transfer_len);
3830: if (rc < 0) {
3831: ISTGT_ERRLOG("lu_dvd_lbread() failed\n");
3832: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3833: break;
3834: }
3835: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3836: break;
3837: }
3838:
3839: case MMC_READ_12:
3840: {
3841: int dpo, fua;
3842:
3843: if (lu_cmd->R_bit == 0) {
3844: ISTGT_ERRLOG("R_bit == 0\n");
3845: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3846: return -1;
3847: }
3848:
3849: data_len = istgt_lu_dvd_build_sense_media(spec, sense_data);
3850: if (data_len != 0) {
3851: *sense_len = data_len;
3852: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3853: break;
3854: }
3855:
3856: dpo = BGET8(&cdb[1], 4);
3857: fua = BGET8(&cdb[1], 3);
3858: lba = (uint64_t) DGET32(&cdb[2]);
3859: transfer_len = (uint32_t) DGET32(&cdb[6]);
3860: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
1.1.1.2 misho 3861: "READ_12(lba %"PRIu64", len %u blocks)\n",
3862: lba, transfer_len);
1.1 misho 3863: rc = istgt_lu_dvd_lbread(spec, conn, lu_cmd, lba, transfer_len);
3864: if (rc < 0) {
3865: ISTGT_ERRLOG("lu_dvd_lbread() failed\n");
3866: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3867: break;
3868: }
3869: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3870: break;
3871: }
3872:
3873: #if 0
3874: case MMC_WRITE_10:
3875: case MMC_WRITE_AND_VERIFY_10:
3876: case MMC_WRITE_12:
3877: case MMC_VERIFY_10:
3878: case MMC_SYNCHRONIZE_CACHE:
3879: /* INVALID COMMAND OPERATION CODE */
3880: BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
3881: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3882: break;
3883: #endif
3884:
3885: /* XXX TODO: fix */
3886: case SPC2_RELEASE_6:
3887: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RELEASE_6\n");
3888: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3889: break;
3890: case SPC2_RELEASE_10:
3891: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RELEASE_10\n");
3892: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3893: break;
3894: case SPC2_RESERVE_6:
3895: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RESERVE_6\n");
3896: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3897: break;
3898: case SPC2_RESERVE_10:
3899: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RESERVE_10\n");
3900: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
3901: break;
3902:
3903: default:
3904: ISTGT_ERRLOG("unsupported SCSI OP=0x%x\n", cdb[0]);
3905: /* INVALID COMMAND OPERATION CODE */
3906: BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
3907: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
3908: break;
3909: }
3910:
3911: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
1.1.1.2 misho 3912: "SCSI OP=0x%x, LUN=0x%16.16"PRIx64" status=0x%x,"
3913: " complete\n",
3914: cdb[0], lu_cmd->lun, lu_cmd->status);
1.1 misho 3915: return 0;
3916: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>