PageRenderTime 76ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/hardfile.cpp

https://github.com/tonioni/WinUAE
C++ | 3150 lines | 2862 code | 210 blank | 78 comment | 728 complexity | be09058b73539c5e8d2476c16ea564ac MD5 | raw file

Large files files are truncated, but you can click here to view the full 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] = bdsi

Large files files are truncated, but you can click here to view the full file