PageRenderTime 38ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/hardfile.cpp

https://github.com/tonioni/WinUAE
C++ | 3150 lines | 2862 code | 210 blank | 78 comment | 728 complexity | be09058b73539c5e8d2476c16ea564ac MD5 | raw file
  1. /*
  2. * UAE - The Un*x Amiga Emulator
  3. *
  4. * Hardfile emulation
  5. *
  6. * Copyright 1995 Bernd Schmidt
  7. * 2002 Toni Wilen (scsi emulation, 64-bit support)
  8. */
  9. #include "sysconfig.h"
  10. #include "sysdeps.h"
  11. #include "threaddep/thread.h"
  12. #include "options.h"
  13. #include "memory.h"
  14. #include "custom.h"
  15. #include "newcpu.h"
  16. #include "disk.h"
  17. #include "autoconf.h"
  18. #include "traps.h"
  19. #include "filesys.h"
  20. #include "execlib.h"
  21. #include "native2amiga.h"
  22. #include "gui.h"
  23. #include "uae.h"
  24. #include "scsi.h"
  25. #include "gayle.h"
  26. #include "execio.h"
  27. #include "zfile.h"
  28. #include "ide.h"
  29. #include "debug.h"
  30. #include "ini.h"
  31. #include "rommgr.h"
  32. #ifdef WITH_CHD
  33. #include "archivers/chd/chdtypes.h"
  34. #include "archivers/chd/chd.h"
  35. #include "archivers/chd/harddisk.h"
  36. #endif
  37. #define HDF_SUPPORT_NSD 1
  38. #define HDF_SUPPORT_TD64 1
  39. #define HDF_SUPPORT_DS 1
  40. #define HDF_SUPPORT_DS_PARTITION 0
  41. #undef DEBUGME
  42. #define hf_log(fmt, ...)
  43. #define hf_log2(fmt, ...)
  44. #define scsi_log(fmt, ...)
  45. #define hf_log3(fmt, ...)
  46. //#define DEBUGME
  47. #ifdef DEBUGME
  48. #undef hf_log
  49. #define hf_log write_log
  50. #undef hf_log2
  51. #define hf_log2 write_log
  52. #undef hf_log3
  53. #define hf_log3 write_log
  54. #undef scsi_log
  55. #define scsi_log write_log
  56. #endif
  57. extern int log_scsiemu;
  58. int enable_ds_partition_hdf;
  59. #define MAX_ASYNC_REQUESTS 50
  60. #define ASYNC_REQUEST_NONE 0
  61. #define ASYNC_REQUEST_TEMP 1
  62. #define ASYNC_REQUEST_CHANGEINT 10
  63. struct hardfileprivdata {
  64. uaecptr d_request[MAX_ASYNC_REQUESTS];
  65. uae_u8 *d_request_iobuf[MAX_ASYNC_REQUESTS];
  66. int d_request_type[MAX_ASYNC_REQUESTS];
  67. uae_u32 d_request_data[MAX_ASYNC_REQUESTS];
  68. smp_comm_pipe requests;
  69. int thread_running;
  70. uae_sem_t sync_sem;
  71. uaecptr base;
  72. int changenum;
  73. uaecptr changeint;
  74. struct scsi_data *sd;
  75. bool directorydrive;
  76. };
  77. #define HFD_CHD_OTHER 5
  78. #define HFD_CHD_HD 4
  79. #define HFD_VHD_DYNAMIC 3
  80. #define HFD_VHD_FIXED 2
  81. STATIC_INLINE uae_u32 gl (uae_u8 *p)
  82. {
  83. return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0);
  84. }
  85. static uae_sem_t change_sem;
  86. static struct hardfileprivdata hardfpd[MAX_FILESYSTEM_UNITS];
  87. static uae_u32 nscmd_cmd;
  88. static void wl (uae_u8 *p, uae_u32 v)
  89. {
  90. p[0] = v >> 24;
  91. p[1] = v >> 16;
  92. p[2] = v >> 8;
  93. p[3] = v;
  94. }
  95. static void ww (uae_u8 *p, uae_u16 v)
  96. {
  97. p[0] = v >> 8;
  98. p[1] = v;
  99. }
  100. static int rl (uae_u8 *p)
  101. {
  102. return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]);
  103. }
  104. static void getchs2 (struct hardfiledata *hfd, int *cyl, int *cylsec, int *head, int *tracksec)
  105. {
  106. unsigned int total = (unsigned int)(hfd->virtsize / 1024);
  107. int heads;
  108. int sectors = 63;
  109. if (hfd->ci.physical_geometry) {
  110. *cyl = hfd->ci.pcyls;
  111. *tracksec = hfd->ci.psecs;
  112. *head = hfd->ci.pheads;
  113. *cylsec = (*head) * (*tracksec);
  114. return;
  115. }
  116. /* do we have RDB values? */
  117. if (hfd->rdbcylinders) {
  118. *cyl = hfd->rdbcylinders;
  119. *tracksec = hfd->rdbsectors;
  120. *head = hfd->rdbheads;
  121. *cylsec = hfd->rdbsectors * hfd->rdbheads;
  122. return;
  123. }
  124. /* what about HDF settings? */
  125. if (hfd->ci.surfaces && hfd->ci.sectors) {
  126. *head = hfd->ci.surfaces;
  127. *tracksec = hfd->ci.sectors;
  128. *cylsec = (*head) * (*tracksec);
  129. *cyl = (unsigned int)(hfd->virtsize / hfd->ci.blocksize) / ((*tracksec) * (*head));
  130. if (*cyl == 0)
  131. *cyl = (unsigned int)hfd->ci.max_lba / ((*tracksec) * (*head));
  132. return;
  133. }
  134. /* no, lets guess something.. */
  135. if (total <= 504 * 1024)
  136. heads = 16;
  137. else if (total <= 1008 * 1024)
  138. heads = 32;
  139. else if (total <= 2016 * 1024)
  140. heads = 64;
  141. else if (total <= 4032 * 1024)
  142. heads = 128;
  143. else
  144. heads = 255;
  145. *cyl = (unsigned int)(hfd->virtsize / hfd->ci.blocksize) / (sectors * heads);
  146. if (*cyl == 0)
  147. *cyl = (unsigned int)hfd->ci.max_lba / (sectors * heads);
  148. *cylsec = sectors * heads;
  149. *tracksec = sectors;
  150. *head = heads;
  151. }
  152. static void getchsx (struct hardfiledata *hfd, int *cyl, int *cylsec, int *head, int *tracksec)
  153. {
  154. getchs2 (hfd, cyl, cylsec, head, tracksec);
  155. hf_log (_T("CHS: %08X-%08X %d %d %d %d %d\n"),
  156. (uae_u32)(hfd->virtsize >> 32),(uae_u32)hfd->virtsize,
  157. *cyl, *cylsec, *head, *tracksec);
  158. }
  159. static void getchsgeometry2 (uae_u64 size, int *pcyl, int *phead, int *psectorspertrack, int mode)
  160. {
  161. int sptt[4];
  162. int i, spt, head, cyl;
  163. uae_u64 total = (unsigned int)(size / 512);
  164. if (mode == 1) {
  165. // old-style head=1, spt=32 always mode
  166. head = 1;
  167. spt = 32;
  168. cyl = total / (head * spt);
  169. } else {
  170. sptt[0] = 63;
  171. sptt[1] = 127;
  172. sptt[2] = 255;
  173. sptt[3] = -1;
  174. for (i = 0; sptt[i] >= 0; i++) {
  175. int maxhead = sptt[i] < 255 ? 16 : 255;
  176. spt = sptt[i];
  177. for (head = 4; head <= maxhead; head++) {
  178. cyl = total / (head * spt);
  179. if (size <= 512 * 1024 * 1024) {
  180. if (cyl <= 1023)
  181. break;
  182. } else {
  183. if (cyl < 16383)
  184. break;
  185. if (cyl < 32767 && head >= 5)
  186. break;
  187. if (cyl <= 65535)
  188. break;
  189. }
  190. if (maxhead > 16) {
  191. head *= 2;
  192. head--;
  193. }
  194. }
  195. if (head <= 16)
  196. break;
  197. }
  198. }
  199. if (head > 16)
  200. head--;
  201. *pcyl = cyl;
  202. *phead = head;
  203. *psectorspertrack = spt;
  204. }
  205. void getchsgeometry (uae_u64 size, int *pcyl, int *phead, int *psectorspertrack)
  206. {
  207. getchsgeometry2 (size, pcyl, phead, psectorspertrack, 0);
  208. }
  209. void getchsgeometry_hdf (struct hardfiledata *hfd, uae_u64 size, int *pcyl, int *phead, int *psectorspertrack)
  210. {
  211. uae_u8 block[512];
  212. int i;
  213. uae_u64 minsize = 512 * 1024 * 1024;
  214. if (size <= minsize) {
  215. *phead = 1;
  216. *psectorspertrack = 32;
  217. }
  218. memset (block, 0, sizeof block);
  219. if (hfd) {
  220. hdf_read(hfd, block, 0, 512);
  221. if (block[0] == 'D' && block[1] == 'O' && block[2] == 'S') {
  222. int mode;
  223. for (mode = 0; mode < 2; mode++) {
  224. uae_u32 rootblock;
  225. uae_u32 chk = 0;
  226. getchsgeometry2 (size, pcyl, phead, psectorspertrack, mode);
  227. rootblock = (2 + ((*pcyl) * (*phead) * (*psectorspertrack) - 1)) / 2;
  228. memset (block, 0, sizeof block);
  229. hdf_read(hfd, block, (uae_u64)rootblock * 512, 512);
  230. for (i = 0; i < 512; i += 4)
  231. chk += (block[i] << 24) | (block[i + 1] << 16) | (block[i + 2] << 8) | (block[i + 3] << 0);
  232. if (!chk && block[0] == 0 && block[1] == 0 && block[2] == 0 && block[3] == 2 &&
  233. block[4] == 0 && block[5] == 0 && block[6] == 0 && block[7] == 0 &&
  234. block[8] == 0 && block[9] == 0 && block[10] == 0 && block[11] == 0 &&
  235. block[508] == 0 && block[509] == 0 && block[510] == 0 && block[511] == 1) {
  236. return;
  237. }
  238. }
  239. }
  240. }
  241. getchsgeometry2 (size, pcyl, phead, psectorspertrack, size <= minsize ? 1 : 2);
  242. }
  243. // partition hdf default
  244. void gethdfgeometry(uae_u64 size, struct uaedev_config_info *ci)
  245. {
  246. int head = 1;
  247. int sectorspertrack = 32;
  248. if (size >= 1048576000) { // >=1000M
  249. head = 16;
  250. while ((size / 512) / ((uae_u64)head * sectorspertrack) >= 32768 && sectorspertrack < 32768) {
  251. sectorspertrack *= 2;
  252. }
  253. }
  254. ci->surfaces = head;
  255. ci->sectors = sectorspertrack;
  256. ci->reserved = 2;
  257. ci->blocksize = 512;
  258. }
  259. void getchspgeometry (uae_u64 total, int *pcyl, int *phead, int *psectorspertrack, bool idegeometry)
  260. {
  261. uae_u64 blocks = total / 512;
  262. if (idegeometry) {
  263. *phead = 16;
  264. *psectorspertrack = 63;
  265. *pcyl = blocks / ((*psectorspertrack) * (*phead));
  266. if (blocks > 16515072) {
  267. /* >8G, CHS=16383/16/63 */
  268. *pcyl = 16383;
  269. *phead = 16;
  270. *psectorspertrack = 63;
  271. return;
  272. }
  273. return;
  274. }
  275. getchsgeometry (total, pcyl, phead, psectorspertrack);
  276. }
  277. static void getchshd (struct hardfiledata *hfd, int *pcyl, int *phead, int *psectorspertrack)
  278. {
  279. getchspgeometry (hfd->virtsize, pcyl, phead, psectorspertrack, false);
  280. }
  281. static void pl (uae_u8 *p, int off, uae_u32 v)
  282. {
  283. p += off * 4;
  284. p[0] = v >> 24;
  285. p[1] = v >> 16;
  286. p[2] = v >> 8;
  287. p[3] = v >> 0;
  288. }
  289. static void rdb_crc (uae_u8 *p)
  290. {
  291. uae_u32 sum;
  292. int i, blocksize;
  293. sum =0;
  294. blocksize = rl (p + 1 * 4);
  295. for (i = 0; i < blocksize; i++)
  296. sum += rl (p + i * 4);
  297. sum = -sum;
  298. pl (p, 2, sum);
  299. }
  300. static uae_u32 get_filesys_version(uae_u8 *fs, int size)
  301. {
  302. int ver = -1, rev = -1;
  303. for (int i = 0; i < size - 6; i++) {
  304. uae_u8 *p = fs + i;
  305. if (p[0] == 'V' && p[1] == 'E' && p[2] == 'R' && p[3] == ':' && p[4] == ' ') {
  306. uae_u8 *p2;
  307. p += 5;
  308. p2 = p;
  309. while (*p2 && p2 - fs < size)
  310. p2++;
  311. if (p2[0] == 0) {
  312. while (*p && (ver < 0 || rev < 0)) {
  313. if (*p == ' ') {
  314. p++;
  315. ver = atol((char*)p);
  316. if (ver < 0)
  317. ver = 0;
  318. while (*p) {
  319. if (*p == ' ')
  320. break;
  321. if (*p == '.') {
  322. p++;
  323. rev = atol((char*)p);
  324. if (rev < 0)
  325. rev = 0;
  326. }
  327. else {
  328. p++;
  329. }
  330. }
  331. break;
  332. }
  333. else {
  334. p++;
  335. }
  336. }
  337. }
  338. break;
  339. }
  340. }
  341. if (ver < 0)
  342. return 0xffffffff;
  343. if (rev < 0)
  344. rev = 0;
  345. return (ver << 16) | rev;
  346. }
  347. // hardware block size is always 256 or 512
  348. // filesystem block size can be 256, 512 or larger
  349. static void create_virtual_rdb (struct hardfiledata *hfd)
  350. {
  351. uae_u8 *rdb, *part, *denv, *fs;
  352. int fsblocksize = hfd->ci.blocksize;
  353. int hardblocksize = fsblocksize >= 512 ? 512 : 256;
  354. int cyl = hfd->ci.surfaces * hfd->ci.sectors;
  355. int cyls = (262144 + (cyl * fsblocksize) - 1) / (cyl * fsblocksize);
  356. int size = cyl * cyls * fsblocksize;
  357. int idx = 0;
  358. uae_u8 *filesys = NULL;
  359. int filesyslen = 0;
  360. uae_u32 fsver = 0;
  361. write_log(_T("Creating virtual RDB (RDB size=%d, %d blocks). H=%d S=%d HBS=%d FSBS=%d)\n"),
  362. size, size / hardblocksize, hfd->ci.surfaces, hfd->ci.sectors, hardblocksize, fsblocksize);
  363. if (hfd->ci.filesys[0]) {
  364. struct zfile *f = NULL;
  365. TCHAR fspath[MAX_DPATH];
  366. cfgfile_resolve_path_out_load(hfd->ci.filesys, fspath, MAX_DPATH, PATH_HDF);
  367. filesys = zfile_load_file(fspath, &filesyslen);
  368. if (filesys) {
  369. fsver = get_filesys_version(filesys, filesyslen);
  370. if (fsver == 0xffffffff)
  371. fsver = (99 << 16) | 99;
  372. if (filesyslen & 3) {
  373. xfree(filesys);
  374. filesys = NULL;
  375. filesyslen = 0;
  376. }
  377. }
  378. }
  379. int filesysblocks = (filesyslen + hardblocksize - 5 * 4 - 1) / (hardblocksize - 5 * 4);
  380. rdb = xcalloc (uae_u8, size);
  381. hfd->virtual_rdb = rdb;
  382. hfd->virtual_size = size;
  383. pl(rdb, 0, 0x5244534b); // "RDSK"
  384. pl(rdb, 1, 256 / 4);
  385. pl(rdb, 2, 0); // chksum
  386. pl(rdb, 3, 7); // hostid
  387. pl(rdb, 4, hardblocksize); // blockbytes
  388. pl(rdb, 5, 0); // flags
  389. pl(rdb, 6, -1); // badblock
  390. pl(rdb, 7, idx + 1); // part
  391. pl(rdb, 8, filesys ? idx + 2 : -1); // fs
  392. pl(rdb, 9, -1); // driveinit
  393. pl(rdb, 10, -1); // reserved
  394. pl(rdb, 11, -1); // reserved
  395. pl(rdb, 12, -1); // reserved
  396. pl(rdb, 13, -1); // reserved
  397. pl(rdb, 14, -1); // reserved
  398. pl(rdb, 15, -1); // reserved
  399. pl(rdb, 16, hfd->ci.highcyl + cyls - 1);
  400. pl(rdb, 17, hfd->ci.sectors);
  401. pl(rdb, 18, hfd->ci.surfaces * fsblocksize / hardblocksize);
  402. pl(rdb, 19, hfd->ci.interleave);
  403. pl(rdb, 20, 0); // park
  404. pl(rdb, 21, -1); // res
  405. pl(rdb, 22, -1); // res
  406. pl(rdb, 23, -1); // res
  407. pl(rdb, 24, 0); // writeprecomp
  408. pl(rdb, 25, 0); // reducedwrite
  409. pl(rdb, 26, 0); // steprate
  410. pl(rdb, 27, -1); // res
  411. pl(rdb, 28, -1); // res
  412. pl(rdb, 29, -1); // res
  413. pl(rdb, 30, -1); // res
  414. pl(rdb, 31, -1); // res
  415. pl(rdb, 32, 0); // rdbblockslo
  416. pl(rdb, 33, cyl * cyls * fsblocksize / hardblocksize - 1); // rdbblockshi
  417. pl(rdb, 34, cyls); // locyl
  418. pl(rdb, 35, hfd->ci.highcyl + cyls - 1); // hicyl
  419. pl(rdb, 36, cyl * fsblocksize / hardblocksize); // cylblocks
  420. pl(rdb, 37, 0); // autopark
  421. pl(rdb, 38, (1 + 1 + (filesysblocks ? 2 + filesysblocks : 0) - 1)); // highrdskblock
  422. pl(rdb, 39, -1); // res
  423. ua_copy ((char*)rdb + 40 * 4, 8, hfd->vendor_id);
  424. ua_copy ((char*)rdb + 42 * 4, 16, hfd->product_id);
  425. ua_copy ((char*)rdb + 46 * 4, 4, _T("UAE"));
  426. rdb_crc (rdb);
  427. idx++;
  428. part = rdb + hardblocksize * idx;
  429. pl(part, 0, 0x50415254); // "PART"
  430. pl(part, 1, 256 / 4);
  431. pl(part, 2, 0); // chksum
  432. pl(part, 3, 7); // hostid
  433. pl(part, 4, -1); // next
  434. pl(part, 5, hfd->ci.bootpri < -128 ? 2 : hfd->ci.bootpri == -128 ? 0 : 1); // bootable/nomount
  435. pl(part, 6, -1);
  436. pl(part, 7, -1);
  437. pl(part, 8, 0); // devflags
  438. part[9 * 4] = _tcslen (hfd->ci.devname);
  439. ua_copy ((char*)part + 9 * 4 + 1, 30, hfd->ci.devname);
  440. denv = part + 128;
  441. pl(denv, 0, 16);
  442. pl(denv, 1, fsblocksize / 4);
  443. pl(denv, 2, 0); // secorg
  444. pl(denv, 3, hfd->ci.surfaces);
  445. pl(denv, 4, 1);
  446. pl(denv, 5, hfd->ci.sectors);
  447. pl(denv, 6, hfd->ci.reserved);
  448. pl(denv, 7, 0); // prealloc
  449. pl(denv, 8, hfd->ci.interleave); // interleave
  450. pl(denv, 9, cyls); // lowcyl
  451. pl(denv, 10, hfd->ci.highcyl + cyls - 1);
  452. pl(denv, 11, hfd->ci.buffers);
  453. pl(denv, 12, hfd->ci.bufmemtype);
  454. pl(denv, 13, hfd->ci.maxtransfer);
  455. pl(denv, 14, hfd->ci.mask);
  456. pl(denv, 15, hfd->ci.bootpri);
  457. pl(denv, 16, hfd->ci.dostype);
  458. rdb_crc (part);
  459. idx++;
  460. if (filesys) {
  461. fs = rdb + hardblocksize * idx;
  462. pl(fs, 0, 0x46534844); // "FSHD"
  463. pl(fs, 1, 256 / 4);
  464. pl(fs, 2, 0); // chksum
  465. pl(fs, 3, 7); // hostid
  466. pl(fs, 4, -1); // next
  467. pl(fs, 5, 0); // flags
  468. pl(fs, 8, hfd->ci.dostype);
  469. pl(fs, 9, fsver); // version
  470. pl(fs, 10, 0x100 | 0x80 | 0x20 | 0x10); // patchflags: seglist + globvec + pri + stack
  471. pl(fs, 15, hfd->ci.stacksize); // stack
  472. pl(fs, 16, hfd->ci.priority); // priority
  473. pl(fs, 18, idx + 1); // first lseg
  474. pl(fs, 19, -1); // globvec
  475. rdb_crc(fs);
  476. idx++;
  477. int offset = 0;
  478. for (;;) {
  479. uae_u8 *lseg = rdb + hardblocksize * idx;
  480. int lsegdatasize = hardblocksize - 5 * 4;
  481. if (lseg + hardblocksize > rdb + size)
  482. break;
  483. pl(lseg, 0, 0x4c534547); // "LSEG"
  484. pl(lseg, 1, hardblocksize / 4);
  485. pl(lseg, 2, 0); // chksum
  486. pl(lseg, 3, 7); // hostid
  487. int v = filesyslen - offset;
  488. if (v <= lsegdatasize) {
  489. memcpy(lseg + 5 * 4, filesys + offset, v);
  490. pl(lseg, 4, -1);
  491. pl(lseg, 1, 5 + v / 4);
  492. rdb_crc(lseg);
  493. break;
  494. }
  495. memcpy(lseg + 5 * 4, filesys + offset, lsegdatasize);
  496. offset += lsegdatasize;
  497. idx++;
  498. pl(lseg, 4, idx); // next
  499. rdb_crc(lseg);
  500. }
  501. xfree(filesys);
  502. }
  503. hfd->virtsize += size;
  504. }
  505. void hdf_hd_close (struct hd_hardfiledata *hfd)
  506. {
  507. if (!hfd)
  508. return;
  509. hdf_close (&hfd->hfd);
  510. }
  511. int hdf_hd_open (struct hd_hardfiledata *hfd)
  512. {
  513. struct uaedev_config_info *ci = &hfd->hfd.ci;
  514. if (hdf_open (&hfd->hfd) <= 0)
  515. return 0;
  516. hfd->hfd.unitnum = ci->uae_unitnum;
  517. if (ci->physical_geometry) {
  518. hfd->cyls = ci->pcyls;
  519. hfd->heads = ci->pheads;
  520. hfd->secspertrack = ci->psecs;
  521. } else if (ci->highcyl && ci->surfaces && ci->sectors) {
  522. hfd->cyls = ci->highcyl;
  523. hfd->heads = ci->surfaces;
  524. hfd->secspertrack = ci->sectors;
  525. } else {
  526. getchshd (&hfd->hfd, &hfd->cyls, &hfd->heads, &hfd->secspertrack);
  527. }
  528. hfd->cyls_def = hfd->cyls;
  529. hfd->secspertrack_def = hfd->secspertrack;
  530. hfd->heads_def = hfd->heads;
  531. if (ci->surfaces && ci->sectors) {
  532. uae_u8 buf[512] = { 0 };
  533. hdf_read (&hfd->hfd, buf, 0, 512);
  534. if (buf[0] != 0 && memcmp (buf, _T("RDSK"), 4)) {
  535. ci->highcyl = (hfd->hfd.virtsize / ci->blocksize) / (ci->sectors * ci->surfaces);
  536. ci->dostype = rl (buf);
  537. create_virtual_rdb (&hfd->hfd);
  538. while (ci->highcyl * ci->surfaces * ci->sectors > hfd->cyls_def * hfd->secspertrack_def * hfd->heads_def) {
  539. hfd->cyls_def++;
  540. }
  541. }
  542. }
  543. hfd->size = hfd->hfd.virtsize;
  544. return 1;
  545. }
  546. static uae_u32 vhd_checksum (uae_u8 *p, int offset)
  547. {
  548. int i;
  549. uae_u32 sum;
  550. sum = 0;
  551. for (i = 0; i < 512; i++) {
  552. if (offset >= 0 && i >= offset && i < offset + 4)
  553. continue;
  554. sum += p[i];
  555. }
  556. return ~sum;
  557. }
  558. static int hdf_write2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len);
  559. static int hdf_read2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len);
  560. static void hdf_init_cache (struct hardfiledata *hfd)
  561. {
  562. }
  563. static void hdf_flush_cache (struct hardfiledata *hdf)
  564. {
  565. }
  566. static int hdf_cache_read (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
  567. {
  568. return hdf_read2 (hfd, buffer, offset, len);
  569. }
  570. static int hdf_cache_write (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
  571. {
  572. return hdf_write2 (hfd, buffer, offset, len);
  573. }
  574. int hdf_open (struct hardfiledata *hfd, const TCHAR *pname)
  575. {
  576. int ret;
  577. uae_u8 tmp[512], tmp2[512];
  578. uae_u32 v;
  579. TCHAR filepath[MAX_DPATH];
  580. if ((!pname || pname[0] == 0) && hfd->ci.rootdir[0] == 0)
  581. return 0;
  582. hfd->adide = 0;
  583. hfd->byteswap = 0;
  584. hfd->hfd_type = 0;
  585. hfd->virtual_size = 0;
  586. hfd->virtual_rdb = NULL;
  587. if (!pname)
  588. pname = hfd->ci.rootdir;
  589. cfgfile_resolve_path_out_load(pname, filepath, MAX_DPATH, PATH_HDF);
  590. #ifdef WITH_CHD
  591. TCHAR nametmp[MAX_DPATH];
  592. _tcscpy (nametmp, filepath);
  593. TCHAR *ext = _tcsrchr (nametmp, '.');
  594. if (ext && !_tcsicmp (ext, _T(".chd"))) {
  595. bool chd_readonly = false;
  596. struct zfile *zf = NULL;
  597. if (!hfd->ci.readonly)
  598. zf = zfile_fopen (nametmp, _T("rb+"));
  599. if (!zf) {
  600. chd_readonly = true;
  601. zf = zfile_fopen (nametmp, _T("rb"));
  602. }
  603. if (zf) {
  604. int err = CHDERR_FILE_NOT_WRITEABLE;
  605. hard_disk_file *chdf;
  606. chd_file *cf = new chd_file();
  607. if (!chd_readonly)
  608. err = cf->open(*zf, true, NULL);
  609. if (err == CHDERR_FILE_NOT_WRITEABLE) {
  610. chd_readonly = true;
  611. err = cf->open(*zf, false, NULL);
  612. }
  613. if (err != CHDERR_NONE) {
  614. zfile_fclose (zf);
  615. delete cf;
  616. goto end;
  617. }
  618. chdf = hard_disk_open(cf);
  619. if (!chdf) {
  620. hfd->ci.readonly = true;
  621. hfd->hfd_type = HFD_CHD_OTHER;
  622. hfd->chd_handle = cf;
  623. } else {
  624. hfd->hfd_type = HFD_CHD_HD;
  625. hfd->chd_handle = chdf;
  626. }
  627. if (chd_readonly)
  628. hfd->ci.readonly = true;
  629. hfd->virtsize = cf->logical_bytes();
  630. hfd->handle_valid = -1;
  631. write_log(_T("CHD '%s' mounted as %s, %s.\n"), filepath, chdf ? _T("HD") : _T("OTHER"), hfd->ci.readonly ? _T("read only") : _T("read/write"));
  632. return 1;
  633. }
  634. }
  635. #endif
  636. ret = hdf_open_target (hfd, filepath);
  637. if (ret <= 0)
  638. return ret;
  639. if (hdf_read_target (hfd, tmp, 0, 512) != 512)
  640. goto nonvhd;
  641. v = gl (tmp + 8); // features
  642. if ((v & 3) != 2)
  643. goto nonvhd;
  644. v = gl (tmp + 8 + 4); // version
  645. if ((v >> 16) != 1)
  646. goto nonvhd;
  647. hfd->hfd_type = gl (tmp + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 8 + 4);
  648. if (hfd->hfd_type != HFD_VHD_FIXED && hfd->hfd_type != HFD_VHD_DYNAMIC)
  649. goto nonvhd;
  650. v = gl (tmp + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 8 + 4 + 4);
  651. if (v == 0)
  652. goto nonvhd;
  653. if (vhd_checksum (tmp, 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 8 + 4 + 4) != v)
  654. goto nonvhd;
  655. if (hdf_read_target (hfd, tmp2, hfd->physsize - sizeof tmp2, 512) != 512)
  656. goto end;
  657. if (memcmp (tmp, tmp2, sizeof tmp))
  658. goto nonvhd;
  659. hfd->vhd_footerblock = hfd->physsize - 512;
  660. hfd->virtsize = (uae_u64)(gl (tmp + 8 + 4 + 4 + 8 + 4 + 4 +4 + 4 + 8)) << 32;
  661. hfd->virtsize |= gl (tmp + 8 + 4 + 4 + 8 + 4 + 4 +4 + 4 + 8 + 4);
  662. if (hfd->hfd_type == HFD_VHD_DYNAMIC) {
  663. uae_u32 size;
  664. hfd->vhd_bamoffset = gl (tmp + 8 + 4 + 4 + 4);
  665. if (hfd->vhd_bamoffset == 0 || hfd->vhd_bamoffset >= hfd->physsize)
  666. goto end;
  667. if (hdf_read_target (hfd, tmp, hfd->vhd_bamoffset, 512) != 512)
  668. goto end;
  669. v = gl (tmp + 8 + 8 + 8 + 4 + 4 + 4);
  670. if (vhd_checksum (tmp, 8 + 8 + 8 + 4 + 4 + 4) != v)
  671. goto end;
  672. v = gl (tmp + 8 + 8 + 8);
  673. if ((v >> 16) != 1)
  674. goto end;
  675. hfd->vhd_blocksize = gl (tmp + 8 + 8 + 8 + 4 + 4);
  676. hfd->vhd_bamoffset = gl (tmp + 8 + 8 + 4);
  677. hfd->vhd_bamsize = (((hfd->virtsize + hfd->vhd_blocksize - 1) / hfd->vhd_blocksize) * 4 + 511) & ~511;
  678. size = hfd->vhd_bamoffset + hfd->vhd_bamsize;
  679. hfd->vhd_header = xmalloc (uae_u8, size);
  680. if (hdf_read_target (hfd, hfd->vhd_header, 0, size) != size)
  681. goto end;
  682. hfd->vhd_sectormap = xmalloc (uae_u8, 512);
  683. hfd->vhd_sectormapblock = -1;
  684. hfd->vhd_bitmapsize = ((hfd->vhd_blocksize / (8 * 512)) + 511) & ~511;
  685. }
  686. write_log (_T("HDF is VHD %s image, virtual size=%lldK (%llx %lld)\n"),
  687. hfd->hfd_type == HFD_VHD_FIXED ? _T("fixed") : _T("dynamic"),
  688. hfd->virtsize / 1024, hfd->virtsize, hfd->virtsize);
  689. hdf_init_cache (hfd);
  690. return 1;
  691. nonvhd:
  692. hfd->hfd_type = 0;
  693. return 1;
  694. end:
  695. hdf_close_target (hfd);
  696. return 0;
  697. }
  698. int hdf_open (struct hardfiledata *hfd)
  699. {
  700. int v = hdf_open (hfd, NULL);
  701. if (!v)
  702. return v;
  703. get_hd_geometry(&hfd->ci);
  704. hfd->geometry = ini_load(hfd->ci.geometry, true);
  705. return v;
  706. }
  707. void hdf_close (struct hardfiledata *hfd)
  708. {
  709. hdf_flush_cache (hfd);
  710. hdf_close_target (hfd);
  711. #ifdef WITH_CHD
  712. if (hfd->hfd_type == HFD_CHD_OTHER) {
  713. chd_file *cf = (chd_file*)hfd->chd_handle;
  714. cf->close();
  715. delete cf;
  716. } else if (hfd->hfd_type == HFD_CHD_HD) {
  717. hard_disk_file *chdf = (hard_disk_file*)hfd->chd_handle;
  718. chd_file *cf = hard_disk_get_chd(chdf);
  719. hard_disk_close(chdf);
  720. cf->close();
  721. delete cf;
  722. }
  723. xfree(hfd->virtual_rdb);
  724. hfd->virtual_rdb = 0;
  725. hfd->virtual_size = 0;
  726. ini_free(hfd->geometry);
  727. hfd->geometry = NULL;
  728. hfd->chd_handle = NULL;
  729. #endif
  730. hfd->hfd_type = 0;
  731. xfree (hfd->vhd_header);
  732. hfd->vhd_header = NULL;
  733. xfree (hfd->vhd_sectormap);
  734. hfd->vhd_sectormap = NULL;
  735. }
  736. int hdf_dup (struct hardfiledata *dhfd, const struct hardfiledata *shfd)
  737. {
  738. return hdf_dup_target (dhfd, shfd);
  739. }
  740. static uae_u64 vhd_read (struct hardfiledata *hfd, void *v, uae_u64 offset, uae_u64 len)
  741. {
  742. uae_u64 read;
  743. uae_u8 *dataptr = (uae_u8*)v;
  744. //write_log (_T("%08x %08x\n"), (uae_u32)offset, (uae_u32)len);
  745. read = 0;
  746. if (offset & 511)
  747. return read;
  748. if (len & 511)
  749. return read;
  750. while (len > 0) {
  751. uae_u32 bamoffset = (offset / hfd->vhd_blocksize) * 4 + hfd->vhd_bamoffset;
  752. uae_u32 sectoroffset = gl (hfd->vhd_header + bamoffset);
  753. if (sectoroffset == 0xffffffff) {
  754. memset (dataptr, 0, 512);
  755. read += 512;
  756. } else {
  757. int bitmapoffsetbits;
  758. int bitmapoffsetbytes;
  759. uae_u64 sectormapblock;
  760. bitmapoffsetbits = (offset / 512) % (hfd->vhd_blocksize / 512);
  761. bitmapoffsetbytes = bitmapoffsetbits / 8;
  762. sectormapblock = sectoroffset * (uae_u64)512 + (bitmapoffsetbytes & ~511);
  763. if (hfd->vhd_sectormapblock != sectormapblock) {
  764. // read sector bitmap
  765. //write_log (_T("BM %08x\n"), sectormapblock);
  766. if (hdf_read_target (hfd, hfd->vhd_sectormap, sectormapblock, 512) != 512) {
  767. write_log (_T("vhd_read: bitmap read error\n"));
  768. return read;
  769. }
  770. hfd->vhd_sectormapblock = sectormapblock;
  771. }
  772. // block allocated in bitmap?
  773. if (hfd->vhd_sectormap[bitmapoffsetbytes & 511] & (1 << (7 - (bitmapoffsetbits & 7)))) {
  774. // read data block
  775. uae_u64 block = sectoroffset * (uae_u64)512 + hfd->vhd_bitmapsize + bitmapoffsetbits * 512;
  776. //write_log (_T("DB %08x\n"), block);
  777. if (hdf_read_target (hfd, dataptr, block, 512) != 512) {
  778. write_log (_T("vhd_read: data read error\n"));
  779. return read;
  780. }
  781. } else {
  782. memset (dataptr, 0, 512);
  783. }
  784. read += 512;
  785. }
  786. len -= 512;
  787. dataptr += 512;
  788. offset += 512;
  789. }
  790. return read;
  791. }
  792. static int vhd_write_enlarge (struct hardfiledata *hfd, uae_u32 bamoffset)
  793. {
  794. uae_u8 *buf, *p;
  795. int len;
  796. uae_u32 block;
  797. int v;
  798. len = hfd->vhd_blocksize + hfd->vhd_bitmapsize + 512;
  799. buf = xcalloc (uae_u8, len);
  800. if (!hdf_resize_target (hfd, hfd->physsize + len - 512)) {
  801. write_log (_T("vhd_enlarge: failure\n"));
  802. return 0;
  803. }
  804. // add footer (same as 512 byte header)
  805. memcpy (buf + len - 512, hfd->vhd_header, 512);
  806. v = hdf_write_target (hfd, buf, hfd->vhd_footerblock, len);
  807. xfree (buf);
  808. if (v != len) {
  809. write_log (_T("vhd_enlarge: footer write error\n"));
  810. return 0;
  811. }
  812. // write new offset to BAM
  813. p = hfd->vhd_header + bamoffset;
  814. block = hfd->vhd_footerblock / 512;
  815. p[0] = block >> 24;
  816. p[1] = block >> 16;
  817. p[2] = block >> 8;
  818. p[3] = block >> 0;
  819. // write to disk
  820. if (hdf_write_target (hfd, hfd->vhd_header + hfd->vhd_bamoffset, hfd->vhd_bamoffset, hfd->vhd_bamsize) != hfd->vhd_bamsize) {
  821. write_log (_T("vhd_enlarge: bam write error\n"));
  822. return 0;
  823. }
  824. hfd->vhd_footerblock += len - 512;
  825. return 1;
  826. }
  827. static uae_u64 vhd_write (struct hardfiledata *hfd, void *v, uae_u64 offset, uae_u64 len)
  828. {
  829. uae_u64 written;
  830. uae_u8 *dataptr = (uae_u8*)v;
  831. //write_log (_T("%08x %08x\n"), (uae_u32)offset, (uae_u32)len);
  832. written = 0;
  833. if (offset & 511)
  834. return written;
  835. if (len & 511)
  836. return written;
  837. while (len > 0) {
  838. uae_u32 bamoffset = (offset / hfd->vhd_blocksize) * 4 + hfd->vhd_bamoffset;
  839. uae_u32 sectoroffset = gl (hfd->vhd_header + bamoffset);
  840. if (sectoroffset == 0xffffffff) {
  841. if (!vhd_write_enlarge (hfd, bamoffset))
  842. return written;
  843. continue;
  844. } else {
  845. int bitmapoffsetbits;
  846. int bitmapoffsetbytes;
  847. bitmapoffsetbits = (offset / 512) % (hfd->vhd_blocksize / 512);
  848. bitmapoffsetbytes = bitmapoffsetbits / 8;
  849. uae_u64 sectormapblock = sectoroffset * (uae_u64)512 + (bitmapoffsetbytes & ~511);
  850. if (hfd->vhd_sectormapblock != sectormapblock) {
  851. // read sector bitmap
  852. if (hdf_read_target (hfd, hfd->vhd_sectormap, sectormapblock, 512) != 512) {
  853. write_log (_T("vhd_write: bitmap read error\n"));
  854. return written;
  855. }
  856. hfd->vhd_sectormapblock = sectormapblock;
  857. }
  858. // write data
  859. if (hdf_write_target (hfd, dataptr, sectoroffset * (uae_u64)512 + hfd->vhd_bitmapsize + bitmapoffsetbits * 512, 512) != 512) {
  860. write_log (_T("vhd_write: data write error\n"));
  861. return written;
  862. }
  863. // block already allocated in bitmap?
  864. if (!(hfd->vhd_sectormap[bitmapoffsetbytes & 511] & (1 << (7 - (bitmapoffsetbits & 7))))) {
  865. // no, we need to mark it allocated and write the modified bitmap back to the disk
  866. hfd->vhd_sectormap[bitmapoffsetbytes & 511] |= (1 << (7 - (bitmapoffsetbits & 7)));
  867. if (hdf_write_target (hfd, hfd->vhd_sectormap, sectormapblock, 512) != 512) {
  868. write_log (_T("vhd_write: bam write error\n"));
  869. return written;
  870. }
  871. }
  872. written += 512;
  873. }
  874. len -= 512;
  875. dataptr += 512;
  876. offset += 512;
  877. }
  878. return written;
  879. }
  880. int vhd_create (const TCHAR *name, uae_u64 size, uae_u32 dostype)
  881. {
  882. struct hardfiledata hfd;
  883. struct zfile *zf;
  884. uae_u8 *b;
  885. int cyl, cylsec, head, tracksec;
  886. uae_u32 crc, blocksize, batsize, batentrysize;
  887. int ret, i;
  888. time_t tm;
  889. if (size >= (uae_u64)10 * 1024 * 1024 * 1024)
  890. blocksize = 2 * 1024 * 1024;
  891. else
  892. blocksize = 512 * 1024;
  893. batsize = (size + blocksize - 1) / blocksize;
  894. batentrysize = batsize;
  895. batsize *= 4;
  896. batsize += 511;
  897. batsize &= ~511;
  898. ret = 0;
  899. b = NULL;
  900. zf = zfile_fopen (name, _T("wb"), 0);
  901. if (!zf)
  902. goto end;
  903. b = xcalloc (uae_u8, 512 + 1024 + batsize + 512);
  904. if (zfile_fwrite (b, 512 + 1024 + batsize + 512, 1, zf) != 1)
  905. goto end;
  906. memset (&hfd, 0, sizeof hfd);
  907. hfd.virtsize = hfd.physsize = size;
  908. hfd.ci.blocksize = 512;
  909. strcpy ((char*)b, "conectix"); // cookie
  910. b[0x0b] = 2; // features
  911. b[0x0d] = 1; // version
  912. b[0x10 + 6] = 2; // data offset
  913. // time stamp
  914. tm = time (NULL) - 946684800;
  915. b[0x18] = tm >> 24;
  916. b[0x19] = tm >> 16;
  917. b[0x1a] = tm >> 8;
  918. b[0x1b] = tm >> 0;
  919. strcpy ((char*)b + 0x1c, "vpc "); // creator application
  920. b[0x21] = 5; // creator version
  921. strcpy ((char*)b + 0x24, "Wi2k"); // creator host os
  922. // original and current size
  923. b[0x28] = b[0x30] = size >> 56;
  924. b[0x29] = b[0x31] = size >> 48;
  925. b[0x2a] = b[0x32] = size >> 40;
  926. b[0x2b] = b[0x33] = size >> 32;
  927. b[0x2c] = b[0x34] = size >> 24;
  928. b[0x2d] = b[0x35] = size >> 16;
  929. b[0x2e] = b[0x36] = size >> 8;
  930. b[0x2f] = b[0x37] = size >> 0;
  931. getchs2 (&hfd, &cyl, &cylsec, &head, &tracksec);
  932. // cylinders
  933. b[0x38] = cyl >> 8;
  934. b[0x39] = cyl;
  935. // heads
  936. b[0x3a] = head;
  937. // sectors per track
  938. b[0x3b] = tracksec;
  939. // disk type
  940. b[0x3c + 3] = HFD_VHD_DYNAMIC;
  941. get_guid_target (b + 0x44);
  942. crc = vhd_checksum (b, -1);
  943. b[0x40] = crc >> 24;
  944. b[0x41] = crc >> 16;
  945. b[0x42] = crc >> 8;
  946. b[0x43] = crc >> 0;
  947. // write header
  948. zfile_fseek (zf, 0, SEEK_SET);
  949. zfile_fwrite (b, 512, 1, zf);
  950. // write footer
  951. zfile_fseek (zf, 512 + 1024 + batsize, SEEK_SET);
  952. zfile_fwrite (b, 512, 1, zf);
  953. // dynamic disk header
  954. memset (b, 0, 1024);
  955. // cookie
  956. strcpy ((char*)b, "cxsparse");
  957. // data offset
  958. for (i = 0; i < 8; i++)
  959. b[0x08 + i] = 0xff;
  960. // table offset (bat)
  961. b[0x10 + 6] = 0x06;
  962. // version
  963. b[0x19] = 1;
  964. // max table entries
  965. b[0x1c] = batentrysize >> 24;
  966. b[0x1d] = batentrysize >> 16;
  967. b[0x1e] = batentrysize >> 8;
  968. b[0x1f] = batentrysize >> 0;
  969. b[0x20] = blocksize >> 24;
  970. b[0x21] = blocksize >> 16;
  971. b[0x22] = blocksize >> 8;
  972. b[0x23] = blocksize >> 0;
  973. crc = vhd_checksum (b, -1);
  974. b[0x24] = crc >> 24;
  975. b[0x25] = crc >> 16;
  976. b[0x26] = crc >> 8;
  977. b[0x27] = crc >> 0;
  978. // write dynamic header
  979. zfile_fseek (zf, 512, SEEK_SET);
  980. zfile_fwrite (b, 1024, 1, zf);
  981. // bat
  982. memset (b, 0, batsize);
  983. memset (b, 0xff, batentrysize * 4);
  984. zfile_fwrite (b, batsize, 1, zf);
  985. zfile_fclose (zf);
  986. zf = NULL;
  987. if (dostype) {
  988. uae_u8 bootblock[512] = { 0 };
  989. bootblock[0] = dostype >> 24;
  990. bootblock[1] = dostype >> 16;
  991. bootblock[2] = dostype >> 8;
  992. bootblock[3] = dostype >> 0;
  993. if (hdf_open (&hfd, name) > 0) {
  994. vhd_write (&hfd, bootblock, 0, 512);
  995. hdf_close (&hfd);
  996. }
  997. }
  998. ret = 1;
  999. end:
  1000. xfree (b);
  1001. zfile_fclose (zf);
  1002. return ret;
  1003. }
  1004. static int hdf_read2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
  1005. {
  1006. int ret = 0, extra = 0;
  1007. if (offset < hfd->virtual_size) {
  1008. uae_s64 len2 = offset + len <= hfd->virtual_size ? len : hfd->virtual_size - offset;
  1009. if (!hfd->virtual_rdb)
  1010. return 0;
  1011. memcpy(buffer, hfd->virtual_rdb + offset, len2);
  1012. len -= len2;
  1013. if (len <= 0)
  1014. return len2;
  1015. offset += len2;
  1016. buffer = (uae_u8*)buffer + len2;
  1017. extra = len2;
  1018. }
  1019. offset -= hfd->virtual_size;
  1020. if (hfd->hfd_type == HFD_VHD_DYNAMIC)
  1021. ret = vhd_read (hfd, buffer, offset, len);
  1022. else if (hfd->hfd_type == HFD_VHD_FIXED)
  1023. ret = hdf_read_target (hfd, buffer, offset + 512, len);
  1024. #ifdef WITH_CHD
  1025. else if (hfd->hfd_type == HFD_CHD_OTHER) {
  1026. chd_file *cf = (chd_file*)hfd->chd_handle;
  1027. if (cf->read_bytes(offset, buffer, len) == CHDERR_NONE)
  1028. ret = len;
  1029. else
  1030. return 0;
  1031. } else if (hfd->hfd_type == HFD_CHD_HD) {
  1032. hard_disk_file *chdf = (hard_disk_file*)hfd->chd_handle;
  1033. hard_disk_info *chdi = hard_disk_get_info(chdf);
  1034. chd_file *cf = hard_disk_get_chd(chdf);
  1035. uae_u8 *buf = (uae_u8*)buffer;
  1036. int got = 0;
  1037. offset /= chdi->sectorbytes;
  1038. while (len > 0) {
  1039. if (cf->read_units(offset, buf) != CHDERR_NONE)
  1040. break;
  1041. got += chdi->sectorbytes;
  1042. buf += chdi->sectorbytes;
  1043. len -= chdi->sectorbytes;
  1044. offset++;
  1045. }
  1046. ret = got;
  1047. }
  1048. #endif
  1049. else
  1050. ret = hdf_read_target (hfd, buffer, offset, len);
  1051. if (ret <= 0)
  1052. return ret;
  1053. ret += extra;
  1054. return ret;
  1055. }
  1056. static int hdf_write2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
  1057. {
  1058. int ret = 0, extra = 0;
  1059. // writes to virtual RDB are ignored
  1060. if (offset < hfd->virtual_size) {
  1061. uae_s64 len2 = offset + len <= hfd->virtual_size ? len : hfd->virtual_size - offset;
  1062. len -= len2;
  1063. if (len <= 0)
  1064. return len2;
  1065. offset += len2;
  1066. buffer = (uae_u8*)buffer + len2;
  1067. extra = len2;
  1068. }
  1069. offset -= hfd->virtual_size;
  1070. if (hfd->hfd_type == HFD_VHD_DYNAMIC)
  1071. ret = vhd_write (hfd, buffer, offset, len);
  1072. else if (hfd->hfd_type == HFD_VHD_FIXED)
  1073. ret = hdf_write_target (hfd, buffer, offset + 512, len);
  1074. #ifdef WITH_CHD
  1075. else if (hfd->hfd_type == HFD_CHD_OTHER)
  1076. return 0;
  1077. else if (hfd->hfd_type == HFD_CHD_HD) {
  1078. if (hfd->ci.readonly)
  1079. return 0;
  1080. hard_disk_file *chdf = (hard_disk_file*)hfd->chd_handle;
  1081. hard_disk_info *chdi = hard_disk_get_info(chdf);
  1082. chd_file *cf = hard_disk_get_chd(chdf);
  1083. uae_u8 *buf = (uae_u8*)buffer;
  1084. int got = 0;
  1085. offset /= chdi->sectorbytes;
  1086. while (len > 0) {
  1087. if (cf->write_units(offset, buf) != CHDERR_NONE)
  1088. break;
  1089. got += chdi->sectorbytes;
  1090. buf += chdi->sectorbytes;
  1091. len -= chdi->sectorbytes;
  1092. offset++;
  1093. }
  1094. ret = got;
  1095. }
  1096. #endif
  1097. else
  1098. ret = hdf_write_target (hfd, buffer, offset, len);
  1099. if (ret <= 0)
  1100. return ret;
  1101. ret += extra;
  1102. return ret;
  1103. }
  1104. static void adide_decode (void *v, int len)
  1105. {
  1106. int i;
  1107. uae_u8 *buffer = (uae_u8*)v;
  1108. for (i = 0; i < len; i += 2) {
  1109. uae_u8 *b = buffer + i;
  1110. uae_u16 w = (b[0] << 8) | (b[1] << 0);
  1111. uae_u16 o = adide_decode_word(w);
  1112. b[0] = o >> 8;
  1113. b[1] = o >> 0;
  1114. }
  1115. }
  1116. static void adide_encode (void *v, int len)
  1117. {
  1118. int i;
  1119. uae_u8 *buffer = (uae_u8*)v;
  1120. for (i = 0; i < len; i += 2) {
  1121. uae_u8 *b = buffer + i;
  1122. uae_u16 w = (b[0] << 8) | (b[1] << 0);
  1123. uae_u16 o = adide_encode_word(w);
  1124. b[0] = o >> 8;
  1125. b[1] = o >> 0;
  1126. }
  1127. }
  1128. static void hdf_byteswap (void *v, int len)
  1129. {
  1130. int i;
  1131. uae_u8 *b = (uae_u8*)v;
  1132. for (i = 0; i < len; i += 2) {
  1133. uae_u8 tmp = b[i];
  1134. b[i] = b[i + 1];
  1135. b[i + 1] = tmp;
  1136. }
  1137. }
  1138. int hdf_read_rdb (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
  1139. {
  1140. int v;
  1141. v = hdf_read (hfd, buffer, offset, len);
  1142. if (v > 0 && offset < 16 * 512 && !hfd->byteswap && !hfd->adide) {
  1143. uae_u8 *buf = (uae_u8*)buffer;
  1144. bool changed = false;
  1145. if (buf[0] == 0x39 && buf[1] == 0x10 && buf[2] == 0xd3 && buf[3] == 0x12) { // AdIDE encoded "CPRM"
  1146. hfd->adide = 1;
  1147. changed = true;
  1148. write_log (_T("HDF: adide scrambling detected\n"));
  1149. } else if (!memcmp (buf, "DRKS", 4)) {
  1150. hfd->byteswap = 1;
  1151. changed = true;
  1152. write_log (_T("HDF: byteswapped RDB detected\n"));
  1153. }
  1154. if (changed)
  1155. v = hdf_read (hfd, buffer, offset, len);
  1156. }
  1157. return v;
  1158. }
  1159. int hdf_read(struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
  1160. {
  1161. int v;
  1162. hf_log3 (_T("cmd_read: %p %04x-%08x (%d) %08x (%d)\n"),
  1163. buffer, (uae_u32)(offset >> 32), (uae_u32)offset, (uae_u32)(offset / hfd->ci.blocksize), (uae_u32)len, (uae_u32)(len / hfd->ci.blocksize));
  1164. if (!hfd->adide) {
  1165. v = hdf_cache_read (hfd, buffer, offset, len);
  1166. } else {
  1167. offset += 512;
  1168. v = hdf_cache_read (hfd, buffer, offset, len);
  1169. adide_decode (buffer, len);
  1170. }
  1171. if (hfd->byteswap)
  1172. hdf_byteswap (buffer, len);
  1173. return v;
  1174. }
  1175. int hdf_write(struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
  1176. {
  1177. int v;
  1178. hf_log3 (_T("cmd_write: %p %04x-%08x (%d) %08x (%d)\n"),
  1179. buffer, (uae_u32)(offset >> 32), (uae_u32)offset, (uae_u32)(offset / hfd->ci.blocksize), (uae_u32)len, (uae_u32)(len / hfd->ci.blocksize));
  1180. if (hfd->byteswap)
  1181. hdf_byteswap (buffer, len);
  1182. if (!hfd->adide) {
  1183. v = hdf_cache_write (hfd, buffer, offset, len);
  1184. } else {
  1185. offset += 512;
  1186. adide_encode (buffer, len);
  1187. v = hdf_cache_write (hfd, buffer, offset, len);
  1188. adide_decode (buffer, len);
  1189. }
  1190. if (hfd->byteswap)
  1191. hdf_byteswap (buffer, len);
  1192. return v;
  1193. }
  1194. static uae_u64 cmd_readx(struct hardfiledata *hfd, uae_u8 *dataptr, uae_u64 offset, uae_u64 len)
  1195. {
  1196. m68k_cancel_idle();
  1197. gui_flicker_led (LED_HD, hfd->unitnum, 1);
  1198. return hdf_read (hfd, dataptr, offset, len);
  1199. }
  1200. static uae_u64 cmd_read(TrapContext *ctx, struct hardfiledata *hfd, uaecptr dataptr, uae_u64 offset, uae_u64 len)
  1201. {
  1202. if (!len)
  1203. return 0;
  1204. if (!ctx && real_address_allowed()) {
  1205. addrbank *bank_data = &get_mem_bank (dataptr);
  1206. if (!bank_data)
  1207. return 0;
  1208. if (bank_data->check(dataptr, len)) {
  1209. uae_u8 *buffer = bank_data->xlateaddr(dataptr);
  1210. return cmd_readx(hfd, buffer, offset, len);
  1211. }
  1212. }
  1213. int total = 0;
  1214. while (len > 0) {
  1215. uae_u8 buf[RTAREA_TRAP_DATA_EXTRA_SIZE];
  1216. int max = RTAREA_TRAP_DATA_EXTRA_SIZE & ~511;
  1217. int size = len > max ? max : len;
  1218. if (cmd_readx(hfd, buf, offset, size) != size)
  1219. break;
  1220. trap_put_bytes(ctx, buf, dataptr, size);
  1221. offset += size;
  1222. dataptr += size;
  1223. len -= size;
  1224. total += size;
  1225. }
  1226. return total;
  1227. }
  1228. static uae_u64 cmd_writex(struct hardfiledata *hfd, uae_u8 *dataptr, uae_u64 offset, uae_u64 len)
  1229. {
  1230. m68k_cancel_idle();
  1231. gui_flicker_led (LED_HD, hfd->unitnum, 2);
  1232. return hdf_write (hfd, dataptr, offset, len);
  1233. }
  1234. static uae_u64 cmd_write(TrapContext *ctx, struct hardfiledata *hfd, uaecptr dataptr, uae_u64 offset, uae_u64 len)
  1235. {
  1236. if (!len)
  1237. return 0;
  1238. if (!ctx && real_address_allowed()) {
  1239. addrbank *bank_data = &get_mem_bank (dataptr);
  1240. if (!bank_data)
  1241. return 0;
  1242. if (bank_data->check(dataptr, len)) {
  1243. uae_u8 *buffer = bank_data->xlateaddr(dataptr);
  1244. return cmd_writex(hfd, buffer, offset, len);
  1245. }
  1246. }
  1247. int total = 0;
  1248. while (len > 0) {
  1249. uae_u8 buf[RTAREA_TRAP_DATA_EXTRA_SIZE];
  1250. int max = RTAREA_TRAP_DATA_EXTRA_SIZE & ~511;
  1251. int size = len > max ? max : len;
  1252. trap_get_bytes(ctx, buf, dataptr, size);
  1253. if (cmd_writex(hfd, buf, offset, size) != size)
  1254. break;
  1255. offset += size;
  1256. dataptr += size;
  1257. len -= size;
  1258. total += size;
  1259. }
  1260. return total;
  1261. }
  1262. static int checkbounds (struct hardfiledata *hfd, uae_u64 offset, uae_u64 len, int mode)
  1263. {
  1264. uae_u64 max = hfd->virtsize;
  1265. if (offset >= max || offset + len > max || (offset > 0xffffffff && (uae_s64)offset < 0)) {
  1266. write_log (_T("UAEHF SCSI: out of bounds, %08X-%08X + %08X-%08X > %08X-%08X\n"),
  1267. (uae_u32)(offset >> 32),(uae_u32)offset,(uae_u32)(len >> 32),(uae_u32)len,
  1268. (uae_u32)(max >> 32),(uae_u32)max);
  1269. return -1;
  1270. }
  1271. if (hfd->ci.max_lba) {
  1272. max = hfd->ci.max_lba * hfd->ci.blocksize;
  1273. if (offset >= max) {
  1274. write_log (_T("UAEHF SCSI: forced last lba out of bounds, %08X-%08X + %08X-%08X > %08X-%08X\n"),
  1275. (uae_u32)(offset >> 32),(uae_u32)offset,(uae_u32)(len >> 32),(uae_u32)len,
  1276. (uae_u32)(max >> 32),(uae_u32)max);
  1277. return -1;
  1278. }
  1279. }
  1280. if ((mode == 1 || mode == 2) && hfd->ci.badblock_num) {
  1281. offset /= hfd->ci.blocksize;
  1282. len /= hfd->ci.blocksize;
  1283. for (int i = 0; i < hfd->ci.badblock_num; i++) {
  1284. struct uaedev_badblock *bb = &hfd->ci.badblocks[i];
  1285. if (offset + len >= bb->first && offset < bb->last)
  1286. return 1;
  1287. }
  1288. }
  1289. return 0;
  1290. }
  1291. static bool is_writeprotected(struct hardfiledata *hfd)
  1292. {
  1293. return hfd->ci.readonly || hfd->dangerous || currprefs.harddrive_read_only;
  1294. }
  1295. static int nodisk (struct hardfiledata *hfd)
  1296. {
  1297. if (hfd->drive_empty)
  1298. return 1;
  1299. return 0;
  1300. }
  1301. static void setdrivestring(const TCHAR *s, uae_u8 *d, int start, int length)
  1302. {
  1303. int i = 0;
  1304. uae_char *ss = ua(s);
  1305. while (i < length && ss[i]) {
  1306. d[start + i] = ss[i];
  1307. i++;
  1308. }
  1309. while (i > 0) {
  1310. uae_char c = d[start + i - 1];
  1311. if (c != '_')
  1312. break;
  1313. i--;
  1314. }
  1315. while (i < length) {
  1316. d[start + i] = 32;
  1317. i++;
  1318. }
  1319. xfree (ss);
  1320. }
  1321. static const uae_u8 sasi_commands[] =
  1322. {
  1323. 0x00, 0x01, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x12,
  1324. 0xe0, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
  1325. 0xff
  1326. };
  1327. static const uae_u8 sasi_commands2[] =
  1328. {
  1329. 0x12,
  1330. 0xff
  1331. };
  1332. static uae_u64 get_scsi_6_offset(struct hardfiledata *hfd, struct hd_hardfiledata *hdhfd, uae_u8 *cmdbuf, uae_u64 *lba)
  1333. {
  1334. bool chs = hfd->ci.unit_feature_level == HD_LEVEL_SASI_CHS;
  1335. uae_u64 offset;
  1336. if (chs) {
  1337. int cyl, cylsec, head, tracksec;
  1338. if (hdhfd) {
  1339. cyl = hdhfd->cyls;
  1340. head = hdhfd->heads;
  1341. tracksec = hdhfd->secspertrack;
  1342. cylsec = 0;
  1343. } else {
  1344. getchsx(hfd, &cyl, &cylsec, &head, &tracksec);
  1345. }
  1346. int d_head = cmdbuf[1] & 31;
  1347. int d_cyl = cmdbuf[3] | ((cmdbuf[2] >> 6) << 8) | ((cmdbuf[1] >> 7) << 10);
  1348. int d_sec = cmdbuf[2] & 63;
  1349. *lba = ((cmdbuf[1] & (0x1f | 0x80 | 0x40)) << 16) | (cmdbuf[2] << 8) || cmdbuf[3];
  1350. if (d_cyl >= cyl || d_head >= head || d_sec >= tracksec)
  1351. return ~0;
  1352. offset = d_cyl * head * tracksec + d_head * tracksec + d_sec;
  1353. } else {
  1354. offset = ((cmdbuf[1] & 31) << 16) | (cmdbuf[2] << 8) | cmdbuf[3];
  1355. }
  1356. return offset;
  1357. }
  1358. int scsi_hd_emulate (struct hardfiledata *hfd, struct hd_hardfiledata *hdhfd, uae_u8 *cmdbuf, int scsi_cmd_len,
  1359. uae_u8 *scsi_data, int *data_len, uae_u8 *r, int *reply_len, uae_u8 *s, int *sense_len)
  1360. {
  1361. TrapContext *ctx = NULL;
  1362. if (cmdbuf == NULL)
  1363. return 0;
  1364. uae_u64 len, offset;
  1365. int lr = 0, ls = 0;
  1366. int chkerr;
  1367. int scsi_len = -1;
  1368. int status = 0;
  1369. int lun;
  1370. uae_u8 cmd;
  1371. bool sasi = hfd->ci.unit_feature_level >= HD_LEVEL_SASI && hfd->ci.unit_feature_level <= HD_LEVEL_SASI_ENHANCED;
  1372. bool sasie = hfd->ci.unit_feature_level == HD_LEVEL_SASI_ENHANCED;
  1373. bool omti = hfd->ci.unit_feature_level == HD_LEVEL_SASI_CHS;
  1374. uae_u8 sasi_sense = 0;
  1375. uae_u64 current_lba = ~0;
  1376. cmd = cmdbuf[0];
  1377. if (log_scsiemu) {
  1378. write_log (_T("SCSIEMU HD %d: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X CMDLEN=%d DATA=%p\n"), hfd->unitnum,
  1379. cmdbuf[0], cmdbuf[1], cmdbuf[2], cmdbuf[3], cmdbuf[4], cmdbuf[5], cmdbuf[6],
  1380. cmdbuf[7], cmdbuf[8], cmdbuf[9], cmdbuf[10], cmdbuf[11],
  1381. scsi_cmd_len, scsi_data);
  1382. }
  1383. /* REQUEST SENSE */
  1384. if (cmd == 0x03) {
  1385. return 0;
  1386. }
  1387. *reply_len = *sense_len = 0;
  1388. lun = cmdbuf[1] >> 5;
  1389. if (sasi || omti) {
  1390. lun = lun & 1;
  1391. if (lun)
  1392. goto nodisk;
  1393. }
  1394. if (cmd != 0x03 && cmd != 0x12 && lun) {
  1395. status = 2; /* CHECK CONDITION */
  1396. s[0] = 0x70;
  1397. s[2] = 5; /* ILLEGAL REQUEST */
  1398. s[12] = 0x25; /* INVALID LUN */
  1399. ls = 0x12;
  1400. write_log (_T("UAEHF: CMD=%02X LUN=%d ignored\n"), cmdbuf[0], lun);
  1401. goto scsi_done;
  1402. }
  1403. if (sasi || omti) {
  1404. int i;
  1405. for (i = 0; sasi_commands[i] != 0xff; i++) {
  1406. if (sasi_commands[i] == cmdbuf[0])
  1407. break;
  1408. }
  1409. if (sasi_commands[i] == 0xff) {
  1410. if (sasie) {
  1411. for (i = 0; sasi_commands2[i] != 0xff; i++) {
  1412. if (sasi_commands2[i] == cmdbuf[0])
  1413. break;
  1414. }
  1415. if (sasi_commands2[i] == 0xff)
  1416. goto errreq;
  1417. } else {
  1418. goto errreq;
  1419. }
  1420. }
  1421. switch (cmdbuf[0])
  1422. {
  1423. case 0x05: /* READ VERIFY */
  1424. if (nodisk(hfd))
  1425. goto nodisk;
  1426. offset = get_scsi_6_offset(hfd, hdhfd, cmdbuf, &current_lba);
  1427. if (offset == ~0) {
  1428. chkerr = 1;
  1429. goto checkfail;
  1430. }
  1431. current_lba = offset;
  1432. offset *= hfd->ci.blocksize;
  1433. chkerr = checkbounds(hfd, offset, hfd->ci.blocksize, 1);
  1434. if (chkerr) {
  1435. current_lba = offset;
  1436. goto checkfail;
  1437. }
  1438. scsi_len = 0;
  1439. goto scsi_done;
  1440. case 0x0c: /* INITIALIZE DRIVE CHARACTERISTICS */
  1441. scsi_len = 8;
  1442. write_log(_T("INITIALIZE DRIVE CHARACTERISTICS: "));
  1443. write_log(_T("Heads: %d Cyls: %d Secs: %d\n"),
  1444. (scsi_data[1] >> 4) | ((scsi_data[0] & 0xc0) << 4),
  1445. ((scsi_data[1] & 15) << 8) | (scsi_data[2]),
  1446. scsi_data[5]);
  1447. for (int i = 0; i < 8; i++) {
  1448. write_log(_T("%02X "), scsi_data[i]);
  1449. }
  1450. write_log(_T("\n"));
  1451. goto scsi_done;
  1452. case 0x11: // ASSIGN ALTERNATE TRACK
  1453. if (nodisk(hfd))
  1454. goto nodisk;
  1455. // do nothing, swallow data
  1456. scsi_len = 4;
  1457. goto scsi_done;
  1458. case 0x12: /* INQUIRY */
  1459. {
  1460. int cyl, cylsec, head, tracksec;
  1461. int alen = cmdbuf[4];
  1462. if (nodisk(hfd))
  1463. goto nodisk;
  1464. if (hdhfd) {
  1465. cyl = hdhfd->cyls;
  1466. head = hdhfd->heads;
  1467. tracksec = hdhfd->secspertrack;
  1468. cylsec = 0;
  1469. } else {
  1470. getchsx(hfd, &cyl, &cylsec, &head, &tracksec);
  1471. }
  1472. r[0] = 0;
  1473. r[1] = 11;
  1474. r[9] = cyl >> 8;
  1475. r[10] = cyl;
  1476. r[11] = head;
  1477. scsi_len = lr = alen > 12 ? 12 : alen;
  1478. goto scsi_done;
  1479. }
  1480. break;
  1481. }
  1482. }
  1483. switch (cmdbuf[0])
  1484. {
  1485. case 0x12: /* INQUIRY */
  1486. {
  1487. if ((cmdbuf[1] & 1) || cmdbuf[2] != 0)
  1488. goto err;
  1489. int alen = (cmdbuf[3] << 8) | cmdbuf[4];
  1490. if (lun != 0) {
  1491. r[0] = 0x7f;
  1492. } else {
  1493. r[0] = 0;
  1494. }
  1495. r[2] = 2; /* supports SCSI-2 */
  1496. r[3] = 2; /* response data format */
  1497. r[4] = 32; /* additional length */
  1498. r[7] = 0;
  1499. lr = alen < 36 ? alen : 36;
  1500. if (hdhfd) {
  1501. r[2] = hdhfd->ansi_version;
  1502. r[3] = hdhfd->ansi_version >= 2 ? 2 : 0;
  1503. }
  1504. setdrivestring(hfd->vendor_id, r, 8, 8);
  1505. setdrivestring(hfd->product_id, r, 16, 16);
  1506. setdrivestring(hfd->product_rev, r, 32, 4);
  1507. uae_u8 *rr;
  1508. if (ini_getdata(hfd->geometry, _T("INQUIRY"), _T("00"), &rr, &lr)) {
  1509. if (lr > alen)
  1510. lr = alen;
  1511. memcpy(r, rr, lr);
  1512. xfree(rr);
  1513. }
  1514. if (lun == 0 && hfd->drive_empty) {
  1515. r[0] |= 0x20; // not present
  1516. r[1] |= 0x80; // removable..
  1517. }
  1518. scsi_len = lr;
  1519. }
  1520. goto scsi_done;
  1521. case 0x1b: /* START/STOP UNIT */
  1522. scsi_len = 0;
  1523. hfd->unit_stopped = (cmdbuf[4] & 1) == 0;
  1524. goto scsi_done;
  1525. }
  1526. if (hfd->unit_stopped) {
  1527. status = 2; /* CHECK CONDITION */
  1528. s[0] = 0x70;
  1529. s[2] = 2; /* NOT READY */
  1530. s[12] = 4; /* not ready */
  1531. s[13] = 2; /* need initialise command */
  1532. ls = 0x12;
  1533. goto scsi_done;
  1534. }
  1535. switch (cmdbuf[0])
  1536. {
  1537. case 0x00: /* TEST UNIT READY */
  1538. if (nodisk (hfd))
  1539. goto nodisk;
  1540. scsi_len = 0;
  1541. break;
  1542. case 0x01: /* REZERO UNIT */
  1543. if (nodisk (hfd))
  1544. goto nodisk;
  1545. scsi_len = 0;
  1546. break;
  1547. case 0x04: /* FORMAT UNIT */
  1548. // do nothing
  1549. if (nodisk (hfd))
  1550. goto nodisk;
  1551. if (is_writeprotected(hfd))
  1552. goto readprot;
  1553. scsi_len = 0;
  1554. break;
  1555. case 0x05: /* VERIFY TRACK */
  1556. // do nothing
  1557. if (nodisk (hfd))
  1558. goto nodisk;
  1559. scsi_len = 0;
  1560. break;
  1561. case 0x06: /* FORMAT TRACK */
  1562. case 0x07: /* FORMAT BAD TRACK */
  1563. if (nodisk (hfd))
  1564. goto nodisk;
  1565. if (is_writeprotected(hfd))
  1566. goto readprot;
  1567. // do nothing
  1568. if (cmdbuf[5] & 0x40) {
  1569. // data from sector buffer
  1570. } else {
  1571. // data is static 0x6c
  1572. }
  1573. scsi_len = 0;
  1574. break;
  1575. case 0x09: /* READ VERIFY */
  1576. if (nodisk(hfd))
  1577. goto nodisk;
  1578. offset = get_scsi_6_offset(hfd, hdhfd, cmdbuf, &current_lba);
  1579. if (offset == ~0) {
  1580. chkerr = 1;
  1581. goto checkfail;
  1582. }
  1583. current_lba = offset;
  1584. offset *= hfd->ci.blocksize;
  1585. chkerr = checkbounds(hfd, offset, hfd->ci.blocksize, 1);
  1586. if (chkerr) {
  1587. current_lba = offset;
  1588. goto checkfail;
  1589. }
  1590. scsi_len = 0;
  1591. break;
  1592. case 0x0b: /* SEEK (6) */
  1593. if (nodisk (hfd))
  1594. goto nodisk;
  1595. offset = get_scsi_6_offset(hfd, hdhfd, cmdbuf, &current_lba);
  1596. if (offset == ~0) {
  1597. chkerr = 1;
  1598. goto checkfail;
  1599. }
  1600. current_lba = offset;
  1601. offset *= hfd->ci.blocksize;
  1602. chkerr = checkbounds(hfd, offset, hfd->ci.blocksize, 3);
  1603. if (chkerr)
  1604. goto checkfail;
  1605. scsi_len = 0;
  1606. break;
  1607. case 0x08: /* READ (6) */
  1608. if (nodisk (hfd))
  1609. goto nodisk;
  1610. offset = get_scsi_6_offset(hfd, hdhfd, cmdbuf, &current_lba);
  1611. if (offset == ~0) {
  1612. chkerr = 1;
  1613. goto checkfail;
  1614. }
  1615. current_lba = offset;
  1616. offset *= hfd->ci.blocksize;
  1617. len = cmdbuf[4];
  1618. if (!len)
  1619. len = 256;
  1620. len *= hfd->ci.blocksize;
  1621. chkerr = checkbounds(hfd, offset, len, 1);
  1622. if (chkerr)
  1623. goto checkfail;
  1624. scsi_len = (uae_u32)cmd_readx(hfd, scsi_data, offset, len);
  1625. break;
  1626. case 0x0e: /* READ SECTOR BUFFER */
  1627. len = hfd->ci.blocksize;
  1628. scsi_len = len;
  1629. memset(scsi_data, 0, len);
  1630. if (len > sizeof(hfd->sector_buffer))
  1631. len = sizeof(hfd->sector_buffer);
  1632. memcpy(scsi_data, hfd->sector_buffer, len);
  1633. break;
  1634. case 0x0f: /* WRITE SECTOR BUFFER */
  1635. len = hfd->ci.blocksize;
  1636. scsi_len = len;
  1637. if (len > sizeof(hfd->sector_buffer))
  1638. len = sizeof(hfd->sector_buffer);
  1639. memcpy(hfd->sector_buffer, scsi_data, len);
  1640. break;
  1641. case 0x0a: /* WRITE (6) */
  1642. if (nodisk (hfd))
  1643. goto nodisk;
  1644. if (is_writeprotected(hfd))
  1645. goto readprot;
  1646. offset = get_scsi_6_offset(hfd, hdhfd, cmdbuf, &current_lba);
  1647. if (offset == ~0) {
  1648. chkerr = 1;
  1649. goto checkfail;
  1650. }
  1651. current_lba = offset;
  1652. offset *= hfd->ci.blocksize;
  1653. len = cmdbuf[4];
  1654. if (!len)
  1655. len = 256;
  1656. len *= hfd->ci.blocksize;
  1657. chkerr = checkbounds(hfd, offset, len, 2);
  1658. if (chkerr)
  1659. goto checkfail;
  1660. scsi_len = (uae_u32)cmd_writex(hfd, scsi_data, offset, len);
  1661. break;
  1662. case 0x55: // MODE SELECT(10)
  1663. case 0x15: // MODE SELECT(6)
  1664. {
  1665. bool select10 = cmdbuf[0] == 0x55;
  1666. bool sp = (cmdbuf[1] & 1) != 0;
  1667. bool pf = (cmdbuf[1] & 0x10) != 0;
  1668. int plen;
  1669. uae_u8 bd[8];
  1670. if (nodisk (hfd))
  1671. goto nodisk;
  1672. // we don't support save pages
  1673. if (pf)
  1674. goto errreq;
  1675. // assume error first
  1676. status = 2; /* CHECK CONDITION */
  1677. s[0] = 0x70;
  1678. s[2] = 5; /* ILLEGAL REQUEST */
  1679. s[12] = 0x26; /* INVALID FIELD IN PARAMETER LIST */
  1680. ls = 0x12;
  1681. memset(bd, 0, sizeof bd);
  1682. uae_u8 *p = scsi_data;
  1683. if (select10) {
  1684. plen = (cmdbuf[7] << 8) | cmdbuf[8];
  1685. memcpy(bd, p, plen > 8 ? 8 : plen);
  1686. p += plen > 8 ? 8 : plen;
  1687. } else {
  1688. plen = cmdbuf[4];
  1689. if (plen > 0)
  1690. bd[0] = scsi_data[0];
  1691. if (plen > 1)
  1692. bd[2] = scsi_data[1]; // medium type
  1693. if (plen > 2)
  1694. bd[3] = scsi_data[2];
  1695. if (plen > 3)
  1696. bd[7] = scsi_data[3]; // bd len
  1697. p += plen > 4 ? 4 : plen;
  1698. }
  1699. if (bd[0] != 0 || bd[1] != 0 || bd[2] != 0 || bd[3] != 0 || bd[4] != 0 || bd[5] != 0)
  1700. goto scsi_done;
  1701. int bdlen = (bd[6] << 8) | bd[7];
  1702. if (bdlen != 0 && bdlen != 8)
  1703. goto scsi_done;
  1704. if (bdlen) {
  1705. int block = (p[4] << 24) | (p[5] << 16) | (p[6] << 8) | (p[7] << 0);
  1706. if (block != 512)
  1707. goto scsi_done;
  1708. p += bdlen;
  1709. }
  1710. for (;;) {
  1711. int rem = plen - (p - scsi_data);
  1712. if (!rem)
  1713. break;
  1714. if (rem < 2)
  1715. goto scsi_done;
  1716. uae_u8 pc = *p++;
  1717. if (pc >= 0x40)
  1718. goto scsi_done;
  1719. uae_u8 pagelen = *p++;
  1720. rem -= 2;
  1721. if (!pagelen || pagelen > rem)
  1722. goto scsi_done;
  1723. if (pc != 0 && pc != 1 && pc != 3 && pc != 4)
  1724. goto scsi_done;
  1725. if (pc == 0)
  1726. break;
  1727. p += pagelen;
  1728. }
  1729. status = 0;
  1730. ls = 0;
  1731. scsi_len = 0;
  1732. break;
  1733. }
  1734. case 0x5a: // MODE SENSE(10)
  1735. case 0x1a: /* MODE SENSE(6) */
  1736. {
  1737. uae_u8 *p;
  1738. bool pcodeloop = false;
  1739. bool sense10 = cmdbuf[0] == 0x5a;
  1740. int pc = cmdbuf[2] >> 6;
  1741. int pcode = cmdbuf[2] & 0x3f;
  1742. int dbd = cmdbuf[1] & 8;
  1743. int cyl, head, tracksec;
  1744. int totalsize, bdsize, alen;
  1745. if (nodisk (hfd))
  1746. goto nodisk;
  1747. if (hdhfd) {
  1748. cyl = hdhfd->cyls;
  1749. head = hdhfd->heads;
  1750. tracksec = hdhfd->secspertrack;
  1751. } else {
  1752. int cylsec;
  1753. getchsx (hfd, &cyl, &cylsec, &head, &tracksec);
  1754. }
  1755. //write_log (_T("MODE SENSE PC=%d CODE=%d DBD=%d\n"), pc, pcode, dbd);
  1756. p = r;
  1757. if (sense10) {
  1758. totalsize = 8 - 2;
  1759. alen = (cmdbuf[7] << 8) | cmdbuf[8];
  1760. p[2] = 0;
  1761. p[3] = is_writeprotected(hfd) ? 0x80 : 0x00;
  1762. p[4] = 0;
  1763. p[5] = 0;
  1764. p[6] = 0;
  1765. p[7] = 0;
  1766. p += 8;
  1767. } else {
  1768. totalsize = 4 - 1;
  1769. alen = cmdbuf[4];
  1770. p[1] = 0;
  1771. p[2] = is_writeprotected(hfd) ? 0x80 : 0x00;
  1772. p[3] = 0;
  1773. p += 4;
  1774. }
  1775. bdsize = 0;
  1776. if (!dbd) {
  1777. uae_u32 blocks = (uae_u32)(hfd->virtsize / hfd->ci.blocksize);
  1778. wl(p + 0, blocks >= 0x00ffffff ? 0x00ffffff : blocks);
  1779. wl(p + 4, hfd->ci.blocksize);
  1780. bdsize = 8;
  1781. p += bdsize;
  1782. }
  1783. if (pcode == 0x3f) {
  1784. pcode = 1; // page = 0 must be last
  1785. pcodeloop = true;
  1786. }
  1787. for (;;) {
  1788. int psize = 0;
  1789. if (pcode == 0) {
  1790. p[0] = 0;
  1791. p[1] = 0;
  1792. p[2] = 0x20;
  1793. p[3] = 0;
  1794. psize = 4;
  1795. } else if (pcode == 1) {
  1796. // error recovery page
  1797. p[0] = 1;
  1798. p[1] = 0x0a;
  1799. psize = p[1] + 2;
  1800. // return defaults (0)
  1801. } else if (pcode == 3) {
  1802. // format parameters
  1803. p[0] = 3;
  1804. p[1] = 22;
  1805. p[3] = 1;
  1806. p[10] = tracksec >> 8;
  1807. p[11] = tracksec;
  1808. p[12] = hfd->ci.blocksize >> 8;
  1809. p[13] = hfd->ci.blocksize;
  1810. p[15] = 1; // interleave
  1811. p[20] = 0x80;
  1812. psize = p[1] + 2;
  1813. } else if (pcode == 4) {
  1814. // rigid drive geometry
  1815. p[0] = 4;
  1816. wl(p + 1, cyl);
  1817. p[1] = 22;
  1818. p[5] = head;
  1819. wl(p + 13, cyl);
  1820. ww(p + 20, 5400);
  1821. psize = p[1] + 2;
  1822. } else {
  1823. if (!pcodeloop)
  1824. goto err;
  1825. }
  1826. totalsize += psize;
  1827. p += psize;
  1828. if (!pcodeloop)
  1829. break;
  1830. if (pcode == 0)
  1831. break;
  1832. pcode++;
  1833. if (pcode == 0x3f)
  1834. pcode = 0;
  1835. }
  1836. if (sense10) {
  1837. totalsize += bdsize;
  1838. r[6] = bdsize >> 8;
  1839. r[7] = bdsize & 0xff;
  1840. r[0] = totalsize >> 8;
  1841. r[1] = totalsize & 0xff;
  1842. } else {
  1843. totalsize += bdsize;
  1844. r[3] = (uae_u8)bdsize;
  1845. r[0] = (uae_u8)totalsize;
  1846. }
  1847. scsi_len = lr = totalsize + 1;
  1848. if (scsi_len > alen)
  1849. scsi_len = alen;
  1850. if (lr > alen)
  1851. lr = alen;
  1852. break;
  1853. }
  1854. break;
  1855. case 0x1d: /* SEND DIAGNOSTICS */
  1856. break;
  1857. case 0x25: /* READ CAPACITY */
  1858. {
  1859. int pmi = cmdbuf[8] & 1;
  1860. uae_u32 lba = (cmdbuf[2] << 24) | (cmdbuf[3] << 16) | (cmdbuf[4] << 8) | cmdbuf[5];
  1861. uae_u64 blocks;
  1862. int cyl, head, tracksec;
  1863. if (nodisk (hfd))
  1864. goto nodisk;
  1865. blocks = hfd->virtsize / hfd->ci.blocksize;
  1866. if (hfd->ci.max_lba)
  1867. blocks = hfd->ci.max_lba;
  1868. if (hdhfd) {
  1869. cyl = hdhfd->cyls;
  1870. head = hdhfd->heads;
  1871. tracksec = hdhfd->secspertrack;
  1872. } else {
  1873. int cylsec;
  1874. getchsx (hfd, &cyl, &cylsec, &head, &tracksec);
  1875. }
  1876. if (pmi == 0 && lba != 0)
  1877. goto errreq;
  1878. if (pmi) {
  1879. lba += tracksec * head;
  1880. lba /= tracksec * head;
  1881. lba *= tracksec * head;
  1882. if (lba > blocks)
  1883. lba = blocks;
  1884. blocks = lba;
  1885. }
  1886. wl (r, (uae_u32)(blocks <= 0x100000000 ? blocks - 1 : 0xffffffff));
  1887. wl (r + 4, hfd->ci.blocksize);
  1888. scsi_len = lr = 8;
  1889. }
  1890. break;
  1891. case 0x2b: /* SEEK (10) */
  1892. if (nodisk (hfd))
  1893. goto nodisk;
  1894. offset = rl (cmdbuf + 2);
  1895. current_lba = offset;
  1896. offset *= hfd->ci.blocksize;
  1897. chkerr = checkbounds(hfd, offset, hfd->ci.blocksize, 3);
  1898. if (chkerr)
  1899. goto checkfail;
  1900. scsi_len = 0;
  1901. break;
  1902. case 0x28: /* READ (10) */
  1903. if (nodisk (hfd))
  1904. goto nodisk;
  1905. offset = rl (cmdbuf + 2);
  1906. current_lba = offset;
  1907. offset *= hfd->ci.blocksize;
  1908. len = rl (cmdbuf + 7 - 2) & 0xffff;
  1909. len *= hfd->ci.blocksize;
  1910. chkerr = checkbounds(hfd, offset, len, 1);
  1911. if (chkerr)
  1912. goto checkfail;
  1913. scsi_len = (uae_u32)cmd_readx (hfd, scsi_data, offset, len);
  1914. break;
  1915. case 0x2a: /* WRITE (10) */
  1916. if (nodisk (hfd))
  1917. goto nodisk;
  1918. if (is_writeprotected(hfd))
  1919. goto readprot;
  1920. offset = rl (cmdbuf + 2);
  1921. current_lba = offset;
  1922. offset *= hfd->ci.blocksize;
  1923. len = rl (cmdbuf + 7 - 2) & 0xffff;
  1924. len *= hfd->ci.blocksize;
  1925. chkerr = checkbounds(hfd, offset, len, 2);
  1926. if (chkerr)
  1927. goto checkfail;
  1928. scsi_len = (uae_u32)cmd_writex (hfd, scsi_data, offset, len);
  1929. break;
  1930. case 0x2f: /* VERIFY (10) */
  1931. {
  1932. int bytchk = cmdbuf[1] & 2;
  1933. if (nodisk (hfd))
  1934. goto nodisk;
  1935. if (bytchk) {
  1936. offset = rl (cmdbuf + 2);
  1937. current_lba = offset;
  1938. offset *= hfd->ci.blocksize;
  1939. len = rl (cmdbuf + 7 - 2) & 0xffff;
  1940. len *= hfd->ci.blocksize;
  1941. chkerr = checkbounds (hfd, offset, len, 1);
  1942. if (chkerr)
  1943. goto checkfail;
  1944. uae_u8 *vb = xmalloc(uae_u8, hfd->ci.blocksize);
  1945. while (len > 0) {
  1946. int readlen = cmd_readx (hfd, vb, offset, hfd->ci.blocksize);
  1947. if (readlen != hfd->ci.blocksize || memcmp (vb, scsi_data, hfd->ci.blocksize)) {
  1948. xfree (vb);
  1949. goto miscompare;
  1950. }
  1951. scsi_data += hfd->ci.blocksize;
  1952. offset += hfd->ci.blocksize;
  1953. len -= hfd->ci.blocksize;
  1954. }
  1955. xfree (vb);
  1956. }
  1957. scsi_len = 0;
  1958. }
  1959. break;
  1960. case 0x35: /* SYNCRONIZE CACHE (10) */
  1961. if (nodisk (hfd))
  1962. goto nodisk;
  1963. scsi_len = 0;
  1964. break;
  1965. case 0xa8: /* READ (12) */
  1966. if (nodisk (hfd))
  1967. goto nodisk;
  1968. offset = rl (cmdbuf + 2);
  1969. current_lba = offset;
  1970. offset *= hfd->ci.blocksize;
  1971. len = rl (cmdbuf + 6);
  1972. len *= hfd->ci.blocksize;
  1973. chkerr = checkbounds(hfd, offset, len, 1);
  1974. if (chkerr)
  1975. goto checkfail;
  1976. scsi_len = (uae_u32)cmd_readx (hfd, scsi_data, offset, len);
  1977. break;
  1978. case 0xaa: /* WRITE (12) */
  1979. if (nodisk (hfd))
  1980. goto nodisk;
  1981. if (is_writeprotected(hfd))
  1982. goto readprot;
  1983. offset = rl (cmdbuf + 2);
  1984. current_lba = offset;
  1985. offset *= hfd->ci.blocksize;
  1986. len = rl (cmdbuf + 6);
  1987. len *= hfd->ci.blocksize;
  1988. chkerr = checkbounds(hfd, offset, len, 2);
  1989. if (chkerr)
  1990. goto checkfail;
  1991. scsi_len = (uae_u32)cmd_writex (hfd, scsi_data, offset, len);
  1992. break;
  1993. case 0x37: /* READ DEFECT DATA */
  1994. if (nodisk (hfd))
  1995. goto nodisk;
  1996. scsi_len = lr = 4;
  1997. r[0] = 0;
  1998. r[1] = cmdbuf[1] & 0x1f;
  1999. r[2] = 0;
  2000. r[3] = 0;
  2001. #if 0
  2002. status = 2; /* CHECK CONDITION */
  2003. s[0] = 0x70;
  2004. s[2] = 0; /* NO SENSE */
  2005. s[12] = 0x1c; /* DEFECT LIST NOT FOUND */
  2006. ls = 0x12;
  2007. #endif
  2008. break;
  2009. case 0xe0: /* RAM DIAGNOSTICS */
  2010. case 0xe3: /* DRIVE DIAGNOSTIC */
  2011. case 0xe4: /* CONTROLLER INTERNAL DIAGNOSTICS */
  2012. scsi_len = 0;
  2013. break;
  2014. readprot:
  2015. status = 2; /* CHECK CONDITION */
  2016. s[0] = 0x70;
  2017. s[2] = 7; /* DATA PROTECT */
  2018. s[12] = 0x27; /* WRITE PROTECTED */
  2019. ls = 0x12;
  2020. sasi_sense = 0x03; // write fault
  2021. break;
  2022. nodisk:
  2023. status = 2; /* CHECK CONDITION */
  2024. s[0] = 0x70;
  2025. s[2] = 2; /* NOT READY */
  2026. s[12] = 0x3A; /* MEDIUM NOT PRESENT */
  2027. ls = 0x12;
  2028. sasi_sense = 0x04; // drive not ready
  2029. break;
  2030. default:
  2031. err:
  2032. write_log (_T("UAEHF: unsupported scsi command 0x%02X LUN=%d\n"), cmdbuf[0], lun);
  2033. errreq:
  2034. status = 2; /* CHECK CONDITION */
  2035. s[0] = 0x70;
  2036. s[2] = 5; /* ILLEGAL REQUEST */
  2037. s[12] = 0x24; /* ILLEGAL FIELD IN CDB */
  2038. ls = 0x12;
  2039. sasi_sense = 0x22; // invalid parameter
  2040. break;
  2041. checkfail:
  2042. status = 2; /* CHECK CONDITION */
  2043. s[0] = 0x70 | ((current_lba != ~0) ? 0x80 : 0x00);
  2044. if (chkerr < 0) {
  2045. s[2] = 5; /* ILLEGAL REQUEST */
  2046. s[12] = 0x21; /* LOGICAL BLOCK OUT OF RANGE */
  2047. sasi_sense = 0x21; // illegal disk address
  2048. } else {
  2049. s[2] = 3; /* MEDIUM ERROR */
  2050. if (chkerr == 1) {
  2051. s[12] = 0x11; /* Unrecovered Read Error */
  2052. sasi_sense = 0x11; // uncorrectable data error
  2053. }
  2054. if (chkerr == 2) {
  2055. s[12] = 0x0c; /* Write Error */
  2056. sasi_sense = 0x03; // write fault
  2057. }
  2058. }
  2059. ls = 0x12;
  2060. break;
  2061. miscompare:
  2062. status = 2; /* CHECK CONDITION */
  2063. s[0] = 0x70 | ((current_lba != ~0) ? 0x80 : 0x00);
  2064. s[2] = 5; /* ILLEGAL REQUEST */
  2065. s[12] = 0x1d; /* MISCOMPARE DURING VERIFY OPERATION */
  2066. ls = 0x12;
  2067. sasi_sense = 0x11; // uncorrectable data error
  2068. break;
  2069. }
  2070. scsi_done:
  2071. if (ls > 7)
  2072. s[7] = ls - 8;
  2073. if (log_scsiemu)
  2074. write_log (_T("-> DATAOUT=%d ST=%d SENSELEN=%d REPLYLEN=%d\n"), scsi_len, status, ls, lr);
  2075. *data_len = scsi_len;
  2076. *reply_len = lr;
  2077. if (lr > 0 && lr < 512) {
  2078. if (log_scsiemu) {
  2079. write_log (_T("REPLY: "));
  2080. for (int i = 0; i < lr && i < 40; i++)
  2081. write_log (_T("%02X."), r[i]);
  2082. write_log (_T("\n"));
  2083. }
  2084. }
  2085. if (ls > 0) {
  2086. if (omti || sasi) {
  2087. if (sasi_sense != 0) {
  2088. bool islba = (s[0] & 0x80) != 0;
  2089. ls = 4;
  2090. s[0] = sasi_sense | (islba ? 0x80 : 0x00);
  2091. s[1] = (lun & 1) << 5;
  2092. s[2] = 0;
  2093. s[3] = 0;
  2094. if (islba) {
  2095. s[1] |= (current_lba >> 16) & 31;
  2096. s[2] = (current_lba >> 8) & 255;
  2097. s[3] = (current_lba >> 0) & 255;
  2098. }
  2099. }
  2100. if (log_scsiemu && ls) {
  2101. write_log(_T("-> SENSE STATUS:\n"));
  2102. for (int i = 0; i < ls; i++)
  2103. write_log(_T("%02X."), s[i]);
  2104. write_log(_T("\n"));
  2105. }
  2106. } else {
  2107. if (s[0] & 0x80) {
  2108. s[3] = (current_lba >> 24) & 255;
  2109. s[4] = (current_lba >> 16) & 255;
  2110. s[5] = (current_lba >> 8) & 255;
  2111. s[6] = (current_lba >> 0) & 255;
  2112. }
  2113. if (log_scsiemu && ls) {
  2114. write_log(_T("-> SENSE STATUS: KEY=%d ASC=%02X ASCQ=%02X\n"), s[2], s[12], s[13]);
  2115. for (int i = 0; i < ls; i++)
  2116. write_log(_T("%02X."), s[i]);
  2117. write_log(_T("\n"));
  2118. }
  2119. }
  2120. memset (hfd->scsi_sense, 0, MAX_SCSI_SENSE);
  2121. memcpy (hfd->scsi_sense, s, ls);
  2122. }
  2123. *sense_len = ls;
  2124. return status;
  2125. }
  2126. static int handle_scsi (TrapContext *ctx, uae_u8 *iobuf, uaecptr request, struct hardfiledata *hfd, struct scsi_data *sd, bool safeonly)
  2127. {
  2128. int ret = 0;
  2129. uae_u32 scsicmdaddr = get_long_host(iobuf + 40);
  2130. uae_u8 scsicmd[30];
  2131. trap_get_bytes(ctx, scsicmd, scsicmdaddr, sizeof scsicmd);
  2132. uaecptr scsi_data = get_long_host(scsicmd + 0);
  2133. int scsi_len = get_long_host(scsicmd + 4);
  2134. uaecptr scsi_cmd = get_long_host(scsicmd + 12);
  2135. uae_u16 scsi_cmd_len = get_word_host(scsicmd + 16);
  2136. uae_u8 scsi_flags = get_byte_host(scsicmd + 20);
  2137. uaecptr scsi_sense = get_long_host(scsicmd + 22);
  2138. uae_u16 scsi_sense_len = get_word_host(scsicmd + 26);
  2139. uae_u8 cmd = trap_get_byte(ctx, scsi_cmd);
  2140. scsi_sense_len = (scsi_flags & 4) ? 4 : /* SCSIF_OLDAUTOSENSE */
  2141. (scsi_flags & 2) ? scsi_sense_len : /* SCSIF_AUTOSENSE */
  2142. 32;
  2143. scsi_log (_T("hdf scsiemu: cmd=%02X,%d flags=%02X sense=%p,%d data=%p,%d\n"),
  2144. cmd, scsi_cmd_len, scsi_flags, scsi_sense, scsi_sense_len, scsi_data, scsi_len);
  2145. sd->cmd_len = scsi_cmd_len;
  2146. sd->data_len = scsi_len;
  2147. trap_get_bytes(ctx, sd->cmd, scsi_cmd, sd->cmd_len);
  2148. for (int i = 0; i < sd->cmd_len; i++) {
  2149. scsi_log (_T("%02X%c"), sd->cmd[i], i < sd->cmd_len - 1 ? '.' : ' ');
  2150. }
  2151. scsi_log (_T("\n"));
  2152. if (safeonly && !scsi_cmd_is_safe(sd->cmd[0])) {
  2153. sd->reply_len = 0;
  2154. sd->data_len = 0;
  2155. sd->status = 2;
  2156. sd->sense_len = 18;
  2157. sd->sense[0] = 0x70;
  2158. sd->sense[2] = 5; /* ILLEGAL REQUEST */
  2159. sd->sense[12] = 0x30; /* INCOMPATIBLE MEDIUM INSERTED */
  2160. } else {
  2161. scsi_emulate_analyze(sd);
  2162. scsi_start_transfer(sd);
  2163. if (sd->direction > 0) {
  2164. trap_get_bytes(ctx, sd->buffer, scsi_data, sd->data_len);
  2165. scsi_emulate_cmd(sd);
  2166. } else {
  2167. scsi_emulate_cmd(sd);
  2168. if (sd->direction < 0)
  2169. trap_put_bytes(ctx, sd->buffer, scsi_data, sd->data_len);
  2170. }
  2171. }
  2172. put_word_host(scsicmd + 18, sd->status != 0 ? 0 : sd->cmd_len); /* fake scsi_CmdActual */
  2173. put_byte_host(scsicmd + 21, sd->status); /* scsi_Status */
  2174. if (sd->reply_len > 0) {
  2175. trap_put_bytes(ctx, sd->reply, scsi_data, sd->reply_len);
  2176. scsi_log (_T("RD:"));
  2177. int i = 0;
  2178. while (i < sd->reply_len && i < 24) {
  2179. scsi_log (_T("%02X%c"), sd->reply[i], i < sd->reply_len - 1 ? '.' : ' ');
  2180. i++;
  2181. }
  2182. scsi_log (_T("\n"));
  2183. }
  2184. if (scsi_sense) {
  2185. int slen = sd->sense_len < scsi_sense_len ? sd->sense_len : scsi_sense_len;
  2186. trap_put_bytes(ctx, sd->sense, scsi_sense, slen);
  2187. if (scsi_sense_len > sd->sense_len) {
  2188. trap_set_bytes(ctx, scsi_sense + sd->sense_len, 0, scsi_sense_len - sd->sense_len);
  2189. }
  2190. put_word_host(scsicmd + 28, slen); /* scsi_SenseActual */
  2191. } else {
  2192. put_word_host(scsicmd + 28, 0);
  2193. }
  2194. if (sd->data_len < 0) {
  2195. put_long_host(scsicmd + 8, 0); /* scsi_Actual */
  2196. ret = 20;
  2197. } else {
  2198. put_long_host(scsicmd + 8, sd->data_len); /* scsi_Actual */
  2199. }
  2200. trap_put_bytes(ctx, scsicmd, scsicmdaddr, sizeof scsicmd);
  2201. return ret;
  2202. }
  2203. void hardfile_send_disk_change (struct hardfiledata *hfd, bool insert)
  2204. {
  2205. int newstate = insert ? 0 : 1;
  2206. uae_sem_wait (&change_sem);
  2207. hardfpd[hfd->unitnum].changenum++;
  2208. write_log (_T("uaehf.device:%d media status=%d changenum=%d\n"), hfd->unitnum, insert, hardfpd[hfd->unitnum].changenum);
  2209. hfd->drive_empty = newstate;
  2210. int j = 0;
  2211. while (j < MAX_ASYNC_REQUESTS) {
  2212. if (hardfpd[hfd->unitnum].d_request_type[j] == ASYNC_REQUEST_CHANGEINT) {
  2213. uae_Cause (hardfpd[hfd->unitnum].d_request_data[j]);
  2214. }
  2215. j++;
  2216. }
  2217. if (hardfpd[hfd->unitnum].changeint)
  2218. uae_Cause (hardfpd[hfd->unitnum].changeint);
  2219. uae_sem_post (&change_sem);
  2220. }
  2221. void hardfile_do_disk_change (struct uaedev_config_data *uci, bool insert)
  2222. {
  2223. int fsid = uci->configoffset;
  2224. struct hardfiledata *hfd;
  2225. const struct expansionromtype *ert = get_unit_expansion_rom(uci->ci.controller_type);
  2226. if (ert && (ert->deviceflags & EXPANSIONTYPE_PCMCIA)) {
  2227. pcmcia_reinsert(&currprefs);
  2228. return;
  2229. }
  2230. hfd = get_hardfile_data (fsid);
  2231. if (!hfd)
  2232. return;
  2233. hardfile_send_disk_change (hfd, insert);
  2234. }
  2235. static int add_async_request (struct hardfileprivdata *hfpd, uae_u8 *iobuf, uaecptr request, int type, uae_u32 data)
  2236. {
  2237. int i;
  2238. i = 0;
  2239. while (i < MAX_ASYNC_REQUESTS) {
  2240. if (hfpd->d_request[i] == request) {
  2241. hfpd->d_request_type[i] = type;
  2242. hfpd->d_request_data[i] = data;
  2243. hf_log (_T("old async request %p (%d) added\n"), request, type);
  2244. return 0;
  2245. }
  2246. i++;
  2247. }
  2248. i = 0;
  2249. while (i < MAX_ASYNC_REQUESTS) {
  2250. if (hfpd->d_request[i] == 0) {
  2251. hfpd->d_request[i] = request;
  2252. hfpd->d_request_iobuf[i] = iobuf;
  2253. hfpd->d_request_type[i] = type;
  2254. hfpd->d_request_data[i] = data;
  2255. hf_log (_T("async request %p (%d) added (total=%d)\n"), request, type, i);
  2256. return 0;
  2257. }
  2258. i++;
  2259. }
  2260. hf_log (_T("async request overflow %p!\n"), request);
  2261. return -1;
  2262. }
  2263. static int release_async_request(struct hardfileprivdata *hfpd, uaecptr request)
  2264. {
  2265. int i = 0;
  2266. while (i < MAX_ASYNC_REQUESTS) {
  2267. if (hfpd->d_request[i] == request) {
  2268. int type = hfpd->d_request_type[i];
  2269. hfpd->d_request[i] = 0;
  2270. xfree(hfpd->d_request_iobuf[i]);
  2271. hfpd->d_request_iobuf[i] = 0;
  2272. hfpd->d_request_data[i] = 0;
  2273. hfpd->d_request_type[i] = 0;
  2274. hf_log (_T("async request %p removed\n"), request);
  2275. return type;
  2276. }
  2277. i++;
  2278. }
  2279. hf_log (_T("tried to remove non-existing request %p\n"), request);
  2280. return -1;
  2281. }
  2282. static void abort_async (struct hardfileprivdata *hfpd, uaecptr request, int errcode, int type)
  2283. {
  2284. int i;
  2285. hf_log (_T("aborting async request %p\n"), request);
  2286. i = 0;
  2287. while (i < MAX_ASYNC_REQUESTS) {
  2288. if (hfpd->d_request[i] == request && hfpd->d_request_type[i] == ASYNC_REQUEST_TEMP) {
  2289. /* ASYNC_REQUEST_TEMP = request is processing */
  2290. sleep_millis (1);
  2291. i = 0;
  2292. continue;
  2293. }
  2294. i++;
  2295. }
  2296. i = release_async_request (hfpd, request);
  2297. if (i >= 0) {
  2298. hf_log (_T("asyncronous request=%08X aborted, error=%d\n"), request, errcode);
  2299. }
  2300. }
  2301. static void hardfile_thread (void *devs);
  2302. static int start_thread (TrapContext *ctx, int unit)
  2303. {
  2304. struct hardfileprivdata *hfpd = &hardfpd[unit];
  2305. if (hfpd->thread_running)
  2306. return 1;
  2307. memset (hfpd, 0, sizeof (struct hardfileprivdata));
  2308. hfpd->base = trap_get_areg(ctx, 6);
  2309. init_comm_pipe (&hfpd->requests, 300, 3);
  2310. uae_sem_init (&hfpd->sync_sem, 0, 0);
  2311. uae_start_thread (_T("hardfile"), hardfile_thread, hfpd, NULL);
  2312. uae_sem_wait (&hfpd->sync_sem);
  2313. return hfpd->thread_running;
  2314. }
  2315. static int mangleunit (int unit)
  2316. {
  2317. if (unit <= 99)
  2318. return unit;
  2319. if (unit == 100)
  2320. return 8;
  2321. if (unit == 110)
  2322. return 9;
  2323. return -1;
  2324. }
  2325. static uae_u32 REGPARAM2 hardfile_open (TrapContext *ctx)
  2326. {
  2327. uaecptr ioreq = trap_get_areg (ctx, 1); /* IOReq */
  2328. int unit = mangleunit (trap_get_dreg(ctx, 0));
  2329. int err = IOERR_OPENFAIL;
  2330. /* boot device port size == 0!? KS 1.x size = 12???
  2331. * Ignore message size, too many programs do not set it correct
  2332. * int size = get_word (ioreq + 0x12);
  2333. */
  2334. /* Check unit number */
  2335. if (unit >= 0 && unit < MAX_FILESYSTEM_UNITS) {
  2336. struct hardfileprivdata *hfpd = &hardfpd[unit];
  2337. struct hardfiledata *hfd = get_hardfile_data_controller(unit);
  2338. if (hfd) {
  2339. if (hfd->ci.type == UAEDEV_DIR) {
  2340. if (start_thread(ctx, unit)) {
  2341. hfpd->directorydrive = true;
  2342. trap_put_word(ctx, hfpd->base + 32, trap_get_word(ctx, hfpd->base + 32) + 1);
  2343. trap_put_long(ctx, ioreq + 24, unit); /* io_Unit */
  2344. trap_put_byte(ctx, ioreq + 31, 0); /* io_Error */
  2345. trap_put_byte(ctx, ioreq + 8, 7); /* ln_type = NT_REPLYMSG */
  2346. if (!hfpd->sd)
  2347. hfpd->sd = scsi_alloc_generic(hfd, UAEDEV_DIR, unit);
  2348. hf_log(_T("virtual hardfile_open, unit %d (%d), OK\n"), unit, trap_get_dreg(ctx, 0));
  2349. return 0;
  2350. }
  2351. } else {
  2352. if ((hfd->handle_valid || hfd->drive_empty) && start_thread(ctx, unit)) {
  2353. hfpd->directorydrive = false;
  2354. trap_put_word(ctx, hfpd->base + 32, trap_get_word(ctx, hfpd->base + 32) + 1);
  2355. trap_put_long(ctx, ioreq + 24, unit); /* io_Unit */
  2356. trap_put_byte(ctx, ioreq + 31, 0); /* io_Error */
  2357. trap_put_byte(ctx, ioreq + 8, 7); /* ln_type = NT_REPLYMSG */
  2358. if (!hfpd->sd)
  2359. hfpd->sd = scsi_alloc_generic(hfd, UAEDEV_HDF, unit);
  2360. hf_log(_T("hardfile_open, unit %d (%d), OK\n"), unit, trap_get_dreg(ctx, 0));
  2361. return 0;
  2362. }
  2363. }
  2364. }
  2365. }
  2366. if (unit < 1000)
  2367. err = 50; /* HFERR_NoBoard */
  2368. hf_log (_T("hardfile_open, unit %d (%d), ERR=%d\n"), unit, trap_get_dreg(ctx, 0), err);
  2369. trap_put_long(ctx, ioreq + 20, (uae_u32)err);
  2370. trap_put_byte(ctx, ioreq + 31, (uae_u8)err);
  2371. return (uae_u32)err;
  2372. }
  2373. static uae_u32 REGPARAM2 hardfile_close (TrapContext *ctx)
  2374. {
  2375. uaecptr request = trap_get_areg (ctx, 1); /* IOReq */
  2376. int unit = mangleunit (trap_get_long(ctx, request + 24));
  2377. if (unit < 0 || unit >= MAX_FILESYSTEM_UNITS) {
  2378. return 0;
  2379. }
  2380. struct hardfileprivdata *hfpd = &hardfpd[unit];
  2381. if (!hfpd)
  2382. return 0;
  2383. trap_put_word(ctx, hfpd->base + 32, trap_get_word(ctx, hfpd->base + 32) - 1);
  2384. if (trap_get_word(ctx, hfpd->base + 32) == 0) {
  2385. scsi_free(hfpd->sd);
  2386. hfpd->sd = NULL;
  2387. write_comm_pipe_pvoid(&hfpd->requests, NULL, 0);
  2388. write_comm_pipe_pvoid(&hfpd->requests, NULL, 0);
  2389. write_comm_pipe_u32(&hfpd->requests, 0, 1);
  2390. }
  2391. return 0;
  2392. }
  2393. static uae_u32 REGPARAM2 hardfile_expunge (TrapContext *context)
  2394. {
  2395. return 0; /* Simply ignore this one... */
  2396. }
  2397. static void outofbounds (int cmd, uae_u64 offset, uae_u64 len, uae_u64 max)
  2398. {
  2399. write_log (_T("UAEHF: cmd %d: out of bounds, %08X-%08X + %08X-%08X > %08X-%08X\n"), cmd,
  2400. (uae_u32)(offset >> 32),(uae_u32)offset,(uae_u32)(len >> 32),(uae_u32)len,
  2401. (uae_u32)(max >> 32),(uae_u32)max);
  2402. }
  2403. static void unaligned (int cmd, uae_u64 offset, uae_u64 len, int blocksize)
  2404. {
  2405. write_log (_T("UAEHF: cmd %d: unaligned access, %08X-%08X, %08X-%08X, %08X\n"), cmd,
  2406. (uae_u32)(offset >> 32),(uae_u32)offset,(uae_u32)(len >> 32),(uae_u32)len,
  2407. blocksize);
  2408. }
  2409. static bool isbadblock(struct hardfiledata *hfd, uae_u64 offset, uae_u64 len)
  2410. {
  2411. if (!hfd->ci.badblock_num)
  2412. return false;
  2413. offset /= hfd->ci.blocksize;
  2414. len /= hfd->ci.blocksize;
  2415. for (int i = 0; i < hfd->ci.badblock_num; i++) {
  2416. struct uaedev_badblock *bb = &hfd->ci.badblocks[i];
  2417. if (offset + len >= bb->first && offset < bb->last) {
  2418. return true;
  2419. }
  2420. }
  2421. return false;
  2422. }
  2423. static bool vdisk(struct hardfileprivdata *hfdp)
  2424. {
  2425. return hfdp->directorydrive;
  2426. }
  2427. static uae_u32 hardfile_do_io (TrapContext *ctx, struct hardfiledata *hfd, struct hardfileprivdata *hfpd, uae_u8 *iobuf, uaecptr request)
  2428. {
  2429. uae_u32 dataptr, offset, actual = 0, cmd;
  2430. uae_u64 offset64;
  2431. int unit;
  2432. uae_u32 error = 0, len;
  2433. int async = 0;
  2434. int bmask = hfd->ci.blocksize - 1;
  2435. unit = get_long_host(iobuf + 24);
  2436. cmd = get_word_host(iobuf + 28); /* io_Command */
  2437. dataptr = get_long_host(iobuf + 40);
  2438. switch (cmd)
  2439. {
  2440. case CMD_READ:
  2441. if (nodisk (hfd))
  2442. goto no_disk;
  2443. if (vdisk(hfpd))
  2444. goto v_disk;
  2445. offset = get_long_host(iobuf + 44);
  2446. len = get_long_host(iobuf + 36); /* io_Length */
  2447. if (offset & bmask) {
  2448. unaligned (cmd, offset, len, hfd->ci.blocksize);
  2449. goto bad_command;
  2450. }
  2451. if (len & bmask) {
  2452. unaligned (cmd, offset, len, hfd->ci.blocksize);
  2453. goto bad_len;
  2454. }
  2455. if (len + offset > hfd->virtsize) {
  2456. outofbounds(cmd, offset, len, hfd->virtsize);
  2457. goto bad_len;
  2458. }
  2459. if (isbadblock(hfd, offset, len)) {
  2460. goto bad_block;
  2461. }
  2462. actual = (uae_u32)cmd_read(ctx, hfd, dataptr, offset, len);
  2463. break;
  2464. #if HDF_SUPPORT_TD64
  2465. case TD_READ64:
  2466. #endif
  2467. #if HDF_SUPPORT_NSD
  2468. case NSCMD_TD_READ64:
  2469. #endif
  2470. #if defined(HDF_SUPPORT_NSD) || defined(HDF_SUPPORT_TD64)
  2471. if (nodisk (hfd))
  2472. goto no_disk;
  2473. if (vdisk(hfpd))
  2474. goto v_disk;
  2475. offset64 = get_long_host(iobuf + 44) | ((uae_u64)get_long_host(iobuf + 32) << 32);
  2476. len = get_long_host(iobuf + 36); /* io_Length */
  2477. if (offset64 & bmask) {
  2478. unaligned (cmd, offset64, len, hfd->ci.blocksize);
  2479. goto bad_command;
  2480. }
  2481. if (len & bmask) {
  2482. unaligned (cmd, offset64, len, hfd->ci.blocksize);
  2483. goto bad_len;
  2484. }
  2485. if (len + offset64 > hfd->virtsize || (uae_s64)offset64 < 0) {
  2486. outofbounds (cmd, offset64, len, hfd->virtsize);
  2487. goto bad_len;
  2488. }
  2489. if (isbadblock(hfd, offset64, len)) {
  2490. goto bad_block;
  2491. }
  2492. actual = (uae_u32)cmd_read(ctx, hfd, dataptr, offset64, len);
  2493. break;
  2494. #endif
  2495. case CMD_WRITE:
  2496. case CMD_FORMAT: /* Format */
  2497. if (nodisk (hfd))
  2498. goto no_disk;
  2499. if (vdisk(hfpd))
  2500. goto v_disk;
  2501. if (is_writeprotected(hfd)) {
  2502. error = 28; /* write protect */
  2503. } else {
  2504. offset = get_long_host(iobuf + 44);
  2505. len = get_long_host(iobuf + 36); /* io_Length */
  2506. if (offset & bmask) {
  2507. unaligned (cmd, offset, len, hfd->ci.blocksize);
  2508. goto bad_command;
  2509. }
  2510. if (len & bmask) {
  2511. unaligned (cmd, offset, len, hfd->ci.blocksize);
  2512. goto bad_len;
  2513. }
  2514. if (len + offset > hfd->virtsize) {
  2515. outofbounds (cmd, offset, len, hfd->virtsize);
  2516. goto bad_len;
  2517. }
  2518. if (isbadblock(hfd, offset, len)) {
  2519. goto bad_block;
  2520. }
  2521. actual = (uae_u32)cmd_write(ctx, hfd, dataptr, offset, len);
  2522. }
  2523. break;
  2524. #if HDF_SUPPORT_TD64
  2525. case TD_WRITE64:
  2526. case TD_FORMAT64:
  2527. #endif
  2528. #if HDF_SUPPORT_NSD
  2529. case NSCMD_TD_WRITE64:
  2530. case NSCMD_TD_FORMAT64:
  2531. #endif
  2532. #if defined(HDF_SUPPORT_NSD) || defined(HDF_SUPPORT_TD64)
  2533. if (nodisk (hfd))
  2534. goto no_disk;
  2535. if (vdisk(hfpd))
  2536. goto v_disk;
  2537. if (is_writeprotected(hfd)) {
  2538. error = 28; /* write protect */
  2539. } else {
  2540. offset64 = get_long_host(iobuf + 44) | ((uae_u64)get_long_host(iobuf + 32) << 32);
  2541. len = get_long_host(iobuf + 36); /* io_Length */
  2542. if (offset64 & bmask) {
  2543. unaligned (cmd, offset64, len, hfd->ci.blocksize);
  2544. goto bad_command;
  2545. }
  2546. if (len & bmask) {
  2547. unaligned (cmd, offset64, len, hfd->ci.blocksize);
  2548. goto bad_len;
  2549. }
  2550. if (len + offset64 > hfd->virtsize || (uae_s64)offset64 < 0) {
  2551. outofbounds (cmd, offset64, len, hfd->virtsize);
  2552. goto bad_len;
  2553. }
  2554. if (isbadblock(hfd, offset64, len)) {
  2555. goto bad_block;
  2556. }
  2557. actual = (uae_u32)cmd_write(ctx, hfd, dataptr, offset64, len);
  2558. }
  2559. break;
  2560. #endif
  2561. #if HDF_SUPPORT_NSD
  2562. case NSCMD_DEVICEQUERY:
  2563. if (vdisk(hfpd))
  2564. goto v_disk;
  2565. trap_put_long(ctx, dataptr + 0, 0);
  2566. trap_put_long(ctx, dataptr + 4, 16); /* size */
  2567. trap_put_word(ctx, dataptr + 8, NSDEVTYPE_TRACKDISK);
  2568. trap_put_word(ctx, dataptr + 10, 0);
  2569. trap_put_long(ctx, dataptr + 12, nscmd_cmd);
  2570. actual = 16;
  2571. break;
  2572. #endif
  2573. case CMD_GETDRIVETYPE:
  2574. if (vdisk(hfpd))
  2575. goto v_disk;
  2576. #if HDF_SUPPORT_NSD
  2577. actual = DRIVE_NEWSTYLE;
  2578. break;
  2579. #else
  2580. goto no_cmd;
  2581. #endif
  2582. case CMD_GETNUMTRACKS:
  2583. {
  2584. int cyl, cylsec, head, tracksec;
  2585. getchsx (hfd, &cyl, &cylsec, &head, &tracksec);
  2586. actual = cyl * head;
  2587. break;
  2588. }
  2589. case CMD_GETGEOMETRY:
  2590. {
  2591. int cyl, cylsec, head, tracksec;
  2592. uae_u64 size;
  2593. getchsx (hfd, &cyl, &cylsec, &head, &tracksec);
  2594. trap_put_long(ctx, dataptr + 0, hfd->ci.blocksize);
  2595. size = hfd->virtsize / hfd->ci.blocksize;
  2596. if (!size)
  2597. size = hfd->ci.max_lba;
  2598. if (size > 0x00ffffffff)
  2599. size = 0xffffffff;
  2600. trap_put_long(ctx, dataptr + 4, (uae_u32)size);
  2601. trap_put_long(ctx, dataptr + 8, cyl);
  2602. trap_put_long(ctx, dataptr + 12, cylsec);
  2603. trap_put_long(ctx, dataptr + 16, head);
  2604. trap_put_long(ctx, dataptr + 20, tracksec);
  2605. trap_put_long(ctx, dataptr + 24, 0); /* bufmemtype */
  2606. trap_put_byte(ctx, dataptr + 28, 0); /* type = DG_DIRECT_ACCESS */
  2607. trap_put_byte(ctx, dataptr + 29, 0); /* flags */
  2608. }
  2609. break;
  2610. case CMD_PROTSTATUS:
  2611. if (is_writeprotected(hfd))
  2612. actual = -1;
  2613. else
  2614. actual = 0;
  2615. break;
  2616. case CMD_CHANGESTATE:
  2617. actual = hfd->drive_empty ? 1 :0;
  2618. break;
  2619. /* Some commands that just do nothing and return zero */
  2620. case CMD_UPDATE:
  2621. case CMD_CLEAR:
  2622. case CMD_MOTOR:
  2623. case CMD_SEEK:
  2624. break;
  2625. #if HDF_SUPPORT_TD64
  2626. case TD_SEEK64:
  2627. if (vdisk(hfpd))
  2628. goto v_disk;
  2629. break;
  2630. #endif
  2631. #ifdef HDF_SUPPORT_NSD
  2632. case NSCMD_TD_SEEK64:
  2633. if (vdisk(hfpd))
  2634. goto v_disk;
  2635. break;
  2636. #endif
  2637. case CMD_REMOVE:
  2638. hfpd->changeint = get_long (request + 40);
  2639. break;
  2640. case CMD_CHANGENUM:
  2641. actual = hfpd->changenum;
  2642. break;
  2643. case CMD_ADDCHANGEINT:
  2644. if (vdisk(hfpd))
  2645. goto v_disk;
  2646. error = add_async_request (hfpd, iobuf, request, ASYNC_REQUEST_CHANGEINT, get_long_host(iobuf + 40));
  2647. if (!error)
  2648. async = 1;
  2649. break;
  2650. case CMD_REMCHANGEINT:
  2651. if (vdisk(hfpd))
  2652. goto v_disk;
  2653. release_async_request (hfpd, request);
  2654. break;
  2655. #if HDF_SUPPORT_DS
  2656. case HD_SCSICMD: /* SCSI */
  2657. if (vdisk(hfpd)) {
  2658. error = handle_scsi(ctx, iobuf, request, hfd, hfpd->sd, true);
  2659. } else if (HDF_SUPPORT_DS_PARTITION || enable_ds_partition_hdf || (!hfd->ci.sectors && !hfd->ci.surfaces && !hfd->ci.reserved)) {
  2660. error = handle_scsi(ctx, iobuf, request, hfd, hfpd->sd, false);
  2661. } else { /* we don't want users trashing their "partition" hardfiles with hdtoolbox */
  2662. error = handle_scsi(ctx, iobuf, request, hfd, hfpd->sd, true);
  2663. }
  2664. actual = 30; // sizeof(struct SCSICmd)
  2665. break;
  2666. #endif
  2667. case CD_EJECT:
  2668. if (vdisk(hfpd))
  2669. goto v_disk;
  2670. if (hfd->ci.sectors && hfd->ci.surfaces) {
  2671. int len = get_long_host(iobuf + 36);
  2672. if (len) {
  2673. if (hfd->drive_empty) {
  2674. hardfile_media_change (hfd, NULL, true, false);
  2675. } else {
  2676. hardfile_media_change (hfd, NULL, false, false);
  2677. }
  2678. } else {
  2679. if (hfd->drive_empty) {
  2680. hardfile_media_change (hfd, NULL, true, false);
  2681. }
  2682. }
  2683. } else {
  2684. error = IOERR_NOCMD;
  2685. }
  2686. break;
  2687. bad_block:
  2688. error = 45; // HFERR_BadStatus
  2689. break;
  2690. bad_command:
  2691. error = IOERR_BADADDRESS;
  2692. break;
  2693. bad_len:
  2694. error = IOERR_BADLENGTH;
  2695. break;
  2696. v_disk:
  2697. error = IOERR_BadDriveType;
  2698. break;
  2699. no_disk:
  2700. error = 29; /* no disk */
  2701. break;
  2702. default:
  2703. /* Command not understood. */
  2704. error = IOERR_NOCMD;
  2705. break;
  2706. }
  2707. put_long_host(iobuf + 32, actual);
  2708. put_byte_host(iobuf + 31, error);
  2709. hf_log2 (_T("hf: unit=%d, request=%p, cmd=%d offset=%u len=%d, actual=%d error%=%d\n"), unit, request,
  2710. get_word_host(iobuf + 28), get_long_host(iobuf + 44), get_long_host(iobuf + 36), actual, error);
  2711. return async;
  2712. }
  2713. static uae_u32 REGPARAM2 hardfile_abortio (TrapContext *ctx)
  2714. {
  2715. uae_u32 request = trap_get_areg (ctx, 1);
  2716. int unit = mangleunit (trap_get_long(ctx, request + 24));
  2717. struct hardfiledata *hfd = get_hardfile_data_controller(unit);
  2718. struct hardfileprivdata *hfpd = &hardfpd[unit];
  2719. hf_log2 (_T("uaehf.device abortio "));
  2720. start_thread (ctx, unit);
  2721. if (!hfd || !hfpd || !hfpd->thread_running) {
  2722. trap_put_byte(ctx, request + 31, 32);
  2723. hf_log2 (_T("error\n"));
  2724. return trap_get_byte(ctx, request + 31);
  2725. }
  2726. trap_put_byte(ctx, request + 31, -2);
  2727. hf_log2 (_T("unit=%d, request=%08X\n"), unit, request);
  2728. abort_async(hfpd, request, -2, 0);
  2729. return 0;
  2730. }
  2731. static int hardfile_can_quick (uae_u32 command)
  2732. {
  2733. switch (command)
  2734. {
  2735. case CMD_REMCHANGEINT:
  2736. return -1;
  2737. case CMD_RESET:
  2738. case CMD_STOP:
  2739. case CMD_START:
  2740. case CMD_CHANGESTATE:
  2741. case CMD_PROTSTATUS:
  2742. case CMD_MOTOR:
  2743. case CMD_GETDRIVETYPE:
  2744. case CMD_GETGEOMETRY:
  2745. case CMD_GETNUMTRACKS:
  2746. case NSCMD_DEVICEQUERY:
  2747. return 1;
  2748. }
  2749. return 0;
  2750. }
  2751. static int hardfile_canquick (TrapContext *ctx, struct hardfiledata *hfd, uae_u8 *iobuf)
  2752. {
  2753. uae_u32 command = get_word_host(iobuf + 28);
  2754. return hardfile_can_quick (command);
  2755. }
  2756. static uae_u32 REGPARAM2 hardfile_beginio (TrapContext *ctx)
  2757. {
  2758. int canquick;
  2759. uae_u32 request = trap_get_areg(ctx, 1);
  2760. uae_u8 *iobuf = xmalloc(uae_u8, 48);
  2761. trap_get_bytes(ctx, iobuf, request, 48);
  2762. uae_u8 flags = get_byte_host(iobuf + 30);
  2763. int cmd = get_word_host(iobuf + 28);
  2764. int unit = mangleunit(get_long_host(iobuf + 24));
  2765. #if 0
  2766. if (cmd == CMD_GETGEOMETRY)
  2767. activate_debugger();
  2768. #endif
  2769. struct hardfiledata *hfd = get_hardfile_data_controller(unit);
  2770. struct hardfileprivdata *hfpd = &hardfpd[unit];
  2771. put_byte_host(iobuf + 8, NT_MESSAGE);
  2772. start_thread(ctx, unit);
  2773. if (!hfd || !hfpd || !hfpd->thread_running) {
  2774. put_byte_host(iobuf + 31, 32);
  2775. uae_u8 v = get_byte_host(iobuf + 31);
  2776. trap_put_bytes(ctx, iobuf + 8, request + 8, 48 - 8);
  2777. xfree(iobuf);
  2778. return v;
  2779. }
  2780. put_byte_host(iobuf + 31, 0);
  2781. canquick = hardfile_canquick(ctx, hfd, iobuf);
  2782. if (((flags & 1) && canquick) || (canquick < 0)) {
  2783. hf_log (_T("hf quickio unit=%d request=%p cmd=%d\n"), unit, request, cmd);
  2784. if (hardfile_do_io(ctx, hfd, hfpd, iobuf, request)) {
  2785. hf_log2 (_T("uaehf.device cmd %d bug with IO_QUICK\n"), cmd);
  2786. }
  2787. uae_u8 v = get_byte_host(iobuf + 31);
  2788. trap_put_bytes(ctx, iobuf + 8, request + 8, 48 - 8);
  2789. xfree(iobuf);
  2790. if (!(flags & 1))
  2791. uae_ReplyMsg(request);
  2792. return v;
  2793. } else {
  2794. hf_log2 (_T("hf asyncio unit=%d request=%p cmd=%d\n"), unit, request, cmd);
  2795. add_async_request(hfpd, iobuf, request, ASYNC_REQUEST_TEMP, 0);
  2796. put_byte_host(iobuf + 30, get_byte_host(iobuf + 30) & ~1);
  2797. trap_put_bytes(ctx, iobuf + 8, request + 8, 48 - 8);
  2798. trap_set_background(ctx);
  2799. write_comm_pipe_pvoid(&hfpd->requests, ctx, 0);
  2800. write_comm_pipe_pvoid(&hfpd->requests, iobuf, 0);
  2801. write_comm_pipe_u32(&hfpd->requests, request, 1);
  2802. return 0;
  2803. }
  2804. }
  2805. static void hardfile_thread (void *devs)
  2806. {
  2807. struct hardfileprivdata *hfpd = (struct hardfileprivdata*)devs;
  2808. uae_set_thread_priority (NULL, 1);
  2809. hfpd->thread_running = 1;
  2810. uae_sem_post (&hfpd->sync_sem);
  2811. for (;;) {
  2812. TrapContext *ctx = (TrapContext*)read_comm_pipe_pvoid_blocking(&hfpd->requests);
  2813. uae_u8 *iobuf = (uae_u8*)read_comm_pipe_pvoid_blocking(&hfpd->requests);
  2814. uaecptr request = (uaecptr)read_comm_pipe_u32_blocking (&hfpd->requests);
  2815. uae_sem_wait (&change_sem);
  2816. if (!request) {
  2817. hfpd->thread_running = 0;
  2818. uae_sem_post (&hfpd->sync_sem);
  2819. uae_sem_post (&change_sem);
  2820. return;
  2821. } else if (hardfile_do_io(ctx, get_hardfile_data_controller(hfpd - &hardfpd[0]), hfpd, iobuf, request) == 0) {
  2822. put_byte_host(iobuf + 30, get_byte_host(iobuf + 30) & ~1);
  2823. trap_put_bytes(ctx, iobuf + 8, request + 8, 48 - 8);
  2824. release_async_request(hfpd, request);
  2825. uae_ReplyMsg(request);
  2826. } else {
  2827. hf_log2 (_T("async request %08X\n"), request);
  2828. trap_put_bytes(ctx, iobuf + 8, request + 8, 48 - 8);
  2829. }
  2830. trap_background_set_complete(ctx);
  2831. uae_sem_post (&change_sem);
  2832. }
  2833. }
  2834. void hardfile_reset (void)
  2835. {
  2836. int i, j;
  2837. struct hardfileprivdata *hfpd;
  2838. for (i = 0; i < MAX_FILESYSTEM_UNITS; i++) {
  2839. hfpd = &hardfpd[i];
  2840. if (hfpd->base && valid_address (hfpd->base, 36) && get_word (hfpd->base + 32) > 0) {
  2841. for (j = 0; j < MAX_ASYNC_REQUESTS; j++) {
  2842. uaecptr request;
  2843. if ((request = hfpd->d_request[j]))
  2844. abort_async (hfpd, request, 0, 0);
  2845. }
  2846. }
  2847. memset (hfpd, 0, sizeof (struct hardfileprivdata));
  2848. }
  2849. }
  2850. void hardfile_install (void)
  2851. {
  2852. uae_u32 functable, datatable;
  2853. uae_u32 initcode, openfunc, closefunc, expungefunc;
  2854. uae_u32 beginiofunc, abortiofunc;
  2855. uae_sem_init (&change_sem, 0, 1);
  2856. ROM_hardfile_resname = ds (currprefs.uaescsidevmode == 1 ? _T("scsi.device") : _T("uaehf.device"));
  2857. ROM_hardfile_resid = ds (_T("UAE hardfile.device 0.6"));
  2858. nscmd_cmd = here ();
  2859. dw (NSCMD_DEVICEQUERY);
  2860. dw (CMD_RESET);
  2861. dw (CMD_READ);
  2862. dw (CMD_WRITE);
  2863. dw (CMD_UPDATE);
  2864. dw (CMD_CLEAR);
  2865. dw (CMD_START);
  2866. dw (CMD_STOP);
  2867. dw (CMD_FLUSH);
  2868. dw (CMD_MOTOR);
  2869. dw (CMD_SEEK);
  2870. dw (CMD_FORMAT);
  2871. dw (CMD_REMOVE);
  2872. dw (CMD_CHANGENUM);
  2873. dw (CMD_CHANGESTATE);
  2874. dw (CMD_PROTSTATUS);
  2875. dw (CMD_GETDRIVETYPE);
  2876. dw (CMD_GETGEOMETRY);
  2877. dw (CMD_ADDCHANGEINT);
  2878. dw (CMD_REMCHANGEINT);
  2879. dw (HD_SCSICMD);
  2880. dw (NSCMD_TD_READ64);
  2881. dw (NSCMD_TD_WRITE64);
  2882. dw (NSCMD_TD_SEEK64);
  2883. dw (NSCMD_TD_FORMAT64);
  2884. dw (0);
  2885. /* initcode */
  2886. initcode = filesys_initcode;
  2887. /* Open */
  2888. openfunc = here ();
  2889. calltrap (deftrap (hardfile_open)); dw (RTS);
  2890. /* Close */
  2891. closefunc = here ();
  2892. calltrap (deftrap (hardfile_close)); dw (RTS);
  2893. /* Expunge */
  2894. expungefunc = here ();
  2895. calltrap (deftrap (hardfile_expunge)); dw (RTS);
  2896. /* BeginIO */
  2897. beginiofunc = here ();
  2898. calltrap (deftrap (hardfile_beginio));
  2899. dw (RTS);
  2900. /* AbortIO */
  2901. abortiofunc = here ();
  2902. calltrap (deftrap (hardfile_abortio)); dw (RTS);
  2903. /* FuncTable */
  2904. functable = here ();
  2905. dl (openfunc); /* Open */
  2906. dl (closefunc); /* Close */
  2907. dl (expungefunc); /* Expunge */
  2908. dl (EXPANSION_nullfunc); /* Null */
  2909. dl (beginiofunc); /* BeginIO */
  2910. dl (abortiofunc); /* AbortIO */
  2911. dl (0xFFFFFFFFul); /* end of table */
  2912. /* DataTable */
  2913. datatable = here ();
  2914. dw (0xE000); /* INITBYTE */
  2915. dw (0x0008); /* LN_TYPE */
  2916. dw (0x0300); /* NT_DEVICE */
  2917. dw (0xC000); /* INITLONG */
  2918. dw (0x000A); /* LN_NAME */
  2919. dl (ROM_hardfile_resname);
  2920. dw (0xE000); /* INITBYTE */
  2921. dw (0x000E); /* LIB_FLAGS */
  2922. dw (0x0600); /* LIBF_SUMUSED | LIBF_CHANGED */
  2923. dw (0xD000); /* INITWORD */
  2924. dw (0x0014); /* LIB_VERSION */
  2925. dw (0x0032); /* 50 */
  2926. dw (0xD000);
  2927. dw (0x0016); /* LIB_REVISION */
  2928. dw (0x0001);
  2929. dw (0xC000);
  2930. dw (0x0018); /* LIB_IDSTRING */
  2931. dl (ROM_hardfile_resid);
  2932. dw (0x0000); /* end of table */
  2933. ROM_hardfile_init = here ();
  2934. dl (0x00000100); /* ??? */
  2935. dl (functable);
  2936. dl (datatable);
  2937. filesys_initcode_ptr = here();
  2938. filesys_initcode_real = initcode;
  2939. dl (initcode);
  2940. }