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