PageRenderTime 65ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/scsiemul.cpp

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