diff --git a/mounter/README.md b/3rdparty/mounter/README.md similarity index 100% rename from mounter/README.md rename to 3rdparty/mounter/README.md diff --git a/mounter/mounter.c b/3rdparty/mounter/mounter.c similarity index 100% rename from mounter/mounter.c rename to 3rdparty/mounter/mounter.c diff --git a/mounter/mounter.h b/3rdparty/mounter/mounter.h similarity index 100% rename from mounter/mounter.h rename to 3rdparty/mounter/mounter.h diff --git a/mounter/ndkcompat.h b/3rdparty/mounter/ndkcompat.h similarity index 100% rename from mounter/ndkcompat.h rename to 3rdparty/mounter/ndkcompat.h diff --git a/3rdparty/odfs-rom/.gitignore b/3rdparty/odfs-rom/.gitignore new file mode 100644 index 0000000..06ad98f --- /dev/null +++ b/3rdparty/odfs-rom/.gitignore @@ -0,0 +1,2 @@ +obj/** +out/** \ No newline at end of file diff --git a/3rdparty/odfs-rom/Makefile b/3rdparty/odfs-rom/Makefile new file mode 100644 index 0000000..76de3a5 --- /dev/null +++ b/3rdparty/odfs-rom/Makefile @@ -0,0 +1,31 @@ +INCLUDE=/opt/amiga/m68k-amigaos/ndk-include +AS=vasmm68k_mot +ASFLAGS=-Fhunk -I$(INCLUDE) -quiet +LINKER=vlink +LINKFLAGS=-bamigahunk -s -sc -sd +OBJDIR=obj +ODFS_VERSION=0.4 +ODFS_URL="https://github.com/reinauer/ODFileSystem/releases/download/v$(ODFS_VERSION)/ODFileSystem-rom" +SHELL=/bin/bash + +.PHONY: all clean + +SRCS = resident.S +OBJS = $(SRCS:%.S=$(OBJDIR)/%.o) + +all: out/odfs.rom + +$(OBJDIR)/%.o: %.S + @mkdir -p $(OBJDIR) + $(AS) $(ASFLAGS) -o $@ $< + +$(OBJDIR)/ODFileSystem-rom: + curl -fsSL $(ODFS_URL) -o $@ + +out/odfs.rom: $(OBJDIR)/resident.o $(OBJDIR)/ODFileSystem-rom + @mkdir -p out + @set -o pipefail ; $(LINKER) $(LINKFLAGS) $^ -o $@ 2>&1 | (grep -v "already an executable file." || true) + +clean: + @rm -f $(OBJDIR)/* + @rm -rf out/* \ No newline at end of file diff --git a/3rdparty/odfs-rom/README.md b/3rdparty/odfs-rom/README.md new file mode 100644 index 0000000..ac1a641 --- /dev/null +++ b/3rdparty/odfs-rom/README.md @@ -0,0 +1,11 @@ +# odfs-rom + +This will download the version of ODFS from [github](https://github.com/reinauer/ODFileSystem) and glue a romtag to it to make it loadable by the LIDE bootrom + +## Description +This romtag code does the following +* If FileSystem.resource doesn't already exist, create it +* Check if there's already a filesystem with dostype CD01 in FSR +* If not, add it to filesystem.resource + +[ODFileSystem](https://github.com/reinauer/ODFileSystem) by Stefan Reinauer is licensed under the BSD 2-Clause license diff --git a/3rdparty/odfs-rom/resident.S b/3rdparty/odfs-rom/resident.S new file mode 100644 index 0000000..7295373 --- /dev/null +++ b/3rdparty/odfs-rom/resident.S @@ -0,0 +1,99 @@ + include "lvo/exec_lib.i" + include "exec/lists.i" + include "exec/types.i" + include "exec/memory.i" + include "exec/resident.i" + include "resources/filesysres.i" + +CDFS_DOSTYPE EQU $43443031 ; CD01 + +;; Entrypoint jump here allows us to give the real seglist address in the FSE +entrypoint: bra.w odfs + +romtag: dc.w RTC_MATCHWORD ; rt_MatchWord + dc.l romtag ; rt_MatchTag + dc.l endskip ; rt_EndSkip + dc.b RTF_COLDSTART ; rt_Flags + dc.b 1 ; rt_Version + dc.b NT_UNKNOWN ; rt_Type + dc.b 0 ; rt_Pri + dc.l name ; rt_Name + dc.l name ; rt_IdString + dc.l init ; rt_Init + +init: movem.l d2/a2/a6,-(sp) + move.l 4,a6 + + ;; Open FileSystem.resource + lea.l fileSysResName(pc),a1 + jsr _LVOOpenResource(a6) + move.l d0,a2 + tst.l d0 + bne.s .fsr + + ;; No FileSysRes found so we create it + move.l #FileSysResource_SIZEOF,d0 + move.l #MEMF_PUBLIC|MEMF_CLEAR,d1 + jsr _LVOAllocMem(a6) + tst.l d0 + beq.w .done + + move.l d0,a1 + lea.l fsr_FileSysEntries(a1),a0 + NEWLIST a0 + lea.l name(pc),a0 + move.l a0,fsr_Creator(a1) + move.l a0,LN_NAME(a1) + move.b #NT_RESOURCE,LN_TYPE(a1) + move.l a1,a2 + jsr _LVOAddResource(a6) + +.fsr: ; Check if there's a CDFS there already + moveq.l #0,d2 ; Clear found flag + jsr _LVOForbid(a6) + lea.l fsr_FileSysEntries(a2),a0 +.nxtfe: move.l LN_SUCC(a0),a0 + tst.l (a0) + beq.s .fsend + cmp.l #CDFS_DOSTYPE,fse_DosType(a0) + bne.s .nxtfe + moveq #1,d2 ; found + +.fsend: jsr _LVOPermit(a6) + tst.l d2 + bne.s .done + + move.l #(fse_GlobalVec+4),d0 ; fileSysEntry_SIZEOF + move.l #MEMF_PUBLIC|MEMF_CLEAR,d1 + jsr _LVOAllocMem(a6) + tst.l d0 + beq.s .done + move.l d0,a1 + lea.l name(pc),a0 + move.l a0,LN_NAME(a1) + move.l #CDFS_DOSTYPE,fse_DosType(a1) + move.l #1<<16,fse_Version(a1) + move.l #$190,fse_PatchFlags(a1) ; SegList+StackSize+GlobalVec + move.l #8192,fse_StackSize(a1) + move.l #10,fse_Priority(a1) + move.l #-1,fse_GlobalVec(a1) + lea.l entrypoint(pc),a0 + sub.l #4,a0 ; Seglist at -4 + move.l a0,d0 + lsr.l #2,d0 ; to BPTR + move.l d0,fse_SegList(a1) + lea.l fsr_FileSysEntries(a2),a0 + jsr _LVOForbid(a6) + jsr _LVOAddHead(a6) + jsr _LVOPermit(a6) + +.done: moveq #0,d0 + movem.l (sp)+,d2/a2/a6 + rts + +fileSysResName: FSRNAME +name: dc.b "cdfs",0 + + CNOP 0,4 +endskip: +odfs: ; After linking, ODFS will be here \ No newline at end of file diff --git a/Makefile b/Makefile index 968f84a..bb359cf 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ else DISK=lide-update.adf endif -.PHONY: clean all lideflash disk lha rename/renamelide lidetool/lidetool +.PHONY: clean all lideflash disk lha lidetool/lidetool all: $(PROJECT) \ AIDE-$(PROJECT) \ @@ -46,11 +46,12 @@ all: $(PROJECT) \ lide-N2630-low.rom \ rename/renamelide \ lideflash \ + odfs.rom \ $(ROM) OBJDIR = obj/$(TARGET) -SRCS = device.c ata.c atapi.c scsi.c iotask.c lide_alib.c mounter/mounter.c debug.c +SRCS = device.c ata.c atapi.c scsi.c iotask.c lide_alib.c 3rdparty/mounter/mounter.c debug.c OBJ = $(addprefix $(OBJDIR)/,$(notdir $(SRCS:%c=%o))) @@ -93,7 +94,7 @@ $(OBJDIR)/%.o: %.c @printf "${GREEN}$@${NC}\n" @${CC} -o $@ -c $< ${CFLAGS} -$(OBJDIR)/%.o: mounter/%.c +$(OBJDIR)/%.o: 3rdparty/mounter/%.c @mkdir -p $(OBJDIR) @printf "${GREEN}$@${NC}\n" @${CC} -o $@ -c $< ${CFLAGS} @@ -124,6 +125,14 @@ rename/renamelide: @${MAKE} -C rename @printf "Done.\n" +3rdparty/odfs-rom/out/odfs.rom: + @printf "${WHITE}#### Building $@ ####${NC}\n" + @${MAKE} -C 3rdparty/odfs-rom + @printf "Done.\n" + +odfs.rom: 3rdparty/odfs-rom/out/odfs.rom + @cp $^ $@ + $(BUILDDIR)/AIDE-boot-$(VERSION).adf: AIDE-$(PROJECT) @printf "${WHITE}#### Building $@ ####${NC}\n" @${MAKE} -C aide-boot @@ -132,10 +141,11 @@ $(BUILDDIR)/AIDE-boot-$(VERSION).adf: AIDE-$(PROJECT) disk: $(BUILDDIR)/$(DISK) $(BUILDDIR)/AIDE-boot-$(VERSION).adf -$(BUILDDIR)/$(DISK): $(ROM) AIDE-lide.device lideflash/lideflash rename/renamelide lidetool/lidetool +$(BUILDDIR)/$(DISK): $(ROM) AIDE-lide.device lideflash/lideflash rename/renamelide lidetool/lidetool odfs.rom @printf "${WHITE}#### Building $@ ####${NC}\n" @mkdir -p $(BUILDDIR) @cp $(ROM) build + @cp odfs.rom build @echo 'lideflash -I $(ROM)' > $(BUILDDIR)/startup-sequence @xdftool $(BUILDDIR)/$(DISK) format lide-update + \ boot install + \ @@ -149,10 +159,11 @@ $(BUILDDIR)/$(DISK): $(ROM) AIDE-lide.device lideflash/lideflash rename/renameli write info/Expansion.info Expansion.info + \ write info/lide.device.info Expansion/lide.device.info + \ write lide.device Expansion/lide.device + \ - write AIDE-lide.device AIDE-lide.device + write AIDE-lide.device AIDE-lide.device + \ + write odfs.rom odfs.rom @printf "Done.\n" -$(BUILDDIR)/lide-update.lha: lideflash/lideflash $(ROM) rename/renamelide lidetool/lidetool lide.device info/lide.device.info AIDE-lide.device +$(BUILDDIR)/lide-update.lha: lideflash/lideflash $(ROM) lide-atbus.rom lide-N2630-high.rom lide-N2630-low.rom rename/renamelide lidetool/lidetool lide.device info/lide.device.info AIDE-lide.device odfs.rom @mkdir -p $(BUILDDIR) cp $^ $(BUILDDIR) cd $(BUILDDIR) && lha -c ../$@ $(notdir $^) @@ -184,5 +195,6 @@ clean: @${MAKE} -C lideflash clean @${MAKE} -C lidetool clean @${MAKE} -C rename clean + @${MAKE} -C 3rdparty/odfs-rom clean @-rm -rf $(BUILDDIR) @${MAKE} -C aide-boot clean diff --git a/README.md b/README.md index 9a694b2..abe1023 100644 --- a/README.md +++ b/README.md @@ -73,21 +73,27 @@ Releases contain the following builds lide.device supports booting from CD-ROM but requires a CD Filesystem to be loaded for this to work. There are a few options: -1. `CDFileSystem` from AmigaOS 3.2.2 loaded with LoadModule -2. `BootCDFileSystem` from OS 4 either: +1. [`ODFileSystem`](https://github.com/reinauer/ODFileSystem) (recommended) added to the IDE/Accelerator ROM (subject to board support) +2. `CDFileSystem` from AmigaOS 3.2.2 loaded with LoadModule +3. `BootCDFileSystem` from OS 4 either: * Added to a custom Kickstart ROM **OR** * Added to the IDE/Accelerator ROM (subject to board support) -### Loading BootCDFileSystem from Board ROM -The following boards support loading BootCDFileSystem from ROM: +### Loading ODFileSystem from Board ROM +The following boards are known to support loading ODFileSystem from ROM: * RIPPLE * RIDE * 68EC020-TK * 68030-TK2 -`BootCDFileSystem` must be flashed to the second bank of the ROM. -This can be achieved on RIPPLE and 68EC020-TK boards using `lideflash` i.e -`lideflash -C BootCDFileSystem` +`ODFileSystem` must be flashed to the second bank of the ROM. +The ROM image to flash is the `odfs.rom` file, which can be obtained from either: + +* The [latest release](https://github.com/LIV2/lide.device/releases/latest), or +* The `odfs.rom` file included on the `lide-update` ADF + +For RIPPLE and 68EC020-TK boards you can install it using `lideflash` i.e +`lideflash -C odfs.rom` ## Large drive (>4GB) support For drives larger than 4GB it is required to use a Filesystem that supports TD64, NSD or SCSI-Direct @@ -146,6 +152,7 @@ Thanks to [MHeinrichs](https://gitlab.com/MHeinrichs) for contributing improveme reloc.S is adapted from the [A4091](https://github.com/A4091/a4091-software) open-source driver and is Copyright Stefan Reinauer mounter.c adapted from the [A4091](https://github.com/A4091/a4091-software) open-source driver and is Copyright 2021-2022 Toni Wilen The fast read/write routines for ATA devices are adapted from [Frédéric REQUIN](https://github.com/fredrequin)'s [at_apollo_device](https://github.com/fredrequin/at_apollo_device) +[ODFileSystem](https://github.com/reinauer/ODFileSystem) by Stefan Reinauer is licensed under the BSD 2-Clause license ## License All software contained that is not provided by a third-party is covered by a GPL 2.0 Only license diff --git a/ata.c b/ata.c index abc284f..bb3025f 100644 --- a/ata.c +++ b/ata.c @@ -232,12 +232,13 @@ bool ata_identify(struct IDEUnit *unit, UWORD *buffer) * * Sets the transfer routine for the unit * - * @param unit Pointer to an IDEUnit strict + * @param unit Pointer to an IDEUnit struct * @param method Transfer routine */ void ata_set_xfer(struct IDEUnit *unit, enum xfer method) { switch (method) { default: +#if NEXT_REG >= 512 case longword_movem: unit->read_fast = ata_read_long_movem; unit->read_unaligned = ata_read_unaligned_long; @@ -246,6 +247,7 @@ void ata_set_xfer(struct IDEUnit *unit, enum xfer method) { unit->xferMethod = longword_movem; break; +#endif case longword_move: unit->read_fast = ata_read_long_move; unit->read_unaligned = ata_read_unaligned_long; @@ -419,7 +421,7 @@ bool ata_init_unit(struct IDEUnit *unit, void *base) { * @param multiple DRQ Block size * @return non-zero on error */ -bool ata_set_multiple(struct IDEUnit *unit, BYTE multiple) { +BYTE ata_set_multiple(struct IDEUnit *unit, BYTE multiple) { UBYTE drvSel = (unit->flags.primary) ? 0xE0 : 0xF0; // Select drive ata_select(unit,drvSel,true); @@ -764,8 +766,8 @@ BYTE ata_set_pio(struct IDEUnit *unit, UBYTE pio) { if ((error = write_taskfile_lba(unit,ATA_CMD_SET_FEATURES,0,pio,0x03)) != 0) return error; - if ((error = ata_wait_ready(unit,ATA_RDY_WAIT_COUNT))) - return error; + if (!ata_wait_ready(unit,ATA_RDY_WAIT_COUNT)) + return IOERR_UNITBUSY; if (ata_check_error(unit)) return IOERR_BADLENGTH; @@ -777,11 +779,14 @@ BYTE ata_set_pio(struct IDEUnit *unit, UBYTE pio) { * * Handle SCSI ATA PASSTHROUGH (12) command to send ATA commands to the drive * + * Requires that the cmd->scsi_Data buffer is word aligned + * * @param unit Pointer to an IDEUnit struct * @param cmd Pointer to a SCSICmd struct * @return non-zero on error */ BYTE scsi_ata_passthrough(struct IDEUnit *unit, struct SCSICmd *cmd) { + struct SCSI_CDB_ATA *cdb = (struct SCSI_CDB_ATA *)cmd->scsi_Command; bool byt_blok = (cdb->length & ATA_BYT_BLOK) ? true : false; @@ -824,12 +829,14 @@ BYTE scsi_ata_passthrough(struct IDEUnit *unit, struct SCSICmd *cmd) { case ATA_PIO_IN: // Data to Host if (count < 2) return IOERR_BADLENGTH; + if ((ULONG)cmd->scsi_Data & 1) return IOERR_BADADDRESS; src = (UWORD *)unit->drive.data; dest = cmd->scsi_Data; break; case ATA_PIO_OUT: // Data to Drive if (count < 2) return IOERR_BADLENGTH; + if ((ULONG)cmd->scsi_Data & 1) return IOERR_BADADDRESS; src = cmd->scsi_Data; dest = (UWORD *)unit->drive.data; break; @@ -857,7 +864,7 @@ BYTE scsi_ata_passthrough(struct IDEUnit *unit, struct SCSICmd *cmd) { if (protocol == ATA_PIO_IN || protocol == ATA_PIO_OUT) { for (int i = 0; i < count/2; i++) { - if (i % 512 == 0) { + if (i % 256 == 0) { if (!ata_wait_drq(unit,ATA_DRQ_WAIT_COUNT,true)) { ata_save_error(unit); return IOERR_UNITBUSY; diff --git a/ata.h b/ata.h index 065c701..eaf5af2 100644 --- a/ata.h +++ b/ata.h @@ -105,7 +105,7 @@ enum xfer_dir { bool ata_init_unit(struct IDEUnit *unit, void *base); bool ata_select(struct IDEUnit *unit, UBYTE select, bool wait); bool ata_identify(struct IDEUnit *, UWORD *); -bool ata_set_multiple(struct IDEUnit *unit, BYTE multiple); +BYTE ata_set_multiple(struct IDEUnit *unit, BYTE multiple); void ata_set_xfer(struct IDEUnit *unit, enum xfer method); BYTE ata_read(void *buffer, uint64_t lba, ULONG count, struct IDEUnit *unit); diff --git a/atapi.c b/atapi.c index 6b707bc..8dc4f02 100644 --- a/atapi.c +++ b/atapi.c @@ -262,15 +262,17 @@ bool atapi_identify(struct IDEUnit *unit, UWORD *buffer) { BYTE atapi_translate(APTR io_Data, ULONG lba, ULONG count, ULONG *io_Actual, struct IDEUnit *unit, enum xfer_dir direction) { Trace("atapi_translate enter\n"); - struct SCSICmd *cmd = MakeSCSICmd(SZ_CDB_10); - if (cmd == NULL) return TDERR_NoMem; + struct SCSICmd *cmd; + if ((cmd = scsi_get_unit_cmd(unit)) == NULL) return TDERR_NoMem; struct SCSI_CDB_10 *cdb = (struct SCSI_CDB_10 *)cmd->scsi_Command; + UBYTE errorCode = 0; UBYTE senseKey = 0; UBYTE asc = 0; UBYTE asq = 0; if (count == 0) { + scsi_release_unit_cmd(unit); return IOERR_BADLENGTH; } Trace("%ld lba %ld count\n %ld bs\n",lba,count,unit->blockShift); @@ -343,10 +345,9 @@ BYTE atapi_translate(APTR io_Data, ULONG lba, ULONG count, ULONG *io_Actual, str done: Trace("atapi_packet returns %ld\n",ret); + scsi_release_unit_cmd(unit); *io_Actual = cmd->scsi_Actual; - DeleteSCSICmd(cmd); - return ret; } @@ -578,8 +579,8 @@ BYTE atapi_packet(struct SCSICmd *cmd, struct IDEUnit *unit) { * @returns nonzero if there was an error */ BYTE atapi_test_unit_ready(struct IDEUnit *unit, bool immediate) { - struct SCSICmd *cmd = MakeSCSICmd(SZ_CDB_10); - if (cmd == NULL) return TDERR_NoMem; + struct SCSICmd *cmd; + if ((cmd = scsi_get_unit_cmd(unit)) == NULL) return TDERR_NoMem; struct SCSI_CDB_10 *cdb = (struct SCSI_CDB_10 *)cmd->scsi_Command; UBYTE senseError = 0; @@ -638,9 +639,8 @@ BYTE atapi_test_unit_ready(struct IDEUnit *unit, bool immediate) { } done: + scsi_release_unit_cmd(unit); atapi_update_presence(unit,(ret == 0)); // Update the media presence - DeleteSCSICmd(cmd); - return ret; } @@ -657,15 +657,16 @@ BYTE atapi_test_unit_ready(struct IDEUnit *unit, bool immediate) { */ BYTE atapi_request_sense(struct IDEUnit *unit, UBYTE *errorCode, UBYTE *senseKey, UBYTE *asc, UBYTE *asq) { struct ExecBase *SysBase = unit->SysBase; + struct SCSICmd *cmd; + + if ((cmd = scsi_get_sense_cmd(unit)) == NULL) return TDERR_NoMem; - struct SCSICmd *cmd = MakeSCSICmd(SZ_CDB_10); - if (cmd == NULL) return TDERR_NoMem; UBYTE *cdb = (UBYTE *)cmd->scsi_Command; UBYTE *buf; if ((buf = AllocMem(18,MEMF_CLEAR|MEMF_ANY)) == NULL) { - DeleteSCSICmd(cmd); + scsi_release_sense_cmd(unit); return TDERR_NoMem; } @@ -688,8 +689,8 @@ BYTE atapi_request_sense(struct IDEUnit *unit, UBYTE *errorCode, UBYTE *senseKey *asc = buf[12]; *asq = buf[13]; - DeleteSCSICmd(cmd); if (buf) FreeMem(buf,18); + scsi_release_sense_cmd(unit); return ret; } @@ -702,8 +703,9 @@ BYTE atapi_request_sense(struct IDEUnit *unit, UBYTE *errorCode, UBYTE *senseKey * @return non-zero on error */ BYTE atapi_get_capacity(struct IDEUnit *unit) { - struct SCSICmd *cmd = MakeSCSICmd(SZ_CDB_10); - if (cmd == NULL) return TDERR_NoMem; + struct SCSICmd *cmd; + if ((cmd = scsi_get_unit_cmd(unit)) == NULL) return TDERR_NoMem; + struct SCSI_CDB_10 *cdb = (struct SCSI_CDB_10 *)cmd->scsi_Command; BYTE ret; @@ -742,8 +744,7 @@ BYTE atapi_get_capacity(struct IDEUnit *unit) { } Trace("New geometry: %ld %ld\n",unit->logicalSectors, unit->blockSize); - - DeleteSCSICmd(cmd); + scsi_release_unit_cmd(unit); return ret; } @@ -761,8 +762,9 @@ BYTE atapi_get_capacity(struct IDEUnit *unit) { * @return Non-zero on error */ BYTE atapi_mode_sense(struct IDEUnit *unit, BYTE page_code, BYTE subpage_code, UWORD *buffer, UWORD length, UWORD *actual, BOOL dbd) { - struct SCSICmd *cmd = MakeSCSICmd(SZ_CDB_10); - if (cmd == NULL) return TDERR_NoMem; + struct SCSICmd *cmd; + if ((cmd = scsi_get_unit_cmd(unit)) == NULL) return TDERR_NoMem; + UBYTE *cdb = cmd->scsi_Command; BYTE ret; @@ -786,8 +788,7 @@ BYTE atapi_mode_sense(struct IDEUnit *unit, BYTE page_code, BYTE subpage_code, U ret = atapi_packet(cmd,unit); if (actual) *actual = cmd->scsi_Actual; - - DeleteSCSICmd(cmd); + scsi_release_unit_cmd(unit); return ret; } @@ -817,13 +818,11 @@ BYTE atapi_scsi_mode_sense_6(struct SCSICmd *cmd, struct IDEUnit *unit) { return TDERR_NoMem; } - cmd_sense = MakeSCSICmd(SZ_CDB_10); - - if (cmd_sense == NULL) { + if ((cmd_sense = scsi_get_unit_cmd(unit)) == NULL) { ret = TDERR_NoMem; goto cleanup; } - + cmd_sense->scsi_CmdLength = SZ_CDB_10; cmd_sense->scsi_Command[0] = SCSI_CMD_MODE_SENSE_10; cmd_sense->scsi_Command[1] = cmd->scsi_Command[1]; // DBD flag cmd_sense->scsi_Command[2] = cmd->scsi_Command[2]; // Page Code @@ -862,10 +861,10 @@ BYTE atapi_scsi_mode_sense_6(struct SCSICmd *cmd, struct IDEUnit *unit) { cmd->scsi_CmdActual = cmd->scsi_CmdLength; cmd->scsi_SenseActual = cmd_sense->scsi_SenseActual; + scsi_release_unit_cmd(unit); cleanup: if (buf) FreeMem(buf,len); - if (cmd_sense) DeleteSCSICmd(cmd_sense); return ret; } @@ -900,13 +899,11 @@ BYTE atapi_scsi_mode_select_6(struct SCSICmd *cmd, struct IDEUnit *unit) { src = (UBYTE *)cmd->scsi_Data; dst = buf; - cmd_select = MakeSCSICmd(SZ_CDB_10); - - if (cmd_select == NULL) { + if ((cmd_select = scsi_get_unit_cmd(unit)) == NULL) { ret = TDERR_NoMem; goto cleanup; } - + cmd_select->scsi_CmdLength = SZ_CDB_10; cmd_select->scsi_Command[0] = SCSI_CMD_MODE_SELECT_10; cmd_select->scsi_Command[1] = cmd->scsi_Command[1]; // PF / SP cmd_select->scsi_Command[7] = (bufSize >> 8) & 0xFF; // Parameter list length @@ -939,9 +936,9 @@ BYTE atapi_scsi_mode_select_6(struct SCSICmd *cmd, struct IDEUnit *unit) { cmd->scsi_CmdActual = cmd->scsi_CmdLength; cmd->scsi_Actual = cmd_select->scsi_Actual; + scsi_release_unit_cmd(unit); cleanup: if (buf) FreeMem(buf,bufSize); - if (cmd_select) DeleteSCSICmd(cmd_select); return ret; } @@ -1175,10 +1172,10 @@ BYTE atapi_read_toc(struct IDEUnit *unit, BYTE *buf, ULONG bufSize) { return IOERR_BADADDRESS; } - struct SCSICmd *cmd = MakeSCSICmd(SZ_CDB_10); - - if (cmd == NULL) return TDERR_NoMem; + struct SCSICmd *cmd; + if ((cmd = scsi_get_unit_cmd(unit)) == NULL) return TDERR_NoMem; + cmd->scsi_CmdLength = SZ_CDB_10; cmd->scsi_Data = (UWORD *)buf; cmd->scsi_Length = bufSize; cmd->scsi_Flags = SCSIF_READ; @@ -1187,10 +1184,8 @@ BYTE atapi_read_toc(struct IDEUnit *unit, BYTE *buf, ULONG bufSize) { cmd->scsi_Command[7] = bufSize >> 8; cmd->scsi_Command[8] = bufSize & 0xFF; + scsi_release_unit_cmd(unit); ret = atapi_packet(cmd,unit) != 0; - - DeleteSCSICmd(cmd); - return ret; } @@ -1278,10 +1273,10 @@ BYTE atapi_play_track_index(struct IDEUnit *unit, UBYTE start, UBYTE end) { BYTE atapi_play_audio_msf(struct IDEUnit *unit, struct SCSI_TRACK_MSF *start, struct SCSI_TRACK_MSF *end) { BYTE ret = 0; - struct SCSICmd *cmd = MakeSCSICmd(SZ_CDB_10); - - if (cmd == NULL) return TDERR_NoMem; + struct SCSICmd *cmd; + if ((cmd = scsi_get_unit_cmd(unit)) == NULL) return TDERR_NoMem; + cmd->scsi_CmdLength = SZ_CDB_10; cmd->scsi_Command[0] = SCSI_CMD_PLAY_AUDIO_MSF; cmd->scsi_Command[3] = start->minute; cmd->scsi_Command[4] = start->second; @@ -1295,10 +1290,9 @@ BYTE atapi_play_audio_msf(struct IDEUnit *unit, struct SCSI_TRACK_MSF *start, st cmd->scsi_Data = NULL; cmd->scsi_Length = 0; + scsi_release_unit_cmd(unit); ret = atapi_packet(cmd,unit); - DeleteSCSICmd(cmd); - return ret; } @@ -1341,7 +1335,7 @@ BYTE atapi_autosense(struct SCSICmd *scsi_command, struct IDEUnit *unit) { if (scsi_command->scsi_SenseData == NULL || scsi_command->scsi_SenseLength == 0) return IOERR_BADADDRESS; - struct SCSICmd *cmd = MakeSCSICmd(SZ_CDB_12); + struct SCSICmd *cmd = scsi_get_sense_cmd(unit); if (cmd != NULL) { for (int retry=3; retry > 0; retry--) { @@ -1359,8 +1353,7 @@ BYTE atapi_autosense(struct SCSICmd *scsi_command, struct IDEUnit *unit) { sleep_us(unit->itask->tr,250000); } - - DeleteSCSICmd(cmd); + scsi_release_sense_cmd(unit); return ret; } else { return TDERR_NoMem; diff --git a/device.c b/device.c index 5f85f96..7999303 100644 --- a/device.c +++ b/device.c @@ -25,7 +25,7 @@ #include "td64.h" #include "debug.h" #include "lide_alib.h" -#include "mounter/mounter.h" +#include "3rdparty/mounter/mounter.h" #ifdef FAKE_CONFIGDEV extern UBYTE bootblock, bootblock_end; @@ -139,10 +139,10 @@ struct ConfigDev *CreateFakeConfigDev(struct ExecBase *SysBase, struct Library * // cd_Rom.er_Reserved0c is used as a pointer to diagArea by strap ULONG *da_Pointer = (ULONG *)&cd->cd_Rom.er_Reserved0c; *da_Pointer = (ULONG)diagArea; + } else { + FreeConfigDev(cd); + cd = NULL; } - } else { - FreeConfigDev(cd); - cd = NULL; } return cd; } @@ -189,13 +189,13 @@ static BOOL FindCDFS() { struct FileSysResource *fsr = OpenResource(FSRNAME); struct FileSysEntry *fse; - if (fsr == NULL) return false; + if (fsr == NULL) return FALSE; for (fse = (struct FileSysEntry *)fsr->fsr_FileSysEntries.lh_Head; fse->fse_Node.ln_Succ != NULL; fse = (struct FileSysEntry *)fse->fse_Node.ln_Succ) { - if (fse->fse_DosType == 'CD01') return true; + if (fse->fse_DosType == 'CD01') return TRUE; } - return false; + return FALSE; } #endif @@ -250,12 +250,13 @@ static void Cleanup(struct DeviceBase *dev) { if (dev->ExpansionBase) CloseLibrary((struct Library *)dev->ExpansionBase); - struct IOTask *itask; + struct IOTask *itask, *next; for (itask = (struct IOTask *)dev->ideTasks.mlh_Head; itask->mn_Node.mln_Succ != NULL; - itask = (struct IOTask *)itask->mn_Node.mln_Succ) + itask = next) { + next = (struct IOTask *)itask->mn_Node.mln_Succ; itask->cd->cd_Flags |= CDF_CONFIGME; FreeMem(itask,sizeof(struct IOTask)); } @@ -619,7 +620,13 @@ static void open(struct DeviceBase *dev asm("a6"), struct IORequest *ioreq asm(" } -static void td_get_geometry(struct IOStdReq *ioreq) { +static BYTE td_get_geometry(struct IOStdReq *ioreq) { + if (ioreq->io_Data == NULL || ((ULONG)ioreq->io_Data & 1)) + return IOERR_BADADDRESS; + + if (ioreq->io_Length < sizeof(struct DriveGeometry)) + return IOERR_BADLENGTH; + struct DriveGeometry *geometry = (struct DriveGeometry *)ioreq->io_Data; struct IDEUnit *unit = (struct IDEUnit *)ioreq->io_Unit; @@ -642,6 +649,8 @@ static void td_get_geometry(struct IOStdReq *ioreq) { geometry->dg_Flags = (unit->flags.atapi) ? DGF_REMOVABLE : 0; ioreq->io_Actual = sizeof(struct DriveGeometry); + + return 0; } @@ -682,7 +691,6 @@ const UWORD supported_commands[] = TD_ADDCHANGEINT, TD_REMCHANGEINT, TD_REMOVE, - TD_PROTSTATUS, TD_CHANGENUM, TD_CHANGESTATE, TD_EJECT, @@ -766,8 +774,7 @@ static void begin_io(struct DeviceBase *dev asm("a6"), struct IOStdReq *ioreq as break; case TD_GETGEOMETRY: - td_get_geometry(ioreq); - error = 0; + error = td_get_geometry(ioreq); break; case TD_REMOVE: @@ -856,6 +863,10 @@ static void begin_io(struct DeviceBase *dev asm("a6"), struct IOStdReq *ioreq as // End IO Task commands // case NSCMD_DEVICEQUERY: + if (ioreq->io_Data == NULL || ((ULONG)ioreq->io_Data & 1)) { + error = IOERR_BADADDRESS; + break; + } if (ioreq->io_Length >= sizeof(struct NSDeviceQueryResult)) { struct NSDeviceQueryResult *result = ioreq->io_Data; @@ -1025,6 +1036,7 @@ void TweakBootList(struct ExecBase *SysBase, char *deviceName) { */ static struct Library * init(BPTR seg_list asm("a0")) { + BOOL CDBoot = FALSE; struct ExecBase *SysBase = *(struct ExecBase **)4UL; Info("Init driver.\n"); struct DeviceBase *mydev = (struct DeviceBase *)MakeLibrary((ULONG *)&device_vectors, // Vectors @@ -1033,7 +1045,9 @@ static struct Library * init(BPTR seg_list asm("a0")) sizeof(struct DeviceBase), // Library data size seg_list); // Segment list - BOOL CDBoot = FindCDFS(); +#ifdef CDBOOT + CDBoot = FindCDFS(); +#endif if (mydev != NULL) { Info("Add Device.\n"); diff --git a/device.h b/device.h index aa8ff56..bec8018 100644 --- a/device.h +++ b/device.h @@ -6,6 +6,7 @@ #define _DEVICE_H #include #include +#include #include #define OAHR_MANUF_ID 5194 #define BSC_MANUF_ID 2092 @@ -68,6 +69,8 @@ struct IDEUnit { ata_xfer_func write_unaligned; volatile UBYTE *shadowDevHead; volatile void *changeInt; + struct SCSICmd *scsiCmd; + struct SCSICmd *senseCmd; UBYTE unitNum; UBYTE deviceType; UBYTE last_error[6]; @@ -90,6 +93,8 @@ struct IDEUnit { unsigned char xferMultiple : 1; unsigned char lba : 1; unsigned char lba48 : 1; + unsigned char scsiCmdInUse : 1; + unsigned char senseCmdInUse : 1; } flags; }; diff --git a/iotask.c b/iotask.c index 38ab751..db07c90 100644 --- a/iotask.c +++ b/iotask.c @@ -202,7 +202,6 @@ static BYTE handle_scsi_command(struct IOStdReq *ioreq) { default: error = IOERR_NOCMD; - fake_scsi_sense(scsi_command,0,0,error); break; } } @@ -217,10 +216,13 @@ static BYTE handle_scsi_command(struct IOStdReq *ioreq) { Warn("SCSI: Error: %ld\n",error); Warn("SCSI: Command: %ld\n",scsi_command->scsi_Command); scsi_command->scsi_Status = SCSI_CHECK_CONDITION; + if (scsi_command->scsi_SenseActual == 0) + fake_scsi_sense(scsi_command,0,0,error); + return HFERR_BadStatus; } else { scsi_command->scsi_Status = 0; + return 0; } - return error; } /** @@ -256,6 +258,10 @@ static BYTE init_units(struct IOTask *itask) { unit->multipleCount = 0; unit->shadowDevHead = &itask->shadowDevHead; *unit->shadowDevHead = 0; + unit->scsiCmd = NULL; + unit->flags.scsiCmdInUse = false; + unit->senseCmd = NULL; + unit->flags.senseCmdInUse = false; // Initialize the change int list unit->changeInts.mlh_Tail = NULL; @@ -279,6 +285,8 @@ static BYTE init_units(struct IOTask *itask) { } else { // Clear this to skip the pre-select BSY wait later *unit->shadowDevHead = 0; + if (unit->scsiCmd) DeleteSCSICmd(unit->scsiCmd); + if (unit->senseCmd) DeleteSCSICmd(unit->senseCmd); FreeMem(unit,sizeof(struct IDEUnit)); } } @@ -309,6 +317,8 @@ static void cleanup(struct IOTask *itask) { ObtainSemaphore(&itask->dev->ulSem); Remove((struct Node *)unit); ReleaseSemaphore(&itask->dev->ulSem); + if (unit->scsiCmd != NULL) DeleteSCSICmd(unit->scsiCmd); + if (unit->senseCmd != NULL) DeleteSCSICmd(unit->senseCmd); FreeMem(unit,sizeof(struct IDEUnit)); } } diff --git a/scsi.c b/scsi.c index d8dedd3..45b5264 100644 --- a/scsi.c +++ b/scsi.c @@ -52,13 +52,23 @@ void fake_scsi_sense(struct SCSICmd* command, ULONG info, ULONG specific, BYTE e sense->asq = 0x00; break; case IOERR_BADADDRESS: - sense->senseKey = 0x03; + sense->senseKey = 0x05; // ILLEGAL REQUEST sense->asc = 0x21; // LBA Out of range sense->asq = 0x00; break; + case IOERR_BADLENGTH: + sense->senseKey = 0x05; // ILLEGAL REQUEST + sense->asc = 0x1A; // Parameter list length error + sense->asq = 0x00; + break; case IOERR_NOCMD: - sense->senseKey = 0x05; // Invalid Command operation code - sense->asc = 0x20; + sense->senseKey = 0x05; // ILLEGAL REQUEST + sense->asc = 0x20; // Invalid Command operation code + sense->asq = 0x00; + break; + case HFERR_BadStatus: + sense->senseKey = 0x05; // ILLEGAL REQUEST + sense->asc = 0x20; // Invalid Command operation code sense->asq = 0x00; break; case TDERR_NotSpecified: @@ -83,7 +93,7 @@ void fake_scsi_sense(struct SCSICmd* command, ULONG info, ULONG specific, BYTE e * @param cdbSize Size of CDB to create * @returns Pointer to an initialized SCSICmd struct */ -struct SCSICmd * MakeSCSICmd(ULONG cdbSize) { +struct SCSICmd *MakeSCSICmd(ULONG cdbSize) { struct ExecBase *SysBase = *(struct ExecBase **)4UL; UBYTE *cdb = NULL; struct SCSICmd *cmd = NULL; @@ -123,6 +133,106 @@ void DeleteSCSICmd(struct SCSICmd *cmd) { } } +/** + * scsi_lazy_alloc_cmd + * + * Lazily allocate (on first use) and clear a reusable SCSICmd + * + * If the SCSICmd pointed to by *cmd has not been allocated yet it is created + * with a SZ_CDB_12 sized CDB. The SCSICmd struct and its CDB are then cleared, + * preserving the CDB buffer for reuse. On allocation failure *cmd is left NULL. + * The caller is responsible for setting scsi_CmdLength and for freeing the + * SCSICmd via DeleteSCSICmd() when it is no longer needed. + * + * @param cmd Address of the SCSICmd pointer to allocate / reuse +*/ +static void scsi_lazy_alloc_cmd(struct SCSICmd **cmd) { + UBYTE *cdb; + struct SCSICmd *p; + + if (cmd == NULL) return; + + if (*cmd == NULL) { + *cmd = MakeSCSICmd(SZ_CDB_12); + } + p = *cmd; + if (p == NULL) return; + + cdb = p->scsi_Command; + memset(p,0,sizeof(struct SCSICmd)); + memset(cdb,0,SZ_CDB_12); + p->scsi_Command = cdb; + +} + +/** + * scsi_get_unit_cmd + * + * Get the unit's reusable SCSICmd, lazily allocating it on first use + * + * The SCSICmd is allocated once per unit and reused for subsequent commands to + * avoid repeated alloc/free cycles that lead to memory fragmentation. The + * command and its CDB are cleared before being returned. The caller is + * responsible for setting scsi_CmdLength. The cached SCSICmd is freed when the + * unit is torn down. + * + * NOT re-entrant: there is a single SCSICmd per unit, so a command obtained from + * this function must not still be in use when it is called again for the same + * unit. In particular, a function that has an outstanding SCSICmd must not call + * another function that also obtains one (e.g. issuing REQUEST SENSE while the + * original command is still live) - such nested users must use the separate + * sense SCSICmd via scsi_get_sense_cmd() instead. + * + * @param unit Pointer to an IDEUnit struct + * @returns Pointer to the unit's SCSICmd struct, or NULL on allocation failure +*/ +struct SCSICmd *scsi_get_unit_cmd(struct IDEUnit *unit) { + struct ExecBase *SysBase = unit->SysBase; + if (unit->flags.scsiCmdInUse == false) { + scsi_lazy_alloc_cmd(&unit->scsiCmd); + unit->flags.scsiCmdInUse = true; + return unit->scsiCmd; + } else { + Alert(0x01DEBAD1); + return NULL; + } +} + +/** + * scsi_get_sense_cmd + * + * Get the unit's reusable sense SCSICmd, lazily allocating it on first use + * + * This is a second per-unit SCSICmd, separate from the one returned by + * scsi_get_unit_cmd(). It exists so that REQUEST SENSE / autosense can be issued + * while a command obtained from scsi_get_unit_cmd() is still live, without the two + * aliasing each other (see the re-entrancy note on scsi_get_unit_cmd). The caller + * is responsible for setting scsi_CmdLength. The cached SCSICmd is freed when + * the unit is torn down. + * + * @param unit Pointer to an IDEUnit struct + * @returns Pointer to the unit's sense SCSICmd struct, or NULL on allocation failure +*/ +struct SCSICmd *scsi_get_sense_cmd(struct IDEUnit *unit) { + struct ExecBase *SysBase = unit->SysBase; + if (unit->flags.senseCmdInUse == false) { + scsi_lazy_alloc_cmd(&unit->senseCmd); + unit->flags.senseCmdInUse = true; + return unit->senseCmd; + } else { + Alert(0x01DEBAD2); + return NULL; + } +} + +void scsi_release_unit_cmd(struct IDEUnit *unit) { + unit->flags.scsiCmdInUse = false; +} + +void scsi_release_sense_cmd(struct IDEUnit *unit) { + unit->flags.senseCmdInUse = false; +} + /** * scsi_inquiry_emu * @@ -135,11 +245,9 @@ BYTE scsi_inquiry_emu(struct IDEUnit *unit, struct SCSICmd *scsi_command) { struct ExecBase *SysBase = unit->SysBase; struct SCSI_Inquiry *data = (struct SCSI_Inquiry *)scsi_command->scsi_Data; - BYTE error; - if (data == NULL) { + if (data == NULL) return IOERR_BADADDRESS; - } data->peripheral_type = unit->deviceType; data->removable_media = 0; @@ -148,17 +256,12 @@ BYTE scsi_inquiry_emu(struct IDEUnit *unit, struct SCSICmd *scsi_command) { data->additional_length = (sizeof(struct SCSI_Inquiry) - 4); UWORD *identity = AllocMem(512,MEMF_CLEAR|MEMF_ANY); - if (!identity) { - error = TDERR_NoMem; - fake_scsi_sense(scsi_command,0,0,error); - return error; - } + if (!identity) + return TDERR_NoMem; if (!(ata_identify(unit,identity))) { - error = HFERR_SelTimeout; - fake_scsi_sense(scsi_command,0,0,error); FreeMem(identity,512); - return error; + return HFERR_SelTimeout; } CopyMem(&identity[ata_identify_model],&data->vendor,24); @@ -186,13 +289,9 @@ BYTE scsi_inquiry_emu(struct IDEUnit *unit, struct SCSICmd *scsi_command) { */ BYTE scsi_read_capacity_10_emu(struct IDEUnit *unit, struct SCSICmd *scsi_command) { struct SCSI_CAPACITY_10 *data = (struct SCSI_CAPACITY_10 *)scsi_command->scsi_Data; - BYTE error; - if (data == NULL) { - error = IOERR_BADADDRESS; - fake_scsi_sense(scsi_command,0,0,error); - return error; - } + if (data == NULL) + return IOERR_BADADDRESS; struct SCSI_READ_CAPACITY_10 *cdb = (struct SCSI_READ_CAPACITY_10 *)scsi_command->scsi_Command; @@ -228,13 +327,9 @@ BYTE scsi_read_capacity_10_emu(struct IDEUnit *unit, struct SCSICmd *scsi_comman */ BYTE scsi_read_capacity_16_emu(struct IDEUnit *unit, struct SCSICmd *scsi_command) { struct SCSI_CAPACITY_16 *data = (struct SCSI_CAPACITY_16 *)scsi_command->scsi_Data; - BYTE error; - if (data == NULL) { - error = IOERR_BADADDRESS; - fake_scsi_sense(scsi_command,0,0,error); - return error; - } + if (data == NULL) + return IOERR_BADADDRESS; data->block_size = unit->blockSize; data->lba = unit->logicalSectors - 1; @@ -253,22 +348,17 @@ BYTE scsi_read_capacity_16_emu(struct IDEUnit *unit, struct SCSICmd *scsi_comman * @param scsi_command Pointer to a SCSICmd struct */ BYTE scsi_mode_sense_emu(struct IDEUnit *unit, struct SCSICmd *scsi_command) { - BYTE error; UBYTE *data = (APTR)scsi_command->scsi_Data; UBYTE *command = (APTR)scsi_command->scsi_Command; - if (data == NULL) { + if (data == NULL) return IOERR_BADADDRESS; - } UBYTE page = command[2] & 0x3F; UBYTE subpage = command[3]; - if (subpage != 0 || (page != 0x3F && page != 0x03 && page != 0x04)) { - error = HFERR_BadStatus; - fake_scsi_sense(scsi_command,0,0,error); - return error; - } + if (subpage != 0 || (page != 0x3F && page != 0x03 && page != 0x04)) + return IOERR_NOCMD; if (scsi_command->scsi_Length < ((page == 0x03 || page == 0x04) ? 28 : (page == 0x3f ? 52 : 0))) return IOERR_BADLENGTH; diff --git a/scsi.h b/scsi.h index bb4d8ab..3c08f3f 100644 --- a/scsi.h +++ b/scsi.h @@ -168,7 +168,11 @@ struct __attribute__((packed)) SCSI_CDB_ATA { #define ATA_BYT_BLOK (1<<2) void fake_scsi_sense(struct SCSICmd* command, ULONG info, ULONG specific, BYTE error); -struct SCSICmd * MakeSCSICmd(ULONG cdbSize); +struct SCSICmd *MakeSCSICmd(ULONG cdbSize); +struct SCSICmd *scsi_get_unit_cmd(struct IDEUnit *unit); +struct SCSICmd *scsi_get_sense_cmd(struct IDEUnit *unit); +void scsi_release_unit_cmd(struct IDEUnit *unit); +void scsi_release_sense_cmd(struct IDEUnit *unit); void DeleteSCSICmd(struct SCSICmd *cmd); BYTE scsi_inquiry_emu(struct IDEUnit *unit, struct SCSICmd *scsi_command); BYTE scsi_read_capacity_10_emu(struct IDEUnit *unit, struct SCSICmd *scsi_command);