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