1 /*
2 * UAE - The Un*x Amiga Emulator
3 *
4 * scsi.device emulation
5 *
6 * Copyright 1995 Bernd Schmidt
7 * Copyright 1999 Patrick Ohly
8 * Copyright 2001 Brian King
9 * Copyright 2002 Toni Wilen
10 *
11 */
12 
13 #include "sysconfig.h"
14 #include "sysdeps.h"
15 
16 #ifdef SCSIEMU
17 
18 #include "threaddep/thread.h"
19 #include "options.h"
20 #include "uae/memory.h"
21 #include "custom.h"
22 #include "events.h"
23 #include "newcpu.h"
24 #include "autoconf.h"
25 #include "traps.h"
26 #include "execlib.h"
27 #include "native2amiga.h"
28 #include "blkdev.h"
29 #include "scsidev.h"
30 #include "uae.h"
31 #include "execio.h"
32 #include "savestate.h"
33 
34 #define CDDEV_COMMANDS
35 
36 #define UAEDEV_SCSI _T("uaescsi.device")
37 #define UAEDEV_SCSI_ID 1
38 #define UAEDEV_DISK _T("uaedisk.device")
39 #define UAEDEV_DISK_ID 2
40 
41 #define MAX_ASYNC_REQUESTS 20
42 #define MAX_OPEN_DEVICES 20
43 
44 #define ASYNC_REQUEST_NONE 0
45 #define ASYNC_REQUEST_TEMP 1
46 #define ASYNC_REQUEST_CHANGEINT 10
47 #define ASYNC_REQUEST_FRAMEINT 11
48 
49 struct devstruct {
50 	int unitnum, aunit;
51 	int opencnt;
52 	int changenum;
53 	int drivetype;
54 	int iscd;
55 	volatile uaecptr d_request[MAX_ASYNC_REQUESTS];
56 	volatile int d_request_type[MAX_ASYNC_REQUESTS];
57 	volatile uae_u32 d_request_data[MAX_ASYNC_REQUESTS];
58 	struct device_info di;
59 	uaecptr changeint;
60 	int changeint_mediastate;
61 
62 	int configblocksize;
63 	int volumelevel;
64 	int fadeframes;
65 	int fadetarget;
66 	int fadecounter;
67 
68 	smp_comm_pipe requests;
69 	int thread_running;
70 	uae_sem_t sync_sem;
71 	TCHAR *tape_directory;
72 	bool readonly;
73 };
74 
75 struct priv_devstruct {
76 	int inuse;
77 	int unit;
78 	int mode;
79 	int type;
80 	int flags; /* OpenDevice() */
81 };
82 
83 static struct devstruct devst[MAX_TOTAL_SCSI_DEVICES];
84 static struct priv_devstruct pdevst[MAX_OPEN_DEVICES];
85 static uae_u32 nscmd_cmd;
86 static uae_sem_t change_sem;
87 
devinfo(struct devstruct * devst,struct device_info * di)88 static struct device_info *devinfo (struct devstruct *devst, struct device_info *di)
89 {
90 	struct device_info *dio = sys_command_info (devst->unitnum, di, 0);
91 	if (dio) {
92 		if (!devst->configblocksize)
93 			devst->configblocksize = dio->bytespersector;
94 	}
95 	return di;
96 }
97 
io_log(const TCHAR * msg,uaecptr request)98 static void io_log (const TCHAR *msg, uaecptr request)
99 {
100 	if (log_scsi)
101 		write_log (_T("%s: %08X %d %08X %d %d io_actual=%d io_error=%d\n"),
102 		msg, request, get_word (request + 28), get_long (request + 40),
103 		get_long (request + 36), get_long (request + 44),
104 		get_long (request + 32), get_byte (request + 31));
105 }
106 
getdevstruct(int unit)107 static struct devstruct *getdevstruct (int unit)
108 {
109 	int i;
110 	for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
111 		if (unit >= 0 && devst[i].aunit == unit)
112 			return &devst[i];
113 	}
114 	return 0;
115 }
116 
getpdevstruct(uaecptr request)117 static struct priv_devstruct *getpdevstruct (uaecptr request)
118 {
119 	int i = get_long (request + 24);
120 	if (i < 0 || i >= MAX_OPEN_DEVICES || pdevst[i].inuse == 0) {
121 		write_log (_T("uaescsi.device: corrupt iorequest %08X %d\n"), request, i);
122 		return 0;
123 	}
124 	return &pdevst[i];
125 }
126 
getdevname(int type)127 static const TCHAR *getdevname (int type)
128 {
129 	switch (type) {
130 	case UAEDEV_SCSI_ID:
131 		return UAEDEV_SCSI;
132 	case UAEDEV_DISK_ID:
133 		return UAEDEV_DISK;
134 	default:
135 		return _T("NULL");
136 	}
137 }
138 
139 static void *dev_thread (void *devs);
start_thread(struct devstruct * dev)140 static int start_thread (struct devstruct *dev)
141 {
142 	if (dev->thread_running)
143 		return 1;
144 	init_comm_pipe (&dev->requests, 100, 1);
145 	uae_sem_init (&dev->sync_sem, 0, 0);
146 	uae_start_thread (_T("uaescsi"), dev_thread, dev, NULL);
147 	uae_sem_wait (&dev->sync_sem);
148 	return dev->thread_running;
149 }
150 
dev_close_3(struct devstruct * dev,struct priv_devstruct * pdev)151 static void dev_close_3 (struct devstruct *dev, struct priv_devstruct *pdev)
152 {
153 	if (!dev->opencnt) return;
154 	dev->opencnt--;
155 	if (!dev->opencnt) {
156 		sys_command_close (dev->unitnum);
157 		pdev->inuse = 0;
158 		write_comm_pipe_u32 (&dev->requests, 0, 1);
159 	}
160 }
161 
dev_close_2(TrapContext * context)162 static uae_u32 REGPARAM2 dev_close_2 (TrapContext *context)
163 {
164 	uae_u32 request = m68k_areg (regs, 1);
165 	struct priv_devstruct *pdev = getpdevstruct (request);
166 	struct devstruct *dev;
167 
168 	if (!pdev)
169 		return 0;
170 	dev = getdevstruct (pdev->unit);
171 	if (log_scsi)
172 		write_log (_T("%s:%d close, req=%08X\n"), getdevname (pdev->type), pdev->unit, request);
173 	if (!dev)
174 		return 0;
175 	dev_close_3 (dev, pdev);
176 	put_long (request + 24, 0);
177 	put_word (m68k_areg (regs, 6) + 32, get_word (m68k_areg (regs, 6) + 32) - 1);
178 	return 0;
179 }
180 
dev_close(TrapContext * context)181 static uae_u32 REGPARAM2 dev_close (TrapContext *context)
182 {
183 	return dev_close_2 (context);
184 }
diskdev_close(TrapContext * context)185 static uae_u32 REGPARAM2 diskdev_close (TrapContext *context)
186 {
187 	return dev_close_2 (context);
188 }
189 
openfail(uaecptr ioreq,int error)190 static int openfail (uaecptr ioreq, int error)
191 {
192 	put_long (ioreq + 20, -1);
193 	put_byte (ioreq + 31, error);
194 	return (uae_u32)-1;
195 }
196 
dev_open_2(TrapContext * context,int type)197 static uae_u32 REGPARAM2 dev_open_2 (TrapContext *context, int type)
198 {
199 	uaecptr ioreq = m68k_areg (regs, 1);
200 	uae_u32 unit = m68k_dreg (regs, 0);
201 	uae_u32 flags = m68k_dreg (regs, 1);
202 	struct devstruct *dev = getdevstruct (unit);
203 	struct priv_devstruct *pdev = 0;
204 	int i, v;
205 
206 	if (log_scsi)
207 		write_log (_T("opening %s:%d ioreq=%08X\n"), getdevname (type), unit, ioreq);
208 	if (get_word (ioreq + 0x12) < IOSTDREQ_SIZE && get_word (ioreq + 0x12) > 0)
209 		return openfail (ioreq, IOERR_BADLENGTH);
210 	if (!dev)
211 		return openfail (ioreq, 32); /* badunitnum */
212 	if (!dev->opencnt) {
213 		for (i = 0; i < MAX_OPEN_DEVICES; i++) {
214 			pdev = &pdevst[i];
215 			if (pdev->inuse == 0)
216 				break;
217 		}
218 		if (dev->drivetype == INQ_SEQD) {
219 			v = sys_command_open_tape (dev->unitnum, dev->tape_directory, dev->readonly);
220 		} else {
221 			v = sys_command_open (dev->unitnum);
222 		}
223 		if (!v)
224 			return openfail (ioreq, IOERR_OPENFAIL);
225 		pdev->type = type;
226 		pdev->unit = unit;
227 		pdev->flags = flags;
228 		pdev->inuse = 1;
229 		put_long (ioreq + 24, pdev - pdevst);
230 		start_thread (dev);
231 	} else {
232 		for (i = 0; i < MAX_OPEN_DEVICES; i++) {
233 			pdev = &pdevst[i];
234 			if (pdev->inuse && pdev->unit == unit) break;
235 		}
236 		if (i == MAX_OPEN_DEVICES)
237 			return openfail (ioreq, IOERR_OPENFAIL);
238 		put_long (ioreq + 24, pdev - pdevst);
239 	}
240 	dev->opencnt++;
241 
242 	put_word (m68k_areg (regs, 6) + 32, get_word (m68k_areg (regs, 6) + 32) + 1);
243 	put_byte (ioreq + 31, 0);
244 	put_byte (ioreq + 8, 7);
245 	return 0;
246 }
247 
dev_open(TrapContext * context)248 static uae_u32 REGPARAM2 dev_open (TrapContext *context)
249 {
250 	return dev_open_2 (context, UAEDEV_SCSI_ID);
251 }
diskdev_open(TrapContext * context)252 static uae_u32 REGPARAM2 diskdev_open (TrapContext *context)
253 {
254 	return dev_open_2 (context, UAEDEV_DISK_ID);
255 }
256 
dev_expunge(TrapContext * context)257 static uae_u32 REGPARAM2 dev_expunge (TrapContext *context)
258 {
259 	return 0;
260 }
diskdev_expunge(TrapContext * context)261 static uae_u32 REGPARAM2 diskdev_expunge (TrapContext *context)
262 {
263 	return 0;
264 }
265 
is_async_request(struct devstruct * dev,uaecptr request)266 static int is_async_request (struct devstruct *dev, uaecptr request)
267 {
268 	int i = 0;
269 	while (i < MAX_ASYNC_REQUESTS) {
270 		if (dev->d_request[i] == request) return 1;
271 		i++;
272 	}
273 	return 0;
274 }
275 
276 #if 0
277 static int scsiemul_switchscsi (const TCHAR *name)
278 {
279 	struct devstruct *dev = NULL;
280 	struct device_info *discsi, discsi2;
281 	int i, opened[MAX_TOTAL_SCSI_DEVICES];
282 	bool wasopen = false;
283 
284 	for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++)
285 		opened[i] = sys_command_isopen (i);
286 
287 	dev = &devst[0];
288 	if (dev->opencnt)
289 		wasopen = true;
290 	sys_command_close (dev->unitnum);
291 
292 	dev = NULL;
293 	if (device_func_init (DEVICE_TYPE_ANY)) {
294 		if (devst[0].di.media_inserted < 0)
295 			devst[0].di.media_inserted = 0;
296 		i = 0;
297 		while (i < MAX_TOTAL_SCSI_DEVICES && dev == NULL) {
298 			discsi = 0;
299 			if (sys_command_open ( i)) {
300 				discsi = sys_command_info (i, &discsi2, 0);
301 				if (discsi && discsi->type == INQ_ROMD) {
302 					if (!_tcsicmp (currprefs.cdimagefile[0], discsi->label)) {
303 						dev = &devst[0];
304 						dev->unitnum = i;
305 						dev->drivetype = discsi->type;
306 						memcpy (&dev->di, discsi, sizeof (struct device_info));
307 						dev->iscd = 1;
308 						write_log (_T("%s mounted as uaescsi.device:0\n"), discsi->label);
309 						if (dev->di.media_inserted) {
310 							dev->di.media_inserted = 0;
311 							scsi_do_disk_change (dev->di.id, 1, NULL);
312 						}
313 					}
314 				}
315 				if (opened[i] == 0 && !wasopen)
316 					sys_command_close ( i);
317 			}
318 			i++;
319 		}
320 		if (dev)
321 			return dev->unitnum;
322 	}
323 	return -1;
324 }
325 #endif
326 
327 // pollmode is 1 if no change interrupts found -> increase time of media change
scsi_do_disk_change(int unitnum,int insert,int * pollmode)328 int scsi_do_disk_change (int unitnum, int insert, int *pollmode)
329 {
330 	int i, j, ret;
331 
332 	ret = -1;
333 	if (!change_sem)
334 		return ret;
335 	uae_sem_wait (&change_sem);
336 	for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
337 		struct devstruct *dev = &devst[i];
338 		if (dev->di.unitnum == unitnum + 1) {
339 			ret = i;
340 			if ((dev->changeint_mediastate > 0 && insert == 0) || (dev->changeint_mediastate <= 0 && insert)) {
341 				dev->changeint_mediastate = insert;
342 				if (pollmode)
343 					*pollmode = 1;
344 				if (dev->aunit >= 0) {
345 					struct priv_devstruct *pdev = &pdevst[dev->aunit];
346 					devinfo (dev, &dev->di);
347 				}
348 				dev->changenum++;
349 				j = 0;
350 				while (j < MAX_ASYNC_REQUESTS) {
351 					if (dev->d_request_type[j] == ASYNC_REQUEST_CHANGEINT) {
352 						uae_Cause (dev->d_request_data[j]);
353 						if (pollmode)
354 							*pollmode = 0;
355 					}
356 					j++;
357 				}
358 				if (dev->changeint) {
359 					uae_Cause (dev->changeint);
360 					if (pollmode)
361 						*pollmode = 0;
362 				}
363 			}
364 		}
365 	}
366 	uae_sem_post (&change_sem);
367 	return ret;
368 }
369 
add_async_request(struct devstruct * dev,uaecptr request,int type,uae_u32 data)370 static int add_async_request (struct devstruct *dev, uaecptr request, int type, uae_u32 data)
371 {
372 	int i;
373 
374 	if (log_scsi)
375 		write_log (_T("async request %08x (%d) added\n"), request, type);
376 	i = 0;
377 	while (i < MAX_ASYNC_REQUESTS) {
378 		if (dev->d_request[i] == request) {
379 			dev->d_request_type[i] = type;
380 			dev->d_request_data[i] = data;
381 			return 0;
382 		}
383 		i++;
384 	}
385 	i = 0;
386 	while (i < MAX_ASYNC_REQUESTS) {
387 		if (dev->d_request[i] == 0) {
388 			dev->d_request[i] = request;
389 			dev->d_request_type[i] = type;
390 			dev->d_request_data[i] = data;
391 			return 0;
392 		}
393 		i++;
394 	}
395 	return -1;
396 }
397 
release_async_request(struct devstruct * dev,uaecptr request)398 static int release_async_request (struct devstruct *dev, uaecptr request)
399 {
400 	int i = 0;
401 
402 	if (log_scsi)
403 		write_log (_T("async request %08x removed\n"), request);
404 	while (i < MAX_ASYNC_REQUESTS) {
405 		if (dev->d_request[i] == request) {
406 			int type = dev->d_request_type[i];
407 			dev->d_request[i] = 0;
408 			dev->d_request_data[i] = 0;
409 			dev->d_request_type[i] = 0;
410 			return type;
411 		}
412 		i++;
413 	}
414 	return -1;
415 }
416 
abort_async(struct devstruct * dev,uaecptr request,int errcode,int type)417 static void abort_async (struct devstruct *dev, uaecptr request, int errcode, int type)
418 {
419 	int i;
420 	i = 0;
421 	while (i < MAX_ASYNC_REQUESTS) {
422 		if (dev->d_request[i] == request && dev->d_request_type[i] == ASYNC_REQUEST_TEMP) {
423 			/* ASYNC_REQUEST_TEMP = request is processing */
424 			sleep_millis (10);
425 			i = 0;
426 			continue;
427 		}
428 		i++;
429 	}
430 	i = release_async_request (dev, request);
431 	if (i >= 0 && log_scsi)
432 		write_log (_T("asyncronous request=%08X aborted, error=%d\n"), request, errcode);
433 }
434 
command_read(struct devstruct * dev,uaecptr data,uae_u64 offset,uae_u32 length,uae_u32 * io_actual)435 static int command_read (struct devstruct *dev, uaecptr data, uae_u64 offset, uae_u32 length, uae_u32 *io_actual)
436 {
437 	int blocksize = dev->di.bytespersector;
438 
439 	length /= blocksize;
440 	offset /= blocksize;
441 	while (length > 0) {
442 		uae_u8 buffer[4096];
443 		if (!sys_command_read (dev->unitnum, buffer, offset, 1))
444 			return 20;
445 		memcpyha_safe (data, buffer, blocksize);
446 		data += blocksize;
447 		offset++;
448 		length--;
449 	}
450 	return 0;
451 }
452 
command_write(struct devstruct * dev,uaecptr data,uae_u64 offset,uae_u32 length,uae_u32 * io_actual)453 static int command_write (struct devstruct *dev, uaecptr data, uae_u64 offset, uae_u32 length, uae_u32 *io_actual)
454 {
455 	uae_u32 blocksize = dev->di.bytespersector;
456 	length /= blocksize;
457 	offset /= blocksize;
458 	while (length > 0) {
459 		uae_u8 buffer[4096];
460 		int err;
461 		memcpyah_safe (buffer, data, blocksize);
462 		err = sys_command_write (dev->unitnum, buffer, offset, 1);
463 		if (!err)
464 			return 20;
465 		if (err < 0)
466 			return 28; // write protected
467 		data += blocksize;
468 		offset++;
469 		length--;
470 	}
471 	return 0;
472 }
473 
command_cd_read(struct devstruct * dev,uaecptr data,uae_u64 offset,uae_u32 length,uae_u32 * io_actual)474 static int command_cd_read (struct devstruct *dev, uaecptr data, uae_u64 offset, uae_u32 length, uae_u32 *io_actual)
475 {
476 	uae_u32 len, sector, startoffset;
477 	int blocksize;
478 
479 	blocksize = dev->configblocksize;
480 	*io_actual = 0;
481 	startoffset = offset % blocksize;
482 	offset -= startoffset;
483 	sector = offset / blocksize;
484 	while (length > 0) {
485 		uae_u8 temp[4096];
486 		if (blocksize != 2048) {
487 			if (!sys_command_cd_rawread (dev->unitnum, temp, sector, 1, blocksize))
488 				return 20;
489 		} else {
490 			if (!sys_command_cd_read (dev->unitnum, temp, sector, 1))
491 				return 20;
492 		}
493 		if (startoffset > 0) {
494 			len = blocksize - startoffset;
495 			if (len > length) len = length;
496 			memcpyha_safe (data, temp + startoffset, len);
497 			length -= len;
498 			data += len;
499 			startoffset = 0;
500 			*io_actual += len;
501 		} else if (length >= blocksize) {
502 			len = blocksize;
503 			memcpyha_safe (data, temp, len);
504 			length -= len;
505 			data += len;
506 			*io_actual += len;
507 		} else {
508 			memcpyha_safe (data, temp, length);
509 			*io_actual += length;
510 			length = 0;
511 		}
512 		sector++;
513 	}
514 	return 0;
515 }
516 
dev_do_io_other(struct devstruct * dev,uaecptr request)517 static int dev_do_io_other (struct devstruct *dev, uaecptr request)
518 {
519 	uae_u32 command;
520 	uae_u32 io_data = get_long (request + 40); // 0x28
521 	uae_u32 io_length = get_long (request + 36); // 0x24
522 	uae_u32 io_actual = get_long (request + 32); // 0x20
523 	uae_u32 io_offset = get_long (request + 44); // 0x2c
524 	uae_u32 io_error = 0;
525 	struct priv_devstruct *pdev = getpdevstruct (request);
526 
527 	if (!pdev)
528 		return 0;
529 	command = get_word (request + 28);
530 
531 	if (log_scsi)
532 		write_log (_T("SCSI OTHER %d: DATA=%08X LEN=%08X OFFSET=%08X ACTUAL=%08X\n"),
533 			command, io_data, io_length, io_offset, io_actual);
534 	switch (command)
535 	{
536 	case CMD_UPDATE:
537 	case CMD_CLEAR:
538 	case CMD_FLUSH:
539 	case CMD_MOTOR:
540 	case CMD_SEEK:
541 		io_actual = 0;
542 		break;
543 	case CMD_GETDRIVETYPE:
544 		io_actual = dev->drivetype;
545 		break;
546 	case HD_SCSICMD:
547 		{
548 			uae_u32 sdd = get_long (request + 40);
549 			io_error = sys_command_scsi_direct (dev->unitnum, dev->drivetype, sdd);
550 			if (log_scsi)
551 				write_log (_T("scsidev other: did io: sdd %08x request %08x error %d\n"), sdd, request, get_byte (request + 31));
552 		}
553 		break;
554 	default:
555 		io_error = IOERR_NOCMD;
556 		break;
557 	}
558 
559 	put_long (request + 32, io_actual);
560 	put_byte (request + 31, io_error);
561 	io_log (_T("dev_io_other"), request);
562 	return 0;
563 }
564 
565 
dev_do_io_tape(struct devstruct * dev,uaecptr request)566 static int dev_do_io_tape (struct devstruct *dev, uaecptr request)
567 {
568 	uae_u32 command;
569 	uae_u32 io_data = get_long (request + 40); // 0x28
570 	uae_u32 io_length = get_long (request + 36); // 0x24
571 	uae_u32 io_actual = get_long (request + 32); // 0x20
572 	uae_u32 io_offset = get_long (request + 44); // 0x2c
573 	uae_u32 io_error = 0;
574 	struct priv_devstruct *pdev = getpdevstruct (request);
575 
576 	if (!pdev)
577 		return 0;
578 	command = get_word (request + 28);
579 
580 	if (log_scsi)
581 		write_log (_T("TAPE %d: DATA=%08X LEN=%08X OFFSET=%08X ACTUAL=%08X\n"),
582 			command, io_data, io_length, io_offset, io_actual);
583 	switch (command)
584 	{
585 	case CMD_UPDATE:
586 	case CMD_CLEAR:
587 	case CMD_FLUSH:
588 	case CMD_MOTOR:
589 	case CMD_SEEK:
590 		io_actual = 0;
591 		break;
592 	case CMD_GETDRIVETYPE:
593 		io_actual = dev->drivetype;
594 		break;
595 	case HD_SCSICMD:
596 		{
597 			uae_u32 sdd = get_long (request + 40);
598 			io_error = sys_command_scsi_direct (dev->unitnum, INQ_SEQD, sdd);
599 			if (log_scsi)
600 				write_log (_T("scsidev tape: did io: sdd %08x request %08x error %d\n"), sdd, request, get_byte (request + 31));
601 		}
602 		break;
603 	default:
604 		io_error = IOERR_NOCMD;
605 		break;
606 	}
607 
608 	put_long (request + 32, io_actual);
609 	put_byte (request + 31, io_error);
610 	io_log (_T("dev_io_tape"), request);
611 	return 0;
612 }
613 
dev_do_io_cd(struct devstruct * dev,uaecptr request)614 static int dev_do_io_cd (struct devstruct *dev, uaecptr request)
615 {
616 	uae_u32 command;
617 	uae_u32 io_data = get_long (request + 40); // 0x28
618 	uae_u32 io_length = get_long (request + 36); // 0x24
619 	uae_u32 io_actual = get_long (request + 32); // 0x20
620 	uae_u32 io_offset = get_long (request + 44); // 0x2c
621 	uae_u32 io_error = 0;
622 	uae_u64 io_offset64;
623 	int async = 0;
624 	int bmask = dev->di.bytespersector - 1;
625 	struct priv_devstruct *pdev = getpdevstruct (request);
626 
627 	if (!pdev)
628 		return 0;
629 	command = get_word (request + 28);
630 
631 	if (log_scsi)
632 		write_log (_T("CD %d: DATA=%08X LEN=%08X OFFSET=%08X ACTUAL=%08X\n"),
633 			command, io_data, io_length, io_offset, io_actual);
634 
635 	switch (command)
636 	{
637 	case CMD_READ:
638 		if (dev->di.media_inserted <= 0)
639 			goto no_media;
640 		if (dev->drivetype == INQ_ROMD) {
641 			io_error = command_cd_read (dev, io_data, io_offset, io_length, &io_actual);
642 		} else {
643 			if ((io_offset & bmask) || bmask == 0 || io_data == 0)
644 				goto bad_command;
645 			if ((io_length & bmask) || io_length == 0)
646 				goto bad_len;
647 			io_error = command_read (dev, io_data, io_offset, io_length, &io_actual);
648 		}
649 		break;
650 	case TD_READ64:
651 	case NSCMD_TD_READ64:
652 		if (dev->di.media_inserted <= 0)
653 			goto no_media;
654 		io_offset64 = get_long (request + 44) | ((uae_u64)get_long (request + 32) << 32);
655 		if ((io_offset64 & bmask) || bmask == 0 || io_data == 0)
656 			goto bad_command;
657 		if ((io_length & bmask) || io_length == 0)
658 			goto bad_len;
659 		if (dev->drivetype == INQ_ROMD)
660 			io_error = command_cd_read (dev, io_data, io_offset64, io_length, &io_actual);
661 		else
662 			io_error = command_read (dev, io_data, io_offset64, io_length, &io_actual);
663 		break;
664 
665 	case CMD_WRITE:
666 		if (dev->di.media_inserted <= 0)
667 			goto no_media;
668 		if (dev->di.write_protected || dev->drivetype == INQ_ROMD) {
669 			io_error = 28; /* writeprotect */
670 		} else if ((io_offset & bmask) || bmask == 0 || io_data == 0) {
671 			goto bad_command;
672 		} else if ((io_length & bmask) || io_length == 0) {
673 			goto bad_len;
674 		} else {
675 			io_error = command_write (dev, io_data, io_offset, io_length, &io_actual);
676 		}
677 		break;
678 	case TD_WRITE64:
679 	case NSCMD_TD_WRITE64:
680 		if (dev->di.media_inserted <= 0)
681 			goto no_media;
682 		io_offset64 = get_long (request + 44) | ((uae_u64)get_long (request + 32) << 32);
683 		if (dev->di.write_protected || dev->drivetype == INQ_ROMD) {
684 			io_error = 28; /* writeprotect */
685 		} else if ((io_offset64 & bmask) || bmask == 0 || io_data == 0) {
686 			goto bad_command;
687 		} else if ((io_length & bmask) || io_length == 0) {
688 			goto bad_len;
689 		} else {
690 			io_error = command_write (dev, io_data, io_offset64, io_length, &io_actual);
691 		}
692 		break;
693 
694 	case CMD_FORMAT:
695 		if (dev->di.media_inserted <= 0)
696 			goto no_media;
697 		if (dev->di.write_protected || dev->drivetype == INQ_ROMD) {
698 			io_error = 28; /* writeprotect */
699 		} else if ((io_offset & bmask) || bmask == 0 || io_data == 0) {
700 			goto bad_command;
701 		} else if ((io_length & bmask) || io_length == 0) {
702 			goto bad_len;
703 		} else {
704 			io_error = command_write (dev, io_data, io_offset, io_length, &io_actual);
705 		}
706 		break;
707 	case TD_FORMAT64:
708 	case NSCMD_TD_FORMAT64:
709 		if (dev->di.media_inserted <= 0)
710 			goto no_media;
711 		io_offset64 = get_long (request + 44) | ((uae_u64)get_long (request + 32) << 32);
712 		if (dev->di.write_protected || dev->drivetype == INQ_ROMD) {
713 			io_error = 28; /* writeprotect */
714 		} else if ((io_offset64 & bmask) || bmask == 0 || io_data == 0) {
715 			goto bad_command;
716 		} else if ((io_length & bmask) || io_length == 0) {
717 			goto bad_len;
718 		} else {
719 			io_error = command_write (dev, io_data, io_offset64, io_length, &io_actual);
720 		}
721 		break;
722 
723 	case CMD_UPDATE:
724 	case CMD_CLEAR:
725 	case CMD_FLUSH:
726 	case CMD_MOTOR:
727 	case CMD_SEEK:
728 		io_actual = 0;
729 		break;
730 	case CMD_REMOVE:
731 		io_actual = dev->changeint;
732 		dev->changeint = io_data;
733 		dev->changeint_mediastate = dev->di.media_inserted;
734 		break;
735 	case CMD_CHANGENUM:
736 		io_actual = dev->changenum;
737 		break;
738 	case CMD_CHANGESTATE:
739 		if (dev->di.media_inserted >= 0) {
740 			io_actual = devinfo (dev, &dev->di)->media_inserted > 0 ? 0 : 1;
741 		} else {
742 			io_actual = 1;
743 		}
744 		break;
745 	case CMD_PROTSTATUS:
746 		io_actual = devinfo (dev, &dev->di)->write_protected ? -1 : 0;
747 		break;
748 	case CMD_GETDRIVETYPE:
749 		io_actual = dev->drivetype;
750 		break;
751 	case CMD_GETNUMTRACKS:
752 		if (dev->di.media_inserted <= 0)
753 			goto no_media;
754 		io_actual = dev->di.cylinders;
755 		break;
756 	case CMD_GETGEOMETRY:
757 		{
758 			struct device_info *di;
759 			di = devinfo (dev, &dev->di);
760 			if (di->media_inserted <= 0)
761 				goto no_media;
762 			put_long (io_data + 0, di->bytespersector);
763 			put_long (io_data + 4, di->sectorspertrack * di->trackspercylinder * di->cylinders);
764 			put_long (io_data + 8, di->cylinders);
765 			put_long (io_data + 12, di->sectorspertrack * di->trackspercylinder);
766 			put_long (io_data + 16, di->trackspercylinder);
767 			put_long (io_data + 20, di->sectorspertrack);
768 			put_long (io_data + 24, 0); /* bufmemtype */
769 			put_byte (io_data + 28, di->type);
770 			put_byte (io_data + 29, di->removable ? 1 : 0); /* flags */
771 			io_actual = 30;
772 		}
773 		break;
774 	case CMD_ADDCHANGEINT:
775 		dev->changeint_mediastate = dev->di.media_inserted;
776 		io_error = add_async_request (dev, request, ASYNC_REQUEST_CHANGEINT, io_data);
777 		if (!io_error)
778 			async = 1;
779 		break;
780 	case CMD_REMCHANGEINT:
781 		release_async_request (dev, request);
782 		break;
783 
784 	case CD_TOCLSN:
785 	case CD_TOCMSF:
786 	{
787 		int msf = command == CD_TOCMSF;
788 		struct cd_toc_head toc;
789 		if (sys_command_cd_toc (dev->di.unitnum, &toc)) {
790 			if (io_offset == 0 && io_length > 0) {
791 				int pos = toc.lastaddress;
792 				put_byte (io_data, toc.first_track);
793 				put_byte (io_data + 1, toc.last_track);
794 				if (msf)
795 					pos = lsn2msf (pos);
796 				put_long (io_data + 2, pos);
797 				io_offset++;
798 				io_length--;
799 				io_data += 6;
800 				io_actual++;
801 			}
802 			for (int i = toc.first_track_offset; i < toc.last_track_offset && io_length > 0; i++) {
803 				if (io_offset == toc.toc[i].point) {
804 					int pos = toc.toc[i].paddress;
805 					put_byte (io_data, (toc.toc[i].control << 4) | toc.toc[i].adr);
806 					put_byte (io_data + 1, toc.toc[i].point);
807 					if (msf)
808 						pos = lsn2msf (pos);
809 					put_long (io_data + 2, pos);
810 					io_offset++;
811 					io_length--;
812 					io_data += 6;
813 					io_actual++;
814 				}
815 			}
816 		} else {
817 			io_error = IOERR_NotSpecified;
818 		}
819 	}
820 	break;
821 	case CD_ADDFRAMEINT:
822 		io_error = add_async_request (dev, request, ASYNC_REQUEST_FRAMEINT, io_data);
823 		if (!io_error)
824 			async = 1;
825 		break;
826 	case CD_REMFRAMEINT:
827 		release_async_request (dev, request);
828 		break;
829 	case CD_ATTENUATE:
830 	{
831 		if (io_offset != -1) {
832 			dev->fadeframes = io_length & 0x7fff;
833 			dev->fadetarget = io_offset & 0x7fff;
834 		}
835 		io_actual = dev->volumelevel;
836 	}
837 	break;
838 	case CD_INFO:
839 	{
840 		uae_u16 status = 0;
841 		struct cd_toc_head toc;
842 		uae_u8 subq[SUBQ_SIZE] = { 0 };
843 		sys_command_cd_qcode (dev->di.unitnum, subq);
844 		status |= 1 << 0; // door closed
845 		if (dev->di.media_inserted) {
846 			status |= 1 << 1;
847 			status |= 1 << 2; // motor on
848 			if (sys_command_cd_toc (dev->di.unitnum, &toc)) {
849 				status |= 1 << 3; // toc
850 				if (subq[1] == AUDIO_STATUS_IN_PROGRESS || subq[1] == AUDIO_STATUS_PAUSED)
851 					status |= 1 << 5; // audio play
852 				if (subq[1] == AUDIO_STATUS_PAUSED)
853 					status |= 1 << 6; // paused
854 				if (isdatatrack (&toc, 0))
855 					status |= 1 << 4; // data track
856 			}
857 		}
858 		put_word (io_data +  0, 75);		// PlaySpeed
859 		put_word (io_data +  2, 1200);		// ReadSpeed (randomly chose 16x)
860 		put_word (io_data +  4, 1200);		// ReadXLSpeed
861 		put_word (io_data +  6, dev->configblocksize); // SectorSize
862 		put_word (io_data +  8, -1);		// XLECC
863 		put_word (io_data + 10, 0);			// EjectReset
864 		put_word (io_data + 12, 0);			// Reserved * 4
865 		put_word (io_data + 14, 0);
866 		put_word (io_data + 16, 0);
867 		put_word (io_data + 18, 0);
868 		put_word (io_data + 20, 1200);		// MaxSpeed
869 		put_word (io_data + 22, 0xffff);	// AudioPrecision (volume)
870 		put_word (io_data + 24, status);	// Status
871 		put_word (io_data + 26, 0);			// Reserved2 * 4
872 		put_word (io_data + 28, 0);
873 		put_word (io_data + 30, 0);
874 		put_word (io_data + 32, 0);
875 		io_actual = 34;
876 	}
877 	break;
878 	case CD_CONFIG:
879 	{
880 		while (get_long (io_data) != TAG_DONE) {
881 			uae_u32 tag = get_long (io_data);
882 			uae_u32 data = get_long (io_data + 4);
883 			if (tag == 4) {
884 				// TAGCD_SECTORSIZE
885 				if (data == 2048 || data == 2336 || data == 2352)
886 					dev->configblocksize = data;
887 				else
888 					io_error = IOERR_BADADDRESS;
889 
890 			}
891 			io_data += 8;
892 		}
893 		break;
894 	}
895 	case CD_PAUSE:
896 	{
897 		int old = sys_command_cd_pause (dev->di.unitnum, io_length);
898 		if (old >= 0)
899 			io_actual = old;
900 		else
901 			io_error = IOERR_BADADDRESS;
902 		break;
903 	}
904 	case CD_PLAYLSN:
905 	{
906 		int start = io_offset;
907 		int end = io_length + start;
908 		if (!sys_command_cd_play (dev->di.unitnum, start, end, 0))
909 			io_error = IOERR_BADADDRESS;
910 	}
911 	break;
912 	case CD_PLAYMSF:
913 	{
914 		int start = msf2lsn (io_offset);
915 		int end = msf2lsn (io_length) + start;
916 		if (!sys_command_cd_play (dev->di.unitnum, start, end, 0))
917 			io_error = IOERR_BADADDRESS;
918 	}
919 	break;
920 	case CD_PLAYTRACK:
921 	{
922 		struct cd_toc_head toc;
923 		int ok = 0;
924 		if (sys_command_cd_toc (dev->di.unitnum, &toc)) {
925 			for (int i = toc.first_track_offset; i < toc.last_track_offset; i++) {
926 				if (i == io_offset && i + io_length <= toc.last_track_offset) {
927 					ok = sys_command_cd_play (dev->di.unitnum, toc.toc[i].address, toc.toc[i + io_length].address, 0);
928 					break;
929 				}
930 			}
931 		}
932 		if (!ok)
933 			io_error = IOERR_BADADDRESS;
934 	}
935 	break;
936 	case CD_QCODEMSF:
937 	case CD_QCODELSN:
938 	{
939 		uae_u8 subq[SUBQ_SIZE];
940 		if (sys_command_cd_qcode (dev->di.unitnum, subq)) {
941 			if (subq[1] == AUDIO_STATUS_IN_PROGRESS || subq[1] == AUDIO_STATUS_PAUSED) {
942 				put_byte (io_data + 0, subq[4 + 0]);
943 				put_byte (io_data + 1, frombcd (subq[4 + 1]));
944 				put_byte (io_data + 2, frombcd (subq[4 + 2]));
945 				put_byte (io_data + 3, subq[4 + 6]);
946 				int trackpos = fromlongbcd (subq + 4 + 3);
947 				int diskpos = fromlongbcd (subq + 4 + 7);
948 				if (command == CD_QCODELSN) {
949 					trackpos = msf2lsn (trackpos);
950 					diskpos = msf2lsn (diskpos);
951 				}
952 				put_long (io_data + 4, trackpos);
953 				put_long (io_data + 8, diskpos);
954 				io_actual = 12;
955 			} else {
956 				io_error = IOERR_InvalidState;
957 			}
958 		} else {
959 			io_error = IOERR_BADADDRESS;
960 		}
961 	}
962 	break;
963 
964 	case HD_SCSICMD:
965 		{
966 			uae_u32 sdd = get_long (request + 40);
967 			io_error = sys_command_scsi_direct (dev->unitnum, INQ_ROMD, sdd);
968 			if (log_scsi)
969 				write_log (_T("scsidev cd: did io: sdd %08x request %08x error %d\n"), sdd, request, get_byte (request + 31));
970 		}
971 		break;
972 	case NSCMD_DEVICEQUERY:
973 		put_long (io_data + 0, 0);
974 		put_long (io_data + 4, 16); /* size */
975 		put_word (io_data + 8, NSDEVTYPE_TRACKDISK);
976 		put_word (io_data + 10, 0);
977 		put_long (io_data + 12, nscmd_cmd);
978 		io_actual = 16;
979 		break;
980 	default:
981 		io_error = IOERR_NOCMD;
982 		break;
983 bad_len:
984 		io_error = IOERR_BADLENGTH;
985 		break;
986 bad_command:
987 		io_error = IOERR_BADADDRESS;
988 		break;
989 no_media:
990 		io_error = TDERR_DiskChanged;
991 		break;
992 	}
993 	put_long (request + 32, io_actual);
994 	put_byte (request + 31, io_error);
995 	io_log (_T("dev_io_cd"), request);
996 	return async;
997 }
998 
dev_do_io(struct devstruct * dev,uaecptr request)999 static int dev_do_io (struct devstruct *dev, uaecptr request)
1000 {
1001 	if (dev->drivetype == INQ_SEQD) {
1002 		return dev_do_io_tape (dev, request);
1003 	} else if (dev->drivetype == INQ_ROMD) {
1004 		return dev_do_io_cd (dev, request);
1005 	} else {
1006 		return dev_do_io_other (dev, request);
1007 	}
1008 }
1009 
dev_can_quick(uae_u32 command)1010 static int dev_can_quick (uae_u32 command)
1011 {
1012 	switch (command)
1013 	{
1014 	case CMD_RESET:
1015 	case CMD_STOP:
1016 	case CMD_START:
1017 	case CMD_CHANGESTATE:
1018 	case CMD_PROTSTATUS:
1019 	case CMD_GETDRIVETYPE:
1020 		return 1;
1021 	case CMD_GETNUMTRACKS:
1022 	case CMD_ADDCHANGEINT:
1023 	case CMD_REMCHANGEINT:
1024 	case CD_ADDFRAMEINT:
1025 	case CD_REMFRAMEINT:
1026 		return -1;
1027 	}
1028 	return 0;
1029 }
1030 
dev_canquick(struct devstruct * dev,uaecptr request)1031 static int dev_canquick (struct devstruct *dev, uaecptr request)
1032 {
1033 	uae_u32 command = get_word (request + 28);
1034 	return dev_can_quick (command);
1035 }
1036 
dev_beginio(TrapContext * context)1037 static uae_u32 REGPARAM2 dev_beginio (TrapContext *context)
1038 {
1039 	uae_u32 request = m68k_areg (regs, 1);
1040 	uae_u8 flags = get_byte (request + 30);
1041 	int command = get_word (request + 28);
1042 	struct priv_devstruct *pdev = getpdevstruct (request);
1043 	struct devstruct *dev;
1044 	int canquick;
1045 
1046 	put_byte (request + 8, NT_MESSAGE);
1047 	if (!pdev) {
1048 		put_byte (request + 31, 32);
1049 		return get_byte (request + 31);
1050 	}
1051 	dev = getdevstruct (pdev->unit);
1052 	if (!dev) {
1053 		put_byte (request + 31, 32);
1054 		return get_byte (request + 31);
1055 	}
1056 	put_byte (request + 31, 0);
1057 	canquick = dev_canquick (dev, request);
1058 	if (((flags & 1) && canquick) || (canquick < 0)) {
1059 		dev_do_io (dev, request);
1060 		if (!(flags & 1))
1061 			uae_ReplyMsg (request);
1062 		return get_byte (request + 31);
1063 	} else {
1064 		add_async_request (dev, request, ASYNC_REQUEST_TEMP, 0);
1065 		put_byte (request + 30, get_byte (request + 30) & ~1);
1066 		write_comm_pipe_u32 (&dev->requests, request, 1);
1067 		return 0;
1068 	}
1069 }
1070 
dev_thread(void * devs)1071 static void *dev_thread (void *devs)
1072 {
1073 	struct devstruct *dev = (struct devstruct*)devs;
1074 
1075 	uae_set_thread_priority (NULL, 1);
1076 	dev->thread_running = 1;
1077 	uae_sem_post (&dev->sync_sem);
1078 	for (;;) {
1079 		uaecptr request = (uaecptr)read_comm_pipe_u32_blocking (&dev->requests);
1080 		uae_sem_wait (&change_sem);
1081 		if (!request) {
1082 			dev->thread_running = 0;
1083 			uae_sem_post (&dev->sync_sem);
1084 			uae_sem_post (&change_sem);
1085 			return 0;
1086 		} else if (dev_do_io (dev, request) == 0) {
1087 			put_byte (request + 30, get_byte (request + 30) & ~1);
1088 			release_async_request (dev, request);
1089 			uae_ReplyMsg (request);
1090 		} else {
1091 			if (log_scsi)
1092 				write_log (_T("%s:%d async request %08X\n"), getdevname(0), dev->unitnum, request);
1093 		}
1094 		uae_sem_post (&change_sem);
1095 	}
1096 	return 0;
1097 }
1098 
dev_init_2(TrapContext * context,int type)1099 static uae_u32 REGPARAM2 dev_init_2 (TrapContext *context, int type)
1100 {
1101 	uae_u32 base = m68k_dreg (regs, 0);
1102 	if (log_scsi)
1103 		write_log (_T("%s init\n"), getdevname (type));
1104 	return base;
1105 }
1106 
dev_init(TrapContext * context)1107 static uae_u32 REGPARAM2 dev_init (TrapContext *context)
1108 {
1109 	return dev_init_2 (context, UAEDEV_SCSI_ID);
1110 }
diskdev_init(TrapContext * context)1111 static uae_u32 REGPARAM2 diskdev_init (TrapContext *context)
1112 {
1113 	return dev_init_2 (context, UAEDEV_DISK_ID);
1114 }
1115 
dev_abortio(TrapContext * context)1116 static uae_u32 REGPARAM2 dev_abortio (TrapContext *context)
1117 {
1118 	uae_u32 request = m68k_areg (regs, 1);
1119 	struct priv_devstruct *pdev = getpdevstruct (request);
1120 	struct devstruct *dev;
1121 
1122 	if (!pdev) {
1123 		put_byte (request + 31, 32);
1124 		return get_byte (request + 31);
1125 	}
1126 	dev = getdevstruct (pdev->unit);
1127 	if (!dev) {
1128 		put_byte (request + 31, 32);
1129 		return get_byte (request + 31);
1130 	}
1131 	put_byte (request + 31, IOERR_ABORTED);
1132 	if (log_scsi)
1133 		write_log (_T("abortio %s unit=%d, request=%08X\n"), getdevname (pdev->type), pdev->unit, request);
1134 	abort_async (dev, request, IOERR_ABORTED, 0);
1135 	return 0;
1136 }
1137 
1138 #define BTL2UNIT(bus, target, lun) (2 * (bus) + (target) / 8) * 100 + (lun) * 10 + (target % 8)
1139 
scsi_get_cd_drive_mask(void)1140 uae_u32 scsi_get_cd_drive_mask (void)
1141 {
1142 	uae_u32 mask = 0;
1143 	for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
1144 		struct devstruct *dev = &devst[i];
1145 		if (dev->iscd)
1146 			mask |= 1 << i;
1147 	}
1148 	return mask;
1149 }
scsi_get_cd_drive_media_mask(void)1150 uae_u32 scsi_get_cd_drive_media_mask (void)
1151 {
1152 	uae_u32 mask = 0;
1153 	for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
1154 		struct devstruct *dev = &devst[i];
1155 		if (dev->iscd && dev->changeint_mediastate)
1156 			mask |= 1 << i;
1157 	}
1158 	return mask;
1159 }
scsi_add_tape(struct uaedev_config_info * uci)1160 int scsi_add_tape (struct uaedev_config_info *uci)
1161 {
1162 	for (int i = 4; i < MAX_TOTAL_SCSI_DEVICES; i++) {
1163 		struct devstruct *dev = &devst[i];
1164 		if (dev->unitnum >= 0 || dev->drivetype > 0)
1165 			continue;
1166 		if (sys_command_open_tape (i, uci->rootdir, uci->readonly)) {
1167 			dev->drivetype = INQ_SEQD;
1168 			dev->aunit = i;
1169 			dev->unitnum = i;
1170 			dev->tape_directory = my_strdup (uci->rootdir);
1171 			write_log (_T("%s:%d = '%s''\n"), UAEDEV_SCSI, dev->aunit, uci->rootdir);
1172 			return i;
1173 		}
1174 	}
1175 	return -1;
1176 }
dev_reset(void)1177 static void dev_reset (void)
1178 {
1179 	int i, j;
1180 	struct devstruct *dev;
1181 	int unitnum = 0;
1182 
1183 	for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
1184 		dev = &devst[i];
1185 		if (dev->opencnt > 0) {
1186 			for (j = 0; j < MAX_ASYNC_REQUESTS; j++) {
1187 				uaecptr request;
1188 				if ((request = dev->d_request[i]))
1189 					abort_async (dev, request, 0, 0);
1190 			}
1191 			dev->opencnt = 1;
1192 			if (dev->unitnum >= 0)
1193 				sys_command_close (dev->unitnum);
1194 		}
1195 		memset (dev, 0, sizeof (struct devstruct));
1196 		xfree (dev->tape_directory);
1197 		dev->unitnum = dev->aunit = -1;
1198 	}
1199 	for (i = 0; i < MAX_OPEN_DEVICES; i++)
1200 		memset (&pdevst[i], 0, sizeof (struct priv_devstruct));
1201 
1202 	device_func_init (0);
1203 	i = 0;
1204 	while (i < MAX_TOTAL_SCSI_DEVICES) {
1205 		dev = &devst[i];
1206 		struct device_info *discsi, discsi2;
1207 		if (sys_command_open (i)) {
1208 			discsi = sys_command_info (i, &discsi2, 0);
1209 			if (discsi) {
1210 				dev->unitnum = i;
1211 				dev->drivetype = discsi->type;
1212 				memcpy (&dev->di, discsi, sizeof (struct device_info));
1213 				dev->changeint_mediastate = discsi->media_inserted;
1214 				dev->configblocksize = discsi->bytespersector;
1215 				if (discsi->type == INQ_ROMD)
1216 					dev->iscd = 1;
1217 			} else {
1218 				sys_command_close (i);
1219 			}
1220 		}
1221 		i++;
1222 	}
1223 	unitnum = 0;
1224 	for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
1225 		dev = &devst[i];
1226 		if (dev->unitnum >= 0)
1227 			sys_command_close (dev->unitnum);
1228 		if (dev->unitnum >= 0 && dev->iscd) {
1229 			dev->aunit = unitnum;
1230 			dev->volumelevel = 0x7fff;
1231 			unitnum++;
1232 		}
1233 	}
1234 	if (unitnum == 0)
1235 		unitnum = 1;
1236 	for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
1237 		dev = &devst[i];
1238 		if (dev->unitnum >= 0) {
1239 			if (!dev->iscd) {
1240 				dev->aunit = unitnum;
1241 				unitnum++;
1242 			}
1243 			write_log (_T("%s:%d = %s:'%s'\n"), UAEDEV_SCSI, dev->aunit, dev->di.backend, dev->di.label);
1244 		}
1245 		dev->di.label[0] = 0;
1246 	}
1247 }
1248 
1249 static uaecptr ROM_scsidev_resname = 0,
1250 	ROM_scsidev_resid = 0,
1251 	ROM_scsidev_init = 0;
1252 
1253 static uaecptr ROM_diskdev_resname = 0,
1254 	ROM_diskdev_resid = 0,
1255 	ROM_diskdev_init = 0;
1256 
1257 
diskdev_startup(uaecptr resaddr)1258 static uaecptr diskdev_startup (uaecptr resaddr)
1259 {
1260 	/* Build a struct Resident. This will set up and initialize
1261 	* the cd.device */
1262 	if (log_scsi)
1263 		write_log (_T("diskdev_startup(0x%x)\n"), resaddr);
1264 	put_word (resaddr + 0x0, 0x4AFC);
1265 	put_long (resaddr + 0x2, resaddr);
1266 	put_long (resaddr + 0x6, resaddr + 0x1A); /* Continue scan here */
1267 	put_word (resaddr + 0xA, 0x8101); /* RTF_AUTOINIT|RTF_COLDSTART; Version 1 */
1268 	put_word (resaddr + 0xC, 0x0305); /* NT_DEVICE; pri 05 */
1269 	put_long (resaddr + 0xE, ROM_diskdev_resname);
1270 	put_long (resaddr + 0x12, ROM_diskdev_resid);
1271 	put_long (resaddr + 0x16, ROM_diskdev_init);
1272 	resaddr += 0x1A;
1273 	return resaddr;
1274 }
1275 
scsidev_startup(uaecptr resaddr)1276 uaecptr scsidev_startup (uaecptr resaddr)
1277 {
1278 	if (currprefs.scsi != 1)
1279 		return resaddr;
1280 	if (log_scsi)
1281 		write_log (_T("scsidev_startup(0x%x)\n"), resaddr);
1282 	/* Build a struct Resident. This will set up and initialize
1283 	* the uaescsi.device */
1284 	put_word (resaddr + 0x0, 0x4AFC);
1285 	put_long (resaddr + 0x2, resaddr);
1286 	put_long (resaddr + 0x6, resaddr + 0x1A); /* Continue scan here */
1287 	put_word (resaddr + 0xA, 0x8101); /* RTF_AUTOINIT|RTF_COLDSTART; Version 1 */
1288 	put_word (resaddr + 0xC, 0x0305); /* NT_DEVICE; pri 05 */
1289 	put_long (resaddr + 0xE, ROM_scsidev_resname);
1290 	put_long (resaddr + 0x12, ROM_scsidev_resid);
1291 	put_long (resaddr + 0x16, ROM_scsidev_init); /* calls scsidev_init */
1292 	resaddr += 0x1A;
1293 	return resaddr;
1294 	return diskdev_startup (resaddr);
1295 }
1296 
diskdev_install(void)1297 static void diskdev_install (void)
1298 {
1299 	uae_u32 functable, datatable;
1300 	uae_u32 initcode, openfunc, closefunc, expungefunc;
1301 	uae_u32 beginiofunc, abortiofunc;
1302 
1303 	if (currprefs.scsi != 1)
1304 		return;
1305 	if (log_scsi)
1306 		write_log (_T("diskdev_install(): 0x%x\n"), here ());
1307 
1308 	ROM_diskdev_resname = ds (UAEDEV_DISK);
1309 	ROM_diskdev_resid = ds (_T("UAE disk.device 0.1"));
1310 
1311 	/* initcode */
1312 	initcode = here ();
1313 	calltrap (deftrap (diskdev_init)); dw (RTS);
1314 
1315 	/* Open */
1316 	openfunc = here ();
1317 	calltrap (deftrap (diskdev_open)); dw (RTS);
1318 
1319 	/* Close */
1320 	closefunc = here ();
1321 	calltrap (deftrap (diskdev_close)); dw (RTS);
1322 
1323 	/* Expunge */
1324 	expungefunc = here ();
1325 	calltrap (deftrap (diskdev_expunge)); dw (RTS);
1326 
1327 	/* BeginIO */
1328 	beginiofunc = here ();
1329 	calltrap (deftrap (dev_beginio));
1330 	dw (RTS);
1331 
1332 	/* AbortIO */
1333 	abortiofunc = here ();
1334 	calltrap (deftrap (dev_abortio)); dw (RTS);
1335 
1336 	/* FuncTable */
1337 	functable = here ();
1338 	dl (openfunc); /* Open */
1339 	dl (closefunc); /* Close */
1340 	dl (expungefunc); /* Expunge */
1341 	dl (EXPANSION_nullfunc); /* Null */
1342 	dl (beginiofunc); /* BeginIO */
1343 	dl (abortiofunc); /* AbortIO */
1344 	dl (0xFFFFFFFFul); /* end of table */
1345 
1346 	/* DataTable */
1347 	datatable = here ();
1348 	dw (0xE000); /* INITBYTE */
1349 	dw (0x0008); /* LN_TYPE */
1350 	dw (0x0300); /* NT_DEVICE */
1351 	dw (0xC000); /* INITLONG */
1352 	dw (0x000A); /* LN_NAME */
1353 	dl (ROM_diskdev_resname);
1354 	dw (0xE000); /* INITBYTE */
1355 	dw (0x000E); /* LIB_FLAGS */
1356 	dw (0x0600); /* LIBF_SUMUSED | LIBF_CHANGED */
1357 	dw (0xD000); /* INITWORD */
1358 	dw (0x0014); /* LIB_VERSION */
1359 	dw (0x0004); /* 0.4 */
1360 	dw (0xD000); /* INITWORD */
1361 	dw (0x0016); /* LIB_REVISION */
1362 	dw (0x0000); /* end of table already ??? */
1363 	dw (0xC000); /* INITLONG */
1364 	dw (0x0018); /* LIB_IDSTRING */
1365 	dl (ROM_diskdev_resid);
1366 	dw (0x0000); /* end of table */
1367 
1368 	ROM_diskdev_init = here ();
1369 	dl (0x00000100); /* size of device base */
1370 	dl (functable);
1371 	dl (datatable);
1372 	dl (initcode);
1373 }
1374 
1375 
scsidev_install(void)1376 void scsidev_install (void)
1377 {
1378 	uae_u32 functable, datatable;
1379 	uae_u32 initcode, openfunc, closefunc, expungefunc;
1380 	uae_u32 beginiofunc, abortiofunc;
1381 
1382 	if (currprefs.scsi != 1)
1383 		return;
1384 	if (log_scsi)
1385 		write_log (_T("scsidev_install(): 0x%x\n"), here ());
1386 
1387 	ROM_scsidev_resname = ds (UAEDEV_SCSI);
1388 	ROM_scsidev_resid = ds (_T("UAE scsi.device 0.2"));
1389 
1390 	/* initcode */
1391 	initcode = here ();
1392 	calltrap (deftrap (dev_init)); dw (RTS);
1393 
1394 	/* Open */
1395 	openfunc = here ();
1396 	calltrap (deftrap (dev_open)); dw (RTS);
1397 
1398 	/* Close */
1399 	closefunc = here ();
1400 	calltrap (deftrap (dev_close)); dw (RTS);
1401 
1402 	/* Expunge */
1403 	expungefunc = here ();
1404 	calltrap (deftrap (dev_expunge)); dw (RTS);
1405 
1406 	/* BeginIO */
1407 	beginiofunc = here ();
1408 	calltrap (deftrap (dev_beginio));
1409 	dw (RTS);
1410 
1411 	/* AbortIO */
1412 	abortiofunc = here ();
1413 	calltrap (deftrap (dev_abortio)); dw (RTS);
1414 
1415 	/* FuncTable */
1416 	functable = here ();
1417 	dl (openfunc); /* Open */
1418 	dl (closefunc); /* Close */
1419 	dl (expungefunc); /* Expunge */
1420 	dl (EXPANSION_nullfunc); /* Null */
1421 	dl (beginiofunc); /* BeginIO */
1422 	dl (abortiofunc); /* AbortIO */
1423 	dl (0xFFFFFFFFul); /* end of table */
1424 
1425 	/* DataTable */
1426 	datatable = here ();
1427 	dw (0xE000); /* INITBYTE */
1428 	dw (0x0008); /* LN_TYPE */
1429 	dw (0x0300); /* NT_DEVICE */
1430 	dw (0xC000); /* INITLONG */
1431 	dw (0x000A); /* LN_NAME */
1432 	dl (ROM_scsidev_resname);
1433 	dw (0xE000); /* INITBYTE */
1434 	dw (0x000E); /* LIB_FLAGS */
1435 	dw (0x0600); /* LIBF_SUMUSED | LIBF_CHANGED */
1436 	dw (0xD000); /* INITWORD */
1437 	dw (0x0014); /* LIB_VERSION */
1438 	dw (0x0004); /* 0.4 */
1439 	dw (0xD000); /* INITWORD */
1440 	dw (0x0016); /* LIB_REVISION */
1441 	dw (0x0000);
1442 	dw (0xC000); /* INITLONG */
1443 	dw (0x0018); /* LIB_IDSTRING */
1444 	dl (ROM_scsidev_resid);
1445 	dw (0x0000); /* end of table */
1446 
1447 	ROM_scsidev_init = here ();
1448 	dl (0x00000100); /* size of device base */
1449 	dl (functable);
1450 	dl (datatable);
1451 	dl (initcode);
1452 
1453 	nscmd_cmd = here ();
1454 	dw (NSCMD_DEVICEQUERY);
1455 	dw (CMD_RESET);
1456 	dw (CMD_READ);
1457 	dw (CMD_WRITE);
1458 	dw (CMD_UPDATE);
1459 	dw (CMD_CLEAR);
1460 	dw (CMD_START);
1461 	dw (CMD_STOP);
1462 	dw (CMD_FLUSH);
1463 	dw (CMD_MOTOR);
1464 	dw (CMD_SEEK);
1465 	dw (CMD_FORMAT);
1466 	dw (CMD_REMOVE);
1467 	dw (CMD_CHANGENUM);
1468 	dw (CMD_CHANGESTATE);
1469 	dw (CMD_PROTSTATUS);
1470 	dw (CMD_GETDRIVETYPE);
1471 	dw (CMD_GETGEOMETRY);
1472 	dw (CMD_ADDCHANGEINT);
1473 	dw (CMD_REMCHANGEINT);
1474 	dw (HD_SCSICMD);
1475 	dw (NSCMD_TD_READ64);
1476 	dw (NSCMD_TD_WRITE64);
1477 	dw (NSCMD_TD_SEEK64);
1478 	dw (NSCMD_TD_FORMAT64);
1479 	dw (0);
1480 
1481 	diskdev_install ();
1482 }
1483 
scsidev_start_threads(void)1484 void scsidev_start_threads (void)
1485 {
1486 	if (currprefs.scsi != 1) /* quite useless.. */
1487 		return;
1488 	if (log_scsi)
1489 		write_log (_T("scsidev_start_threads()\n"));
1490 	uae_sem_init (&change_sem, 0, 1);
1491 }
1492 
scsidev_reset(void)1493 void scsidev_reset (void)
1494 {
1495 	if (currprefs.scsi != 1)
1496 		return;
1497 	dev_reset ();
1498 }
1499 
1500 #ifdef SAVESTATE
1501 
save_scsidev(int num,int * len,uae_u8 * dstptr)1502 uae_u8 *save_scsidev (int num, int *len, uae_u8 *dstptr)
1503 {
1504 	uae_u8 *dstbak, *dst;
1505 	struct priv_devstruct *pdev;
1506 	struct devstruct *dev;
1507 
1508 	pdev = &pdevst[num];
1509 	if (!pdev->inuse)
1510 		return NULL;
1511 	if (dstptr)
1512 		dstbak = dst = dstptr;
1513 	else
1514 		dstbak = dst = xmalloc (uae_u8, 1000);
1515 	save_u32 (num);
1516 	save_u32 (0);
1517 	save_u32 (pdev->unit);
1518 	save_u32 (pdev->type);
1519 	save_u32 (pdev->mode);
1520 	save_u32 (pdev->flags);
1521 	dev = getdevstruct (pdev->unit);
1522 	if (dev) {
1523 		save_u32 (0);
1524 		save_u32 (dev->aunit);
1525 		save_u32 (dev->opencnt);
1526 		save_u32 (dev->changenum);
1527 		save_u32 (dev->changeint);
1528 		save_u32 (dev->changeint_mediastate);
1529 		save_u32 (dev->configblocksize);
1530 		save_u32 (dev->fadecounter);
1531 		save_u32 (dev->fadeframes);
1532 		save_u32 (dev->fadetarget);
1533 		for (int i = 0; i < MAX_ASYNC_REQUESTS; i++) {
1534 			if (dev->d_request[i]) {
1535 				save_u32 (dev->d_request[i]);
1536 				save_u32 (dev->d_request_type[i]);
1537 				save_u32 (dev->d_request_data[i]);
1538 			}
1539 		}
1540 		save_u32 (0xffffffff);
1541 	} else {
1542 		save_u32 (0xffffffff);
1543 	}
1544 	*len = dst - dstbak;
1545 	return dstbak;
1546 }
1547 
restore_scsidev(uae_u8 * src)1548 uae_u8 *restore_scsidev (uae_u8 *src)
1549 {
1550 	struct priv_devstruct *pdev;
1551 	struct devstruct *dev;
1552 	int i;
1553 
1554 	int num = restore_u32 ();
1555 	if (num == 0)
1556 		dev_reset ();
1557 	pdev = &pdevst[num];
1558 	restore_u32 ();
1559 	restore_u32 ();
1560 	pdev->type = restore_u32 ();
1561 	pdev->mode = restore_u32 ();
1562 	pdev->flags = restore_u32 ();
1563 	if (restore_u32 () != 0xffffffff) {
1564 		dev = getdevstruct (pdev->unit);
1565 		if (dev) {
1566 			dev->aunit = restore_u32 ();
1567 			dev->opencnt = restore_u32 ();
1568 			dev->changenum = restore_u32 ();
1569 			dev->changeint = restore_u32 ();
1570 			dev->changeint_mediastate = restore_u32 ();
1571 			dev->configblocksize = restore_u32 ();
1572 			dev->fadecounter = restore_u32 ();
1573 			dev->fadeframes = restore_u32 ();
1574 			dev->fadetarget = restore_u32 ();
1575 			i = 0;
1576 			for (;;) {
1577 				uae_u32 v = restore_u32 ();
1578 				if (v == 0xffffffff)
1579 					break;
1580 				dev->d_request[i] = v;
1581 				dev->d_request_type[i] = restore_u32 ();
1582 				dev->d_request_data[i] = restore_u32 ();
1583 			}
1584 		}
1585 	}
1586 	return src;
1587 }
1588 
1589 #endif /* SAVESTATE */
1590 
1591 #endif /* SCSIEMU */
1592