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