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
10 #define USE_CHD 0
11
12 #include "sysconfig.h"
13 #include "sysdeps.h"
14
15 #include "threaddep/thread.h"
16 #include "options.h"
17 #include "memory_uae.h"
18 #include "custom.h"
19 #include "newcpu.h"
20 #include "disk.h"
21 #include "autoconf.h"
22 #include "traps.h"
23 #include "filesys.h"
24 #include "execlib.h"
25 #include "native2amiga.h"
26 #include "gui.h"
27 #include "uae.h"
28 #include "scsi.h"
29 #include "gayle.h"
30 #include "execio.h"
31 #include "zfile.h"
32 #include "sleep.h"
33 #include "misc.h"
34
35 #if USE_CHD
36 #include "archivers/chd/chdtypes.h"
37 #include "archivers/chd/chd.h"
38 #endif
39
40 #undef DEBUGME
41 //#define DEBUGME
42
43 #ifdef DEBUGME
44 #define hf_log write_log
45 #define hf_log2 write_log
46 #define hf_log3 write_log
47 #define scsi_log write_log
48 #else
49 # define hf_log(...) { }
50 # define hf_log2(...) { }
51 # define hf_log3(...) { }
52 # define scsi_log(...) { }
53 #endif
54
55 #define MAX_ASYNC_REQUESTS 50
56 #define ASYNC_REQUEST_NONE 0
57 #define ASYNC_REQUEST_TEMP 1
58 #define ASYNC_REQUEST_CHANGEINT 10
59
60 struct hardfileprivdata {
61 volatile uaecptr d_request[MAX_ASYNC_REQUESTS];
62 volatile int d_request_type[MAX_ASYNC_REQUESTS];
63 volatile uae_u32 d_request_data[MAX_ASYNC_REQUESTS];
64 smp_comm_pipe requests;
65 int thread_running;
66 uae_sem_t sync_sem;
67 uaecptr base;
68 int changenum;
69 uaecptr changeint;
70 uae_thread_id tid;
71 };
72
73 #define HFD_VHD_DYNAMIC 3
74 #define HFD_VHD_FIXED 2
75 #define HFD_CHD 1
76
gl(uae_u8 * p)77 STATIC_INLINE uae_u32 gl (uae_u8 *p)
78 {
79 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0);
80 }
81
82 static uae_sem_t change_sem;
83
84 static struct hardfileprivdata hardfpd[MAX_FILESYSTEM_UNITS];
85
86 static uae_u32 nscmd_cmd;
87
wl(uae_u8 * p,int v)88 static void wl (uae_u8 *p, int v)
89 {
90 p[0] = v >> 24;
91 p[1] = v >> 16;
92 p[2] = v >> 8;
93 p[3] = v;
94 }
ww(uae_u8 * p,int v)95 static void ww (uae_u8 *p, int v)
96 {
97 p[0] = v >> 8;
98 p[1] = v;
99 }
rl(uae_u8 * p)100 static int rl (uae_u8 *p)
101 {
102 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]);
103 }
104
105
getchs2(struct hardfiledata * hfd,int * cyl,int * cylsec,int * head,int * tracksec)106 static void getchs2 (struct hardfiledata *hfd, int *cyl, int *cylsec, int *head, int *tracksec)
107 {
108 unsigned int total = (unsigned int)(hfd->virtsize / 1024);
109 int heads;
110 int sectors = 63;
111
112 /* do we have RDB values? */
113 if (hfd->rdbcylinders) {
114 *cyl = hfd->rdbcylinders;
115 *tracksec = hfd->rdbsectors;
116 *head = hfd->rdbheads;
117 *cylsec = hfd->rdbsectors * hfd->rdbheads;
118 return;
119 }
120 /* what about HDF settings? */
121 if (hfd->ci.surfaces && hfd->ci.sectors) {
122 *head = hfd->ci.surfaces;
123 *tracksec = hfd->ci.sectors;
124 *cylsec = (*head) * (*tracksec);
125 *cyl = (unsigned int)(hfd->virtsize / hfd->ci.blocksize) / ((*tracksec) * (*head));
126 return;
127 }
128 /* no, lets guess something.. */
129 if (total <= 504 * 1024)
130 heads = 16;
131 else if (total <= 1008 * 1024)
132 heads = 32;
133 else if (total <= 2016 * 1024)
134 heads = 64;
135 else if (total <= 4032 * 1024)
136 heads = 128;
137 else
138 heads = 255;
139 *cyl = (unsigned int)(hfd->virtsize / hfd->ci.blocksize) / (sectors * heads);
140 *cylsec = sectors * heads;
141 *tracksec = sectors;
142 *head = heads;
143 }
144
getchsx(struct hardfiledata * hfd,int * cyl,int * cylsec,int * head,int * tracksec)145 static void getchsx (struct hardfiledata *hfd, int *cyl, int *cylsec, int *head, int *tracksec)
146 {
147 getchs2 (hfd, cyl, cylsec, head, tracksec);
148 hf_log (_T("CHS: %08X-%08X %d %d %d %d %d\n"),
149 (uae_u32)(hfd->virtsize >> 32),(uae_u32)hfd->virtsize,
150 *cyl, *cylsec, *head, *tracksec);
151 }
152
getchsgeometry2(uae_u64 size,int * pcyl,int * phead,int * psectorspertrack,int mode)153 static void getchsgeometry2 (uae_u64 size, int *pcyl, int *phead, int *psectorspertrack, int mode)
154 {
155 int sptt[4];
156 int i, spt, head, cyl;
157 uae_u64 total = (unsigned int)(size / 512);
158
159 if (mode == 1) {
160 // old-style head=1, spt=32 always mode
161 head = 1;
162 spt = 32;
163 cyl = total / (head * spt);
164
165 } else {
166
167 sptt[0] = 63;
168 sptt[1] = 127;
169 sptt[2] = 255;
170 sptt[3] = -1;
171
172 for (i = 0; sptt[i] >= 0; i++) {
173 spt = sptt[i];
174 for (head = 4; head <= 16;head++) {
175 cyl = total / (head * spt);
176 if (size <= 512 * 1024 * 1024) {
177 if (cyl <= 1023)
178 break;
179 } else {
180 if (cyl < 16383)
181 break;
182 if (cyl < 32767 && head >= 5)
183 break;
184 if (cyl <= 65535)
185 break;
186 }
187 }
188 if (head <= 16)
189 break;
190 }
191
192 }
193
194 *pcyl = cyl;
195 *phead = head;
196 *psectorspertrack = spt;
197 }
198
getchsgeometry(uae_u64 size,int * pcyl,int * phead,int * psectorspertrack)199 void getchsgeometry (uae_u64 size, int *pcyl, int *phead, int *psectorspertrack)
200 {
201 getchsgeometry2 (size, pcyl, phead, psectorspertrack, 0);
202 }
203
getchsgeometry_hdf(struct hardfiledata * hfd,uae_u64 size,int * pcyl,int * phead,int * psectorspertrack)204 void getchsgeometry_hdf (struct hardfiledata *hfd, uae_u64 size, int *pcyl, int *phead, int *psectorspertrack)
205 {
206 uae_u8 block[512];
207 int i;
208
209 if (size <= 512 * 1024 * 1024) {
210 *phead = 1;
211 *psectorspertrack = 32;
212 }
213 memset (block, 0, sizeof block);
214 if (hfd) {
215 hdf_read (hfd, block, 0, 512);
216 if (block[0] == 'D' && block[1] == 'O' && block[2] == 'S') {
217 int mode;
218 for (mode = 0; mode < 2; mode++) {
219 uae_u32 rootblock;
220 uae_u32 chk = 0;
221 getchsgeometry2 (size, pcyl, phead, psectorspertrack, mode);
222 rootblock = (2 + ((*pcyl) * (*phead) * (*psectorspertrack) - 1)) / 2;
223 memset (block, 0, sizeof block);
224 hdf_read (hfd, block, (uae_u64)rootblock * 512, 512);
225 for (i = 0; i < 512; i += 4)
226 chk += (block[i] << 24) | (block[i + 1] << 16) | (block[i + 2] << 8) | (block[i + 3] << 0);
227 if (!chk && block[0] == 0 && block[1] == 0 && block[2] == 0 && block[3] == 2 &&
228 block[4] == 0 && block[5] == 0 && block[6] == 0 && block[7] == 0 &&
229 block[8] == 0 && block[9] == 0 && block[10] == 0 && block[11] == 0 &&
230 block[508] == 0 && block[509] == 0 && block[510] == 0 && block[511] == 1) {
231 return;
232 }
233 }
234 }
235 }
236 getchsgeometry2 (size, pcyl, phead, psectorspertrack, 2);
237 }
238
getchspgeometry(uae_u64 total,int * pcyl,int * phead,int * psectorspertrack,bool idegeometry)239 void getchspgeometry (uae_u64 total, int *pcyl, int *phead, int *psectorspertrack, bool idegeometry)
240 {
241 uae_u64 blocks = total / 512;
242
243 if (blocks > 16515072) {
244 /* >8G, CHS=16383/16/63 */
245 *pcyl = 16383;
246 *phead = 16;
247 *psectorspertrack = 63;
248 return;
249 }
250 if (idegeometry) {
251 *phead = 16;
252 *psectorspertrack = 63;
253 *pcyl = blocks / ((*psectorspertrack) * (*phead));
254 return;
255 }
256 getchsgeometry (total, pcyl, phead, psectorspertrack);
257 }
258
getchshd(struct hardfiledata * hfd,int * pcyl,int * phead,int * psectorspertrack)259 static void getchshd (struct hardfiledata *hfd, int *pcyl, int *phead, int *psectorspertrack)
260 {
261 getchspgeometry (hfd->virtsize, pcyl, phead, psectorspertrack, false);
262 }
263
264
pl(uae_u8 * p,int off,uae_u32 v)265 static void pl (uae_u8 *p, int off, uae_u32 v)
266 {
267 p += off * 4;
268 p[0] = v >> 24;
269 p[1] = v >> 16;
270 p[2] = v >> 8;
271 p[3] = v >> 0;
272 }
273
rdb_crc(uae_u8 * p)274 static void rdb_crc (uae_u8 *p)
275 {
276 uae_u32 sum;
277 int i, blocksize;
278
279 sum =0;
280 blocksize = rl (p + 1 * 4);
281 for (i = 0; i < blocksize; i++)
282 sum += rl (p + i * 4);
283 sum = -sum;
284 pl (p, 2, sum);
285 }
286
create_virtual_rdb(struct hardfiledata * hfd)287 static void create_virtual_rdb (struct hardfiledata *hfd)
288 {
289 uae_u8 *rdb, *part, *denv;
290 int cyl = hfd->ci.surfaces * hfd->ci.sectors;
291 int cyls = 262144 / (cyl * 512);
292 int size = cyl * cyls * 512;
293
294 rdb = xcalloc (uae_u8, size);
295 hfd->virtual_rdb = rdb;
296 hfd->virtual_size = size;
297 part = rdb + 512;
298 pl(rdb, 0, 0x5244534b);
299 pl(rdb, 1, 64);
300 pl(rdb, 2, 0); // chksum
301 pl(rdb, 3, 0); // hostid
302 pl(rdb, 4, 512); // blockbytes
303 pl(rdb, 5, 0); // flags
304 pl(rdb, 6, -1); // badblock
305 pl(rdb, 7, 1); // part
306 pl(rdb, 8, -1); // fs
307 pl(rdb, 9, -1); // driveinit
308 pl(rdb, 10, -1); // reserved
309 pl(rdb, 11, -1); // reserved
310 pl(rdb, 12, -1); // reserved
311 pl(rdb, 13, -1); // reserved
312 pl(rdb, 14, -1); // reserved
313 pl(rdb, 15, -1); // reserved
314 pl(rdb, 16, hfd->ci.highcyl);
315 pl(rdb, 17, hfd->ci.sectors);
316 pl(rdb, 18, hfd->ci.surfaces);
317 pl(rdb, 19, hfd->ci.interleave); // interleave
318 pl(rdb, 20, 0); // park
319 pl(rdb, 21, -1); // res
320 pl(rdb, 22, -1); // res
321 pl(rdb, 23, -1); // res
322 pl(rdb, 24, 0); // writeprecomp
323 pl(rdb, 25, 0); // reducedwrite
324 pl(rdb, 26, 0); // steprate
325 pl(rdb, 27, -1); // res
326 pl(rdb, 28, -1); // res
327 pl(rdb, 29, -1); // res
328 pl(rdb, 30, -1); // res
329 pl(rdb, 31, -1); // res
330 pl(rdb, 32, 0); // rdbblockslo
331 pl(rdb, 33, cyl * cyls); // rdbblockshi
332 pl(rdb, 34, cyls); // locyl
333 pl(rdb, 35, hfd->ci.highcyl + cyls); // hicyl
334 pl(rdb, 36, cyl); // cylblocks
335 pl(rdb, 37, 0); // autopark
336 pl(rdb, 38, 2); // highrdskblock
337 pl(rdb, 39, -1); // res
338 ua_copy ((char*)rdb + 40 * 4, -1, hfd->vendor_id);
339 ua_copy ((char*)rdb + 42 * 4, -1, hfd->product_id);
340 ua_copy ((char*)rdb + 46 * 4, -1, _T("UAE"));
341 rdb_crc (rdb);
342
343 pl(part, 0, 0x50415254);
344 pl(part, 1, 64);
345 pl(part, 2, 0);
346 pl(part, 3, 0);
347 pl(part, 4, -1);
348 pl(part, 5, 1); // bootable
349 pl(part, 6, -1);
350 pl(part, 7, -1);
351 pl(part, 8, 0); // devflags
352 part[9 * 4] = _tcslen (hfd->device_name);
353 ua_copy ((char*)part + 9 * 4 + 1, -1, hfd->device_name);
354
355 denv = part + 128;
356 pl(denv, 0, 80);
357 pl(denv, 1, 512 / 4);
358 pl(denv, 2, 0); // secorg
359 pl(denv, 3, hfd->ci.surfaces);
360 pl(denv, 4, hfd->ci.blocksize / 512);
361 pl(denv, 5, hfd->ci.sectors);
362 pl(denv, 6, hfd->ci.reserved);
363 pl(denv, 7, 0); // prealloc
364 pl(denv, 8, hfd->ci.interleave); // interleave
365 pl(denv, 9, cyls); // lowcyl
366 pl(denv, 10, hfd->ci.highcyl + cyls - 1);
367 pl(denv, 11, hfd->ci.buffers);
368 pl(denv, 12, hfd->ci.bufmemtype);
369 pl(denv, 13, hfd->ci.maxtransfer);
370 pl(denv, 14, hfd->ci.mask);
371 pl(denv, 15, hfd->ci.bootpri);
372 pl(denv, 16, hfd->ci.dostype);
373 rdb_crc (part);
374
375 hfd->virtsize += size;
376
377 }
378
hdf_hd_close(struct hd_hardfiledata * hfd)379 void hdf_hd_close (struct hd_hardfiledata *hfd)
380 {
381 if (!hfd)
382 return;
383 hdf_close (&hfd->hfd);
384 // xfree (hfd->path);
385 }
386
hdf_hd_open(struct hd_hardfiledata * hfd)387 int hdf_hd_open (struct hd_hardfiledata *hfd)
388 {
389 struct uaedev_config_info *ci = &hfd->hfd.ci;
390 if (!hdf_open (&hfd->hfd, NULL))
391 return 0;
392 if (ci->pcyls && ci->pheads && ci->psecs) {
393 hfd->cyls = ci->pcyls;
394 hfd->heads = ci->pheads;
395 hfd->secspertrack = ci->psecs;
396 } else if (ci->highcyl && ci->surfaces && ci->sectors) {
397 hfd->cyls = ci->highcyl;
398 hfd->heads = ci->surfaces;
399 hfd->secspertrack = ci->sectors;
400 } else {
401 getchshd (&hfd->hfd, &hfd->cyls, &hfd->heads, &hfd->secspertrack);
402 }
403 hfd->cyls_def = hfd->cyls;
404 hfd->secspertrack_def = hfd->secspertrack;
405 hfd->heads_def = hfd->heads;
406 if (ci->surfaces && ci->sectors) {
407 uae_u8 buf[512] = { 0 };
408 hdf_read (&hfd->hfd, buf, 0, 512);
409 if (buf[0] != 0 && memcmp (buf, _T("RDSK"), 4)) {
410 ci->highcyl = (hfd->hfd.virtsize / ci->blocksize) / (ci->sectors * ci->surfaces);
411 ci->dostype = rl (buf);
412 create_virtual_rdb (&hfd->hfd);
413 while (ci->highcyl * ci->surfaces * ci->sectors > hfd->cyls_def * hfd->secspertrack_def * hfd->heads_def) {
414 hfd->cyls_def++;
415 }
416 }
417 }
418 hfd->size = hfd->hfd.virtsize;
419 return 1;
420 }
421
vhd_checksum(uae_u8 * p,int offset)422 static uae_u32 vhd_checksum (uae_u8 *p, int offset)
423 {
424 int i;
425 uae_u32 sum;
426
427 sum = 0;
428 for (i = 0; i < 512; i++) {
429 if (offset >= 0 && i >= offset && i < offset + 4)
430 continue;
431 sum += p[i];
432 }
433 return ~sum;
434 }
435
436 static int hdf_write2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len);
437 static int hdf_read2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len);
438
hdf_init_cache(struct hardfiledata * hfd)439 static void hdf_init_cache (struct hardfiledata *hfd)
440 {
441 }
hdf_flush_cache(struct hardfiledata * hdf)442 static void hdf_flush_cache (struct hardfiledata *hdf)
443 {
444 }
445
hdf_cache_read(struct hardfiledata * hfd,void * buffer,uae_u64 offset,int len)446 static int hdf_cache_read (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
447 {
448 return hdf_read2 (hfd, buffer, offset, len);
449 }
450
hdf_cache_write(struct hardfiledata * hfd,void * buffer,uae_u64 offset,int len)451 static int hdf_cache_write (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
452 {
453 return hdf_write2 (hfd, buffer, offset, len);
454 }
455
hdf_open(struct hardfiledata * hfd,const TCHAR * pname)456 int hdf_open (struct hardfiledata *hfd, const TCHAR *pname)
457 {
458 uae_u8 tmp[512], tmp2[512];
459 uae_u32 v;
460
461 if ((!pname || pname[0] == 0) && hfd->ci.rootdir[0] == 0)
462 return 0;
463 hfd->adide = 0;
464 hfd->byteswap = 0;
465 hfd->hfd_type = 0;
466 if (!pname)
467 pname = hfd->ci.rootdir;
468 #if USE_CHD
469 TCHAR nametmp[MAX_DPATH];
470 _tcscpy (nametmp, pname);
471 TCHAR *ext = _tcsrchr (nametmp, '.');
472 if (ext && !_tcsicmp (ext, _T(".chd"))) {
473 struct zfile *zf = zfile_fopen (nametmp, _T("rb"));
474 if (zf) {
475 int err;
476 chd_file *cf = new chd_file();
477 err = cf->open(zf, false, NULL);
478 if (err != CHDERR_NONE) {
479 zfile_fclose (zf);
480 goto nonvhd;
481 }
482 hfd->chd_handle = cf;
483 hfd->ci.readonly = true;
484 hfd->hfd_type = HFD_CHD;
485 hfd->handle_valid = -1;
486 hfd->virtsize = cf->logical_bytes ();
487 goto nonvhd;
488 }
489 }
490 #endif
491 if (!hdf_open_target (hfd, pname))
492 return 0;
493 if (hdf_read_target (hfd, tmp, 0, 512) != 512)
494 goto nonvhd;
495 v = gl (tmp + 8); // features
496 if ((v & 3) != 2)
497 goto nonvhd;
498 v = gl (tmp + 8 + 4); // version
499 if ((v >> 16) != 1)
500 goto nonvhd;
501 hfd->hfd_type = gl (tmp + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 8 + 4);
502 if (hfd->hfd_type != HFD_VHD_FIXED && hfd->hfd_type != HFD_VHD_DYNAMIC)
503 goto nonvhd;
504 v = gl (tmp + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 8 + 4 + 4);
505 if (v == 0)
506 goto nonvhd;
507 if (vhd_checksum (tmp, 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 8 + 4 + 4) != v)
508 goto nonvhd;
509 if (hdf_read_target (hfd, tmp2, hfd->physsize - sizeof tmp2, 512) != 512)
510 goto end;
511 if (memcmp (tmp, tmp2, sizeof tmp))
512 goto nonvhd;
513 hfd->vhd_footerblock = hfd->physsize - 512;
514 hfd->virtsize = (uae_u64)(gl (tmp + 8 + 4 + 4 + 8 + 4 + 4 +4 + 4 + 8)) << 32;
515 hfd->virtsize |= gl (tmp + 8 + 4 + 4 + 8 + 4 + 4 +4 + 4 + 8 + 4);
516 if (hfd->hfd_type == HFD_VHD_DYNAMIC) {
517 uae_u32 size;
518 hfd->vhd_bamoffset = gl (tmp + 8 + 4 + 4 + 4);
519 if (hfd->vhd_bamoffset == 0 || hfd->vhd_bamoffset >= hfd->physsize)
520 goto end;
521 if (hdf_read_target (hfd, tmp, hfd->vhd_bamoffset, 512) != 512)
522 goto end;
523 v = gl (tmp + 8 + 8 + 8 + 4 + 4 + 4);
524 if (vhd_checksum (tmp, 8 + 8 + 8 + 4 + 4 + 4) != v)
525 goto end;
526 v = gl (tmp + 8 + 8 + 8);
527 if ((v >> 16) != 1)
528 goto end;
529 hfd->vhd_blocksize = gl (tmp + 8 + 8 + 8 + 4 + 4);
530 hfd->vhd_bamoffset = gl (tmp + 8 + 8 + 4);
531 hfd->vhd_bamsize = (((hfd->virtsize + hfd->vhd_blocksize - 1) / hfd->vhd_blocksize) * 4 + 511) & ~511;
532 size = hfd->vhd_bamoffset + hfd->vhd_bamsize;
533 hfd->vhd_header = xmalloc (uae_u8, size);
534 if ((uae_u32)hdf_read_target (hfd, hfd->vhd_header, 0, size) != size)
535 goto end;
536 hfd->vhd_sectormap = xmalloc (uae_u8, 512);
537 hfd->vhd_sectormapblock = -1;
538 hfd->vhd_bitmapsize = ((hfd->vhd_blocksize / (8 * 512)) + 511) & ~511;
539 }
540 write_log (_T("HDF is VHD %s image, virtual size=%dK\n"),
541 hfd->hfd_type == HFD_VHD_FIXED ? _T("fixed") : _T("dynamic"),
542 hfd->virtsize / 1024);
543 hdf_init_cache (hfd);
544 return 1;
545 nonvhd:
546 return 1;
547 end:
548 hdf_close_target (hfd);
549 return 0;
550 }
551
hdf_close(struct hardfiledata * hfd)552 void hdf_close (struct hardfiledata *hfd)
553 {
554 hdf_flush_cache (hfd);
555 hdf_close_target (hfd);
556 #if USE_CHD
557 if (hfd->chd_handle) {
558 chd_file *cf = (chd_file*)hfd->chd_handle;
559 cf->close();
560 hfd->chd_handle = NULL;
561 }
562 #endif
563 hfd->hfd_type = 0;
564 xfree (hfd->vhd_header);
565 xfree (hfd->vhd_sectormap);
566 }
567
hdf_dup(struct hardfiledata * dhfd,const struct hardfiledata * shfd)568 int hdf_dup (struct hardfiledata *dhfd, const struct hardfiledata *shfd)
569 {
570 return hdf_dup_target (dhfd, shfd);
571 }
572
573 extern int get_guid_target (uae_u8 *out);
574
vhd_read(struct hardfiledata * hfd,void * v,uae_u64 offset,uae_u64 len)575 static uae_u64 vhd_read (struct hardfiledata *hfd, void *v, uae_u64 offset, uae_u64 len)
576 {
577 uae_u64 read;
578 uae_u8 *dataptr = (uae_u8*)v;
579
580 //write_log (_T("%08x %08x\n"), (uae_u32)offset, (uae_u32)len);
581 read = 0;
582 if (offset & 511)
583 return read;
584 if (len & 511)
585 return read;
586 while (len > 0) {
587 uae_u32 bamoffset = (offset / hfd->vhd_blocksize) * 4 + hfd->vhd_bamoffset;
588 uae_u32 sectoroffset = gl (hfd->vhd_header + bamoffset);
589 if (sectoroffset == 0xffffffff) {
590 memset (dataptr, 0, 512);
591 read += 512;
592 } else {
593 int bitmapoffsetbits;
594 int bitmapoffsetbytes;
595 uae_u64 sectormapblock;
596
597 bitmapoffsetbits = (offset / 512) % (hfd->vhd_blocksize / 512);
598 bitmapoffsetbytes = bitmapoffsetbits / 8;
599 sectormapblock = sectoroffset * (uae_u64)512 + (bitmapoffsetbytes & ~511);
600 if (hfd->vhd_sectormapblock != sectormapblock) {
601 // read sector bitmap
602 //write_log (_T("BM %08x\n"), sectormapblock);
603 if (hdf_read_target (hfd, hfd->vhd_sectormap, sectormapblock, 512) != 512) {
604 write_log (_T("vhd_read: bitmap read error\n"));
605 return read;
606 }
607 hfd->vhd_sectormapblock = sectormapblock;
608 }
609 // block allocated in bitmap?
610 if (hfd->vhd_sectormap[bitmapoffsetbytes & 511] & (1 << (7 - (bitmapoffsetbits & 7)))) {
611 // read data block
612 uae_u64 block = sectoroffset * (uae_u64)512 + hfd->vhd_bitmapsize + bitmapoffsetbits * 512;
613 //write_log (_T("DB %08x\n"), block);
614 if (hdf_read_target (hfd, dataptr, block, 512) != 512) {
615 write_log (_T("vhd_read: data read error\n"));
616 return read;
617 }
618 } else {
619 memset (dataptr, 0, 512);
620 }
621 read += 512;
622 }
623 len -= 512;
624 dataptr += 512;
625 offset += 512;
626 }
627 return read;
628 }
629
vhd_write_enlarge(struct hardfiledata * hfd,uae_u32 bamoffset)630 static int vhd_write_enlarge (struct hardfiledata *hfd, uae_u32 bamoffset)
631 {
632 uae_u8 *buf, *p;
633 int len;
634 uae_u32 block;
635 int v;
636
637 len = hfd->vhd_blocksize + hfd->vhd_bitmapsize + 512;
638 buf = xcalloc (uae_u8, len);
639 if (!hdf_resize_target (hfd, hfd->physsize + len - 512)) {
640 write_log (_T("vhd_enlarge: failure\n"));
641 return 0;
642 }
643 // add footer (same as 512 byte header)
644 memcpy (buf + len - 512, hfd->vhd_header, 512);
645 v = hdf_write_target (hfd, buf, hfd->vhd_footerblock, len);
646 xfree (buf);
647 if (v != len) {
648 write_log (_T("vhd_enlarge: footer write error\n"));
649 return 0;
650 }
651 // write new offset to BAM
652 p = hfd->vhd_header + bamoffset;
653 block = hfd->vhd_footerblock / 512;
654 p[0] = block >> 24;
655 p[1] = block >> 16;
656 p[2] = block >> 8;
657 p[3] = block >> 0;
658 // write to disk
659 if ((uae_u32)hdf_write_target (hfd, hfd->vhd_header + hfd->vhd_bamoffset, hfd->vhd_bamoffset, hfd->vhd_bamsize) != hfd->vhd_bamsize) {
660 write_log (_T("vhd_enlarge: bam write error\n"));
661 return 0;
662 }
663 hfd->vhd_footerblock += len - 512;
664 return 1;
665 }
666
vhd_write(struct hardfiledata * hfd,void * v,uae_u64 offset,uae_u64 len)667 static uae_u64 vhd_write (struct hardfiledata *hfd, void *v, uae_u64 offset, uae_u64 len)
668 {
669 uae_u64 written;
670 uae_u8 *dataptr = (uae_u8*)v;
671
672 //write_log (_T("%08x %08x\n"), (uae_u32)offset, (uae_u32)len);
673 written = 0;
674 if (offset & 511)
675 return written;
676 if (len & 511)
677 return written;
678 while (len > 0) {
679 uae_u32 bamoffset = (offset / hfd->vhd_blocksize) * 4 + hfd->vhd_bamoffset;
680 uae_u32 sectoroffset = gl (hfd->vhd_header + bamoffset);
681 if (sectoroffset == 0xffffffff) {
682 if (!vhd_write_enlarge (hfd, bamoffset))
683 return written;
684 continue;
685 } else {
686 int bitmapoffsetbits;
687 int bitmapoffsetbytes;
688
689 bitmapoffsetbits = (offset / 512) % (hfd->vhd_blocksize / 512);
690 bitmapoffsetbytes = bitmapoffsetbits / 8;
691 uae_u64 sectormapblock = sectoroffset * (uae_u64)512 + (bitmapoffsetbytes & ~511);
692 if (hfd->vhd_sectormapblock != sectormapblock) {
693 // read sector bitmap
694 if (hdf_read_target (hfd, hfd->vhd_sectormap, sectormapblock, 512) != 512) {
695 write_log (_T("vhd_write: bitmap read error\n"));
696 return written;
697 }
698 hfd->vhd_sectormapblock = sectormapblock;
699 }
700 // write data
701 if (hdf_write_target (hfd, dataptr, sectoroffset * (uae_u64)512 + hfd->vhd_bitmapsize + bitmapoffsetbits * 512, 512) != 512) {
702 write_log (_T("vhd_write: data write error\n"));
703 return written;
704 }
705 // block already allocated in bitmap?
706 if (!(hfd->vhd_sectormap[bitmapoffsetbytes & 511] & (1 << (7 - (bitmapoffsetbits & 7))))) {
707 // no, we need to mark it allocated and write the modified bitmap back to the disk
708 hfd->vhd_sectormap[bitmapoffsetbytes & 511] |= (1 << (7 - (bitmapoffsetbits & 7)));
709 if (hdf_write_target (hfd, hfd->vhd_sectormap, sectormapblock, 512) != 512) {
710 write_log (_T("vhd_write: bam write error\n"));
711 return written;
712 }
713 }
714 written += 512;
715 }
716 len -= 512;
717 dataptr += 512;
718 offset += 512;
719 }
720 return written;
721 }
722
723
vhd_create(const TCHAR * name,uae_u64 size,uae_u32 dostype)724 int vhd_create (const TCHAR *name, uae_u64 size, uae_u32 dostype)
725 {
726 struct hardfiledata hfd;
727 struct zfile *zf;
728 uae_u8 *b;
729 int cyl, cylsec, head, tracksec;
730 uae_u32 crc, blocksize, batsize, batentrysize;
731 int ret, i;
732 time_t tm;
733
734 if (size >= (uae_u64)10 * 1024 * 1024 * 1024)
735 blocksize = 2 * 1024 * 1024;
736 else
737 blocksize = 512 * 1024;
738 batsize = (size + blocksize - 1) / blocksize;
739 batentrysize = batsize;
740 batsize *= 4;
741 batsize += 511;
742 batsize &= ~511;
743 ret = 0;
744 b = NULL;
745 zf = zfile_fopen (name, _T("wb"), 0);
746 if (!zf)
747 goto end;
748 b = xcalloc (uae_u8, 512 + 1024 + batsize + 512);
749 if (zfile_fwrite (b, 512 + 1024 + batsize + 512, 1, zf) != 1)
750 goto end;
751
752 memset (&hfd, 0, sizeof hfd);
753 hfd.virtsize = hfd.physsize = size;
754 hfd.ci.blocksize = 512;
755 strcpy ((char*)b, "conectix"); // cookie
756 b[0x0b] = 2; // features
757 b[0x0d] = 1; // version
758 b[0x10 + 6] = 2; // data offset
759 // time stamp
760 tm = time (NULL) - 946684800;
761 b[0x18] = tm >> 24;
762 b[0x19] = tm >> 16;
763 b[0x1a] = tm >> 8;
764 b[0x1b] = tm >> 0;
765 strcpy ((char*)b + 0x1c, "vpc "); // creator application
766 b[0x21] = 5; // creator version
767 strcpy ((char*)b + 0x24, "Wi2k"); // creator host os
768 // original and current size
769 b[0x28] = b[0x30] = size >> 56;
770 b[0x29] = b[0x31] = size >> 48;
771 b[0x2a] = b[0x32] = size >> 40;
772 b[0x2b] = b[0x33] = size >> 32;
773 b[0x2c] = b[0x34] = size >> 24;
774 b[0x2d] = b[0x35] = size >> 16;
775 b[0x2e] = b[0x36] = size >> 8;
776 b[0x2f] = b[0x37] = size >> 0;
777 getchs2 (&hfd, &cyl, &cylsec, &head, &tracksec);
778 // cylinders
779 b[0x38] = cyl >> 8;
780 b[0x39] = cyl;
781 // heads
782 b[0x3a] = head;
783 // sectors per track
784 b[0x3b] = tracksec;
785 // disk type
786 b[0x3c + 3] = HFD_VHD_DYNAMIC;
787 get_guid_target (b + 0x44);
788 crc = vhd_checksum (b, -1);
789 b[0x40] = crc >> 24;
790 b[0x41] = crc >> 16;
791 b[0x42] = crc >> 8;
792 b[0x43] = crc >> 0;
793
794 // write header
795 zfile_fseek (zf, 0, SEEK_SET);
796 zfile_fwrite (b, 512, 1, zf);
797 // write footer
798 zfile_fseek (zf, 512 + 1024 + batsize, SEEK_SET);
799 zfile_fwrite (b, 512, 1, zf);
800
801 // dynamic disk header
802 memset (b, 0, 1024);
803 // cookie
804 strcpy ((char*)b, "cxsparse");
805 // data offset
806 for (i = 0; i < 8; i++)
807 b[0x08 + i] = 0xff;
808 // table offset (bat)
809 b[0x10 + 6] = 0x06;
810 // version
811 b[0x19] = 1;
812 // max table entries
813 b[0x1c] = batentrysize >> 24;
814 b[0x1d] = batentrysize >> 16;
815 b[0x1e] = batentrysize >> 8;
816 b[0x1f] = batentrysize >> 0;
817 b[0x20] = blocksize >> 24;
818 b[0x21] = blocksize >> 16;
819 b[0x22] = blocksize >> 8;
820 b[0x23] = blocksize >> 0;
821 crc = vhd_checksum (b, -1);
822 b[0x24] = crc >> 24;
823 b[0x25] = crc >> 16;
824 b[0x26] = crc >> 8;
825 b[0x27] = crc >> 0;
826
827 // write dynamic header
828 zfile_fseek (zf, 512, SEEK_SET);
829 zfile_fwrite (b, 1024, 1, zf);
830
831 // bat
832 memset (b, 0, batsize);
833 memset (b, 0xff, batentrysize * 4);
834 zfile_fwrite (b, batsize, 1, zf);
835
836 zfile_fclose (zf);
837 zf = NULL;
838
839 if (dostype) {
840 uae_u8 bootblock[512] = { 0 };
841 bootblock[0] = dostype >> 24;
842 bootblock[1] = dostype >> 16;
843 bootblock[2] = dostype >> 8;
844 bootblock[3] = dostype >> 0;
845 if (hdf_open (&hfd, name)) {
846 vhd_write (&hfd, bootblock, 0, 512);
847 hdf_close (&hfd);
848 }
849 }
850
851 ret = 1;
852
853 end:
854 xfree (b);
855 zfile_fclose (zf);
856 return ret;
857 }
858
hdf_read2(struct hardfiledata * hfd,void * buffer,uae_u64 offset,int len)859 static int hdf_read2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
860 {
861 if (hfd->hfd_type == HFD_VHD_DYNAMIC)
862 return vhd_read (hfd, buffer, offset, len);
863 else if (hfd->hfd_type == HFD_VHD_FIXED)
864 return hdf_read_target (hfd, buffer, offset + 512, len);
865 #if USE_CHD
866 else if (hfd->hfd_type == HFD_CHD) {
867 chd_file *cf = (chd_file*)hfd->chd_handle;
868 if (cf->read_bytes(offset, buffer, len) == CHDERR_NONE)
869 return len;
870 return 0;
871 }
872 #endif
873 else
874 return hdf_read_target (hfd, buffer, offset, len);
875 }
876
hdf_write2(struct hardfiledata * hfd,void * buffer,uae_u64 offset,int len)877 static int hdf_write2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
878 {
879 if (hfd->hfd_type == HFD_VHD_DYNAMIC)
880 return vhd_write (hfd, buffer, offset, len);
881 else if (hfd->hfd_type == HFD_VHD_FIXED)
882 return hdf_write_target (hfd, buffer, offset + 512, len);
883 else if (hfd->hfd_type == HFD_CHD)
884 return 0;
885 else
886 return hdf_write_target (hfd, buffer, offset, len);
887 }
888
adide_decode(void * v,int len)889 static void adide_decode (void *v, int len)
890 {
891 int i;
892 uae_u8 *buffer = (uae_u8*)v;
893 for (i = 0; i < len; i += 2) {
894 uae_u8 *b = buffer + i;
895 uae_u16 w = (b[0] << 8) | (b[1] << 0);
896 uae_u16 o = 0;
897
898 if (w & 0x8000)
899 o |= 0x0001;
900 if (w & 0x0001)
901 o |= 0x0002;
902
903 if (w & 0x4000)
904 o |= 0x0004;
905 if (w & 0x0002)
906 o |= 0x0008;
907
908 if (w & 0x2000)
909 o |= 0x0010;
910 if (w & 0x0004)
911 o |= 0x0020;
912
913 if (w & 0x1000)
914 o |= 0x0040;
915 if (w & 0x0008)
916 o |= 0x0080;
917
918 if (w & 0x0800)
919 o |= 0x0100;
920 if (w & 0x0010)
921 o |= 0x0200;
922
923 if (w & 0x0400)
924 o |= 0x0400;
925 if (w & 0x0020)
926 o |= 0x0800;
927
928 if (w & 0x0200)
929 o |= 0x1000;
930 if (w & 0x0040)
931 o |= 0x2000;
932
933 if (w & 0x0100)
934 o |= 0x4000;
935 if (w & 0x0080)
936 o |= 0x8000;
937
938 b[0] = o >> 8;
939 b[1] = o >> 0;
940 }
941 }
adide_encode(void * v,int len)942 static void adide_encode (void *v, int len)
943 {
944 int i;
945 uae_u8 *buffer = (uae_u8*)v;
946 for (i = 0; i < len; i += 2) {
947 uae_u8 *b = buffer + i;
948 uae_u16 w = (b[0] << 8) | (b[1] << 0);
949 uae_u16 o = 0;
950
951 if (w & 0x0001)
952 o |= 0x8000;
953 if (w & 0x0002)
954 o |= 0x0001;
955
956 if (w & 0x0004)
957 o |= 0x4000;
958 if (w & 0x0008)
959 o |= 0x0002;
960
961 if (w & 0x0010)
962 o |= 0x2000;
963 if (w & 0x0020)
964 o |= 0x0004;
965
966 if (w & 0x0040)
967 o |= 0x1000;
968 if (w & 0x0080)
969 o |= 0x0008;
970
971 if (w & 0x0100)
972 o |= 0x0800;
973 if (w & 0x0200)
974 o |= 0x0010;
975
976 if (w & 0x0400)
977 o |= 0x0400;
978 if (w & 0x0800)
979 o |= 0x0020;
980
981 if (w & 0x1000)
982 o |= 0x0200;
983 if (w & 0x2000)
984 o |= 0x0040;
985
986 if (w & 0x4000)
987 o |= 0x0100;
988 if (w & 0x8000)
989 o |= 0x0080;
990
991 b[0] = o >> 8;
992 b[1] = o >> 0;
993 }
994 }
995
hdf_byteswap(void * v,int len)996 static void hdf_byteswap (void *v, int len)
997 {
998 int i;
999 uae_u8 *b = (uae_u8*)v;
1000
1001 for (i = 0; i < len; i += 2) {
1002 uae_u8 tmp = b[i];
1003 b[i] = b[i + 1];
1004 b[i + 1] = tmp;
1005 }
1006 }
1007
hdf_read_rdb(struct hardfiledata * hfd,void * buffer,uae_u64 offset,int len)1008 int hdf_read_rdb (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
1009 {
1010 int v;
1011 v = hdf_read (hfd, buffer, offset, len);
1012 if (v > 0 && offset < 16 * 512 && !hfd->byteswap && !hfd->adide) {
1013 uae_u8 *buf = (uae_u8*)buffer;
1014 bool changed = false;
1015 if (buf[0] == 0x39 && buf[1] == 0x10 && buf[2] == 0xd3 && buf[3] == 0x12) { // AdIDE encoded "CPRM"
1016 hfd->adide = 1;
1017 changed = true;
1018 write_log (_T("HDF: adide scrambling detected\n"));
1019 } else if (!memcmp (buf, "DRKS", 4)) {
1020 hfd->byteswap = 1;
1021 changed = true;
1022 write_log (_T("HDF: byteswapped RDB detected\n"));
1023 }
1024 if (changed)
1025 v = hdf_read (hfd, buffer, offset, len);
1026 }
1027 return v;
1028 }
1029
hdf_read(struct hardfiledata * hfd,void * buffer,uae_u64 offset,int len)1030 int hdf_read (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
1031 {
1032 int v;
1033
1034 hf_log3 (_T("cmd_read: %p %04x-%08x (%d) %08x (%d)\n"),
1035 buffer, (uae_u32)(offset >> 32), (uae_u32)offset, (uae_u32)(offset / hfd->ci.blocksize), (uae_u32)len, (uae_u32)(len / hfd->ci.blocksize));
1036
1037 if (!hfd->adide) {
1038 v = hdf_cache_read (hfd, buffer, offset, len);
1039 } else {
1040 offset += 512;
1041 v = hdf_cache_read (hfd, buffer, offset, len);
1042 adide_decode (buffer, len);
1043 }
1044 if (hfd->byteswap)
1045 hdf_byteswap (buffer, len);
1046 return v;
1047 }
1048
hdf_write(struct hardfiledata * hfd,void * buffer,uae_u64 offset,int len)1049 int hdf_write (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
1050 {
1051 int v;
1052
1053 hf_log3 (_T("cmd_write: %p %04x-%08x (%d) %08x (%d)\n"),
1054 buffer, (uae_u32)(offset >> 32), (uae_u32)offset, (uae_u32)(offset / hfd->ci.blocksize), (uae_u32)len, (uae_u32)(len / hfd->ci.blocksize));
1055
1056 if (hfd->byteswap)
1057 hdf_byteswap (buffer, len);
1058 if (!hfd->adide) {
1059 v = hdf_cache_write (hfd, buffer, offset, len);
1060 } else {
1061 offset += 512;
1062 adide_encode (buffer, len);
1063 v = hdf_cache_write (hfd, buffer, offset, len);
1064 adide_decode (buffer, len);
1065 }
1066 if (hfd->byteswap)
1067 hdf_byteswap (buffer, len);
1068 return v;
1069 }
1070
cmd_readx(struct hardfiledata * hfd,uae_u8 * dataptr,uae_u64 offset,uae_u64 len)1071 static uae_u64 cmd_readx (struct hardfiledata *hfd, uae_u8 *dataptr, uae_u64 offset, uae_u64 len)
1072 {
1073 gui_flicker_led (LED_HD, hfd->unitnum, 1);
1074 return hdf_read (hfd, dataptr, offset, len);
1075 }
cmd_read(struct hardfiledata * hfd,uaecptr dataptr,uae_u64 offset,uae_u64 len)1076 static uae_u64 cmd_read (struct hardfiledata *hfd, uaecptr dataptr, uae_u64 offset, uae_u64 len)
1077 {
1078 addrbank *bank_data = &get_mem_bank (dataptr);
1079 if (!len || !bank_data || !bank_data->check (dataptr, len))
1080 return 0;
1081 return cmd_readx (hfd, bank_data->xlateaddr (dataptr), offset, len);
1082 }
cmd_writex(struct hardfiledata * hfd,uae_u8 * dataptr,uae_u64 offset,uae_u64 len)1083 static uae_u64 cmd_writex (struct hardfiledata *hfd, uae_u8 *dataptr, uae_u64 offset, uae_u64 len)
1084 {
1085 gui_flicker_led (LED_HD, hfd->unitnum, 2);
1086 return hdf_write (hfd, dataptr, offset, len);
1087 }
1088
cmd_write(struct hardfiledata * hfd,uaecptr dataptr,uae_u64 offset,uae_u64 len)1089 static uae_u64 cmd_write (struct hardfiledata *hfd, uaecptr dataptr, uae_u64 offset, uae_u64 len)
1090 {
1091 addrbank *bank_data = &get_mem_bank (dataptr);
1092 if (!len || !bank_data || !bank_data->check (dataptr, len))
1093 return 0;
1094 return cmd_writex (hfd, bank_data->xlateaddr (dataptr), offset, len);
1095 }
1096
checkbounds(struct hardfiledata * hfd,uae_u64 offset,uae_u64 len)1097 static int checkbounds (struct hardfiledata *hfd, uae_u64 offset, uae_u64 len)
1098 {
1099 if (offset >= hfd->virtsize)
1100 return 0;
1101 if (offset + len > hfd->virtsize)
1102 return 0;
1103 return 1;
1104 }
1105
nodisk(struct hardfiledata * hfd)1106 static int nodisk (struct hardfiledata *hfd)
1107 {
1108 if (hfd->drive_empty)
1109 return 1;
1110 return 0;
1111 }
1112
scsi_hd_emulate(struct hardfiledata * hfd,struct hd_hardfiledata * hdhfd,uae_u8 * cmdbuf,int scsi_cmd_len,uae_u8 * scsi_data,int * data_len,uae_u8 * r,int * reply_len,uae_u8 * s,int * sense_len)1113 int scsi_hd_emulate (struct hardfiledata *hfd, struct hd_hardfiledata *hdhfd, uae_u8 *cmdbuf, int scsi_cmd_len,
1114 uae_u8 *scsi_data, int *data_len, uae_u8 *r, int *reply_len, uae_u8 *s, int *sense_len)
1115 {
1116 uae_u64 len, offset;
1117 int lr = 0, ls = 0;
1118 int scsi_len = -1;
1119 int status = 0;
1120 int i, lun;
1121 char *ss;
1122
1123 *reply_len = *sense_len = 0;
1124 memset (r, 0, 256);
1125 memset (s, 0, 256);
1126 lun = cmdbuf[1] >> 5;
1127 if (cmdbuf[0] != 0x03 && cmdbuf[0] != 0x12 && lun) {
1128 status = 2; /* CHECK CONDITION */
1129 s[0] = 0x70;
1130 s[2] = 5; /* ILLEGAL REQUEST */
1131 s[12] = 0x25; /* INVALID LUN */
1132 ls = 0x12;
1133 goto err;
1134 }
1135 switch (cmdbuf[0])
1136 {
1137 case 0x00: /* TEST UNIT READY */
1138 if (nodisk (hfd))
1139 goto nodisk;
1140 scsi_len = 0;
1141 break;
1142 case 0x03: /* REQUEST SENSE */
1143 scsi_len = cmdbuf[4] > MAX_SCSI_SENSE ? MAX_SCSI_SENSE : cmdbuf[4];
1144 memcpy (r, hfd->scsi_sense, scsi_len);
1145 memset (hfd->scsi_sense, 0, MAX_SCSI_SENSE);
1146 break;
1147 case 0x08: /* READ (6) */
1148 if (nodisk (hfd))
1149 goto nodisk;
1150 offset = ((cmdbuf[1] & 31) << 16) | (cmdbuf[2] << 8) | cmdbuf[3];
1151 offset *= hfd->ci.blocksize;
1152 len = cmdbuf[4];
1153 if (!len)
1154 len = 256;
1155 len *= hfd->ci.blocksize;
1156 if (!checkbounds(hfd, offset, len))
1157 goto outofbounds;
1158 scsi_len = (uae_u32)cmd_readx (hfd, scsi_data, offset, len);
1159 break;
1160 case 0x0a: /* WRITE (6) */
1161 if (nodisk (hfd))
1162 goto nodisk;
1163 if (hfd->ci.readonly || hfd->dangerous)
1164 goto readprot;
1165 offset = ((cmdbuf[1] & 31) << 16) | (cmdbuf[2] << 8) | cmdbuf[3];
1166 offset *= hfd->ci.blocksize;
1167 len = cmdbuf[4];
1168 if (!len)
1169 len = 256;
1170 len *= hfd->ci.blocksize;
1171 if (!checkbounds(hfd, offset, len))
1172 goto outofbounds;
1173 scsi_len = (uae_u32)cmd_writex (hfd, scsi_data, offset, len);
1174 break;
1175 case 0x12: /* INQUIRY */
1176 {
1177 if ((cmdbuf[1] & 1) || cmdbuf[2] != 0)
1178 goto err;
1179 int alen = (cmdbuf[3] << 8) | cmdbuf[4];
1180 if (lun != 0) {
1181 r[0] = 0x7f;
1182 } else {
1183 r[0] = 0;
1184 if (hfd->drive_empty) {
1185 r[1] |= 0x80; // removable..
1186 r[0] |= 0x20; // not present
1187 }
1188 }
1189 r[2] = 2; /* supports SCSI-2 */
1190 r[3] = 2; /* response data format */
1191 r[4] = 32; /* additional length */
1192 r[7] = 0x20; /* 16 bit bus */
1193 scsi_len = lr = alen < 36 ? (uae_u32)alen : 36;
1194 if (hdhfd) {
1195 r[2] = hdhfd->ansi_version;
1196 r[3] = hdhfd->ansi_version >= 2 ? 2 : 0;
1197 }
1198 ss = ua (hfd->vendor_id);
1199 i = 0; /* vendor id */
1200 while (i < 8 && ss[i]) {
1201 r[8 + i] = ss[i];
1202 i++;
1203 }
1204 while (i < 8) {
1205 r[8 + i] = 32;
1206 i++;
1207 }
1208 xfree (ss);
1209 ss = ua (hfd->product_id);
1210 i = 0; /* product id */
1211 while (i < 16 && ss[i]) {
1212 r[16 + i] = ss[i];
1213 i++;
1214 }
1215 while (i < 16) {
1216 r[16 + i] = 32;
1217 i++;
1218 }
1219 xfree (ss);
1220 ss = ua (hfd->product_rev);
1221 i = 0; /* product revision */
1222 while (i < 4 && ss[i]) {
1223 r[32 + i] = ss[i];
1224 i++;
1225 }
1226 while (i < 4) {
1227 r[32 + i] = 32;
1228 i++;
1229 }
1230 xfree (ss);
1231 }
1232 break;
1233 case 0x1a: /* MODE SENSE(6) */
1234 {
1235 uae_u8 *p;
1236 int pc = cmdbuf[2] >> 6;
1237 int pcode = cmdbuf[2] & 0x3f;
1238 int dbd = cmdbuf[1] & 8;
1239 int alen = cmdbuf[4];
1240 int cyl, cylsec, head, tracksec;
1241 if (nodisk (hfd))
1242 goto nodisk;
1243 if (hdhfd) {
1244 cyl = hdhfd->cyls;
1245 head = hdhfd->heads;
1246 tracksec = hdhfd->secspertrack;
1247 cylsec = 0;
1248 } else {
1249 getchsx (hfd, &cyl, &cylsec, &head, &tracksec);
1250 }
1251 //write_log (_T("MODE SENSE PC=%d CODE=%d DBD=%d\n"), pc, pcode, dbd);
1252 p = r;
1253 p[0] = 4 - 1;
1254 p[1] = 0;
1255 p[2] = (hfd->ci.readonly || hfd->dangerous) ? 0x80 : 0x00;
1256 p[3] = 0;
1257 p += 4;
1258 if (!dbd) {
1259 if (alen >= r[0] + 1 + 8) {
1260 uae_u32 blocks = (uae_u32)(hfd->virtsize / hfd->ci.blocksize);
1261 p[-1] = 8;
1262 wl(p + 0, blocks);
1263 wl(p + 4, hfd->ci.blocksize);
1264 p += 8;
1265 }
1266 }
1267 if (pcode == 0) {
1268 if (alen >= r[0] + 1 + r[3] + 4) {
1269 p[0] = 0;
1270 p[1] = 3;
1271 p[2] = 0x20;
1272 p[3] = 0;
1273 r[0] += p[1];
1274 }
1275 } else if (pcode == 3) {
1276 // format parameters
1277 if (alen >= r[0] + 1 + r[3] + 24) {
1278 p[0] = 3;
1279 p[1] = 24;
1280 p[3] = 1;
1281 p[10] = tracksec >> 8;
1282 p[11] = tracksec;
1283 p[12] = hfd->ci.blocksize >> 8;
1284 p[13] = hfd->ci.blocksize;
1285 p[15] = 1; // interleave
1286 p[20] = 0x80;
1287 r[0] += p[1];
1288 }
1289 } else if (pcode == 4) {
1290 // rigid drive geometry
1291 if (alen >= r[0] + 1 + r[3] + 16) {
1292 p[0] = 4;
1293 wl(p + 1, cyl);
1294 p[1] = 24;
1295 p[5] = head;
1296 wl(p + 13, cyl);
1297 ww(p + 20, 5400);
1298 r[0] += p[1];
1299 }
1300 } else {
1301 goto err;
1302 }
1303 r[0] += r[3];
1304 scsi_len = lr = r[0] + 1;
1305 if (scsi_len > alen)
1306 scsi_len = alen;
1307 break;
1308 }
1309 break;
1310 case 0x1d: /* SEND DIAGNOSTICS */
1311 break;
1312 case 0x25: /* READ_CAPACITY */
1313 {
1314 int pmi = cmdbuf[8] & 1;
1315 uae_u32 lba = (cmdbuf[2] << 24) | (cmdbuf[3] << 16) | (cmdbuf[4] << 8) | cmdbuf[5];
1316 uae_u32 blocks;
1317 int cyl, cylsec, head, tracksec;
1318 if (nodisk (hfd))
1319 goto nodisk;
1320 blocks = (uae_u32)(hfd->virtsize / hfd->ci.blocksize - 1);
1321 if (hdhfd) {
1322 cyl = hdhfd->cyls;
1323 head = hdhfd->heads;
1324 tracksec = hdhfd->secspertrack;
1325 cylsec = 0;
1326 } else {
1327 getchsx (hfd, &cyl, &cylsec, &head, &tracksec);
1328 }
1329 if (pmi == 0 && lba != 0)
1330 goto errreq;
1331 if (pmi) {
1332 lba += tracksec * head;
1333 lba /= tracksec * head;
1334 lba *= tracksec * head;
1335 if (lba > blocks)
1336 lba = blocks;
1337 blocks = lba;
1338 }
1339 wl (r, blocks);
1340 wl (r + 4, hfd->ci.blocksize);
1341 scsi_len = lr = 8;
1342 }
1343 break;
1344 case 0x28: /* READ (10) */
1345 if (nodisk (hfd))
1346 goto nodisk;
1347 offset = rl (cmdbuf + 2);
1348 offset *= hfd->ci.blocksize;
1349 len = rl (cmdbuf + 7 - 2) & 0xffff;
1350 len *= hfd->ci.blocksize;
1351 if (!checkbounds (hfd, offset, len))
1352 goto outofbounds;
1353 scsi_len = (uae_u32)cmd_readx (hfd, scsi_data, offset, len);
1354 break;
1355 case 0x2a: /* WRITE (10) */
1356 if (nodisk (hfd))
1357 goto nodisk;
1358 if (hfd->ci.readonly || hfd->dangerous)
1359 goto readprot;
1360 offset = rl (cmdbuf + 2);
1361 offset *= hfd->ci.blocksize;
1362 len = rl (cmdbuf + 7 - 2) & 0xffff;
1363 len *= hfd->ci.blocksize;
1364 if (!checkbounds (hfd, offset, len))
1365 goto outofbounds;
1366 scsi_len = (uae_u32)cmd_writex (hfd, scsi_data, offset, len);
1367 break;
1368 #if 0
1369 case 0x2f: /* VERIFY */
1370 {
1371 int bytchk = cmdbuf[1] & 2;
1372 if (nodisk (hfd))
1373 goto nodisk;
1374 offset = rl (cmdbuf + 2);
1375 offset *= hfd->ci.blocksize;
1376 len = rl (cmdbuf + 7 - 2) & 0xffff;
1377 len *= hfd->ci.blocksize;
1378 if (checkbounds (hfd, offset, len)) {
1379 uae_u8 *vb = xmalloc (hfd->ci.blocksize);
1380 while (len > 0) {
1381 int len = cmd_readx (hfd, vb, offset, hfd->ci.blocksize);
1382 if (bytchk) {
1383 if (memcmp (vb, scsi_data, hfd->ci.blocksize))
1384 goto miscompare;
1385 scsi_data += hfd->ci.blocksize;
1386 }
1387 offset += hfd->ci.blocksize;
1388 }
1389 xfree (vb);
1390 }
1391 }
1392 break;
1393 #endif
1394 case 0x35: /* SYNCRONIZE CACHE (10) */
1395 if (nodisk (hfd))
1396 goto nodisk;
1397 scsi_len = 0;
1398 break;
1399 case 0xa8: /* READ (12) */
1400 if (nodisk (hfd))
1401 goto nodisk;
1402 offset = rl (cmdbuf + 2);
1403 offset *= hfd->ci.blocksize;
1404 len = rl (cmdbuf + 6);
1405 len *= hfd->ci.blocksize;
1406 if (!checkbounds(hfd, offset, len))
1407 goto outofbounds;
1408 scsi_len = (uae_u32)cmd_readx (hfd, scsi_data, offset, len);
1409 break;
1410 case 0xaa: /* WRITE (12) */
1411 if (nodisk (hfd))
1412 goto nodisk;
1413 if (hfd->ci.readonly || hfd->dangerous)
1414 goto readprot;
1415 offset = rl (cmdbuf + 2);
1416 offset *= hfd->ci.blocksize;
1417 len = rl (cmdbuf + 6);
1418 len *= hfd->ci.blocksize;
1419 if (!checkbounds(hfd, offset, len))
1420 goto outofbounds;
1421 scsi_len = (uae_u32)cmd_writex (hfd, scsi_data, offset, len);
1422 break;
1423 case 0x37: /* READ DEFECT DATA */
1424 if (nodisk (hfd))
1425 goto nodisk;
1426 status = 2; /* CHECK CONDITION */
1427 s[0] = 0x70;
1428 s[2] = 0; /* NO SENSE */
1429 s[12] = 0x1c; /* DEFECT LIST NOT FOUND */
1430 ls = 0x12;
1431 break;
1432 case 0x1b: /* START/STOP UNIT */
1433 scsi_len = 0;
1434 break;
1435 readprot:
1436 status = 2; /* CHECK CONDITION */
1437 s[0] = 0x70;
1438 s[2] = 7; /* DATA PROTECT */
1439 s[12] = 0x27; /* WRITE PROTECTED */
1440 ls = 0x12;
1441 break;
1442 nodisk:
1443 status = 2; /* CHECK CONDITION */
1444 s[0] = 0x70;
1445 s[2] = 2; /* NOT READY */
1446 s[12] = 0x3A; /* MEDIUM NOT PRESENT */
1447 ls = 0x12;
1448 break;
1449
1450 default:
1451 err:
1452 write_log (_T("UAEHF: unsupported scsi command 0x%02X LUN=%d\n"), cmdbuf[0], lun);
1453 errreq:
1454 lr = -1;
1455 status = 2; /* CHECK CONDITION */
1456 s[0] = 0x70;
1457 s[2] = 5; /* ILLEGAL REQUEST */
1458 s[12] = 0x24; /* ILLEGAL FIELD IN CDB */
1459 ls = 0x12;
1460 break;
1461 outofbounds:
1462 lr = -1;
1463 status = 2; /* CHECK CONDITION */
1464 s[0] = 0x70;
1465 s[2] = 5; /* ILLEGAL REQUEST */
1466 s[12] = 0x21; /* LOGICAL BLOCK OUT OF RANGE */
1467 ls = 0x12;
1468 break;
1469 miscompare:
1470 lr = -1;
1471 status = 2; /* CHECK CONDITION */
1472 s[0] = 0x70;
1473 s[2] = 5; /* ILLEGAL REQUEST */
1474 s[12] = 0x1d; /* MISCOMPARE DURING VERIFY OPERATION */
1475 ls = 0x12;
1476 break;
1477 }
1478 *data_len = scsi_len;
1479 *reply_len = lr;
1480 *sense_len = ls;
1481 if (ls > 0) {
1482 memset (hfd->scsi_sense, 0, MAX_SCSI_SENSE);
1483 memcpy (hfd->scsi_sense, s, ls);
1484 }
1485 return status;
1486 }
1487
handle_scsi(uaecptr request,struct hardfiledata * hfd)1488 static int handle_scsi (uaecptr request, struct hardfiledata *hfd)
1489 {
1490 uae_u32 acmd = get_long (request + 40);
1491 uaecptr scsi_data = get_long (acmd + 0);
1492 int scsi_len = get_long (acmd + 4);
1493 uaecptr scsi_cmd = get_long (acmd + 12);
1494 uae_u16 scsi_cmd_len = get_word (acmd + 16);
1495 uae_u8 scsi_flags = get_byte (acmd + 20);
1496 uaecptr scsi_sense = get_long (acmd + 22);
1497 uae_u16 scsi_sense_len = get_word (acmd + 26);
1498 uae_u8 cmd = get_byte (scsi_cmd);
1499 uae_u8 cmdbuf[256];
1500 int status, ret = 0, reply_len, sense_len;
1501 uae_u32 i;
1502 uae_u8 reply[256], sense[256];
1503 uae_u8 *scsi_data_ptr = NULL;
1504 addrbank *bank_data = &get_mem_bank (scsi_data);
1505
1506 if (bank_data && bank_data->check (scsi_data, scsi_len))
1507 scsi_data_ptr = bank_data->xlateaddr (scsi_data);
1508 scsi_sense_len = (scsi_flags & 4) ? 4 : /* SCSIF_OLDAUTOSENSE */
1509 (scsi_flags & 2) ? scsi_sense_len : /* SCSIF_AUTOSENSE */
1510 32;
1511 status = 0;
1512 memset (reply, 0, sizeof reply);
1513 reply_len = 0; sense_len = 0;
1514 scsi_log (_T("hdf scsiemu: cmd=%02X,%d flags=%02X sense=%p,%d data=%p,%d\n"),
1515 cmd, scsi_cmd_len, scsi_flags, scsi_sense, scsi_sense_len, scsi_data, scsi_len);
1516 for (i = 0; i < scsi_cmd_len; i++) {
1517 cmdbuf[i] = get_byte (scsi_cmd + i);
1518 scsi_log (_T("%02X%c"), get_byte (scsi_cmd + i), i < scsi_cmd_len - 1 ? '.' : ' ');
1519 }
1520 scsi_log (_T("\n"));
1521
1522 status = scsi_hd_emulate (hfd, NULL, cmdbuf, scsi_cmd_len, scsi_data_ptr, &scsi_len, reply, &reply_len, sense, &sense_len);
1523
1524 put_word (acmd + 18, status != 0 ? 0 : scsi_cmd_len); /* fake scsi_CmdActual */
1525 put_byte (acmd + 21, status); /* scsi_Status */
1526 if (reply_len > 0) {
1527 scsi_log (_T("RD:"));
1528 i = 0;
1529 while (i < (uae_u32)reply_len) {
1530 if (i < 24)
1531 scsi_log (_T("%02X%c"), reply[i], i < reply_len - 1 ? '.' : ' ');
1532 put_byte (scsi_data + i, reply[i]);
1533 i++;
1534 }
1535 scsi_log (_T("\n"));
1536 }
1537 i = 0;
1538 if (scsi_sense) {
1539 while (i < (uae_u32)sense_len && i < (uae_u32)scsi_sense_len) {
1540 put_byte (scsi_sense + i, sense[i]);
1541 i++;
1542 }
1543 }
1544 while (i < scsi_sense_len && scsi_sense) {
1545 put_byte (scsi_sense + i, 0);
1546 i++;
1547 }
1548 if (scsi_len < 0) {
1549 put_long (acmd + 8, 0); /* scsi_Actual */
1550 ret = 20;
1551 } else {
1552 put_long (acmd + 8, scsi_len); /* scsi_Actual */
1553 }
1554 return ret;
1555 }
1556
1557
hardfile_send_disk_change(struct hardfiledata * hfd,bool insert)1558 void hardfile_send_disk_change (struct hardfiledata *hfd, bool insert)
1559 {
1560 int newstate = insert ? 0 : 1;
1561
1562 uae_sem_wait (&change_sem);
1563 hardfpd[hfd->unitnum].changenum++;
1564 write_log (_T("uaehf.device:%d media status=%d changenum=%d\n"), hfd->unitnum, insert, hardfpd[hfd->unitnum].changenum);
1565 hfd->drive_empty = newstate;
1566 int j = 0;
1567 while (j < MAX_ASYNC_REQUESTS) {
1568 if (hardfpd[hfd->unitnum].d_request_type[j] == ASYNC_REQUEST_CHANGEINT) {
1569 uae_Cause (hardfpd[hfd->unitnum].d_request_data[j]);
1570 }
1571 j++;
1572 }
1573 if (hardfpd[hfd->unitnum].changeint)
1574 uae_Cause (hardfpd[hfd->unitnum].changeint);
1575 uae_sem_post (&change_sem);
1576 }
1577
hardfile_do_disk_change(struct uaedev_config_data * uci,bool insert)1578 void hardfile_do_disk_change (struct uaedev_config_data *uci, bool insert)
1579 {
1580 int fsid = uci->configoffset;
1581 struct hardfiledata *hfd;
1582
1583 #ifdef GAYLE
1584 if (uci->ci.controller == HD_CONTROLLER_PCMCIA_SRAM) {
1585 gayle_modify_pcmcia_sram_unit (uci->ci.rootdir, uci->ci.readonly, insert);
1586 return;
1587 } else if (uci->ci.controller == HD_CONTROLLER_PCMCIA_IDE) {
1588 gayle_modify_pcmcia_ide_unit (uci->ci.rootdir, uci->ci.readonly, insert);
1589 return;
1590 }
1591 #endif
1592 hfd = get_hardfile_data (fsid);
1593 if (!hfd)
1594 return;
1595 hardfile_send_disk_change (hfd, insert);
1596 }
1597
add_async_request(struct hardfileprivdata * hfpd,uaecptr request,int type,uae_u32 data)1598 static int add_async_request (struct hardfileprivdata *hfpd, uaecptr request, int type, uae_u32 data)
1599 {
1600 int i;
1601
1602 i = 0;
1603 while (i < MAX_ASYNC_REQUESTS) {
1604 if (hfpd->d_request[i] == request) {
1605 hfpd->d_request_type[i] = type;
1606 hfpd->d_request_data[i] = data;
1607 hf_log (_T("old async request %p (%d) added\n"), request, type);
1608 return 0;
1609 }
1610 i++;
1611 }
1612 i = 0;
1613 while (i < MAX_ASYNC_REQUESTS) {
1614 if (hfpd->d_request[i] == 0) {
1615 hfpd->d_request[i] = request;
1616 hfpd->d_request_type[i] = type;
1617 hfpd->d_request_data[i] = data;
1618 hf_log (_T("async request %p (%d) added (total=%d)\n"), request, type, i);
1619 return 0;
1620 }
1621 i++;
1622 }
1623 hf_log (_T("async request overflow %p!\n"), request);
1624 return -1;
1625 }
1626
release_async_request(struct hardfileprivdata * hfpd,uaecptr request)1627 static int release_async_request (struct hardfileprivdata *hfpd, uaecptr request)
1628 {
1629 int i = 0;
1630
1631 while (i < MAX_ASYNC_REQUESTS) {
1632 if (hfpd->d_request[i] == request) {
1633 int type = hfpd->d_request_type[i];
1634 hfpd->d_request[i] = 0;
1635 hfpd->d_request_data[i] = 0;
1636 hfpd->d_request_type[i] = 0;
1637 hf_log (_T("async request %p removed\n"), request);
1638 return type;
1639 }
1640 i++;
1641 }
1642 hf_log (_T("tried to remove non-existing request %p\n"), request);
1643 return -1;
1644 }
1645
abort_async(struct hardfileprivdata * hfpd,uaecptr request,int errcode,int type)1646 static void abort_async (struct hardfileprivdata *hfpd, uaecptr request, int errcode, int type)
1647 {
1648 int i;
1649 hf_log (_T("aborting async request %p\n"), request);
1650 i = 0;
1651 while (i < MAX_ASYNC_REQUESTS) {
1652 if (hfpd->d_request[i] == request && hfpd->d_request_type[i] == ASYNC_REQUEST_TEMP) {
1653 /* ASYNC_REQUEST_TEMP = request is processing */
1654 sleep_millis (1);
1655 i = 0;
1656 continue;
1657 }
1658 i++;
1659 }
1660 i = release_async_request (hfpd, request);
1661 if (i >= 0)
1662 hf_log (_T("asyncronous request=%08X aborted, error=%d\n"), request, errcode);
1663 }
1664
1665 static void *hardfile_thread (void *devs);
start_thread(TrapContext * context,int unit)1666 static int start_thread (TrapContext *context, int unit)
1667 {
1668 struct hardfileprivdata *hfpd = &hardfpd[unit];
1669
1670 if (hfpd->thread_running)
1671 return 1;
1672 memset (hfpd, 0, sizeof (struct hardfileprivdata));
1673 hfpd->base = m68k_areg (regs, 6);
1674 init_comm_pipe (&hfpd->requests, 100, 1);
1675 uae_sem_init (&hfpd->sync_sem, 0, 0);
1676 uae_start_thread (_T("hardfile"), hardfile_thread, hfpd, &hfpd->tid);
1677 uae_sem_wait (&hfpd->sync_sem);
1678 return hfpd->thread_running;
1679 }
1680
mangleunit(int unit)1681 static int mangleunit (int unit)
1682 {
1683 if (unit <= 99)
1684 return unit;
1685 if (unit == 100)
1686 return 8;
1687 if (unit == 110)
1688 return 9;
1689 return -1;
1690 }
1691
hardfile_open(TrapContext * context)1692 static uae_u32 REGPARAM2 hardfile_open (TrapContext *context)
1693 {
1694 uaecptr ioreq = m68k_areg (regs, 1); /* IOReq */
1695 int unit = mangleunit (m68k_dreg (regs, 0));
1696 struct hardfileprivdata *hfpd = &hardfpd[unit];
1697 int err = IOERR_OPENFAIL;
1698 int size = get_word (ioreq + 0x12);
1699
1700 /* boot device port size == 0!? KS 1.x size = 12??? */
1701 if (size >= IOSTDREQ_SIZE || size == 0 || kickstart_version == 0xffff || kickstart_version < 39) {
1702 /* Check unit number */
1703 if (unit >= 0) {
1704 struct hardfiledata *hfd = get_hardfile_data (unit);
1705 if (hfd && (hfd->handle_valid || hfd->drive_empty) && start_thread (context, unit)) {
1706 put_word (hfpd->base + 32, get_word (hfpd->base + 32) + 1);
1707 put_long (ioreq + 24, unit); /* io_Unit */
1708 put_byte (ioreq + 31, 0); /* io_Error */
1709 put_byte (ioreq + 8, 7); /* ln_type = NT_REPLYMSG */
1710 hf_log (_T("hardfile_open, unit %d (%d), OK\n"), unit, m68k_dreg (regs, 0));
1711 return 0;
1712 }
1713 }
1714 if (unit < 1000 || is_hardfile (unit) == FILESYS_VIRTUAL || is_hardfile (unit) == FILESYS_CD)
1715 err = 50; /* HFERR_NoBoard */
1716 } else {
1717 err = IOERR_BADLENGTH;
1718 }
1719 hf_log (_T("hardfile_open, unit %d (%d), ERR=%d\n"), unit, m68k_dreg (regs, 0), err);
1720 put_long (ioreq + 20, (uae_u32)err);
1721 put_byte (ioreq + 31, (uae_u8)err);
1722 return (uae_u32)err;
1723 }
1724
hardfile_close(TrapContext * context)1725 static uae_u32 REGPARAM2 hardfile_close (TrapContext *context)
1726 {
1727 uaecptr request = m68k_areg (regs, 1); /* IOReq */
1728 int unit = mangleunit (get_long (request + 24));
1729 struct hardfileprivdata *hfpd = &hardfpd[unit];
1730
1731 if (!hfpd)
1732 return 0;
1733 put_word (hfpd->base + 32, get_word (hfpd->base + 32) - 1);
1734 if (get_word (hfpd->base + 32) == 0)
1735 write_comm_pipe_u32 (&hfpd->requests, 0, 1);
1736 return 0;
1737 }
1738
hardfile_expunge(TrapContext * context)1739 static uae_u32 REGPARAM2 hardfile_expunge (TrapContext *context)
1740 {
1741 return 0; /* Simply ignore this one... */
1742 }
1743
outofbounds(int cmd,uae_u64 offset,uae_u64 len,uae_u64 max)1744 static void outofbounds (int cmd, uae_u64 offset, uae_u64 len, uae_u64 max)
1745 {
1746 write_log (_T("UAEHF: cmd %d: out of bounds, %08X-%08X + %08X-%08X > %08X-%08X\n"), cmd,
1747 (uae_u32)(offset >> 32),(uae_u32)offset,(uae_u32)(len >> 32),(uae_u32)len,
1748 (uae_u32)(max >> 32),(uae_u32)max);
1749 }
unaligned(int cmd,uae_u64 offset,uae_u64 len,int blocksize)1750 static void unaligned (int cmd, uae_u64 offset, uae_u64 len, int blocksize)
1751 {
1752 write_log (_T("UAEHF: cmd %d: unaligned access, %08X-%08X, %08X-%08X, %08X\n"), cmd,
1753 (uae_u32)(offset >> 32),(uae_u32)offset,(uae_u32)(len >> 32),(uae_u32)len,
1754 blocksize);
1755 }
1756
hardfile_do_io(struct hardfiledata * hfd,struct hardfileprivdata * hfpd,uaecptr request)1757 static uae_u32 hardfile_do_io (struct hardfiledata *hfd, struct hardfileprivdata *hfpd, uaecptr request)
1758 {
1759 uae_u32 dataptr, offset, actual = 0, cmd;
1760 uae_u64 offset64;
1761 int unit = get_long (request + 24);
1762 uae_u32 error = 0, len;
1763 int async = 0;
1764 int bmask = hfd->ci.blocksize - 1;
1765
1766 cmd = get_word (request + 28); /* io_Command */
1767 dataptr = get_long (request + 40);
1768 switch (cmd)
1769 {
1770 case CMD_READ:
1771 if (nodisk (hfd))
1772 goto no_disk;
1773 offset = get_long (request + 44);
1774 len = get_long (request + 36); /* io_Length */
1775 if (offset & bmask) {
1776 unaligned (cmd, offset, len, hfd->ci.blocksize);
1777 goto bad_command;
1778 }
1779 if (len & bmask) {
1780 unaligned (cmd, offset, len, hfd->ci.blocksize);
1781 goto bad_len;
1782 }
1783 if (len + offset > hfd->virtsize) {
1784 outofbounds (cmd, offset, len, hfd->virtsize);
1785 goto bad_len;
1786 }
1787 actual = (uae_u32)cmd_read (hfd, dataptr, offset, len);
1788 break;
1789
1790 case TD_READ64:
1791 case NSCMD_TD_READ64:
1792 if (nodisk (hfd))
1793 goto no_disk;
1794 offset64 = get_long (request + 44) | ((uae_u64)get_long (request + 32) << 32);
1795 len = get_long (request + 36); /* io_Length */
1796 if (offset64 & bmask) {
1797 unaligned (cmd, offset64, len, hfd->ci.blocksize);
1798 goto bad_command;
1799 }
1800 if (len & bmask) {
1801 unaligned (cmd, offset64, len, hfd->ci.blocksize);
1802 goto bad_len;
1803 }
1804 if (len + offset64 > hfd->virtsize) {
1805 outofbounds (cmd, offset64, len, hfd->virtsize);
1806 goto bad_len;
1807 }
1808 actual = (uae_u32)cmd_read (hfd, dataptr, offset64, len);
1809 break;
1810
1811 case CMD_WRITE:
1812 case CMD_FORMAT: /* Format */
1813 if (nodisk (hfd))
1814 goto no_disk;
1815 if (hfd->ci.readonly || hfd->dangerous) {
1816 error = 28; /* write protect */
1817 } else {
1818 offset = get_long (request + 44);
1819 len = get_long (request + 36); /* io_Length */
1820 if (offset & bmask) {
1821 unaligned (cmd, offset, len, hfd->ci.blocksize);
1822 goto bad_command;
1823 }
1824 if (len & bmask) {
1825 unaligned (cmd, offset, len, hfd->ci.blocksize);
1826 goto bad_len;
1827 }
1828 if (len + offset > hfd->virtsize) {
1829 outofbounds (cmd, offset, len, hfd->virtsize);
1830 goto bad_len;
1831 }
1832 actual = (uae_u32)cmd_write (hfd, dataptr, offset, len);
1833 }
1834 break;
1835
1836 case TD_WRITE64:
1837 case TD_FORMAT64:
1838 case NSCMD_TD_WRITE64:
1839 case NSCMD_TD_FORMAT64:
1840 if (nodisk (hfd))
1841 goto no_disk;
1842 if (hfd->ci.readonly || hfd->dangerous) {
1843 error = 28; /* write protect */
1844 } else {
1845 offset64 = get_long (request + 44) | ((uae_u64)get_long (request + 32) << 32);
1846 len = get_long (request + 36); /* io_Length */
1847 if (offset64 & bmask) {
1848 unaligned (cmd, offset64, len, hfd->ci.blocksize);
1849 goto bad_command;
1850 }
1851 if (len & bmask) {
1852 unaligned (cmd, offset64, len, hfd->ci.blocksize);
1853 goto bad_len;
1854 }
1855 if (len + offset64 > hfd->virtsize) {
1856 outofbounds (cmd, offset64, len, hfd->virtsize);
1857 goto bad_len;
1858 }
1859 actual = (uae_u32)cmd_write (hfd, dataptr, offset64, len);
1860 }
1861 break;
1862
1863 case NSCMD_DEVICEQUERY:
1864 put_long (dataptr + 0, 0);
1865 put_long (dataptr + 4, 16); /* size */
1866 put_word (dataptr + 8, NSDEVTYPE_TRACKDISK);
1867 put_word (dataptr + 10, 0);
1868 put_long (dataptr + 12, nscmd_cmd);
1869 actual = 16;
1870 break;
1871
1872 case CMD_GETDRIVETYPE:
1873 actual = DRIVE_NEWSTYLE;
1874 break;
1875
1876 case CMD_GETNUMTRACKS:
1877 {
1878 int cyl, cylsec, head, tracksec;
1879 getchsx (hfd, &cyl, &cylsec, &head, &tracksec);
1880 actual = cyl * head;
1881 break;
1882 }
1883
1884 case CMD_GETGEOMETRY:
1885 {
1886 int cyl, cylsec, head, tracksec;
1887 uae_u64 size;
1888 getchsx (hfd, &cyl, &cylsec, &head, &tracksec);
1889 put_long (dataptr + 0, hfd->ci.blocksize);
1890 size = hfd->virtsize / hfd->ci.blocksize;
1891 if (size > 0x00ffffffff)
1892 size = 0xffffffff;
1893 put_long (dataptr + 4, (uae_u32)size);
1894 put_long (dataptr + 8, cyl);
1895 put_long (dataptr + 12, cylsec);
1896 put_long (dataptr + 16, head);
1897 put_long (dataptr + 20, tracksec);
1898 put_long (dataptr + 24, 0); /* bufmemtype */
1899 put_byte (dataptr + 28, 0); /* type = DG_DIRECT_ACCESS */
1900 put_byte (dataptr + 29, 0); /* flags */
1901 }
1902 break;
1903
1904 case CMD_PROTSTATUS:
1905 if (hfd->ci.readonly || hfd->dangerous)
1906 actual = -1;
1907 else
1908 actual = 0;
1909 break;
1910
1911 case CMD_CHANGESTATE:
1912 actual = hfd->drive_empty ? 1 :0;
1913 break;
1914
1915 /* Some commands that just do nothing and return zero */
1916 case CMD_UPDATE:
1917 case CMD_CLEAR:
1918 case CMD_MOTOR:
1919 case CMD_SEEK:
1920 case TD_SEEK64:
1921 case NSCMD_TD_SEEK64:
1922 break;
1923
1924 case CMD_REMOVE:
1925 hfpd->changeint = get_long (request + 40);
1926 break;
1927
1928 case CMD_CHANGENUM:
1929 actual = hfpd->changenum;
1930 break;
1931
1932 case CMD_ADDCHANGEINT:
1933 error = add_async_request (hfpd, request, ASYNC_REQUEST_CHANGEINT, get_long (request + 40));
1934 if (!error)
1935 async = 1;
1936 break;
1937 case CMD_REMCHANGEINT:
1938 release_async_request (hfpd, request);
1939 break;
1940
1941 case HD_SCSICMD: /* SCSI */
1942 if (!hfd->ci.sectors && !hfd->ci.surfaces && !hfd->ci.reserved) {
1943 error = handle_scsi (request, hfd);
1944 } else { /* we don't want users trashing their "partition" hardfiles with hdtoolbox */
1945 error = IOERR_NOCMD;
1946 write_log (_T("UAEHF: HD_SCSICMD tried on regular HDF, unit %d\n"), unit);
1947 }
1948 break;
1949
1950 case CD_EJECT:
1951 if (hfd->ci.sectors && hfd->ci.surfaces) {
1952 int len = get_long (request + 36);
1953 if (len) {
1954 if (hfd->drive_empty) {
1955 hardfile_media_change (hfd, NULL, true, false);
1956 } else {
1957 hardfile_media_change (hfd, NULL, false, false);
1958 }
1959 } else {
1960 if (hfd->drive_empty) {
1961 hardfile_media_change (hfd, NULL, true, false);
1962 }
1963 }
1964 } else {
1965 error = IOERR_NOCMD;
1966 }
1967 break;
1968
1969 bad_command:
1970 error = IOERR_BADADDRESS;
1971 break;
1972 bad_len:
1973 error = IOERR_BADLENGTH;
1974 break;
1975 no_disk:
1976 error = 29; /* no disk */
1977 break;
1978
1979 default:
1980 /* Command not understood. */
1981 error = IOERR_NOCMD;
1982 break;
1983 }
1984 put_long (request + 32, actual);
1985 put_byte (request + 31, error);
1986
1987 hf_log2 (_T("hf: unit=%d, request=%p, cmd=%d offset=%u len=%d, actual=%d error%=%d\n"), unit, request,
1988 get_word (request + 28), get_long (request + 44), get_long (request + 36), actual, error);
1989
1990 return async;
1991 }
1992
hardfile_abortio(TrapContext * context)1993 static uae_u32 REGPARAM2 hardfile_abortio (TrapContext *context)
1994 {
1995 uae_u32 request = m68k_areg (regs, 1);
1996 int unit = mangleunit (get_long (request + 24));
1997 struct hardfiledata *hfd = get_hardfile_data (unit);
1998 struct hardfileprivdata *hfpd = &hardfpd[unit];
1999
2000 hf_log2 (_T("uaehf.device abortio "));
2001 start_thread (context, unit);
2002 if (!hfd || !hfpd || !hfpd->thread_running) {
2003 put_byte (request + 31, 32);
2004 hf_log2 (_T("error\n"));
2005 return get_byte (request + 31);
2006 }
2007 put_byte (request + 31, -2);
2008 hf_log2 (_T("unit=%d, request=%08X\n"), unit, request);
2009 abort_async (hfpd, request, -2, 0);
2010 return 0;
2011 }
2012
hardfile_can_quick(uae_u32 command)2013 static int hardfile_can_quick (uae_u32 command)
2014 {
2015 switch (command)
2016 {
2017 case CMD_REMCHANGEINT:
2018 return -1;
2019 case CMD_RESET:
2020 case CMD_STOP:
2021 case CMD_START:
2022 case CMD_CHANGESTATE:
2023 case CMD_PROTSTATUS:
2024 case CMD_MOTOR:
2025 case CMD_GETDRIVETYPE:
2026 case CMD_GETGEOMETRY:
2027 case CMD_GETNUMTRACKS:
2028 case NSCMD_DEVICEQUERY:
2029 return 1;
2030 }
2031 return 0;
2032 }
2033
hardfile_canquick(struct hardfiledata * hfd,uaecptr request)2034 static int hardfile_canquick (struct hardfiledata *hfd, uaecptr request)
2035 {
2036 uae_u32 command = get_word (request + 28);
2037 return hardfile_can_quick (command);
2038 }
2039
hardfile_beginio(TrapContext * context)2040 static uae_u32 REGPARAM2 hardfile_beginio (TrapContext *context)
2041 {
2042 uae_u32 request = m68k_areg (regs, 1);
2043 uae_u8 flags = get_byte (request + 30);
2044 int cmd = get_word (request + 28);
2045 int unit = mangleunit (get_long (request + 24));
2046 struct hardfiledata *hfd = get_hardfile_data (unit);
2047 struct hardfileprivdata *hfpd = &hardfpd[unit];
2048 int canquick;
2049
2050 put_byte (request + 8, NT_MESSAGE);
2051 start_thread (context, unit);
2052 if (!hfd || !hfpd || !hfpd->thread_running) {
2053 put_byte (request + 31, 32);
2054 return get_byte (request + 31);
2055 }
2056 put_byte (request + 31, 0);
2057 canquick = hardfile_canquick (hfd, request);
2058 if (((flags & 1) && canquick) || (canquick < 0)) {
2059 hf_log (_T("hf quickio unit=%d request=%p cmd=%d\n"), unit, request, cmd);
2060 if (hardfile_do_io (hfd, hfpd, request))
2061 hf_log2 (_T("uaehf.device cmd %d bug with IO_QUICK\n"), cmd);
2062 if (!(flags & 1))
2063 uae_ReplyMsg (request);
2064 return get_byte (request + 31);
2065 } else {
2066 hf_log2 (_T("hf asyncio unit=%d request=%p cmd=%d\n"), unit, request, cmd);
2067 add_async_request (hfpd, request, ASYNC_REQUEST_TEMP, 0);
2068 put_byte (request + 30, get_byte (request + 30) & ~1);
2069 write_comm_pipe_u32 (&hfpd->requests, request, 1);
2070 return 0;
2071 }
2072 }
2073
hardfile_thread(void * devs)2074 static void *hardfile_thread (void *devs)
2075 {
2076 struct hardfileprivdata *hfpd = (struct hardfileprivdata*)devs;
2077
2078 uae_set_thread_priority (2);
2079 hfpd->thread_running = 1;
2080 uae_sem_post (&hfpd->sync_sem);
2081 for (;;) {
2082 uaecptr request = (uaecptr)read_comm_pipe_u32_blocking (&hfpd->requests);
2083 uae_sem_wait (&change_sem);
2084 if (!request) {
2085 hfpd->thread_running = 0;
2086 uae_sem_post (&hfpd->sync_sem);
2087 uae_sem_post (&change_sem);
2088 return 0;
2089 } else if (hardfile_do_io (get_hardfile_data (hfpd - &hardfpd[0]), hfpd, request) == 0) {
2090 put_byte (request + 30, get_byte (request + 30) & ~1);
2091 release_async_request (hfpd, request);
2092 uae_ReplyMsg (request);
2093 } else {
2094 hf_log2 (_T("async request %08X\n"), request);
2095 }
2096 uae_sem_post (&change_sem);
2097 }
2098 }
2099
hardfile_reset(void)2100 void hardfile_reset (void)
2101 {
2102 int i, j;
2103 struct hardfileprivdata *hfpd;
2104
2105 for (i = 0; i < MAX_FILESYSTEM_UNITS; i++) {
2106 hfpd = &hardfpd[i];
2107 if (hfpd->base && valid_address (hfpd->base, 36) && get_word (hfpd->base + 32) > 0) {
2108 for (j = 0; j < MAX_ASYNC_REQUESTS; j++) {
2109 uaecptr request;
2110 if ((request = hfpd->d_request[i]))
2111 abort_async (hfpd, request, 0, 0);
2112 }
2113 }
2114 memset (hfpd, 0, sizeof (struct hardfileprivdata));
2115 }
2116 }
2117
hardfile_install(void)2118 void hardfile_install (void)
2119 {
2120 uae_u32 functable, datatable;
2121 uae_u32 initcode, openfunc, closefunc, expungefunc;
2122 uae_u32 beginiofunc, abortiofunc;
2123
2124 uae_sem_init (&change_sem, 0, 1);
2125
2126 ROM_hardfile_resname = ds (_T("uaehf.device"));
2127 ROM_hardfile_resid = ds (_T("UAE hardfile.device 0.3"));
2128
2129 nscmd_cmd = here ();
2130 dw (NSCMD_DEVICEQUERY);
2131 dw (CMD_RESET);
2132 dw (CMD_READ);
2133 dw (CMD_WRITE);
2134 dw (CMD_UPDATE);
2135 dw (CMD_CLEAR);
2136 dw (CMD_START);
2137 dw (CMD_STOP);
2138 dw (CMD_FLUSH);
2139 dw (CMD_MOTOR);
2140 dw (CMD_SEEK);
2141 dw (CMD_FORMAT);
2142 dw (CMD_REMOVE);
2143 dw (CMD_CHANGENUM);
2144 dw (CMD_CHANGESTATE);
2145 dw (CMD_PROTSTATUS);
2146 dw (CMD_GETDRIVETYPE);
2147 dw (CMD_GETGEOMETRY);
2148 dw (CMD_ADDCHANGEINT);
2149 dw (CMD_REMCHANGEINT);
2150 dw (HD_SCSICMD);
2151 dw (NSCMD_TD_READ64);
2152 dw (NSCMD_TD_WRITE64);
2153 dw (NSCMD_TD_SEEK64);
2154 dw (NSCMD_TD_FORMAT64);
2155 dw (0);
2156
2157 /* initcode */
2158 #if 0
2159 initcode = here ();
2160 calltrap (deftrap (hardfile_init)); dw (RTS);
2161 #else
2162 initcode = filesys_initcode;
2163 #endif
2164 /* Open */
2165 openfunc = here ();
2166 calltrap (deftrap (hardfile_open)); dw (RTS);
2167
2168 /* Close */
2169 closefunc = here ();
2170 calltrap (deftrap (hardfile_close)); dw (RTS);
2171
2172 /* Expunge */
2173 expungefunc = here ();
2174 calltrap (deftrap (hardfile_expunge)); dw (RTS);
2175
2176 /* BeginIO */
2177 beginiofunc = here ();
2178 calltrap (deftrap (hardfile_beginio));
2179 dw (RTS);
2180
2181 /* AbortIO */
2182 abortiofunc = here ();
2183 calltrap (deftrap (hardfile_abortio)); dw (RTS);
2184
2185 /* FuncTable */
2186 functable = here ();
2187 dl (openfunc); /* Open */
2188 dl (closefunc); /* Close */
2189 dl (expungefunc); /* Expunge */
2190 dl (EXPANSION_nullfunc); /* Null */
2191 dl (beginiofunc); /* BeginIO */
2192 dl (abortiofunc); /* AbortIO */
2193 dl (0xFFFFFFFFul); /* end of table */
2194
2195 /* DataTable */
2196 datatable = here ();
2197 dw (0xE000); /* INITBYTE */
2198 dw (0x0008); /* LN_TYPE */
2199 dw (0x0300); /* NT_DEVICE */
2200 dw (0xC000); /* INITLONG */
2201 dw (0x000A); /* LN_NAME */
2202 dl (ROM_hardfile_resname);
2203 dw (0xE000); /* INITBYTE */
2204 dw (0x000E); /* LIB_FLAGS */
2205 dw (0x0600); /* LIBF_SUMUSED | LIBF_CHANGED */
2206 dw (0xD000); /* INITWORD */
2207 dw (0x0014); /* LIB_VERSION */
2208 dw (0x0004); /* 0.4 */
2209 dw (0xD000);
2210 dw (0x0016); /* LIB_REVISION */
2211 dw (0x0000);
2212 dw (0xC000);
2213 dw (0x0018); /* LIB_IDSTRING */
2214 dl (ROM_hardfile_resid);
2215 dw (0x0000); /* end of table */
2216
2217 ROM_hardfile_init = here ();
2218 dl (0x00000100); /* ??? */
2219 dl (functable);
2220 dl (datatable);
2221 dl (initcode);
2222 }
2223