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