1 /*
2 * UAE - The Un*x Amiga Emulator
3 *
4 * SCSI tape emulation
5 *
6 * Copyright 2013 Toni Wilen
7 *
8 */
9 
10 #include "sysconfig.h"
11 #include "sysdeps.h"
12 
13 #include "options.h"
14 #include "filesys.h"
15 #include "scsi.h"
16 #include "blkdev.h"
17 #include "zfile.h"
18 #include "uae/memory.h"
19 #include "scsi.h"
20 #include "threaddep/thread.h"
21 #include "a2091.h"
22 #include "fsdb.h"
23 
24 int log_tapeemu = 1;
25 
26 #define TAPE_INDEX _T("index.tape")
27 
28 static struct scsi_data_tape *tapeunits[MAX_FILESYSTEM_UNITS];
29 
notape(struct scsi_data_tape * tape)30 static bool notape (struct scsi_data_tape *tape)
31 {
32 	return tape->tape_dir[0] == 0 || tape->nomedia;
33 }
34 
rl(uae_u8 * p)35 static int rl (uae_u8 *p)
36 {
37 	return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]);
38 }
wl(uae_u8 * p,int v)39 static void wl (uae_u8 *p, int v)
40 {
41 	p[0] = v >> 24;
42 	p[1] = v >> 16;
43 	p[2] = v >> 8;
44 	p[3] = v;
45 }
46 
tape_free(struct scsi_data_tape * tape)47 void tape_free (struct scsi_data_tape *tape)
48 {
49 	if (!tape)
50 		return;
51 	zfile_fclose (tape->zf);
52 	zfile_fclose (tape->index);
53 	zfile_closedir_archive (tape->zd);
54 	xfree(tape);
55 	for (int i = 0; i < MAX_FILESYSTEM_UNITS; i++) {
56 		if (tapeunits[i] == tape)
57 			tapeunits[i] = NULL;
58 	}
59 }
60 
tape_init(int unit,struct scsi_data_tape * tape,const TCHAR * tape_directory,bool readonly)61 static void tape_init (int unit, struct scsi_data_tape *tape, const TCHAR *tape_directory, bool readonly)
62 {
63 	TCHAR path[MAX_DPATH];
64 
65 	memset (tape, 0, sizeof (struct scsi_data_tape));
66 	_tcscpy (tape->tape_dir, tape_directory);
67 
68 	tape->blocksize = 512;
69 	tape->wp = readonly;
70 	tape->beom = -1;
71 	tape->nomedia = false;
72 	tape->unloaded = false;
73 
74 	if (my_existsdir (tape->tape_dir)) {
75 		tape->realdir = true;
76 	} else {
77 		tape->zd = zfile_opendir_archive (tape_directory, ZFD_ARCHIVE | ZFD_NORECURSE);
78 		if (!tape->zd)
79 			tape->nomedia = true;
80 	}
81 
82 	_tcscpy (path, tape_directory);
83 	_tcscat (path, FSDB_DIR_SEPARATOR_S);
84 	_tcscat (path, TAPE_INDEX);
85 	tape->index = zfile_fopen (path, _T("rb"), ZFD_NORMAL);
86 	if (tape->index)
87 		write_log (_T("TAPEEMU INDEX: '%s'\n"), path);
88 	tapeunits[unit] = tape;
89 }
90 
tape_alloc(int unitnum,const TCHAR * tape_directory,bool readonly)91 struct scsi_data_tape *tape_alloc (int unitnum, const TCHAR *tape_directory, bool readonly)
92 {
93 	struct scsi_data_tape *tape = xcalloc (struct scsi_data_tape, 1);
94 
95 	tape_init (unitnum, tape, tape_directory, readonly);
96 	return tape;
97 }
98 
tape_media_change(int unitnum,struct uaedev_config_info * ci)99 void tape_media_change (int unitnum, struct uaedev_config_info *ci)
100 {
101 	struct scsi_data_tape *tape = tapeunits[unitnum];
102 	if (!tape)
103 		return;
104 	tape_init (unitnum, tape, ci->rootdir, ci->readonly);
105 }
106 
tape_get_info(int unitnum,struct device_info * di)107 bool tape_get_info (int unitnum, struct device_info *di)
108 {
109 	struct scsi_data_tape *tape = tapeunits[unitnum];
110 	memset (di, 0, sizeof (struct device_info));
111 	if (!tape)
112 		return false;
113 	di->media_inserted = notape (tape) == false;
114 	_tcscpy (di->label, tape->tape_dir);
115 	return true;
116 }
117 
rewind(struct scsi_data_tape * tape)118 static void rewind (struct scsi_data_tape *tape)
119 {
120 	zfile_fclose (tape->zf);
121 	tape->zf = NULL;
122 	my_closedir (tape->od);
123 	tape->file_number = 0;
124 	tape->file_offset = 0;
125 	tape->od = NULL;
126 	tape->beom = -1;
127 	if (tape->index)
128 		zfile_fseek (tape->index, 0, SEEK_SET);
129 	if (tape->zd)
130 		zfile_resetdir_archive (tape->zd);
131 }
132 
erase(struct scsi_data_tape * tape)133 static void erase (struct scsi_data_tape *tape)
134 {
135 	struct my_opendir_s *od;
136 	if (!tape->realdir)
137 		return;
138 	rewind (tape);
139 	od = my_opendir (tape->tape_dir);
140 	if (od) {
141 		for (;;) {
142 			TCHAR path[MAX_DPATH], filename[MAX_DPATH];
143 			if (!my_readdir (od, filename))
144 				break;
145 			TCHAR *ext = _tcsrchr (filename, '.');
146 			if (ext && !_tcsicmp (ext, _T(".tape"))) {
147 				_stprintf (path, _T("%s%s%s"), tape->tape_dir, FSDB_DIR_SEPARATOR_S, filename);
148 				if (my_existsfile (path))
149 					my_unlink (path);
150 			}
151 		}
152 		my_closedir (od);
153 	}
154 }
155 
next_file(struct scsi_data_tape * tape)156 static bool next_file (struct scsi_data_tape *tape)
157 {
158 	zfile_fclose (tape->zf);
159 	tape->zf = NULL;
160 	tape->file_offset = 0;
161 	if (tape->index) {
162 		TCHAR path[MAX_DPATH];
163 		TCHAR name[256];
164 		name[0] = 0;
165 		zfile_fgets (name, sizeof name / sizeof (TCHAR), tape->index);
166 		my_trim (name);
167 		if (name[0] == 0)
168 			goto end;
169 		_tcscpy (path, tape->tape_dir);
170 		_tcscat (path, FSDB_DIR_SEPARATOR_S);
171 		_tcscat (path, name);
172 		tape->zf = zfile_fopen (path, _T("rb"), ZFD_NORMAL);
173 		write_log (_T("TAPEEMU: File '%s'\n"), path);
174 	} else if (tape->realdir) {
175 		TCHAR path[MAX_DPATH], filename[MAX_DPATH];
176 		if (tape->od == NULL)
177 			tape->od =  my_opendir (tape->tape_dir);
178 		if (!tape->od) {
179 			tape_free (tape);
180 			goto end;
181 		}
182 		for (;;) {
183 			if (!my_readdir (tape->od, filename))
184 				goto end;
185 			if (_tcsicmp (filename, TAPE_INDEX))
186 				continue;
187 			_stprintf (path, _T("%s%s%s"), tape->tape_dir, FSDB_DIR_SEPARATOR_S, filename);
188 			if (!my_existsfile (path))
189 				continue;
190 			tape->zf = zfile_fopen (path, _T("rb"), 0);
191 			if (!tape->zf)
192 				continue;
193 			break;
194 		}
195 		if (tape->zf)
196 			write_log (_T("TAPEEMU DIR: File '%s'\n"), zfile_getname (tape->zf));
197 	} else {
198 		tape->zf = zfile_readdir_archive_open (tape->zd, _T("rb"));
199 		if (tape->zf)
200 			write_log (_T("TAPEEMU ARC: File '%s'\n"), zfile_getname (tape->zf));
201 	}
202 	if (tape->zf) {
203 		tape->file_number++;
204 		return true;
205 	}
206 end:
207 	write_log (_T("TAPEEMU: end of tape\n"));
208 	tape->beom = 1;
209 	return false;
210 }
211 
tape_read(struct scsi_data_tape * tape,uae_u8 * scsi_data,int len,bool * eof)212 static int tape_read (struct scsi_data_tape *tape, uae_u8 *scsi_data, int len, bool *eof)
213 {
214 	int got;
215 
216 	*eof = false;
217 	if (tape->beom > 0) {
218 		*eof = true;
219 		return -1;
220 	}
221 
222 	if (!tape->zf) {
223 		rewind (tape);
224 		if (!next_file (tape))
225 			return -1;
226 	}
227 	zfile_fseek (tape->zf, tape->file_offset, SEEK_SET);
228 	got = zfile_fread (scsi_data, 1, len, tape->zf);
229 	tape->file_offset += got;
230 	if (got < len) {
231 		*eof = true;
232 		next_file (tape);
233 	}
234 	return got;
235 }
236 
tape_write(struct scsi_data_tape * tape,uae_u8 * scsi_data,int len)237 static int tape_write (struct scsi_data_tape *tape, uae_u8 *scsi_data, int len)
238 {
239 	TCHAR path[MAX_DPATH], numname[30];
240 	int exists;
241 
242 	if (!tape->realdir)
243 		return -1;
244 	_stprintf (numname, _T("%05d.tape"), tape->file_number);
245 	_stprintf (path, _T("%s%s%s"), tape->tape_dir, FSDB_DIR_SEPARATOR_S, numname);
246 	exists = my_existsfile (path);
247 	struct zfile *zf = zfile_fopen (path, _T("a+b"));
248 	if (!zf)
249 		return -1;
250 	zfile_fseek (zf, 0, SEEK_END);
251 	len = zfile_fwrite (scsi_data, 1, len, zf);
252 	zfile_fclose (zf);
253 	if (!exists) {
254 		_stprintf (path, _T("%s%s%s"), tape->tape_dir, FSDB_DIR_SEPARATOR_S, TAPE_INDEX);
255 		zf = zfile_fopen (path, _T("a+b"));
256 		if (zf) {
257 			zfile_fputs (zf, numname);
258 			zfile_fputs (zf, _T("\n"));
259 		}
260 		zfile_fclose (zf);
261 	}
262 	return len;
263 }
264 
scsi_tape_emulate(struct scsi_data_tape * tape,uae_u8 * cmdbuf,int scsi_cmd_len,uae_u8 * scsi_data,int * data_len,uae_u8 * r,int * reply_len,uae_u8 * s,int * sense_len)265 int scsi_tape_emulate (struct scsi_data_tape *tape, uae_u8 *cmdbuf, int scsi_cmd_len,
266 	uae_u8 *scsi_data, int *data_len, uae_u8 *r, int *reply_len, uae_u8 *s, int *sense_len)
267 {
268 	uae_s64 len;
269 	int lr = 0, ls = 0;
270 	int scsi_len = -1;
271 	int status = 0;
272 	int lun;
273 	bool eof;
274 
275 	if (cmdbuf == NULL)
276 		return 0;
277 
278 	if (log_tapeemu)
279 		write_log (_T("TAPEEMU: %02X.%02X.%02X.%02X.%02X.%02X\n"),
280 		cmdbuf[0], cmdbuf[1], cmdbuf[2], cmdbuf[3], cmdbuf[4], cmdbuf[5]);
281 
282 	if (cmdbuf[0] == 3) {
283 		if (tape->beom == -1)
284 			s[9] |= 0x8; // beginning of media
285 		if (tape->beom == 1)
286 			s[2] |= 0x40; // end of media
287 		if (*sense_len < 0x12)
288 			*sense_len = 0x12;
289 		return 0;
290 	}
291 
292 	*reply_len = *sense_len = 0;
293 	memset (r, 0, 256);
294 	memset (s, 0, 256);
295 	s[0] = 0x70;
296 
297 	lun = cmdbuf[1] >> 5;
298 	if (cmdbuf[0] != 0x03 && cmdbuf[0] != 0x12 && lun) {
299 		status = 2; /* CHECK CONDITION */
300 		s[0] = 0x70;
301 		s[2] = 5; /* ILLEGAL REQUEST */
302 		s[12] = 0x25; /* INVALID LUN */
303 		ls = 0x12;
304 		goto end;
305 	}
306 
307 	switch (cmdbuf[0])
308 	{
309 	case 0x00: /* TEST UNIT READY */
310 		if (notape (tape))
311 			goto notape;
312 		if (tape->unloaded)
313 			goto unloaded;
314 		scsi_len = 0;
315 		break;
316 
317 	case 0x19: /* ERASE */
318 		if (log_tapeemu)
319 			write_log (_T("TAPEEMU ERASE\n"));
320 		if (notape (tape))
321 			goto notape;
322 		if (tape->unloaded)
323 			goto unloaded;
324 		if (tape->wp)
325 			goto writeprot;
326 		erase (tape);
327 		rewind (tape);
328 		tape->beom = 1;
329 		scsi_len = 0;
330 		break;
331 
332 	case 0x1b: /* LOAD/UNLOAD */
333 	{
334 		bool load = (cmdbuf[4] & 1) != 0;
335 		bool ret = (cmdbuf[4] & 2) != 0;
336 		bool eot = (cmdbuf[4] & 4) != 0;
337 		if (log_tapeemu)
338 			write_log (_T("TAPEEMU LOAD/UNLOAD %d:%d:%d\n"), eot, ret, load);
339 		if (notape (tape))
340 			goto notape;
341 		if (load && eot)
342 			goto errreq;
343 		rewind (tape);
344 		tape->unloaded = !load;
345 		if (eot) {
346 			tape->beom = 1;
347 		} else {
348 			tape->beom = -1;
349 		}
350 		scsi_len = 0;
351 		break;
352 	}
353 
354 	case 0x01: /* REWIND */
355 		if (log_tapeemu)
356 			write_log (_T("TAPEEMU: REWIND. IMMED=%d\n"), cmdbuf[1] & 1);
357 		if (notape (tape))
358 			goto notape;
359 		if (tape->unloaded)
360 			goto unloaded;
361 		rewind (tape);
362 		scsi_len = 0;
363 		break;
364 
365 	case 0x11: /* SPACE */
366 	{
367 		int code = cmdbuf[1] & 15;
368 		int count = rl (cmdbuf + 1) & 0xffffff;
369 		if (log_tapeemu)
370 			write_log (_T("TAPEEMU: SPACE code=%d count=%d\n"), code, count);
371 		if (notape (tape))
372 			goto notape;
373 		if (tape->unloaded)
374 			goto unloaded;
375 		if (code >= 2)
376 			goto errreq;
377 		if (code == 1) {
378 			if (!next_file (tape))
379 				goto endoftape;
380 		}
381 		scsi_len = 0;
382 	}
383 	break;
384 
385 	case 0x10: /* WRITE FILEMARK */
386 		len = rl (cmdbuf + 1) & 0xffffff;
387 		if (log_tapeemu)
388 			write_log (_T("TAPEEMU WRITE FILEMARK %lld\n"), len);
389 		if (notape (tape))
390 			goto notape;
391 		if (tape->unloaded)
392 			goto unloaded;
393 		if (tape->wp)
394 			goto writeprot;
395 		if (len > 0) {
396 			tape->file_number++;
397 			tape_write (tape, scsi_data, 0);
398 		}
399 		scsi_len = 0;
400 		break;
401 
402 	case 0x0a: /* WRITE (6) */
403 		len = rl (cmdbuf + 1) & 0xffffff;
404 		if (cmdbuf[1] & 1)
405 			len *= tape->blocksize;
406 		if (log_tapeemu)
407 			write_log (_T("TAPEEMU WRITE %lld (%d, %d)\n"), len, rl (cmdbuf + 1) & 0xffffff, cmdbuf[1] & 1);
408 		if (notape (tape))
409 			goto notape;
410 		if (tape->unloaded)
411 			goto unloaded;
412 		if (tape->wp)
413 			goto writeprot;
414 		if (tape->beom < 0)
415 			tape->beom = 0;
416 		scsi_len = tape_write (tape, scsi_data, len);
417 		if (scsi_len < 0)
418 			goto writeprot;
419 		break;
420 
421 	case 0x08: /* READ (6) */
422 		len = rl (cmdbuf + 1) & 0xffffff;
423 		if (cmdbuf[1] & 1)
424 			len *= tape->blocksize;
425 		if (log_tapeemu)
426 			write_log (_T("TAPEEMU READ %lld (%d, %d)\n"), len, rl (cmdbuf + 1) & 0xffffff, cmdbuf[1] & 1);
427 		if (notape (tape))
428 			goto notape;
429 		if (tape->unloaded)
430 			goto unloaded;
431 		if (tape->beom < 0)
432 			tape->beom = 0;
433 		scsi_len = tape_read (tape, scsi_data, len, &eof);
434 		if (log_tapeemu)
435 			write_log (_T("-> READ %d bytes\n"), scsi_len);
436 		if ((cmdbuf[1] & 1) && scsi_len > 0 && scsi_len < len) {
437 			int gap = tape->blocksize - (scsi_len & (tape->blocksize - 1));
438 			if (gap > 0 && gap < tape->blocksize)
439 				memset (scsi_data + scsi_len, 0, gap);
440 			scsi_len += tape->blocksize - 1;
441 			scsi_len &= ~(tape->blocksize - 1);
442 		}
443 		if (scsi_len < 0) {
444 			tape->beom = 2;
445 			status = SCSI_STATUS_CHECK_CONDITION;
446 			s[0] = 0x80 | 0x70;
447 			s[2] = 8; /* BLANK CHECK */
448 			if (cmdbuf[1] & 1)
449 				wl (&s[3], len / tape->blocksize);
450 			else
451 				wl (&s[3], len);
452 			s[12] = 0;
453 			s[13] = 2; /* End-of-partition/medium detected */
454 			ls = 0x12;
455 		} else if (eof) {
456 			status = SCSI_STATUS_CHECK_CONDITION;
457 			s[0] = 0x80 | 0x70; // Valid + code
458 			s[2] = 0x80 | 0; /* File Mark Detected + NO SENSE */
459 			if (cmdbuf[1] & 1)
460 				wl (&s[3], (len - scsi_len) / tape->blocksize);
461 			else
462 				wl (&s[3], len);
463 			s[12] = 0;
464 			s[13] = 1; /* File Mark detected */
465 			ls = 0x12;
466 			if (log_tapeemu)
467 				write_log (_T("TAPEEMU READ FILE END, %lld remaining\n"), len - scsi_len);
468 		}
469 	break;
470 
471 	case 0x5a: // MODE SENSE(10)
472 	case 0x1a: /* MODE SENSE(6) */
473 	{
474 		uae_u8 *p;
475 		int maxlen;
476 		bool sense10 = cmdbuf[0] == 0x5a;
477 		int totalsize, bdsize;
478 		int pc = cmdbuf[2] >> 6;
479 		int pcode = cmdbuf[2] & 0x3f;
480 		int dbd = cmdbuf[1] & 8;
481 		if (cmdbuf[0] == 0x5a)
482 			dbd = 1;
483 		if (log_tapeemu)
484 			write_log (_T("TAPEEMU MODE SENSE PC=%d CODE=%d DBD=%d\n"), pc, pcode, dbd);
485 		p = r;
486 		if (sense10) {
487 			totalsize = 8 - 2;
488 			maxlen = (cmdbuf[7] << 8) | cmdbuf[8];
489 			p[2] = 0;
490 			p[3] = 0;
491 			p[4] = 0;
492 			p[5] = 0;
493 			p[6] = 0;
494 			p[7] = 0;
495 			p += 8;
496 		} else {
497 			totalsize = 4 - 1;
498 			maxlen = cmdbuf[4];
499 			p[1] = 0;
500 			p[2] = tape->wp ? 0x80 : 0;
501 			p[3] = 0;
502 			p += 4;
503 		}
504 		bdsize = 0;
505 		if (!dbd) {
506 			wl(p + 0, 0);
507 			wl(p + 4, tape->blocksize);
508 			bdsize = 8;
509 			p += bdsize;
510 		}
511 		if (pcode)
512 			goto errreq;
513 		if (sense10) {
514 			totalsize += bdsize;
515 			r[6] = bdsize >> 8;
516 			r[7] = bdsize & 0xff;
517 			r[0] = totalsize >> 8;
518 			r[1] = totalsize & 0xff;
519 		} else {
520 			totalsize += bdsize;
521 			r[3] = bdsize & 0xff;
522 			r[0] = totalsize & 0xff;
523 		}
524 		lr = totalsize + 1;
525 		if (lr > maxlen)
526 			lr = maxlen;
527 	}
528 	break;
529 
530 	case 0x55: // MODE SELECT(10)
531 	case 0x15: // MODE SELECT(6)
532 	{
533 		uae_u8 *p;
534 		bool mode10 = cmdbuf[0] == 0x55;
535 		int nb = 0, bl = 512;
536 		p = scsi_data + 4;
537 		if (mode10)
538 			p += 4;
539 		if (scsi_data[3] >= 8) {
540 			nb = rl (p) & 0xffffff;
541 			bl = rl (p + 4) & 0xffffff;
542 		}
543 		if (log_tapeemu)
544 			write_log (_T("TAPEEMU MODE SELECT BUFM=%d BDL=%d Density=%d NB=%d BL=%d\n"), (scsi_data[2] & 0x10) != 0, scsi_data[3], p[0], nb, bl);
545 		if (nb || bl != 512)
546 			goto err;
547 		scsi_len = 0;
548 		break;
549 	}
550 
551 	case 0x05: /* READ BLOCK LIMITS */
552 		if (log_tapeemu)
553 			write_log (_T("TAPEEMU READ BLOCK LIMITS\n"));
554 		r[0] = 0;
555 		r[1] = 0;
556 		r[2] = 2; // 0x200 = 512
557 		r[3] = 0;
558 		r[4] = 2; // 0x200 = 512
559 		r[5] = 0;
560 		lr = 6;
561 	break;
562 
563 	case 0x16: /* RESERVE UNIT */
564 		if (log_tapeemu)
565 			write_log (_T("TAPEEMU RESERVE UNIT\n"));
566 		scsi_len = 0;
567 		break;
568 
569 	case 0x17: /* RELEASE UNIT */
570 		if (log_tapeemu)
571 			write_log (_T("TAPEEMU RELEASE UNIT\n"));
572 		scsi_len = 0;
573 		break;
574 
575 	case 0x1e: /* PREVENT/ALLOW MEDIUM REMOVAL */
576 		if (log_tapeemu)
577 			write_log (_T("TAPEEMU PREVENT/ALLOW MEDIUM REMOVAL\n"));
578 		scsi_len = 0;
579 		break;
580 
581 	case 0x12: /* INQUIRY */
582 	{
583 		if (log_tapeemu)
584 			write_log (_T("TAPEEMU INQUIRY\n"));
585 		if ((cmdbuf[1] & 1) || cmdbuf[2] != 0)
586 			goto err;
587 		len = cmdbuf[4];
588 		if (cmdbuf[1] >> 5) {
589 			r[0] = 0x7f;
590 		} else {
591 			r[0] = INQ_SEQD;
592 		}
593 		r[1] |= 0x80; // removable
594 		r[2] = 2; /* supports SCSI-2 */
595 		r[3] = 2; /* response data format */
596 		r[4] = 32; /* additional length */
597 		r[7] = 0;
598 		scsi_len = lr = len < 36 ? len : 36;
599 		r[2] = 2;
600 		r[3] = 2;
601 		char *s = ua (_T("UAE"));
602 		memcpy (r + 8, s, strlen (s));
603 		xfree (s);
604 		s = ua (_T("SCSI TAPE"));
605 		memcpy (r + 16, s, strlen (s));
606 		xfree (s);
607 		s = ua (_T("0.1"));
608 		memcpy (r + 32, s, strlen (s));
609 		xfree (s);
610 		for (int i = 8; i < 36; i++) {
611 			if (r[i] == 0)
612 				r[i] = 32;
613 		}
614 	}
615 	break;
616 	default:
617 		write_log (_T("TAPEEMU: unsupported scsi command 0x%02X\n"), cmdbuf[0]);
618 err:
619 		status = SCSI_STATUS_CHECK_CONDITION;
620 		s[0] = 0x70;
621 		s[2] = SCSI_SK_ILLEGAL_REQ;
622 		s[12] = SCSI_INVALID_COMMAND;
623 		ls = 0x12;
624 		break;
625 writeprot:
626 		status = 2; /* CHECK CONDITION */
627 		s[0] = 0x70;
628 		s[2] = 7; /* DATA PROTECT */
629 		s[12] = 0x27; /* WRITE PROTECTED */
630 		ls = 0x12;
631 		break;
632 errreq:
633 		lr = -1;
634 		status = SCSI_STATUS_CHECK_CONDITION;
635 		s[0] = 0x70;
636 		s[2] = SCSI_SK_ILLEGAL_REQ;
637 		s[12] = SCSI_INVALID_FIELD;
638 		ls = 0x12;
639 		break;
640 endoftape:
641 		status = SCSI_STATUS_CHECK_CONDITION;
642 		s[0] = 0x70;
643 		s[2] = SCSI_SK_MED_ERR;
644 		s[12] = 0;
645 		s[13] = 2; /* End-of-partition/medium detected */
646 		ls = 0x12;
647 		break;
648 unloaded:
649 		status = SCSI_STATUS_CHECK_CONDITION;
650 		s[0] = 0x70;
651 		s[2] = SCSI_SK_NOT_READY;
652 		s[12] = SCSI_NOT_READY;
653 		ls = 0x12;
654 		break;
655 notape:
656 		status = SCSI_STATUS_CHECK_CONDITION;
657 		s[0] = 0x70;
658 		s[2] = SCSI_SK_NOT_READY;
659 		s[12] = SCSI_MEDIUM_NOT_PRESENT;
660 		ls = 0x12;
661 		break;
662 	}
663 end:
664 	*data_len = scsi_len;
665 	*reply_len = lr;
666 	*sense_len = ls;
667 	if (lr > 0) {
668 		if (log_tapeemu) {
669 			write_log (_T("TAPEEMU REPLY: "));
670 			for (int i = 0; i < lr && i < 40; i++)
671 				write_log (_T("%02X."), r[i]);
672 			write_log (_T("\n"));
673 		}
674 	}
675 	if (ls > 0) {
676 		if (tape->beom == 1)
677 			s[2] |= 0x40;
678 		if (tape->beom == -1)
679 			s[9] |= 0x8;
680 		if (log_tapeemu) {
681 			write_log (_T("TAPEEMU SENSE: "));
682 			for (int i = 0; i < ls; i++)
683 				write_log (_T("%02X."), s[i]);
684 			write_log (_T("\n"));
685 		}
686 	}
687 	return status;
688 }
689