]> git.sesse.net Git - pistorm/blob - platforms/amiga/piscsi/piscsi.c
Fix direct SCSI reads/writes
[pistorm] / platforms / amiga / piscsi / piscsi.c
1 #include <stdio.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <fcntl.h>
6 #include <unistd.h>
7 #include <endian.h>
8 #include "../hunk-reloc.h"
9 #include "piscsi.h"
10 #include "piscsi-enums.h"
11 #include "../../../config_file/config_file.h"
12 #include "../../../gpio/ps_protocol.h"
13
14 #define BE(val) be32toh(val)
15 #define BE16(val) be16toh(val)
16
17 // Uncomment the line below to enable debug output
18 //#define PISCSI_DEBUG
19
20 #ifdef PISCSI_DEBUG
21 #define DEBUG printf
22 //#define DEBUG_TRIVIAL printf
23 #define DEBUG_TRVIAL(...)
24
25 extern void stop_cpu_emulation(uint8_t disasm_cur);
26
27 static const char *op_type_names[4] = {
28     "BYTE",
29     "WORD",
30     "LONGWORD",
31     "MEM",
32 };
33 #else
34 #define DEBUG(...)
35 #define DEBUG_TRIVIAL(...)
36 #define stop_cpu_emulation(...)
37 #endif
38
39 #ifdef FAKESTORM
40 #define lseek64 lseek
41 #endif
42
43 extern struct emulator_config *cfg;
44
45 struct piscsi_dev devs[8];
46 struct piscsi_fs filesystems[NUM_FILESYSTEMS];
47
48 uint8_t piscsi_num_fs = 0;
49
50 uint8_t piscsi_cur_drive = 0;
51 uint32_t piscsi_u32[4];
52 uint32_t piscsi_dbg[8];
53 uint32_t piscsi_rom_size = 0;
54 uint8_t *piscsi_rom_ptr;
55
56 uint32_t rom_partitions[128];
57 uint32_t rom_partition_prio[128];
58 uint32_t rom_partition_dostype[128];
59 uint32_t rom_cur_partition = 0, rom_cur_fs = 0;
60
61 extern unsigned char ac_piscsi_rom[];
62
63 //static const char *partition_marker = "PART";
64
65 struct hunk_info piscsi_hinfo;
66 struct hunk_reloc piscsi_hreloc[256];
67
68 void piscsi_init() {
69     for (int i = 0; i < 8; i++) {
70         devs[i].fd = -1;
71         devs[i].lba = 0;
72         devs[i].c = devs[i].h = devs[i].s = 0;
73     }
74
75     FILE *in = fopen("./platforms/amiga/piscsi/piscsi.rom", "rb");
76     if (in == NULL) {
77         printf("[PISCSI] Could not open PISCSI Boot ROM file for reading!\n");
78         // Zero out the boot ROM offset from the autoconfig ROM.
79         ac_piscsi_rom[20] = 0;
80         ac_piscsi_rom[21] = 0;
81         ac_piscsi_rom[22] = 0;
82         ac_piscsi_rom[23] = 0;
83         return;
84     }
85     fseek(in, 0, SEEK_END);
86     piscsi_rom_size = ftell(in);
87     fseek(in, 0, SEEK_SET);
88     piscsi_rom_ptr = malloc(piscsi_rom_size);
89     fread(piscsi_rom_ptr, piscsi_rom_size, 1, in);
90
91     fseek(in, PISCSI_DRIVER_OFFSET, SEEK_SET);
92     process_hunks(in, &piscsi_hinfo, piscsi_hreloc, PISCSI_DRIVER_OFFSET);
93
94     fclose(in);
95     printf("[PISCSI] Loaded Boot ROM.\n");
96 }
97
98 void piscsi_find_partitions(struct piscsi_dev *d) {
99     int fd = d->fd;
100     int cur_partition = 0;
101     uint8_t tmp;
102
103     for (int i = 0; i < 16; i++) {
104         if (d->pb[i]) {
105             free(d->pb[i]);
106             d->pb[i] = NULL;
107         }
108     }
109
110     if (!d->rdb || d->rdb->rdb_PartitionList == 0) {
111         DEBUG("[PISCSI] No partitions on disk.\n");
112         return;
113     }
114
115     char *block = malloc(512);
116
117     lseek(fd, BE(d->rdb->rdb_PartitionList) * 512, SEEK_SET);
118 next_partition:;
119     read(fd, block, 512);
120
121     uint32_t first = be32toh(*((uint32_t *)&block[0]));
122     if (first != PART_IDENTIFIER) {
123         DEBUG("Entry at block %d is not a valid partition. Aborting.\n", BE(d->rdb->rdb_PartitionList));
124         return;
125     }
126
127     struct PartitionBlock *pb = (struct PartitionBlock *)block;
128     tmp = pb->pb_DriveName[0];
129     pb->pb_DriveName[tmp + 1] = 0x00;
130     DEBUG("[PISCSI] Partition %d: %s\n", cur_partition, pb->pb_DriveName + 1);
131     DEBUG("Checksum: %.8X HostID: %d\n", BE(pb->pb_ChkSum), BE(pb->pb_HostID));
132     DEBUG("Flags: %d (%.8X) Devflags: %d (%.8X)\n", BE(pb->pb_Flags), BE(pb->pb_Flags), BE(pb->pb_DevFlags), BE(pb->pb_DevFlags));
133     d->pb[cur_partition] = pb;
134
135     if (d->pb[cur_partition]->pb_Next != 0xFFFFFFFF) {
136         uint64_t next = be32toh(pb->pb_Next);
137         block = malloc(512);
138         lseek64(fd, next * 512, SEEK_SET);
139         cur_partition++;
140         DEBUG("[PISCSI] Next partition at block %d.\n", be32toh(pb->pb_Next));
141         goto next_partition;
142     }
143     DEBUG("[PISCSI] No more partitions on disk.\n");
144     d->num_partitions = cur_partition + 1;
145     d->fshd_offs = lseek64(fd, 0, SEEK_CUR);
146
147     return;
148 }
149
150 int piscsi_parse_rdb(struct piscsi_dev *d) {
151     int fd = d->fd;
152     int i = 0;
153     uint8_t *block = malloc(512);
154
155     lseek(fd, 0, SEEK_SET);
156     for (i = 0; i < RDB_BLOCK_LIMIT; i++) {
157         read(fd, block, 512);
158         uint32_t first = be32toh(*((uint32_t *)&block[0]));
159         if (first == RDB_IDENTIFIER)
160             goto rdb_found;
161     }
162     goto no_rdb_found;
163 rdb_found:;
164     struct RigidDiskBlock *rdb = (struct RigidDiskBlock *)block;
165     DEBUG("[PISCSI] RDB found at block %d.\n", i);
166     d->c = be32toh(rdb->rdb_Cylinders);
167     d->h = be32toh(rdb->rdb_Heads);
168     d->s = be32toh(rdb->rdb_Sectors);
169     d->num_partitions = 0;
170     DEBUG("[PISCSI] RDB - first partition at block %d.\n", be32toh(rdb->rdb_PartitionList));
171     if (d->rdb)
172         free(d->rdb);
173     d->rdb = rdb;
174     sprintf(d->rdb->rdb_DriveInitName, "pi-scsi.device");
175     return 0;
176
177 no_rdb_found:;
178     if (block)
179         free(block);
180
181     return -1;
182 }
183
184 void piscsi_refresh_drives() {
185     piscsi_num_fs = 0;
186
187     for (int i = 0; i < NUM_FILESYSTEMS; i++) {
188         if (filesystems[i].binary_data) {
189             free(filesystems[i].binary_data);
190             filesystems[i].binary_data = NULL;
191         }
192         if (filesystems[i].fhb) {
193             free(filesystems[i].fhb);
194             filesystems[i].fhb = NULL;
195         }
196         filesystems[i].h_info.current_hunk = 0;
197         filesystems[i].h_info.reloc_hunks = 0;
198         filesystems[i].FS_ID = 0;
199         filesystems[i].handler = 0;
200     }
201
202     rom_cur_fs = 0;
203
204     for (int i = 0; i < NUM_UNITS; i++) {
205         if (devs[i].fd != -1) {
206             piscsi_parse_rdb(&devs[i]);
207             piscsi_find_partitions(&devs[i]);
208             piscsi_find_filesystems(&devs[i]);
209         }
210     }
211 }
212
213 void piscsi_find_filesystems(struct piscsi_dev *d) {
214     if (!d->num_partitions)
215         return;
216     
217     uint8_t fs_found = 0;
218     
219     uint8_t *fhb_block = malloc(512);
220
221     lseek64(d->fd, d->fshd_offs, SEEK_SET);
222
223     struct FileSysHeaderBlock *fhb = (struct FileSysHeaderBlock *)fhb_block;
224     read(d->fd, fhb_block, 512);
225     
226     while (BE(fhb->fhb_ID) == FS_IDENTIFIER) {
227         char *dosID = (char *)&fhb->fhb_DosType;
228 #ifdef PISCSI_DEBUG
229         uint16_t *fsVer = (uint16_t *)&fhb->fhb_Version;
230
231         DEBUG("[FSHD] FSHD Block found.\n");
232         DEBUG("[FSHD] HostID: %d Next: %d Size: %d\n", BE(fhb->fhb_HostID), BE(fhb->fhb_Next), BE(fhb->fhb_SummedLongs));
233         DEBUG("[FSHD] Flags: %.8X DOSType: %c%c%c/%d\n", BE(fhb->fhb_Flags), dosID[0], dosID[1], dosID[2], dosID[3]);
234         DEBUG("[FSHD] Version: %d.%d\n", BE16(fsVer[0]), BE16(fsVer[1]));
235         DEBUG("[FSHD] Patchflags: %d Type: %d\n", BE(fhb->fhb_PatchFlags), BE(fhb->fhb_Type));
236         DEBUG("[FSHD] Task: %d Lock: %d\n", BE(fhb->fhb_Task), BE(fhb->fhb_Lock));
237         DEBUG("[FSHD] Handler: %d StackSize: %d\n", BE(fhb->fhb_Handler), BE(fhb->fhb_StackSize));
238         DEBUG("[FSHD] Prio: %d Startup: %d\n", BE(fhb->fhb_Priority), BE(fhb->fhb_Startup));
239         DEBUG("[FSHD] SegListBlocks: %d GlobalVec: %d\n", BE(fhb->fhb_Priority), BE(fhb->fhb_Startup));
240         DEBUG("[FSHD] FileSysName: %s\n", fhb->fhb_FileSysName + 1);
241 #endif
242
243         for (int i = 0; i < NUM_FILESYSTEMS; i++) {
244             if (filesystems[i].FS_ID == fhb->fhb_DosType) {
245                 DEBUG("[FSHD] File system %c%c%c/%d already loaded. Skipping.\n", dosID[0], dosID[1], dosID[2], dosID[3]);
246                 if (BE(fhb->fhb_Next) == 0xFFFFFFFF)
247                     goto fs_done;
248                 
249                 goto skip_fs_load_lseg;
250             }
251         }
252
253         if (load_lseg(d->fd, &filesystems[piscsi_num_fs].binary_data, &filesystems[piscsi_num_fs].h_info, filesystems[piscsi_num_fs].relocs) != -1) {
254             filesystems[piscsi_num_fs].FS_ID = fhb->fhb_DosType;
255             filesystems[piscsi_num_fs].fhb = fhb;
256             printf("[FSHD] Loaded and set up file system %d: %c%c%c/%d\n", piscsi_num_fs + 1, dosID[0], dosID[1], dosID[2], dosID[3]);
257             piscsi_num_fs++;
258         }
259
260 skip_fs_load_lseg:;
261         fs_found++;
262         lseek64(d->fd, BE(fhb->fhb_Next) * 512, SEEK_SET);
263         fhb_block = malloc(512);
264         fhb = (struct FileSysHeaderBlock *)fhb_block;
265         read(d->fd, fhb_block, 512);
266     }
267
268     if (!fs_found) {
269         DEBUG("[!!!FSHD] No file systems found on hard drive!\n");
270     }
271
272 fs_done:;
273     if (fhb_block)
274         free(fhb_block);
275 }
276
277 void piscsi_map_drive(char *filename, uint8_t index) {
278     if (index > 7) {
279         printf("[PISCSI] Drive index %d out of range.\nUnable to map file %s to drive.\n", index, filename);
280         return;
281     }
282
283     int32_t tmp_fd = open(filename, O_RDWR);
284     if (tmp_fd == -1) {
285         printf("[PISCSI] Failed to open file %s, could not map drive %d.\n", filename, index);
286         return;
287     }
288
289     struct piscsi_dev *d = &devs[index];
290
291     uint64_t file_size = lseek(tmp_fd, 0, SEEK_END);
292     d->fs = file_size;
293     d->fd = tmp_fd;
294     lseek(tmp_fd, 0, SEEK_SET);
295     printf("[PISCSI] Map %d: [%s] - %llu bytes.\n", index, filename, file_size);
296
297     if (piscsi_parse_rdb(d) == -1) {
298         DEBUG("[PISCSI] No RDB found on disk, making up some CHS values.\n");
299         d->h = 16;
300         d->s = 63;
301         d->c = (file_size / 512) / (d->s * d->h);
302     }
303     printf("[PISCSI] CHS: %d %d %d\n", d->c, d->h, d->s);
304
305     piscsi_find_partitions(d);
306     piscsi_find_filesystems(d);
307 }
308
309 void piscsi_unmap_drive(uint8_t index) {
310     if (devs[index].fd != -1) {
311         DEBUG("[PISCSI] Unmapped drive %d.\n", index);
312         close (devs[index].fd);
313         devs[index].fd = -1;
314     }
315 }
316
317 char *io_cmd_name(int index) {
318     switch (index) {
319         case CMD_INVALID: return "INVALID";
320         case CMD_RESET: return "RESET";
321         case CMD_READ: return "READ";
322         case CMD_WRITE: return "WRITE";
323         case CMD_UPDATE: return "UPDATE";
324         case CMD_CLEAR: return "CLEAR";
325         case CMD_STOP: return "STOP";
326         case CMD_START: return "START";
327         case CMD_FLUSH: return "FLUSH";
328         case TD_MOTOR: return "TD_MOTOR";
329         case TD_SEEK: return "SEEK";
330         case TD_FORMAT: return "FORMAT";
331         case TD_REMOVE: return "REMOVE";
332         case TD_CHANGENUM: return "CHANGENUM";
333         case TD_CHANGESTATE: return "CHANGESTATE";
334         case TD_PROTSTATUS: return "PROTSTATUS";
335         case TD_RAWREAD: return "RAWREAD";
336         case TD_RAWWRITE: return "RAWWRITE";
337         case TD_GETDRIVETYPE: return "GETDRIVETYPE";
338         case TD_GETNUMTRACKS: return "GETNUMTRACKS";
339         case TD_ADDCHANGEINT: return "ADDCHANGEINT";
340         case TD_REMCHANGEINT: return "REMCHANGEINT";
341         case TD_GETGEOMETRY: return "GETGEOMETRY";
342         case TD_EJECT: return "EJECT";
343         case TD_LASTCOMM: return "LASTCOMM/READ64";
344         case TD_WRITE64: return "WRITE64";
345         case HD_SCSICMD: return "HD_SCSICMD";
346         case NSCMD_DEVICEQUERY: return "NSCMD_DEVICEQUERY";
347         case NSCMD_TD_READ64: return "NSCMD_TD_READ64";
348         case NSCMD_TD_WRITE64: return "NSCMD_TD_WRITE64";
349         case NSCMD_TD_FORMAT64: return "NSCMD_TD_FORMAT64";
350
351         default:
352             return "[!!!PISCSI] Unhandled IO command";
353     }
354 }
355
356 #define GETSCSINAME(a) case a: return ""#a"";
357 #define SCSIUNHANDLED(a) return "[!!!PISCSI] Unhandled SCSI command "#a"";
358
359 char *scsi_cmd_name(int index) {
360     switch(index) {
361         GETSCSINAME(SCSICMD_TEST_UNIT_READY);
362         GETSCSINAME(SCSICMD_INQUIRY);
363         GETSCSINAME(SCSICMD_READ_6);
364         GETSCSINAME(SCSICMD_WRITE_6);
365         GETSCSINAME(SCSICMD_READ_10);
366         GETSCSINAME(SCSICMD_WRITE_10);
367         GETSCSINAME(SCSICMD_READ_CAPACITY_10);
368         GETSCSINAME(SCSICMD_MODE_SENSE_6);
369         GETSCSINAME(SCSICMD_READ_DEFECT_DATA_10);
370         default:
371             return "[!!!PISCSI] Unhandled SCSI command";
372     }
373 }
374
375 void print_piscsi_debug_message(int index) {
376     int32_t r = 0;
377
378     switch (index) {
379         case DBG_INIT:
380             DEBUG("[PISCSI] Initializing devices.\n");
381             break;
382         case DBG_OPENDEV:
383             if (piscsi_dbg[0] != 255) {
384                 DEBUG("[PISCSI] Opening device %d (%d). Flags: %d (%.2X)\n", piscsi_dbg[0], piscsi_dbg[2], piscsi_dbg[1], piscsi_dbg[1]);
385             }
386             break;
387         case DBG_CLEANUP:
388             DEBUG("[PISCSI] Cleaning up.\n");
389             break;
390         case DBG_CHS:
391             DEBUG("[PISCSI] C/H/S: %d / %d / %d\n", piscsi_dbg[0], piscsi_dbg[1], piscsi_dbg[2]);
392             break;
393         case DBG_BEGINIO:
394             DEBUG("[PISCSI] BeginIO: io_Command: %d (%s) - io_Flags = %d - quick: %d\n", piscsi_dbg[0], io_cmd_name(piscsi_dbg[0]), piscsi_dbg[1], piscsi_dbg[2]);
395             break;
396         case DBG_ABORTIO:
397             DEBUG("[PISCSI] AbortIO!\n");
398             break;
399         case DBG_SCSICMD:
400             DEBUG("[PISCSI] SCSI Command %d (%s)\n", piscsi_dbg[1], scsi_cmd_name(piscsi_dbg[1]));
401             DEBUG("Len: %d - %.2X %.2X %.2X - Command Length: %d\n", piscsi_dbg[0], piscsi_dbg[1], piscsi_dbg[2], piscsi_dbg[3], piscsi_dbg[4]);
402             break;
403         case DBG_SCSI_UNKNOWN_MODESENSE:
404             DEBUG("[!!!PISCSI] SCSI: Unknown modesense %.4X\n", piscsi_dbg[0]);
405             break;
406         case DBG_SCSI_UNKNOWN_COMMAND:
407             DEBUG("[!!!PISCSI] SCSI: Unknown command %.4X\n", piscsi_dbg[0]);
408             break;
409         case DBG_SCSIERR:
410             DEBUG("[!!!PISCSI] SCSI: An error occured: %.4X\n", piscsi_dbg[0]);
411             break;
412         case DBG_IOCMD:
413             DEBUG_TRIVIAL("[PISCSI] IO Command %d (%s)\n", piscsi_dbg[0], io_cmd_name(piscsi_dbg[0]));
414             break;
415         case DBG_IOCMD_UNHANDLED:
416             DEBUG("[!!!PISCSI] WARN: IO command %.4X (%s) is unhandled by driver.\n", piscsi_dbg[0], io_cmd_name(piscsi_dbg[0]));
417             break;
418         case DBG_SCSI_FORMATDEVICE:
419             DEBUG("[PISCSI] Get SCSI FormatDevice MODE SENSE.\n");
420             break;
421         case DBG_SCSI_RDG:
422             DEBUG("[PISCSI] Get SCSI RDG MODE SENSE.\n");
423             break;
424         case DBG_SCSICMD_RW10:
425 #ifdef PISCSI_DEBUG
426             r = get_mapped_item_by_address(cfg, piscsi_dbg[0]);
427             struct SCSICmd_RW10 *rwdat = NULL;
428             char data[10];
429             if (r != -1) {
430                 uint32_t addr = piscsi_dbg[0] - cfg->map_offset[r];
431                 rwdat = (struct SCSICmd_RW10 *)(&cfg->map_data[r][addr]);
432             }
433             else {
434                 DEBUG_TRIVIAL("[RW10] scsiData: %.8X\n", piscsi_dbg[0]);
435                 for (int i = 0; i < 10; i++) {
436                     data[i] = read8(piscsi_dbg[0] + i);
437                 }
438                 rwdat = data;
439             }
440             if (rwdat) {
441                 DEBUG_TRIVIAL("[RW10] CMD: %.2X\n", rwdat->opcode);
442                 DEBUG_TRIVIAL("[RW10] RDP: %.2X\n", rwdat->rdprotect_flags);
443                 DEBUG_TRIVIAL("[RW10] Block: %d (%d)\n", rwdat->block, BE(rwdat->block));
444                 DEBUG_TRIVIAL("[RW10] Res_Group: %.2X\n", rwdat->res_groupnum);
445                 DEBUG_TRIVIAL("[RW10] Len: %d (%d)\n", rwdat->len, BE16(rwdat->len));
446             }
447 #endif
448             break;
449         case DBG_SCSI_DEBUG_MODESENSE_6:
450             DEBUG_TRIVIAL("[PISCSI] SCSI ModeSense debug. Data: %.8X\n", piscsi_dbg[0]);
451             r = get_mapped_item_by_address(cfg, piscsi_dbg[0]);
452             if (r != -1) {
453 #ifdef PISCSI_DEBUG
454                 uint32_t addr = piscsi_dbg[0] - cfg->map_offset[r];
455                 struct SCSICmd_ModeSense6 *sense = (struct SCSICmd_ModeSense6 *)(&cfg->map_data[r][addr]);
456                 DEBUG_TRIVIAL("[SenseData] CMD: %.2X\n", sense->opcode);
457                 DEBUG_TRIVIAL("[SenseData] DBD: %d\n", sense->reserved_dbd & 0x04);
458                 DEBUG_TRIVIAL("[SenseData] PC: %d\n", (sense->pc_pagecode & 0xC0 >> 6));
459                 DEBUG_TRIVIAL("[SenseData] PageCodes: %.2X %.2X\n", (sense->pc_pagecode & 0x3F), sense->subpage_code);
460                 DEBUG_TRIVIAL("[SenseData] AllocLen: %d\n", sense->alloc_len);
461                 DEBUG_TRIVIAL("[SenseData] Control: %.2X (%d)\n", sense->control, sense->control);
462 #endif
463             }
464             else {
465                 DEBUG("[!!!PISCSI] ModeSense data not immediately available.\n");
466             }
467             break;
468         default:
469             DEBUG("[!!!PISCSI] No debug message available for index %d.\n", index);
470             break;
471     }
472 }
473
474 #define DEBUGME_SIMPLE(i, s) case i: DEBUG(s); break;
475
476 void piscsi_debugme(uint32_t index) {
477     switch (index) {
478         DEBUGME_SIMPLE(1, "[PISCSI-DEBUGME] Arrived at DiagEntry.\n");
479         DEBUGME_SIMPLE(3, "[PISCSI-DEBUGME] Init: Interrupt disable.\n");
480         DEBUGME_SIMPLE(4, "[PISCSI-DEBUGME] Init: Copy/reloc driver.\n");
481         DEBUGME_SIMPLE(5, "[PISCSI-DEBUGME] Init: InitResident.\n");
482         DEBUGME_SIMPLE(7, "[PISCSI-DEBUGME] Init: Begin partition loop.\n");
483         DEBUGME_SIMPLE(8, "[PISCSI-DEBUGME] Init: Partition loop done. Cleaning up and returning to Exec.\n");
484         DEBUGME_SIMPLE(9, "[PISCSI-DEBUGME] Init: Load file systems.\n");
485         DEBUGME_SIMPLE(10, "[PISCSI-DEBUGME] Init: AllocMem for resident.\n");
486         DEBUGME_SIMPLE(11, "[PISCSI-DEBUGME] Init: Checking if resident is loaded.\n");
487         DEBUGME_SIMPLE(22, "[PISCSI-DEBUGME] Arrived at BootEntry.\n");
488         DEBUGME_SIMPLE(30, "[PISCSI-DEBUGME] LoadFileSystems: Opening FileSystem.resource.\n");
489         DEBUGME_SIMPLE(33, "[PISCSI-DEBUGME] FileSystem.resource not available, creating.\n");
490         case 31:
491             DEBUG("[PISCSI-DEBUGME] OpenResource result: %d\n", piscsi_u32[0]);
492             break;
493         case 32:
494             DEBUG("AAAAHH!\n");
495             break;
496         default:
497             DEBUG("[!!!PISCSI-DEBUGME] No debugme message for index %d!\n", index);
498             break;
499     }
500
501     if (index == 8) {
502         stop_cpu_emulation(1);
503     }
504 }
505
506 void handle_piscsi_write(uint32_t addr, uint32_t val, uint8_t type) {
507     int32_t r;
508 #ifndef PISCSI_DEBUG
509     if (type) {}
510 #endif
511
512     struct piscsi_dev *d = &devs[piscsi_cur_drive];
513
514     uint16_t cmd = (addr & 0xFFFF);
515
516     switch (cmd) {
517         case PISCSI_CMD_READ64:
518         case PISCSI_CMD_READ:
519             d = &devs[val];
520             if (d->fd == -1) {
521                 DEBUG("[!!!PISCSI] BUG: Attempted read from unmapped drive %d.\n", val);
522                 break;
523             }
524
525             if (cmd == PISCSI_CMD_READ) {
526                 DEBUG("[PISCSI-%d] %d byte READ from block %d to address %.8X\n", val, piscsi_u32[1], piscsi_u32[0], piscsi_u32[2]);
527                 d->lba = piscsi_u32[0];
528                 lseek(d->fd, (piscsi_u32[0] * 512), SEEK_SET);
529             }
530             else {
531                 uint64_t src = piscsi_u32[3];
532                 src = (src << 32) | piscsi_u32[0];
533                 DEBUG("[PISCSI-%d] %d byte READ64 from block %lld to address %.8X\n", val, piscsi_u32[1], (src / 512), piscsi_u32[2]);
534                 d->lba = (src / 512);
535                 lseek64(d->fd, src, SEEK_SET);
536             }
537
538             r = get_mapped_item_by_address(cfg, piscsi_u32[2]);
539             if (r != -1 && cfg->map_type[r] == MAPTYPE_RAM) {
540                 DEBUG_TRIVIAL("[PISCSI-%d] \"DMA\" Read goes to mapped range %d.\n", val, r);
541                 read(d->fd, cfg->map_data[r] + piscsi_u32[2] - cfg->map_offset[r], piscsi_u32[1]);
542             }
543             else {
544                 DEBUG_TRIVIAL("[PISCSI-%d] No mapped range found for read.\n", val);
545                 uint8_t c = 0;
546                 for (uint32_t i = 0; i < piscsi_u32[1]; i++) {
547                     read(d->fd, &c, 1);
548                     write8(piscsi_u32[2] + i, (uint32_t)c);
549                 }
550             }
551             break;
552         case PISCSI_CMD_WRITE64:
553         case PISCSI_CMD_WRITE:
554             d = &devs[val];
555             if (d->fd == -1) {
556                 DEBUG ("[PISCSI] BUG: Attempted write to unmapped drive %d.\n", val);
557                 break;
558             }
559
560             if (cmd == PISCSI_CMD_WRITE) {
561                 DEBUG("[PISCSI-%d] %d byte WRITE to block %d from address %.8X\n", val, piscsi_u32[1], piscsi_u32[0], piscsi_u32[2]);
562                 d->lba = piscsi_u32[0];
563                 lseek(d->fd, (piscsi_u32[0] * 512), SEEK_SET);
564             }
565             else {
566                 uint64_t src = piscsi_u32[3];
567                 src = (src << 32) | piscsi_u32[0];
568                 DEBUG("[PISCSI-%d] %d byte WRITE64 to block %lld from address %.8X\n", val, piscsi_u32[1], (src / 512), piscsi_u32[2]);
569                 d->lba = (src / 512);
570                 lseek64(d->fd, src, SEEK_SET);
571             }
572
573             r = get_mapped_item_by_address(cfg, piscsi_u32[2]);
574             if (r != -1) {
575                 DEBUG_TRIVIAL("[PISCSI-%d] \"DMA\" Write comes from mapped range %d.\n", val, r);
576                 write(d->fd, cfg->map_data[r] + piscsi_u32[2] - cfg->map_offset[r], piscsi_u32[1]);
577             }
578             else {
579                 DEBUG_TRIVIAL("[PISCSI-%d] No mapped range found for write.\n", val);
580                 uint8_t c = 0;
581                 for (uint32_t i = 0; i < piscsi_u32[1]; i++) {
582                     c = read8(piscsi_u32[2] + i);
583                     write(d->fd, &c, 1);
584                 }
585             }
586             break;
587         case PISCSI_CMD_ADDR1: case PISCSI_CMD_ADDR2: case PISCSI_CMD_ADDR3: case PISCSI_CMD_ADDR4: {
588             int i = ((addr & 0xFFFF) - PISCSI_CMD_ADDR1) / 4;
589             piscsi_u32[i] = val;
590             break;
591         }
592         case PISCSI_CMD_DRVNUM:
593             //printf("%d ", val);
594             if (val % 10 != 0)
595                 piscsi_cur_drive = 255;
596             else
597                 piscsi_cur_drive = val / 10;
598             if (piscsi_cur_drive > NUM_UNITS)
599                 piscsi_cur_drive = 255;
600
601             if (piscsi_cur_drive != 255) {
602                 DEBUG("[PISCSI] (%s) Drive number set to %d (%d)\n", op_type_names[type], piscsi_cur_drive, val);
603             }
604             break;
605         case PISCSI_CMD_DEBUGME:
606             piscsi_debugme(val);
607             break;
608         case PISCSI_CMD_DRIVER: {
609             DEBUG("[PISCSI] Driver copy/patch called, destination address %.8X.\n", val);
610             int r = get_mapped_item_by_address(cfg, val);
611             if (r != -1) {
612                 uint32_t addr = val - cfg->map_offset[r];
613                 uint8_t *dst_data = cfg->map_data[r];
614                 uint8_t cur_partition = 0;
615                 memcpy(dst_data + addr, piscsi_rom_ptr + PISCSI_DRIVER_OFFSET, 0x4000 - PISCSI_DRIVER_OFFSET);
616
617                 piscsi_hinfo.base_offset = val;
618                 
619                 reloc_hunks(piscsi_hreloc, dst_data + addr, &piscsi_hinfo);
620
621                 #define PUTNODELONG(val) *(uint32_t *)&dst_data[p_offs] = htobe32(val); p_offs += 4;
622                 #define PUTNODELONGBE(val) *(uint32_t *)&dst_data[p_offs] = val; p_offs += 4;
623
624                 for (int i = 0; i < 128; i++) {
625                     rom_partitions[i] = 0;
626                     rom_partition_prio[i] = 0;
627                     rom_partition_dostype[i] = 0;
628                 }
629                 rom_cur_partition = 0;
630
631                 uint32_t data_addr = addr + 0x3F00;
632                 sprintf((char *)dst_data + data_addr, "pi-scsi.device");
633                 uint32_t addr2 = addr + 0x4000;
634                 for (int i = 0; i < NUM_UNITS; i++) {
635                     if (devs[i].fd != -1)
636                         piscsi_find_partitions(&devs[i]);
637                     else
638                         goto skip_disk;
639
640                     if (devs[i].num_partitions) {
641                         uint32_t p_offs = addr2;
642                         DEBUG("[PISCSI] Adding %d partitions for unit %d\n", devs[i].num_partitions, i);
643                         for (uint32_t j = 0; j < devs[i].num_partitions; j++) {
644                             DEBUG("Partition %d: %s\n", j, devs[i].pb[j]->pb_DriveName + 1);
645                             sprintf((char *)dst_data + p_offs, "%s", devs[i].pb[j]->pb_DriveName + 1);
646                             p_offs += 0x20;
647                             PUTNODELONG(addr2 + cfg->map_offset[r]);
648                             PUTNODELONG(data_addr + cfg->map_offset[r]);
649                             PUTNODELONG((i * 10));
650                             PUTNODELONG(0);
651                             uint32_t nodesize = (be32toh(devs[i].pb[j]->pb_Environment[0]) + 1) * 4;
652                             memcpy(dst_data + p_offs, devs[i].pb[j]->pb_Environment, nodesize);
653
654                             struct pihd_dosnode_data *dat = (struct pihd_dosnode_data *)(&dst_data[addr2+0x20]);
655
656                             if (BE(devs[i].pb[j]->pb_Flags) & 0x01) {
657                                 DEBUG("Partition is bootable.\n");
658                                 rom_partition_prio[cur_partition] = 0;
659                                 dat->priority = 0;
660                             }
661                             else {
662                                 DEBUG("Partition is not bootable.\n");
663                                 rom_partition_prio[cur_partition] = -128;
664                                 dat->priority = htobe32(-128);
665                             }
666
667                             DEBUG("DOSNode Data:\n");
668                             DEBUG("Name: %s Device: %s\n", dst_data + addr2, dst_data + data_addr);
669                             DEBUG("Unit: %d Flags: %d Pad1: %d\n", BE(dat->unit), BE(dat->flags), BE(dat->pad1));
670                             DEBUG("Node len: %d Block len: %d\n", BE(dat->node_len) * 4, BE(dat->block_len) * 4);
671                             DEBUG("H: %d SPB: %d BPS: %d\n", BE(dat->surf), BE(dat->secs_per_block), BE(dat->blocks_per_track));
672                             DEBUG("Reserved: %d Prealloc: %d\n", BE(dat->reserved_blocks), BE(dat->pad2));
673                             DEBUG("Interleaved: %d Buffers: %d Memtype: %d\n", BE(dat->interleave), BE(dat->buffers), BE(dat->mem_type));
674                             DEBUG("Lowcyl: %d Highcyl: %d Prio: %d\n", BE(dat->lowcyl), BE(dat->highcyl), BE(dat->priority));
675                             DEBUG("Maxtransfer: %.8X Mask: %.8X\n", BE(dat->maxtransfer), BE(dat->transfer_mask));
676                             DEBUG("DOSType: %.8X\n", BE(dat->dostype));
677
678                             rom_partitions[cur_partition] = addr2 + 0x20 + cfg->map_offset[r];
679                             rom_partition_dostype[cur_partition] = dat->dostype;
680                             cur_partition++;
681                             addr2 += 0x100;
682                             p_offs = addr2;
683                         }
684                     }
685 skip_disk:;
686                 }
687             }
688            
689             break;
690         }
691         case PISCSI_CMD_NEXTPART:
692             DEBUG("[PISCSI] Switch partition %d -> %d\n", rom_cur_partition, rom_cur_partition + 1);
693             rom_cur_partition++;
694             break;
695         case PISCSI_CMD_NEXTFS:
696             DEBUG("[PISCSI] Switch file file system %d -> %d\n", rom_cur_fs, rom_cur_fs + 1);
697             rom_cur_fs++;
698             break;
699         case PISCSI_CMD_COPYFS:
700             DEBUG("[PISCSI] Copy file system %d to %.8X and reloc.\n", rom_cur_fs, piscsi_u32[2]);
701             r = get_mapped_item_by_address(cfg, piscsi_u32[2]);
702             if (r != -1) {
703                 uint32_t addr = piscsi_u32[2] - cfg->map_offset[r];
704                 memset(cfg->map_data[r] + addr, 0x00, filesystems[rom_cur_fs].h_info.alloc_size);
705                 memcpy(cfg->map_data[r] + addr, filesystems[rom_cur_fs].binary_data, filesystems[rom_cur_fs].h_info.byte_size);
706                 filesystems[rom_cur_fs].h_info.base_offset = piscsi_u32[2];
707                 reloc_hunks(filesystems[rom_cur_fs].relocs, cfg->map_data[r] + addr, &filesystems[rom_cur_fs].h_info);
708                 filesystems[rom_cur_fs].handler = piscsi_u32[2];
709             }
710             break;
711         case PISCSI_CMD_SETFSH: {
712             int i = 0;
713             DEBUG("[PISCSI] Set handler for partition %d (DeviceNode: %.8X)\n", rom_cur_partition, val);
714             r = get_mapped_item_by_address(cfg, val);
715             if (r != -1) {
716                 uint32_t addr = val - cfg->map_offset[r];
717                 struct DeviceNode *node = (struct DeviceNode *)(cfg->map_data[r] + addr);
718 #ifdef PISCSI_DEBUG
719                 char *dosID = (char *)&rom_partition_dostype[rom_cur_partition];
720 #endif
721                 DEBUG("[PISCSI] Partition DOSType is %c%c%c/%d\n", dosID[0], dosID[1], dosID[2], dosID[3]);
722                 for (i = 0; i < piscsi_num_fs; i++) {
723                     if (rom_partition_dostype[rom_cur_partition] == filesystems[i].FS_ID) {
724                         node->dn_SegList = htobe32((filesystems[i].handler >> 2));
725                         node->dn_GlobalVec = 0xFFFFFFFF;
726                         goto fs_found;
727                     }
728                 }
729                 DEBUG("[!!!PISCSI] Found no handler for file system!\n");
730 fs_found:;
731                 DEBUG("[FS-HANDLER] Next: %d Type: %.8X\n", BE(node->dn_Next), BE(node->dn_Type));
732                 DEBUG("[FS-HANDLER] Task: %d Lock: %d\n", BE(node->dn_Task), BE(node->dn_Lock));
733                 DEBUG("[FS-HANDLER] Handler: %d Stacksize: %d\n", BE((uint32_t)node->dn_Handler), BE(node->dn_StackSize));
734                 DEBUG("[FS-HANDLER] Priority: %d Startup: %d\n", BE((uint32_t)node->dn_Priority), BE(node->dn_Startup));
735                 DEBUG("[FS-HANDLER] SegList: %.8X GlobalVec: %d\n", BE((uint32_t)node->dn_SegList), BE(node->dn_GlobalVec));
736                 DEBUG("[PISCSI] Handler for partition %.8X set to %.8X (%.8X).\n", BE((uint32_t)node->dn_Name), filesystems[i].FS_ID, filesystems[i].handler);
737             }
738             break;
739         }
740         case PISCSI_DBG_VAL1: case PISCSI_DBG_VAL2: case PISCSI_DBG_VAL3: case PISCSI_DBG_VAL4:
741         case PISCSI_DBG_VAL5: case PISCSI_DBG_VAL6: case PISCSI_DBG_VAL7: case PISCSI_DBG_VAL8: {
742             int i = ((addr & 0xFFFF) - PISCSI_DBG_VAL1) / 4;
743             piscsi_dbg[i] = val;
744             break;
745         }
746         case PISCSI_DBG_MSG:
747             print_piscsi_debug_message(val);
748             break;
749         default:
750             DEBUG("[!!!PISCSI] WARN: Unhandled %s register write to %.8X: %d\n", op_type_names[type], addr, val);
751             break;
752     }
753 }
754
755 #define PIB 0x00
756
757 uint32_t handle_piscsi_read(uint32_t addr, uint8_t type) {
758     if (type) {}
759
760     if ((addr & 0xFFFF) >= PISCSI_CMD_ROM) {
761         uint32_t romoffs = (addr & 0xFFFF) - PISCSI_CMD_ROM;
762         if (romoffs < (piscsi_rom_size + PIB)) {
763             //DEBUG("[PISCSI] %s read from Boot ROM @$%.4X (%.8X): ", op_type_names[type], romoffs, addr);
764             uint32_t v = 0;
765             switch (type) {
766                 case OP_TYPE_BYTE:
767                     v = piscsi_rom_ptr[romoffs - PIB];
768                     //DEBUG("%.2X\n", v);
769                     break;
770                 case OP_TYPE_WORD:
771                     v = be16toh(*((uint16_t *)&piscsi_rom_ptr[romoffs - PIB]));
772                     //DEBUG("%.4X\n", v);
773                     break;
774                 case OP_TYPE_LONGWORD:
775                     v = be32toh(*((uint32_t *)&piscsi_rom_ptr[romoffs - PIB]));
776                     //DEBUG("%.8X\n", v);
777                     break;
778             }
779             return v;
780         }
781         return 0;
782     }
783     
784     switch (addr & 0xFFFF) {
785         case PISCSI_CMD_ADDR1: case PISCSI_CMD_ADDR2: case PISCSI_CMD_ADDR3: case PISCSI_CMD_ADDR4: {
786             int i = ((addr & 0xFFFF) - PISCSI_CMD_ADDR1) / 4;
787             return piscsi_u32[i];
788             break;
789         }
790         case PISCSI_CMD_DRVTYPE:
791             if (devs[piscsi_cur_drive].fd == -1) {
792                 DEBUG("[PISCSI] %s Read from DRVTYPE %d, drive not attached.\n", op_type_names[type], piscsi_cur_drive);
793                 return 0;
794             }
795             DEBUG("[PISCSI] %s Read from DRVTYPE %d, drive attached.\n", op_type_names[type], piscsi_cur_drive);
796             return 1;
797             break;
798         case PISCSI_CMD_DRVNUM:
799             return piscsi_cur_drive;
800             break;
801         case PISCSI_CMD_CYLS:
802             DEBUG("[PISCSI] %s Read from CYLS %d: %d\n", op_type_names[type], piscsi_cur_drive, devs[piscsi_cur_drive].c);
803             return devs[piscsi_cur_drive].c;
804             break;
805         case PISCSI_CMD_HEADS:
806             DEBUG("[PISCSI] %s Read from HEADS %d: %d\n", op_type_names[type], piscsi_cur_drive, devs[piscsi_cur_drive].h);
807             return devs[piscsi_cur_drive].h;
808             break;
809         case PISCSI_CMD_SECS:
810             DEBUG("[PISCSI] %s Read from SECS %d: %d\n", op_type_names[type], piscsi_cur_drive, devs[piscsi_cur_drive].s);
811             return devs[piscsi_cur_drive].s;
812             break;
813         case PISCSI_CMD_BLOCKS: {
814             uint32_t blox = devs[piscsi_cur_drive].fs / 512;
815             DEBUG("[PISCSI] %s Read from BLOCKS %d: %d\n", op_type_names[type], piscsi_cur_drive, (uint32_t)(devs[piscsi_cur_drive].fs / 512));
816             DEBUG("fs: %lld (%d)\n", devs[piscsi_cur_drive].fs, blox);
817             return blox;
818             break;
819         }
820         case PISCSI_CMD_GETPART: {
821             DEBUG("[PISCSI] Get ROM partition %d offset: %.8X\n", rom_cur_partition, rom_partitions[rom_cur_partition]);
822             return rom_partitions[rom_cur_partition];
823             break;
824         }
825         case PISCSI_CMD_GETPRIO:
826             DEBUG("[PISCSI] Get partition %d boot priority: %d\n", rom_cur_partition, rom_partition_prio[rom_cur_partition]);
827             return rom_partition_prio[rom_cur_partition];
828             break;
829         case PISCSI_CMD_CHECKFS:
830             DEBUG("[PISCSI] Get current loaded file system: %.8X\n", filesystems[rom_cur_fs].FS_ID);
831             return filesystems[rom_cur_fs].FS_ID;
832         case PISCSI_CMD_FSSIZE:
833             DEBUG("[PISCSI] Get alloc size of loaded file system: %d\n", filesystems[rom_cur_fs].h_info.alloc_size);
834             return filesystems[rom_cur_fs].h_info.alloc_size;
835         default:
836             DEBUG("[!!!PISCSI] WARN: Unhandled %s register read from %.8X\n", op_type_names[type], addr);
837             break;
838     }
839
840     return 0;
841 }