; ;============================================================================= ; IMM DISK DRIVER ;============================================================================= ; ; PARALLEL PORT INTERFACE FOR SCSI DISK DEVICES USING A PARALLEL PORT ; ADAPTER. PRIMARILY TARGETS PARALLEL PORT IOMEGA ZIP DRIVES. ; ; CURRENTLY CODED SPECIFICALLY FOR RCBUS MG014 PARALLEL PORT HARDWARE. ; INTENDED TO CO-EXIST WITH LPT DRIVER. ; ; CREATED BY WAYNE WARTHEN FOR ROMWBW HBIOS. ; MUCH OF THE CODE IS DERIVED FROM FUZIX (ALAN COX). ; ; 5/23/2023 WBW - INITIAL RELEASE ; ;============================================================================= ; ; MG014 STYLE INTERFACE (USED BY RCBUS MG014 MODULE): ; ; PORT 0 (INPUT/OUTPUT): ; ; D7 D6 D5 D4 D3 D2 D1 D0 ; +-------+-------+-------+-------+-------+-------+-------+-------+ ; | PD7 | PD6 | PD5 | PD4 | PD3 | PD2 | PD1 | PD0 | ; +-------+-------+-------+-------+-------+-------+-------+-------+ ; ; PORT 1 (INPUT): ; ; D7 D6 D5 D4 D3 D2 D1 D0 ; +-------+-------+-------+-------+-------+-------+-------+-------+ ; | | | | /ERR | SEL | POUT | BUSY | /ACK | ; +-------+-------+-------+-------+-------+-------+-------+-------+ ; ; PORT 2 (INPUT/OUTPUT): ; ; D7 D6 D5 D4 D3 D2 D1 D0 ; +-------+-------+-------+-------+-------+-------+-------+-------+ ; | LED | | | | /SEL | /RES | /LF | /STB | ; +-------+-------+-------+-------+-------+-------+-------+-------+ ; ;============================================================================= ; ; TODO: ; ; - TIMEOUT IS INFINITE!!! ; ; - ASSIGN DRIVE LETTERS EVEN WHEN NO MEDIA AT BOOT ; ; - OPTIMIZE READ/WRITE LOOPS ; ; - COMMENT MORE OF THE CODE ; ; - THERE ARE CURRENTLY NO BUFFER OVERRUN CHECKS. WE ASSUME SCSI ; DEVICES WILL SEND/REQUEST THE EXPECTED NUMBER OF BYTES. ; ; - MAKE THE MG014 STATUS LED DO SOMETHING USEFUL? ; ; NOTES: ; ; - THIS DRIVER IS FOR THE ZIP DRIVE EMM INTERFACE. IT WILL SIMPLY ; FAIL TO EVEN RECOGNIZE A ZIP DRIVE WITH THE OLDER PPA INTERFACE. ; THERE DOES NOT SEEM TO BE A WAY TO VISUALLY DETERMINE IF A ZIP ; DRIVE IS EMM OR PPA. SIGH. ; ; - THERE ARE SOME HARD CODED TIMEOUT LOOPS IN THE CODE. THEY ARE ; WORKING OK ON A 7 MHZ Z80. THEY ARE LIKELY TO NEED TWEAKING ON ; FASTER CPUS. ; ; - THIS DRIVER OPERATES PURELY IN NIBBLE MODE. I SUSPECT IT IS ; POSSIBLE TO USE FULL BYTE MODE (PS2 STYLE), BUT I HAVE NOT ; ATTEMPTED IT. ; ; - RELATIVE TO ABOVE, THIS BEAST IS SLOW. IN ADDITION TO THE ; NIBBLE MODE READS, THE MG014 ASSIGNS SIGNALS DIFFERENTLY THAN ; THE STANDARD IBM PARALLEL PORT WHICH NECESSITATES A BUNCH OF EXTRA ; BIT FIDDLING ON EVERY READ. ; ; IMM PORT OFFSETS ; IMM_IODATA .EQU 0 ; PORT A, DATA, OUT IMM_IOSTAT .EQU 1 ; PORT B, STATUS, IN IMM_IOCTRL .EQU 2 ; PORT C, CTRL, OUT IMM_IOSETUP .EQU 3 ; PPI SETUP ; ; SCSI UNIT IDS ; IMM_SELF .EQU 7 IMM_TGT .EQU 6 ; ; SCSI COMMAND CODES ; SCSI_CMD_READ .EQU $08 SCSI_CMD_INQ .EQU $12 SCSI_CMD_TEST .EQU $00 SCSI_CMD_START .EQU $1B SCSI_CMD_SENSE .EQU $03 SCSI_CMD_WRITE .EQU $0A SCSI_CMD_RDCAP .EQU $25 ; ; IMM DEVICE STATUS ; IMM_STOK .EQU 0 IMM_STINVUNIT .EQU -1 IMM_STNOMEDIA .EQU -2 IMM_STCMDERR .EQU -3 IMM_STIOERR .EQU -4 IMM_STTO .EQU -5 IMM_STNOTSUP .EQU -6 ; ; IMM DEVICE CONFIGURATION ; IMM_CFGSIZ .EQU 12 ; SIZE OF CFG TBL ENTRIES ; ; PER DEVICE DATA OFFSETS IN CONFIG TABLE ENTRIES ; IMM_DEV .EQU 0 ; OFFSET OF DEVICE NUMBER (BYTE) IMM_MODE .EQU 1 ; OPERATION MODE: IMM MODE (BYTE) IMM_STAT .EQU 2 ; LAST STATUS (BYTE) IMM_IOBASE .EQU 3 ; IO BASE ADDRESS (BYTE) IMM_MEDCAP .EQU 4 ; MEDIA CAPACITY (DWORD) IMM_LBA .EQU 8 ; OFFSET OF LBA (DWORD) ; ;============================================================================= ; INITIALIZATION ENTRY POINT ;============================================================================= ; IMM_INIT: LD IY,IMM_CFG ; POINT TO START OF CONFIG TABLE ; IMM_INIT1: LD A,(IY) ; LOAD FIRST BYTE TO CHECK FOR END CP $FF ; CHECK FOR END OF TABLE VALUE JR NZ,IMM_INIT2 ; IF NOT END OF TABLE, CONTINUE XOR A ; SIGNAL SUCCESS RET ; AND RETURN ; IMM_INIT2: CALL NEWLINE ; FORMATTING PRTS("IMM:$") ; DRIVER LABEL ; PRTS(" IO=0x$") ; LABEL FOR IO ADDRESS LD A,(IY+IMM_IOBASE) ; GET IO BASE ADDRES CALL PRTHEXBYTE ; DISPLAY IT ; PRTS(" MODE=$") ; LABEL FOR MODE LD A,(IY+IMM_MODE) ; GET MODE BITS LD DE,IMM_STR_MODE_NONE ; MODE LABEL CP IMMMODE_NONE ; TEST FOR MODE JR Z,IMM_INIT3 ; IF SO, DISPLAY IT LD DE,IMM_STR_MODE_MG014 ; MODE LABEL CP IMMMODE_MG014 ; TEST FOR MODE JR Z,IMM_INIT3 ; IF SO, DISPLAY IT LD DE,IMM_STR_MODE_UNK ; MODE LABEL IMM_INIT3: CALL WRITESTR ; DISPLAY MODE ; ; CHECK FOR HARDWARE PRESENCE CALL IMM_DETECT ; PROBE FOR INTERFACE JR Z,IMM_INIT4 ; IF FOUND, CONTINUE CALL PC_SPACE ; FORMATTING LD DE,IMM_STR_NOHW ; NO IMM MESSAGE CALL WRITESTR ; DISPLAY IT JR IMM_INIT6 ; SKIP CFG ENTRY ; IMM_INIT4: ; UPDATE DRIVER RELATIVE UNIT NUMBER IN CONFIG TABLE LD A,(IMM_DEVNUM) ; GET NEXT UNIT NUM TO ASSIGN LD (IY+IMM_DEV),A ; UPDATE IT INC A ; BUMP TO NEXT UNIT NUM TO ASSIGN LD (IMM_DEVNUM),A ; SAVE IT ; ; ADD UNIT TO GLOBAL DISK UNIT TABLE LD BC,IMM_FNTBL ; BC := FUNC TABLE ADR PUSH IY ; CFG ENTRY POINTER POP DE ; COPY TO DE CALL DIO_ADDENT ; ADD ENTRY TO GLOBAL DISK DEV TABLE ; CALL IMM_RESET ; RESET/INIT THE INTERFACE ; ; START PRINTING DEVICE INFO CALL IMM_PRTPREFIX ; PRINT DEVICE PREFIX ; ; CHECK FOR BAD STATUS LD A,(IY+IMM_STAT) ; GET STATUS OR A ; SET FLAGS JP Z,IMM_INIT5 ; CONTINUE CALL PC_SPACE ; FORMATTING CALL IMM_PRTSTATSTR ; PRINT STATUS STRING JR IMM_INIT6 ; LOOP TILL DONE ; IMM_INIT5: ; PRINT STORAGE CAPACITY (BLOCK COUNT) PRTS(" BLOCKS=0x$") ; PRINT FIELD LABEL LD A,IMM_MEDCAP ; OFFSET TO CAPACITY FIELD CALL LDHLIYA ; HL := IY + A, REG A TRASHED CALL LD32 ; GET THE CAPACITY VALUE CALL PRTHEX32 ; PRINT HEX VALUE ; ; PRINT STORAGE SIZE IN MB PRTS(" SIZE=$") ; PRINT FIELD LABEL LD B,11 ; 11 BIT SHIFT TO CONVERT BLOCKS --> MB CALL SRL32 ; RIGHT SHIFT CALL PRTDEC32 ; PRINT DWORD IN DECIMAL PRTS("MB$") ; PRINT SUFFIX ; IMM_INIT6: LD DE,IMM_CFGSIZ ; SIZE OF CFG TABLE ENTRY ADD IY,DE ; BUMP POINTER JP IMM_INIT1 ; AND LOOP ; ;---------------------------------------------------------------------- ; PROBE FOR IMM HARDWARE ;---------------------------------------------------------------------- ; ; ON RETURN, ZF SET INDICATES HARDWARE FOUND ; IMM_DETECT: ; INITIALIZE 8255 LD A,(IY+IMM_IOBASE) ; BASE PORT ADD A,IMM_IOSETUP ; BUMP TO SETUP PORT LD C,A ; MOVE TO C FOR I/O LD A,$82 ; CONFIG A OUT, B IN, C OUT OUT (C),A ; DO IT CALL DELAY ; CALL IMM_DISCONNECT CALL IMM_CONNECT CALL IMM_DISCONNECT ; ; EXPECTING S1=$B8, S2=$18, S3=$38 LD A,(IMM_S1) CP $B8 RET NZ LD A,(IMM_S2) CP $18 RET NZ LD A,(IMM_S3) CP $38 RET NZ ; XOR A RET ; ;============================================================================= ; DRIVER FUNCTION TABLE ;============================================================================= ; IMM_FNTBL: .DW IMM_STATUS .DW IMM_RESET .DW IMM_SEEK .DW IMM_READ .DW IMM_WRITE .DW IMM_VERIFY .DW IMM_FORMAT .DW IMM_DEVICE .DW IMM_MEDIA .DW IMM_DEFMED .DW IMM_CAP .DW IMM_GEOM #IF (($ - IMM_FNTBL) != (DIO_FNCNT * 2)) .ECHO "*** INVALID IMM FUNCTION TABLE ***\n" #ENDIF ; IMM_VERIFY: IMM_FORMAT: IMM_DEFMED: SYSCHKERR(ERR_NOTIMPL) ; NOT IMPLEMENTED RET ; ; ; IMM_READ: CALL HB_DSKREAD LD A,SCSI_CMD_READ LD (IMM_CMD_RW),A JP IMM_IO ; ; ; IMM_WRITE: CALL HB_DSKREAD LD A,SCSI_CMD_WRITE LD (IMM_CMD_RW),A JP IMM_IO ; ; ; IMM_IO: LD (IMM_DSKBUF),HL ; SAVE DISK BUFFER ADDRESS CALL IMM_CHKERR ; CHECK FOR ERR STATUS AND RESET IF SO JR NZ,IMM_IO3 ; BAIL OUT ON ERROR ; ; SETUP LBA ; 3 BYTES, LITTLE ENDIAN -> BIG ENDIAN LD HL,IMM_CMD_RW+1 ; START OF LBA FIELD IN CDB (MSB) LD A,(IY+IMM_LBA+2) ; THIRD BYTE OF LBA FIELD IN CFG (MSB) LD (HL),A INC HL LD A,(IY+IMM_LBA+1) LD (HL),A INC HL LD A,(IY+IMM_LBA+0) LD (HL),A INC HL ; ; DO SCSI IO LD DE,(IMM_DSKBUF) LD BC,512 LD HL,IMM_CMD_RW CALL IMM_RUNCMD CALL Z,IMM_CHKCMD JR NZ,IMM_IO2 ; IF ERROR, SKIP INCREMENT ; INCREMENT LBA LD A,IMM_LBA ; LBA OFFSET CALL LDHLIYA ; HL := IY + A, REG A TRASHED CALL INC32HL ; INCREMENT THE VALUE ; INCREMENT DMA LD HL,IDE_DSKBUF+1 ; POINT TO MSB OF BUFFER ADR INC (HL) ; BUMP DMA BY INC (HL) ; ... 512 BYTES XOR A ; SIGNAL SUCCESS ; IMM_IO2: IMM_IO3: LD HL,(IMM_DSKBUF) ; CURRENT DMA TO HL OR A ; SET FLAGS BASED ON RETURN CODE RET Z ; RETURN IF SUCCESS LD A,ERR_IO ; SIGNAL IO ERROR OR A ; SET FLAGS RET ; AND DONE ; ; ; IMM_STATUS: ; RETURN UNIT STATUS LD A,(IY+IMM_STAT) ; GET STATUS OF SELECTED DEVICE OR A ; SET FLAGS RET ; AND RETURN ; ; ; IMM_RESET: JP IMM_INITDEV ; ; ; IMM_DEVICE: LD D,DIODEV_IMM ; D := DEVICE TYPE LD E,(IY+IMM_DEV) ; E := PHYSICAL DEVICE NUMBER LD C,%01000000 ; C := REMOVABLE HARD DISK LD H,(IY+IMM_MODE) ; H := MODE LD L,(IY+IMM_IOBASE) ; L := BASE I/O ADDRESS XOR A ; SIGNAL SUCCESS RET ; ; IMM_GETMED ; IMM_MEDIA: LD A,E ; GET FLAGS OR A ; SET FLAGS JR Z,IMM_MEDIA1 ; JUST REPORT CURRENT STATUS AND MEDIA ; CALL IMM_RESET ; RESET IMM INTERFACE ; IMM_MEDIA1: LD A,(IY+IMM_STAT) ; GET STATUS OR A ; SET FLAGS LD D,0 ; NO MEDIA CHANGE DETECTED LD E,MID_HD ; ASSUME WE ARE OK RET Z ; RETURN IF GOOD INIT LD E,MID_NONE ; SIGNAL NO MEDIA LD A,ERR_NOMEDIA ; NO MEDIA ERROR OR A ; SET FLAGS RET ; AND RETURN ; ; ; IMM_SEEK: BIT 7,D ; CHECK FOR LBA FLAG CALL Z,HB_CHS2LBA ; CLEAR MEANS CHS, CONVERT TO LBA RES 7,D ; CLEAR FLAG REGARDLESS (DOES NO HARM IF ALREADY LBA) LD (IY+IMM_LBA+0),L ; SAVE NEW LBA LD (IY+IMM_LBA+1),H ; ... LD (IY+IMM_LBA+2),E ; ... LD (IY+IMM_LBA+3),D ; ... XOR A ; SIGNAL SUCCESS RET ; AND RETURN ; ; ; IMM_CAP: LD A,(IY+IMM_STAT) ; GET STATUS PUSH AF ; SAVE IT LD A,IMM_MEDCAP ; OFFSET TO CAPACITY FIELD CALL LDHLIYA ; HL := IY + A, REG A TRASHED CALL LD32 ; GET THE CURRENT CAPACITY INTO DE:HL LD BC,512 ; 512 BYTES PER BLOCK POP AF ; RECOVER STATUS OR A ; SET FLAGS RET ; ; ; IMM_GEOM: ; FOR LBA, WE SIMULATE CHS ACCESS USING 16 HEADS AND 16 SECTORS ; RETURN HS:CC -> DE:HL, SET HIGH BIT OF D TO INDICATE LBA CAPABLE CALL IMM_CAP ; GET TOTAL BLOCKS IN DE:HL, BLOCK SIZE TO BC LD L,H ; DIVIDE BY 256 FOR # TRACKS LD H,E ; ... HIGH BYTE DISCARDED, RESULT IN HL LD D,16 | $80 ; HEADS / CYL = 16, SET LBA CAPABILITY BIT LD E,16 ; SECTORS / TRACK = 16 RET ; DONE, A STILL HAS IMM_CAP STATUS ; ;============================================================================= ; FUNCTION SUPPORT ROUTINES ;============================================================================= ; IMM_WRITEDATA: LD C,(IY+IMM_IOBASE) OUT (C),A CALL DELAY RET ; ; ; IMM_WRITECTRL: XOR $0B LD C,(IY+IMM_IOBASE) INC C INC C OUT (C),A CALL DELAY RET ; ; ; IMM_READSTATUS: LD C,(IY+IMM_IOBASE) INC C IN A,(C) LD C,0 ; INIT RESULT ; BIT 0,A ; ACK = $01 JR Z,IMM_READSTATUS1 SET 6,C ; $40 ; IMM_READSTATUS1: ; BIT 1,A ; BUSY = $02 JR NZ,IMM_READSTATUS2 SET 7,C ; $80 ; IMM_READSTATUS2: ; BIT 2,A ; PAPER = $04 JR Z,IMM_READSTATUS3 SET 5,C ; $20 ; IMM_READSTATUS3: ; BIT 3,A ; SELECT = $08 JR Z,IMM_READSTATUS4 SET 4,C ; $10 ; IMM_READSTATUS4: ; BIT 4,A ; FAULT = $10 JR Z,IMM_READSTATUS5 SET 3,C ; $08 ; IMM_READSTATUS5: LD A,C RET ; ; ; IMM_CPP: PUSH AF LD A,$0C CALL IMM_WRITECTRL LD A,$AA CALL IMM_WRITEDATA LD A,$55 CALL IMM_WRITEDATA LD A,$00 CALL IMM_WRITEDATA LD A,$FF CALL IMM_WRITEDATA CALL IMM_READSTATUS AND $B8 LD (IMM_S1),A LD A,$87 CALL IMM_WRITEDATA CALL IMM_READSTATUS AND $B8 LD (IMM_S2),A LD A,$78 CALL IMM_WRITEDATA CALL IMM_READSTATUS AND $38 LD (IMM_S3),A POP AF CALL IMM_WRITEDATA LD A,$0C CALL IMM_WRITECTRL LD A,$0D CALL IMM_WRITECTRL LD A,$0C CALL IMM_WRITECTRL LD A,$FF CALL IMM_WRITEDATA ; ; CONNECT: S1=$B8 S2=$18 S3=$30 ; DISCONNECT: S1=$B8 S2=$18 S3=$38 ; #IF (IMMTRACE >= 2) PRTS("\r\nCPP: S1=$") LD A,(IMM_S1) CALL PRTHEXBYTE PRTS(" S2=$") LD A,(IMM_S2) CALL PRTHEXBYTE PRTS(" S3=$") LD A,(IMM_S3) CALL PRTHEXBYTE #ENDIF ; XOR A ; ASSUME SUCCESS FOR NOW RET ; IMM_S1 .DB 0 IMM_S2 .DB 0 IMM_S3 .DB 0 ; ; ; IMM_CONNECT: LD A,$E0 CALL IMM_CPP LD A,$30 CALL IMM_CPP LD A,$E0 CALL IMM_CPP RET ; ; ; IMM_DISCONNECT: LD A,$30 CALL IMM_CPP RET ; ; ; IMM_RESETPULSE: LD A,$04 CALL IMM_WRITECTRL LD A,$40 CALL IMM_WRITEDATA CALL DELAY ; 16 US, IDEALLY, 1 US LD A,$0C CALL IMM_WRITECTRL LD A,$0D CALL IMM_WRITECTRL CALL DELAY ; 48 US, IDEALLY, 50 US CALL DELAY CALL DELAY LD A,$0C CALL IMM_WRITECTRL LD A,$04 CALL IMM_WRITECTRL RET ; ; ; IMM_SELECT: #IF IMMTRACE >= 2) PRTS("\r\nSELECT: $") #ENDIF LD A,$0C CALL IMM_WRITECTRL ; LD HL,500 ; TIMEOUT COUNTER ; IMM_SELECT1: CALL IMM_READSTATUS AND $08 JR Z,IMM_SELECT2 ; IF CLEAR, MOVE ON DEC HL LD A,H OR L JP Z,IMM_CMD_TIMEOUT ; TIMEOUT JR IMM_SELECT1 ; IMM_SELECT2: LD A,$04 CALL IMM_WRITECTRL LD A,$80 | (1 << IMM_TGT) CALL IMM_WRITEDATA CALL DELAY LD A,$0C CALL IMM_WRITECTRL ; #IF IMMTRACE >= 2) CALL IMM_READSTATUS CALL PC_SPACE CALL PRTHEXBYTE #ENDIF ; LD A,$0D CALL IMM_WRITECTRL ; #IF IMMTRACE >= 2) CALL IMM_READSTATUS CALL PC_SPACE CALL PRTHEXBYTE #ENDIF ; LD HL,500 ; TIMEOUT COUNTER ; IMM_SELECT3: CALL IMM_READSTATUS #IF IMMTRACE >= 2) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF AND $08 JR NZ,IMM_SELECT4 ; IF CLEAR, MOVE ON DEC HL LD A,H OR L JP Z,IMM_CMD_TIMEOUT ; TIMEOUT JR IMM_SELECT3 ; IMM_SELECT4: LD A,$0C CALL IMM_WRITECTRL ; XOR A RET ; ; ; IMM_SENDCMD: ; #IF IMMTRACE >= 2) PRTS("\r\nSENDCMD:$") #ENDIF ; LD HL,0 IMM_SENDCMD1: PUSH HL CALL IMM_WAITDONE POP HL CP $A8 JR NZ,IMM_SENDCMD2 LD A,$04 CALL IMM_WRITECTRL LD A,(DE) ; #IF IMMTRACE >= 2) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF ; CALL IMM_WRITEDATA INC DE INC HL LD A,$05 CALL IMM_WRITECTRL LD A,(DE) ; #IF IMMTRACE >= 2) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF ; CALL IMM_WRITEDATA INC DE INC HL LD A,$00 CALL IMM_WRITECTRL JR IMM_SENDCMD1 ; IMM_SENDCMD2: LD A,$04 CALL IMM_WRITECTRL ; #IF IMMTRACE >= 2) CALL PC_SPACE CALL PRTHEXWORDHL PRTS(" BYTES$") #ENDIF ; RET ; ; ; IMM_WAITBUSY: LD HL,500 ; NORMAL TIMEOUT COUNTER ; IMM_WAITBUSY_HL: ; VARIABLE TIMEOUT ENTRY LD A,$0C CALL IMM_WRITECTRL ; IMM_WAITBUSY2: CALL IMM_READSTATUS BIT 7,A RET NZ ; IF SET, MOVE ON DEC HL LD A,H OR L ; TODO: IMPLEMENT TIMEOUT!!! ;JP Z,IMM_CMD_TIMEOUT ; TIMEOUT JR IMM_WAITBUSY2 ; ; ; IMM_WAITDONE: LD HL,500 ; NORMAL TIMEOUT COUNTER ; IMM_WAITDONE_HL: ; VARIABLE TIMEOUT ENTRY CALL IMM_WAITBUSY_HL AND $B8 PUSH AF LD A,$04 CALL IMM_WRITECTRL POP AF RET ; ; ; IMM_NEGOTIATE: #IF IMMTRACE >= 2) PRTS("\r\nNEGO: $") #ENDIF LD A,$04 CALL IMM_WRITECTRL CALL DELAY ; 16 US, IDEALLY 5 US LD A,$00 CALL IMM_WRITEDATA LD DE,7 ; 112 US, IDEALLY 100 US CALL VDELAY LD A,$06 CALL IMM_WRITECTRL CALL DELAY ; 16 US, IDEALLY 5 US CALL IMM_READSTATUS PUSH AF ; SAVE RESULT CALL DELAY ; 16 US, IDEALLY 5 US LD A,$07 CALL IMM_WRITECTRL CALL DELAY ; 16 US, IDEALLY 5 US LD A,$06 CALL IMM_WRITECTRL ; POP AF ; #IF IMMTRACE >= 2) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF ; AND $20 ; #IF IMMTRACE >= 2) CALL PC_SPACE CALL PC_GT CALL PRTHEXBYTE #ENDIF ; CP $20 JP NZ,IMM_CMD_IOERR RET ; ; ; IMM_GETBYTE: CALL IMM_WAITBUSY LD A,$04 CALL IMM_WRITECTRL LD A,$06 CALL IMM_WRITECTRL CALL IMM_READSTATUS AND $F0 RRCA RRCA RRCA RRCA PUSH AF LD A,$05 CALL IMM_WRITECTRL CALL IMM_READSTATUS AND $F0 POP HL OR H PUSH AF LD A,$04 CALL IMM_WRITECTRL POP AF RET ; ; DE=BUFFER ; HL=LENGTH (0 FOR VARIABLE) ; IMM_GETDATA: LD A,H OR L JR NZ,IMM_GETDATALEN ; #IF IMMTRACE >= 2) PRTS("\r\nGETDATA:$") #ENDIF ; IMM_GETDATA1: PUSH HL CALL IMM_WAITDONE POP HL CP $98 JR NZ,IMM_GETDATA2 LD A,$04 CALL IMM_WRITECTRL LD A,$06 CALL IMM_WRITECTRL CALL IMM_READSTATUS AND $F0 RRCA RRCA RRCA RRCA PUSH AF LD A,$05 CALL IMM_WRITECTRL CALL IMM_READSTATUS AND $F0 POP BC OR B LD (DE),A INC DE INC HL LD A,$04 CALL IMM_WRITECTRL LD A,$0C CALL IMM_WRITECTRL JR IMM_GETDATA1 ; IMM_GETDATA2: ; #IF IMMTRACE >= 2) CALL PC_SPACE CALL PRTHEXWORDHL PRTS(" BYTES$") #ENDIF ; RET ; IMM_GETDATALEN: ; #IF IMMTRACE >= 2) PRTS("\r\nGETDLEN:$") CALL PC_SPACE CALL PRTHEXWORDHL PRTS(" BYTES$") #ENDIF ; LD A,$04 CALL IMM_WRITECTRL IMM_GETDATALEN1: LD A,$06 CALL IMM_WRITECTRL CALL IMM_READSTATUS AND $F0 RRCA RRCA RRCA RRCA PUSH AF LD A,$05 CALL IMM_WRITECTRL CALL IMM_READSTATUS AND $F0 POP BC OR B LD (DE),A INC DE DEC HL LD A,$04 CALL IMM_WRITECTRL LD A,H OR L JR NZ,IMM_GETDATALEN1 LD A,$0C CALL IMM_WRITECTRL RET ; ; DE=BUFFER ; HL=LENGTH (0 FOR VARIABLE) ; IMM_PUTDATA: LD A,H OR L JR NZ,IMM_PUTDATALEN ; #IF IMMTRACE >= 2) PRTS("\r\nPUTDATA:$") #ENDIF ; IMM_PUTDATA1: PUSH HL CALL IMM_WAITDONE POP HL CP $88 JR NZ,IMM_PUTDATA2 LD A,$04 CALL IMM_WRITECTRL LD A,(DE) CALL IMM_WRITEDATA INC DE INC HL LD A,$05 CALL IMM_WRITECTRL LD A,(DE) CALL IMM_WRITEDATA INC DE INC HL LD A,$00 CALL IMM_WRITECTRL JR IMM_PUTDATA1 ; IMM_PUTDATA2: LD A,$04 CALL IMM_WRITECTRL ; #IF IMMTRACE >= 2) CALL PC_SPACE CALL PRTHEXWORDHL PRTS(" BYTES$") #ENDIF ; RET ; IMM_PUTDATALEN: ; #IF IMMTRACE >= 2) PRTS("\r\nPUTDLEN:$") CALL PC_SPACE CALL PRTHEXWORDHL PRTS(" BYTES$") #ENDIF ; LD A,$04 CALL IMM_WRITECTRL IMM_PUTDATALEN1: LD A,(DE) CALL IMM_WRITEDATA INC DE DEC HL LD A,$05 CALL IMM_WRITECTRL LD A,(DE) CALL IMM_WRITEDATA INC DE DEC HL LD A,$00 CALL IMM_WRITECTRL LD A,H OR L JR NZ,IMM_PUTDATALEN1 LD A,$04 CALL IMM_WRITECTRL RET ; ; ; IMM_GETSTATUS: ; #IF IMMTRACE >= 2) PRTS("\r\nSTATUS:$") #ENDIF ; CALL IMM_GETBYTE LD (IMM_CMDSTAT),A ; #IF IMMTRACE >= 2) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF ; CALL IMM_WAITDONE CP $B8 RET NZ CALL IMM_GETBYTE LD (IMM_CMDSTAT+1),A ; #IF IMMTRACE >= 2) CALL PC_SPACE CALL PRTHEXBYTE #ENDIF ; RET ; ; ; IMM_ENDREAD: LD A,$04 CALL IMM_WRITECTRL LD A,$0C CALL IMM_WRITECTRL LD A,$0E CALL IMM_WRITECTRL LD A,$04 CALL IMM_WRITECTRL RET ; ; HL: COMMAND BUFFER ; DE: TRANSFER BUFFER ; BC: TRANSFER LENGTH (0=VARIABLE) ; IMM_RUNCMD: LD (IMM_CMDSTK),SP ; FOR ERROR ABORTS LD (IMM_DSKBUF),DE ; SAVE BUF PTR LD (IMM_XFRLEN),BC ; SAVE XFER LEN PUSH HL CALL IMM_CONNECT CALL IMM_SELECT CALL IMM_WAITBUSY POP DE CALL IMM_SENDCMD ; IMM_RUNCMD_PHASE: LD HL,50000 ; LONG TIMEOUT HERE CALL IMM_WAITDONE_HL ; #IF IMMTRACE >= 2) PRTS("\r\nPHASE: $") CALL PRTHEXBYTE #ENDIF ; CP $88 ; DEVICE WANTS TO RCV DATA JR Z,IMM_RUNCMD_WRITE CP $98 ; DEVICE WANTS TO SEND DATA JR Z,IMM_RUNCMD_READ CP $B8 ; DEVICE WANTS TO BE DONE JR Z,IMM_RUNCMD_END JR IMM_CMD_IOERR ; IMM_RUNCMD_WRITE: LD DE,(IMM_DSKBUF) LD HL,(IMM_XFRLEN) ; XFER LENGTH CALL IMM_PUTDATA ; SEND DATA NOW JR IMM_RUNCMD_PHASE ; IMM_RUNCMD_READ: CALL IMM_NEGOTIATE CALL IMM_WAITDONE ; CHECK FOR STATUS $98??? LD DE,(IMM_DSKBUF) LD HL,(IMM_XFRLEN) ; XFER LENGTH CALL IMM_GETDATA ; GET THE DATA NOW CALL IMM_ENDREAD JR IMM_RUNCMD_PHASE ; IMM_RUNCMD_END: CALL IMM_NEGOTIATE CALL IMM_WAITDONE ; CHECK FOR STATUS $B8??? CALL IMM_GETSTATUS CALL IMM_ENDREAD CALL IMM_DISCONNECT XOR A ; SIGNAL SUCCESS RET ; IMM_CMD_IOERR: LD A,IMM_STIOERR JR IMM_CMD_ERR ; IMM_CMD_TIMEOUT: LD A,IMM_STTO JR IMM_CMD_ERR ; IMM_CMD_ERR: LD SP,(IMM_CMDSTK) ; UNWIND STACK PUSH AF ; SAVE STATUS ;CALL IMM_RESETPULSE ; CLEAN UP THE MESS??? LD DE,62 CALL VDELAY CALL IMM_DISCONNECT LD DE,62 CALL VDELAY POP AF ; RECOVER STATUS JP IMM_ERR ; ERROR EXIT ; ; ; IMM_CHKCMD: ; SCSI COMMAND COMPLETED, CHECK SCSI CMD STATUS LD A,(IMM_CMDSTAT) ; GET STATUS BYTE OR A ; SET FLAGS RET Z ; IF ZERO, ALL GOOD, DONE ; ; DO WE HAVE A CHECK CONDITION? CP 2 ; CHECK CONDITION RESULT? JR Z,IMM_CHKCMD1 ; IF SO, REQUEST SENSE JP IMM_IOERR ; ELSE, GENERAL I/O ERROR ; IMM_CHKCMD1: ; USE REQUEST SENSE CMD TO GET ERROR DETAILS LD DE,HB_WRKBUF ; PUT DATA IN WORK BUF LD BC,0 ; VARIABLE LENGTH REQUEST LD HL,IMM_CMD_SENSE ; REQUEST SENSE CMD CALL IMM_RUNCMD ; DO IT JP NZ,IMM_IOERR ; BAIL IF ERROR IN CMD ; ; REQ SENSE CMD COMPLETED #IF IMMTRACE >= 2) LD A,16 LD DE,HB_WRKBUF CALL Z,PRTHEXBUF #ENDIF ; ; CHECK SCSI CMD STATUS LD A,(IMM_CMDSTAT) ; GET STATUS BYTE OR A ; SET FLAGS JP NZ,IMM_IOERR ; IF FAILED, GENERAL I/O ERROR ; ; RETURN RESULT BASED ON REQ SENSE DATA LD A,(HB_WRKBUF+12) ; GET ADDITIONAL SENSE CODE CP $3A ; NO MEDIA? JP Z,IMM_NOMEDIA ; IF SO, RETURN NO MEDIA ERR JP IMM_IOERR ; ELSE GENERAL I/O ERR ; ; CHECK CURRENT DEVICE FOR ERROR STATUS AND ATTEMPT TO RECOVER ; VIA RESET IF DEVICE IS IN ERROR. ; IMM_CHKERR: LD A,(IY+IMM_STAT) ; GET STATUS OR A ; SET FLAGS CALL NZ,IMM_RESET ; IF ERROR STATUS, RESET BUS RET ; ; (RE)INITIALIZE DEVICE ; IMM_INITDEV: ; INITIALIZE 8255 LD A,(IY+IMM_IOBASE) ; BASE PORT ADD A,IMM_IOSETUP ; BUMP TO SETUP PORT LD C,A ; MOVE TO C FOR I/O LD A,$82 ; CONFIG A OUT, B IN, C OUT OUT (C),A ; DO IT CALL DELAY ; CALL IMM_DISCONNECT CALL IMM_CONNECT CALL IMM_RESETPULSE LD DE,62 CALL VDELAY CALL IMM_DISCONNECT LD DE,62 CALL VDELAY ; LD B,4 IMM_INITDEV1: PUSH BC ; ; REQUEST SENSE COMMAND LD DE,HB_WRKBUF LD BC,0 LD HL,IMM_CMD_SENSE CALL IMM_RUNCMD JR NZ,IMM_INITDEV2 ; CMD PROC ERROR ; ; CHECK CMD STATUS LD A,(IMM_CMDSTAT) ; GET STATUS BYTE OR A ; SET FLAGS JR NZ,IMM_INITDEV2 ; BAD CMD STATUS ; #IF IMMTRACE >= 2) LD A,16 LD DE,HB_WRKBUF CALL PRTHEXBUF #ENDIF ; ; CHECK SENSE KEY LD A,(HB_WRKBUF + 2) OR A ; IMM_INITDEV2: POP BC JR Z,IMM_INITDEV3 ; IF NO ERROR, MOVE ON DJNZ IMM_INITDEV1 ; TRY UNTIL COUNTER EXHAUSTED JP IMM_IOERR ; HANDLE ERROR ; IMM_INITDEV3: ; READ & RECORD DEVICE CAPACITY LD DE,HB_WRKBUF LD BC,0 LD HL,IMM_CMD_RDCAP CALL IMM_RUNCMD CALL Z,IMM_CHKCMD RET NZ ; MEDIA PROBLEM ; #IF IMMTRACE >= 2) LD A,8 LD DE,HB_WRKBUF CALL PRTHEXBUF #ENDIF ; ; INCREMENT, BIG->LITTLE ENDIAN, SAVE LD A,IMM_MEDCAP ; OFFSET IN CFG FOR CAPACITY CALL LDHLIYA ; POINTER TO HL PUSH HL ; SAVE IT LD HL,HB_WRKBUF ; POINT TO VALUE IN CMD RESULT CALL LD32 ; LOAD IT TO DE:HL LD A,L ; FLIP BYTES LD L,D ; ... BIG ENDIAN LD D,A ; ... TO LITTLE ENDIAN LD A,H LD H,E LD E,A CALL INC32 ; INCREMENT TO FINAL VALUE POP BC ; RECOVER SAVE LOCATION CALL ST32 ; STORE VALUE ; XOR A ; SIGNAL SUCCESS LD (IY+IMM_STAT),A ; RECORD IT RET ;;;; ;;;; *** DEBUG *** ;;;; ;;; LD DE,HB_WRKBUF ;;; LD BC,512 ;;; LD HL,IMM_CMD_READ ;;; CALL IMM_RUNCMD ;;; CALL Z,IMM_CHKCMD ;;; LD DE,HB_WRKBUF ;;; CALL Z,DUMP_BUFFER ;;;; ;;; LD DE,HB_WRKBUF ;;; LD BC,512 ;;; LD HL,IMM_CMD_READ ;;; CALL IMM_RUNCMD ;;; CALL Z,IMM_CHKCMD ;;; LD DE,HB_WRKBUF ;;; CALL Z,DUMP_BUFFER ;;;; ;;; LD DE,HB_WRKBUF ;;; LD BC,0 ;;; LD HL,IMM_CMD_INQ ;;; CALL IMM_RUNCMD ;;; CALL Z,IMM_CHKCMD ;;; LD DE,HB_WRKBUF ;;; CALL Z,DUMP_BUFFER ;;;; ;;; LD DE,HB_WRKBUF ;;; LD BC,512 ;;; LD HL,IMM_CMD_WRITE ;;; CALL IMM_RUNCMD ;;; CALL Z,IMM_CHKCMD ;;;; ;;; LD DE,HB_WRKBUF ;;; LD BC,512 ;;; LD HL,IMM_CMD_READ2 ;;; CALL IMM_RUNCMD ;;; CALL Z,IMM_CHKCMD ;;; LD DE,HB_WRKBUF ;;; CALL Z,DUMP_BUFFER ;;;; ;;; RET ;;;; ;;;IMM_CMD .DB $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 ; TEMPLATE ;;;IMM_CMD_READ .DB $08, $00, $00, $00, $01, $00 ; READ SECTOR $0000 ;;;IMM_CMD_INQ .DB $12, $00, $00, $00, $FF, $00 ; INQUIRY ;;;IMM_CMD_TEST .DB $00, $00, $00, $00, $00, $00 ; TEST UNIT READY ;;;IMM_CMD_START .DB $1B, $00, $00, $00, $01, $00 ; START UNIT ;;;IMM_CMD_WRITE .DB $0A, $00, $F0, $00, $01, $00 ; READ SECTOR $F000 ;;;IMM_CMD_READ2 .DB $08, $00, $F0, $00, $01, $00 ; READ SECTOR $F000 ; ;============================================================================= ; ERROR HANDLING AND DIAGNOSTICS ;============================================================================= ; ; ERROR HANDLERS ; IMM_INVUNIT: LD A,IMM_STINVUNIT JR IMM_ERR2 ; SPECIAL CASE FOR INVALID UNIT ; IMM_NOMEDIA: LD A,IMM_STNOMEDIA JR IMM_ERR ; IMM_CMDERR: LD A,IMM_STCMDERR JR IMM_ERR ; IMM_IOERR: LD A,IMM_STIOERR JR IMM_ERR ; IMM_TO: LD A,IMM_STTO JR IMM_ERR ; IMM_NOTSUP: LD A,IMM_STNOTSUP JR IMM_ERR ; IMM_ERR: LD (IY+IMM_STAT),A ; SAVE NEW STATUS ; IMM_ERR2: #IF (IMMTRACE >= 2) CALL IMM_PRTSTAT #ENDIF OR A ; SET FLAGS RET ; ; ; IMM_PRTERR: RET Z ; DONE IF NO ERRORS ; FALL THRU TO IMM_PRTSTAT ; ; PRINT FULL DEVICE STATUS LINE ; IMM_PRTSTAT: PUSH AF PUSH DE PUSH HL LD A,(IY+IMM_STAT) CP IMM_STINVUNIT JR Z,IMM_PRTSTAT2 ; INVALID UNIT IS SPECIAL CASE CALL IMM_PRTPREFIX ; PRINT UNIT PREFIX JR IMM_PRTSTAT3 IMM_PRTSTAT2: CALL NEWLINE PRTS("IMM:$") ; NO UNIT NUM IN PREFIX FOR INVALID UNIT IMM_PRTSTAT3: CALL PC_SPACE ; FORMATTING CALL IMM_PRTSTATSTR POP HL POP DE POP AF RET ; ; PRINT STATUS STRING ; IMM_PRTSTATSTR: PUSH AF PUSH DE LD A,(IY+IMM_STAT) OR A LD DE,IMM_STR_STOK JR Z,IMM_PRTSTATSTR1 INC A LD DE,IMM_STR_STINVUNIT JR Z,IMM_PRTSTATSTR1 INC A LD DE,IMM_STR_STNOMEDIA JR Z,IMM_PRTSTATSTR1 INC A LD DE,IMM_STR_STCMDERR JR Z,IMM_PRTSTATSTR1 INC A LD DE,IMM_STR_STIOERR JR Z,IMM_PRTSTATSTR1 INC A LD DE,IMM_STR_STTO JR Z,IMM_PRTSTATSTR1 INC A LD DE,IMM_STR_STNOTSUP JR Z,IMM_PRTSTATSTR1 LD DE,IMM_STR_STUNK IMM_PRTSTATSTR1: CALL WRITESTR POP DE POP AF RET ; ; PRINT DIAGNONSTIC PREFIX ; IMM_PRTPREFIX: PUSH AF CALL NEWLINE PRTS("IMM$") LD A,(IY+IMM_DEV) ; GET CURRENT DEVICE NUM CP $FE ; NOT YET ASSIGNED? JR Z,IMM_PRTPREFIX1 ; SKIP DEV NUM IF SO CALL PRTDECB IMM_PRTPREFIX1: CALL PC_COLON POP AF RET ; ;============================================================================= ; STRING DATA ;============================================================================= ; IMM_STR_STOK .TEXT "OK$" IMM_STR_STINVUNIT .TEXT "INVALID UNIT$" IMM_STR_STNOMEDIA .TEXT "NO MEDIA$" IMM_STR_STCMDERR .TEXT "COMMAND ERROR$" IMM_STR_STIOERR .TEXT "IO ERROR$" IMM_STR_STTO .TEXT "TIMEOUT$" IMM_STR_STNOTSUP .TEXT "NOT SUPPORTED$" IMM_STR_STUNK .TEXT "UNKNOWN ERROR$" ; IMM_STR_NOHW .TEXT "NOT PRESENT$" ; IMM_STR_MODE_NONE .TEXT "NONE$" IMM_STR_MODE_MG014 .TEXT "MG014$" IMM_STR_MODE_UNK .TEXT "???$" ; ;============================================================================= ; DATA STORAGE ;============================================================================= ; IMM_DEVNUM .DB 0 ; TEMP DEVICE NUM USED DURING INIT IMM_CMDSTK .DW 0 ; STACK PTR FOR CMD ABORTING IMM_DSKBUF .DW 0 ; WORKING DISK BUFFER POINTER IMM_XFRLEN .DW 0 ; WORKING TRANSFER LENGTH IMM_CMDSTAT .DB 0, 0 ; CMD RESULT STATUS ; IMM_TYPE_MAP: .DW IMM_STR_NONE .DW IMM_STR_MG014 ; IMM_STR_NONE .DB "$" IMM_STR_MG014 .DB "MG014$" ; ; SCSI COMMAND TEMPLATES ; IMM_CMD_RW .DB $00, $00, $00, $00, $01, $00 ; READ/WRITE SECTOR IMM_CMD_SENSE .DB $03, $00, $00, $00, $FF, $00 ; REQUEST SENSE DATA IMM_CMD_RDCAP .DB $25, $00, $00, $00, $00, $00, $00, $00, $00, $00 ; READ CAPACITY ; ; IMM DEVICE CONFIGURATION TABLE ; IMM_CFG: ; #IF (IMMCNT >= 1) ; IMM0_CFG: ; DEVICE 0 .DB 0 ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY) .DB IMM0MODE ; DRIVER DEVICE MODE .DB 0 ; DEVICE STATUS .DB IMM0BASE ; IO BASE ADDRESS .DW 0,0 ; DEVICE CAPACITY .DW 0,0 ; CURRENT LBA #ENDIF ; #IF (IMMCNT >= 2) ; IMM1_CFG: ; DEVICE 1 .DB 0 ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY) .DB IMM1MODE ; DRIVER DEVICE MODE .DB 0 ; DEVICE STATUS .DB IMM1BASE ; IO BASE ADDRESS .DW 0,0 ; DEVICE CAPACITY .DW 0,0 ; CURRENT LBA #ENDIF ; #IF ($ - IMM_CFG) != (IMMCNT * IMM_CFGSIZ) .ECHO "*** INVALID IMM CONFIG TABLE ***\n" #ENDIF ; .DB $FF ; END MARKER