; ;============================================================================= ; SCSI DISK DRIVER FOR 5380 ;============================================================================= ; ; DISK DEVICE DRIVER FOR THE 5380 SCSI CHIP. ; DERIVED FROM CODE PROVIDED BY JAY COTTON. ; ; TODO: ; ; NOTES: ; SCSIBASE .EQU $40 ; ; SCSI DEVICE STATUS CODES ; SCSI_STOK .EQU 0 SCSI_STNOMEDIA .EQU -1 SCSI_STIOERR .EQU -2 SCSI_STTO .EQU -3 SCSI_STNOTRDY .EQU -4 ; ; NCR 5380 I/O REGISTERS ; SCSI_SR_CSD .EQU SCSIBASE ; CURRENT SCSI DATA SCSI_SR_ICR .EQU SCSIBASE + $01 ; INITIATOR COMMAND SCSI_SR_MR .EQU SCSIBASE + $02 ; MODE SCSI_SR_TCR .EQU SCSIBASE + $03 ; TARGET COMMAND SCSI_SR_CSBS .EQU SCSIBASE + $04 ; CURRENT SCSI BUS STAT. SCSI_SR_BSR .EQU SCSIBASE + $05 ; BUS STATUS SCSI_SR_IDR .EQU SCSIBASE + $06 ; INITIATOR DMA RECV. SCSI_SR_RPI .EQU SCSIBASE + $07 ; RESET PARITY/IRQ ; ; NCR 5380 OUTPUT ONLY REGISTERS ; SCSI_SR_ODR .EQU SCSIBASE ; OUTPUT DATA SCSI_SR_SER .EQU SCSIBASE + $04 ; SELECT ENABLE SCSI_SR_SDS .EQU SCSIBASE + $05 ; START DMA SEND SCSI_SR_SDTR .EQU SCSIBASE + $06 ; START TARGET DMA RECV. SCSI_SR_SDIR .EQU SCSIBASE + $07 ; START INITIATOR DMA RECV. ; ; SCSI CURRENT BUS STATUS BIT MASKS ; SCSI_SM_RST .EQU $80 ; RESET SCSI_SM_BSY .EQU $40 ; BUSY SCSI_SM_REQ .EQU $20 ; REQUEST SCSI_SM_MSG .EQU $10 ; MESSAGE SCSI_SM_CD .EQU $08 ; CMD/DATA SCSI_SM_IO .EQU $04 ; IN/OUT SCSI_SM_SEL .EQU $02 ; SELECT SCSI_SM_DBP .EQU $01 ; PARITY BIT ; SCSI_SM_PHM .EQU $08 ; PHASE MATCH BIT ; ; SDCI DEVICE CONFIGURATION ; ; PER DEVICE DATA OFFSETS IN CFG BLOCK ; SCSI_DEV .EQU 0 ; OFFSET OF DEVICE NUMBER (BYTE) SCSI_IOBASE .EQU 1 ; IO BASE ADDRESS (BYTE) SCSI_LUN .EQU 2 ; TARGET LUN SCSI_STAT .EQU 3 ; LAST STATUS (BYTE) SCSI_MEDCAP .EQU 4 ; MEDIA CAPACITY (DWORD) SCSI_LBA .EQU 8 ; OFFSET OF LBA (DWORD) ; ;-------------------------------------------------------------------------------------------------- ; HBIOS MODULE HEADER ;-------------------------------------------------------------------------------------------------- ; ORG_SCSI .EQU $ ; .DW SIZ_SCSI ; MODULE SIZE .DW SCSI_INITPHASE ; ADR OF INIT PHASE HANDLER ; SCSI_INITPHASE: ; INIT PHASE HANDLER, A=PHASE ;CP HB_PHASE_PREINIT ; PREINIT PHASE? ;JP Z,SCSI_PREINIT ; DO PREINIT CP HB_PHASE_INIT ; INIT PHASE? JP Z,SCSI_INIT ; DO INIT RET ; DONE ; SCSI_CFGSIZ .EQU 12 ; SIZE OF CFG TBL ENTRIES ; SCSI_CFGTBL: ; #IF (SCSICNT >= 1) ; SCSI0_CFG: .DB $FE ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY) .DB SCSIBASE ; IO BASE ADDRESS .DB SCSI0_LUN ; SCSI TARGET LUN .DB SCSI_STNOTRDY ; DEVICE STATUS .DW $0000,$0010 ; DEVICE CAPACITY (BLOCKS) .DW 0,0 ; CURRENT LBA ; DEVECHO "SCSI: IO=" DEVECHO SCSIBASE DEVECHO ", TGT ID=" DEVECHO SCSI_TID DEVECHO ", LUN=" DEVECHO SCSI0_LUN DEVECHO "\n" #ENDIF ; #IF (SCSICNT >= 2) .DB $FE ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY) .DB SCSIBASE ; IO BASE ADDRESS .DB SCSI1_LUN ; SCSI TARGET LUN .DB SCSI_STNOTRDY ; DEVICE STATUS .DW $0000,$0010 ; DEVICE CAPACITY (BLOCKS) .DW 0,0 ; CURRENT LBA ; DEVECHO "SCSI: IO=" DEVECHO SCSIBASE DEVECHO ", TGT ID=" DEVECHO SCSI_TID DEVECHO ", LUN=" DEVECHO SCSI1_LUN DEVECHO "\n" #ENDIF ; #IF ($ - SCSI_CFGTBL) != (SCSICNT * SCSI_CFGSIZ) .ECHO "*** INVALID SCSI CONFIG TABLE ***\n" #ENDIF ; .DB $FF ; END OF TABLE MARKER ; ;============================================================================= ; INITIALIZATION ENTRY POINT ;============================================================================= ; SCSI_INIT: CALL NEWLINE ; FORMATTING PRTS("SCSI:$") ; TAG ; PRTS(" IO=0x$") ; LABEL FOR IO ADDRESS LD A,SCSIBASE ; GET IO BASE ADDRES CALL PRTHEXBYTE ; DISPLAY IT ; CALL SCSI_DETECT ; DETECT THE SCSI INTERFACE JR Z,SCSI_INIT1 ; IF FOUND CONTINUE PRTS(" NOT PRESENT$") ; SHOW NOT PRESENT XOR A ; SUCCESS RET ; AND BAIL OUT ; SCSI_INIT1: PRTS(" TGT_ID=$") ; LABEL FOR IO ADDRESS LD A,SCSI_TID ; GET IO BASE ADDRES CALL PRTDEC8 ; DISPLAY IT ; XOR A ; ZERO ACCUM LD (SCSI_DEVNUM),A ; INIT DEV UNIT NUM FOR DYNAMIC ASSIGNMENT LD IY,SCSI_CFGTBL ; POINT TO START OF CONFIG TABLE ; SCSI_INIT2: LD A,(IY) ; LOAD FIRST BYTE TO CHECK FOR END CP $FF ; CHECK FOR END OF TABLE VALUE RET Z ; RETURN IF DONE ; CALL SCSI_INIT3 ; REGISTER & INIT DEVICE ; LD DE,SCSI_CFGSIZ ; SIZE OF CFG TABLE ENTRY ADD IY,DE ; BUMP POINTER JP SCSI_INIT2 ; AND LOOP ; SCSI_INIT3: ; UPDATE DRIVER RELATIVE UNIT NUMBER IN CONFIG TABLE LD A,(SCSI_DEVNUM) ; GET NEXT UNIT NUM TO ASSIGN LD (IY+SCSI_DEV),A ; UPDATE IT INC A ; BUMP TO NEXT UNIT NUM TO ASSIGN LD (SCSI_DEVNUM),A ; SAVE IT ; ; ADD UNIT TO GLOBAL DISK UNIT TABLE LD BC,SCSI_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 SCSI_PRTPREFIX ; TAG FOR ACTIVE DEVICE ; PRTS(" LUN=$") ; LUN LABEL LD A,(IY+SCSI_LUN) ; LOAD LUN CALL PRTDEC8 ; DISPLAY IT ; CALL SCSI_INITDEV ; INITIALIZE DEVICE #IF (SCSITRACE < 2) JP NZ,SCSI_PRTSTATSTR ; IF ERROR, EXIT VIA PRINT #ELSE RET NZ #ENDIF ; ; PRINT STORAGE CAPACITY (BLOCK COUNT) PRTS(" BLOCKS=0x$") ; PRINT FIELD LABEL LD A,SCSI_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 ; ; PRINT INQUIRY DATA (STILL IN HB_WRKBUF FROM INITDEV) CALL PC_SPACE ; FORMATTING CALL PC_LBKT ; FORMATTING LD HL,HB_WRKBUF+8 ; START OF ASCII DATA LD B,28 ; VENDOR, PRODUCT, AND REVISTION FIELDS SCSI_INIT4: LD A,(HL) ; LOAD NEXT CHAR CALL COUT ; PRINT IT INC HL ; BUMP BUFFER POINTER DJNZ SCSI_INIT4 ; LOOP AS NEEDED CALL PC_RBKT ; FORMATTING ; SCSI_INIT5: XOR A ; SUCCESS RET ; ;============================================================================= ; DRIVER FUNCTION TABLE ;============================================================================= ; SCSI_FNTBL: .DW SCSI_STATUS .DW SCSI_RESET .DW SCSI_SEEK .DW SCSI_READ .DW SCSI_WRITE .DW SCSI_VERIFY .DW SCSI_FORMAT .DW SCSI_DEVICE .DW SCSI_MEDIA .DW SCSI_DEFMED .DW SCSI_CAP .DW SCSI_GEOM #IF (($ - SCSI_FNTBL) != (DIO_FNCNT * 2)) .ECHO "*** INVALID SCSI FUNCTION TABLE ***\n" #ENDIF ; SCSI_VERIFY: SCSI_FORMAT: SCSI_DEFMED: SYSCHKERR(ERR_NOTIMPL) ; NOT IMPLEMENTED RET ; ; ; SCSI_READ: CALL HB_DSKREAD ; HOOK HBIOS DISK READ SUPERVISOR LD E,SCSI_CMD_READ ; SETUP READ COMMAND JP SCSI_IO ; DO THE IO ; ; ; SCSI_WRITE: CALL HB_DSKWRITE ; HOOK HBIOS DISK WRITE SUPERVISOR LD E,SCSI_CMD_WRITE ; SETUP WRITE COMMAND JP SCSI_IO ; DO THE IO ; ; ; SCSI_STATUS: LD A,(IY+SCSI_STAT) ; GET STATUS OF SELECTED DEVICE OR A ; SET FLAGS RET ; AND RETURN ; ; ; SCSI_RESET: CALL SCSI_INITDEV ; REINITIALIZE UNIT OR A ; SET RESULT FLAGS RET ; ; ; SCSI_DEVICE: LD D,DIODEV_SCSI ; D := DEVICE TYPE LD E,(IY+SCSI_DEV) ; E := PHYSICAL DEVICE NUMBER LD C,%00110000 ; C := GENERIC HARD DISK ATTRIBUTES LD H,0 ; H := MODE LD L,(SCSI_IOBASE) ; L := BASE I/O ADDRESS XOR A ; SIGNAL SUCCESS RET ; ; ; SCSI_MEDIA: LD A,E ; GET FLAGS OR A ; SET FLAGS JR Z,SCSI_MEDIA1 ; JUST REPORT CURRENT STATUS AND MEDIA CALL SCSI_INITDEV ; REINITIALIZE DEVICE ; SCSI_MEDIA1: LD A,(IY+SCSI_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 ; ; ; SCSI_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+SCSI_LBA+0),L ; SAVE NEW LBA LD (IY+SCSI_LBA+1),H ; ... LD (IY+SCSI_LBA+2),E ; ... LD (IY+SCSI_LBA+3),D ; ... XOR A ; SIGNAL SUCCESS RET ; AND RETURN ; ; ; SCSI_CAP: LD A,(IY+SCSI_STAT) ; GET STATUS PUSH AF ; SAVE IT LD A,SCSI_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 ; ; ; SCSI_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 SCSI_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 SCSI_CAP STATUS ; ;============================================================================= ; FUNCTION SUPPORT ROUTINES ;============================================================================= ; ; ON RETURN, ZF SET INDICATES HARDWARE FOUND ; SCSI_DETECT: LD C,SCSIBASE+3 LD A,$05 OUT (C),A NOP IN A,(C) CP $05 RET NZ LD A,$0A OUT (C),A NOP IN A,(C) CP $0A RET ; ; INITIALIZE DEVICE ; SCSI_INITDEV: ; INQUIRY COMMAND TO DETERMINE IF DEVICE EXISTS LD HL,HB_WRKBUF ; BUFFER FOR INQUIRY DATA CALL SCSI_INQUIRY ; RUN THE COMMAND JP NZ,SCSI_NOMEDIA ; CONVERT FAILURE TO NO MEDIA ; ; GET DEVICE CAPACITY CALL SCSI_CAPACITY RET NZ ; XOR A LD (IY+SCSI_STAT),A RET ; ; ; SCSI_IO: ; #IF (ESPSDTRACE == 1) PUSH HL LD HL,SCSI_PRTERR ; SET UP ESPSD_PRTERR EX (SP),HL ; ... TO FILTER ALL EXITS #ENDIF ; LD (SCSI_DSKBUF),HL ; SAVE DISK BUFFER ADDRESS PUSH DE ; SAVE COMMAND BYTE PUSH HL ; SAVE BUFFER ADDRESS CALL SCSI_CHKERR ; CHECK FOR ERR STATUS AND RESET IF SO POP HL ; RESTORE BUFFER ADDRESS POP DE ; RESTORE COMMAND BYTE RET NZ ; BAIL OUT ON ERROR ; ; SETUP SCSI COMMAND LD A,E LD (SCSI_S_CDB),A ; SET SCSI COMMAND ; SETUP DISK BUFFER POINTERS LD (SCSI_BUF_OUT),HL ; INPUT BUFFER LD (SCSI_BUF_IN),HL ; OUTPUT BUFFER ; SETUP CDB LD HL,SCSI_S_CDB ; SET HL TO R/W CBD LD (SCSI_CUR_CDB),HL ; SAVE IN IOT ; SETUP LUN/LBA LD A,(IY+SCSI_LUN) ; PUT LUN IN ACCUM RRCA ; MOVE TO TOP 3 BITS RRCA ; ... RRCA ; ... LD B,A ; SAVE IN B LD A,(IY+SCSI_LBA+2) ; GET MSB OF LBA AND %00011111 ; CLEAR LUN BITS OR B ; MERGE WITH LUN LD (SCSI_CUR_LUN),A ; PUT IN CDB LD A,(IY+SCSI_LBA+1) ; LBA MID LD (SCSI_CUR_LBN),A ; PUT IN CDB LD A,(IY+SCSI_LBA+0) ; LBA MID LD (SCSI_CUR_LBN+1),A ; PUT IN CDB ; DO THE SCSI TRANSACTION CALL SCSI_GO ; DO THE SCSI TRANSACTION JR NZ,SCSI_IO1 ; IF ERROR, SKIP INCREMENT ; INCREMENT LBA LD A,SCSI_LBA ; LBA OFFSET CALL LDHLIYA ; HL := IY + A, REG A TRASHED CALL INC32HL ; INCREMENT THE VALUE ; INCREMENT DMA LD HL,SCSI_DSKBUF+1 ; POINT TO MSB OF BUFFER ADR INC (HL) ; BUMP DMA BY INC (HL) ; ... 512 BYTES XOR A ; SIGNAL SUCCESS SCSI_IO1: LD HL,(SCSI_DSKBUF) ; CURRENT DMA TO HL OR A ; SET FLAGS RET Z ; DONE IF NO ERROR LD A,ERR_IO ; SIGNAL IO ERROR OR A ; SET FLAGS RET ; AND DONE ; ; CHECK CURRENT DEVICE FOR ERROR STATUS AND ATTEMPT TO RECOVER ; VIA RESET IF DEVICE IS IN ERROR. ; SCSI_CHKERR: LD A,(IY+SCSI_STAT) ; GET STATUS OR A ; SET FLAGS CALL NZ,SCSI_RESET ; IF ERROR STATUS, RESET BUS RET ; ; ISSUE SCSI INQUIRY COMMAND ; ON INPUT, HL POINTS TO OUTPUT DATA BUFFER ; SCSI_INQUIRY: ; SETUP BUFFER POINTERS LD (SCSI_BUF_OUT),HL ; INPUT BUFFER LD (SCSI_BUF_IN),HL ; OUTPUT BUFFER ; SETUP INQUIRY CDB LD HL,SCSI_S_INQ ; SET HL TO INQ CBD LD (SCSI_CUR_CDB),HL ; SAVE IN IOT ; SETUP LUN LD A,(IY+SCSI_LUN) ; PUT LUN IN ACCUM RRCA ; MOVE TO TOP 3 BITS RRCA ; ... RRCA ; ... LD (SCSI_INQ_LUN),A ; PUT IN INQ CDB ; DO THE SCSI TRANSACTION JP SCSI_GO ; DO THE SCSI TRANSACTION ; ; ISSUE SCSI CAPACITY COMMAND AND CAPTURE ; RESULTS AS DEVICE CAPACITY ; SCSI_CAPACITY: ; SETUP BUFFER POINTERS LD HL,SCSI_CAP_BUF LD (SCSI_BUF_OUT),HL ; INPUT BUFFER LD (SCSI_BUF_IN),HL ; OUTPUT BUFFER ; SETUP READ CAPACITY CDB LD HL,SCSI_S_CAP ; SET HL TO CAP CBD LD (SCSI_CUR_CDB),HL ; SAVE IN IOT ; SETUP LUN LD A,(IY+SCSI_LUN) ; PUT LUN IN ACCUM RRCA ; MOVE TO TOP 3 BITS RRCA ; ... RRCA ; ... LD (SCSI_CAP_LUN),A ; PUT IN INQ CDB ; DO THE SCSI TRANSACTION CALL SCSI_GO ; DO THE SCSI TRANSACTION RET NZ ; ABORT ON ERROR ; ; RETURNED LBA IS BIG ENDIAN. CONVERT TO A STANDARD 32-BIT ; INTEGER IN DE:HL LD HL,SCSI_CAP_BUF ; HL POINTS TO START OF BUF LD D,(HL) ; MSB INC HL ; NEXT BYTE LD E,(HL) PUSH DE ; SAVE HIGH WORD INC HL LD D,(HL) INC HL LD E,(HL) ; LSB POP HL ; RECOVER HIGH WORD EX DE,HL ; AND SWAP ; ; RETURNED CAPACITY IS THE *LAST* LBA. WE WANT THE NUMBER OF ; BLOCKS AVAILABLE, SO WE NEED TO INCREMENT THE RETURNED VALUE. CALL INC32 ; ; COPY CAPACITY TO DEVICE CONFIG DATA FIELD PUSH HL ; SAVE HL LD A,SCSI_MEDCAP ; OFFSET OF MEDIA CAPACITY FIELD CALL LDHLIYA ; HL POINTS TO MEDIA CAPACITY FIELD PUSH HL ; MOVE HL POP BC ; ... TO BC POP HL ; RECOVER HL CALL ST32 ; SAVE CAP TO CFG BLOCK ; XOR A RET ; DONE ; ;============================================================================= ; COMMAND PROCESSING ;============================================================================= ; ; WRAPPER FOR HBIOS INVOCATION ; SCSI_GO: PUSH IX ; PRESERVE IX LD IX,SCSI_S_IOT ; POINT TO IO TABLE CALL SCSI_GO1 ; RUN THE TRANSACTION POP IX ; RESTORE IX AND %00111110 ; IGNORE RESERVED BITS OF STATUS JP NZ,SCSI_IOERR ; HANDLE ERROR RET ; DONE ; ;------------------------------------------------------------------------------- ;DO SCSI TRANSACTION ;------------------------------------------------------------------------------- ; SCSI_GO1: LD A,$FF ;PRESET ERROR STATUS LD L,(IX+4) ;POINT TO STATUS ADDRESS LD H,(IX+5) ;POINT TO STATUS ADDRESS LD (HL),A ;SET ERROR ; XOR A ; OUT (SCSI_SR_MR),A ;RESET CONTROL REG OUT (SCSI_SR_TCR),A ;CLEAR COMMAND REG. OUT (SCSI_SR_ICR),A ; LD A,(IX) ;GET TID BIT 7,A ; TURN ON MY ID OUT (SCSI_SR_ODR),A ;SET TARGET ID LD A,$01 ;DRIVE BUS OUT (SCSI_SR_ICR),A ; LD A,$05 ;SET SEL AND DRIVE BUS OUT (SCSI_SR_ICR),A ; ; ;WAIT FOR SCSI BUSY LD BC,0 ;INIT TIMEOUT S_SWT: IN A,(SCSI_SR_CSBS) ;GET BUS STATUS AND SCSI_SM_BSY ;MASK TO BUSY BIT JR NZ,S_BSYA ;JMP IF BUSY ACTIVE NOP ;KILL A LITTLE TIME NOP NOP NOP DEC BC ;DEC TIMEOUT LD A,B ;TEST TIMEOUT=0 OR C JR NZ,S_SWT ;JMP IF NO TIMEOUT XOR A ;CLEAR A OUT (SCSI_SR_ICR),A ;CLEAR SEL AND DATA JR S_EXIT ;ERROR EXIT ; ;BUSY IS ACTIVE S_BSYA: XOR A ;CLEAR A OUT (SCSI_SR_ICR),A ;CLEAR SEL AND DATA ;------------------------------------------------------------------------------- ; ;TARGET IS SELECTED SO TEST BSY AND REQ ;THEN DECODE REQUESTED PHASE ; ;------------------------------------------------------------------------------- PHASE: XOR A OUT (SCSI_SR_ICR),A ;RESET INITIATOR ; S_WTREQ: IN A,(SCSI_SR_CSBS) ;GET BUS STATUS LD B,A ;SAVE COPY AND SCSI_SM_BSY ;MASK TO BUSY BIT JR NZ,S_WTRQ1 ;STILL BUSY SO CONT. ;------------------------------------------------------------------------------- ;BUSY LOST SO EXIT ;------------------------------------------------------------------------------- S_EXIT: LD L,(IX+4) ;GET STATUS POINTER LD H,(IX+5) ;GET STATUS POINTER LD A,(HL) RET ;BUSY LOST? WERE DONE ; S_WTRQ1: LD A,B ;RECOVER STATUS AND SCSI_SM_REQ ;REQUEST ACTIVE? JR Z,S_WTREQ ;LOOP TILL REQUEST ;------------------------------------------------------------------------------- ;REQUEST IS ACTIVE SO SET 5380 TO REQUESTED PHASE ;------------------------------------------------------------------------------- LD A,B ;RECOVER BUS STATUS RR A ;SHIFT STATUS TO PHASE BITS RR A AND $07 ;MASK TO PHASE BITS OUT (SCSI_SR_TCR),A ;SET PHASE ; ;JUMP TO PHASE HANDLER ; LD A,B ;RECOVER BUS STATUS RR A AND $0E ;MASK TO PHASE BITS LD E,A ; LD D,0 LD HL,PHTABL ;POINT TO TABLE ADD HL,DE ;OFFSET INTO TABLE LD E,(HL) ;GET EXECUTION ADDRESS INC HL LD D,(HL) PUSH DE RET ;EXECUTE PHASE ;------------------------------------------------------------------------------- ;PHASE TABLE ;------------------------------------------------------------------------------- PHTABL: .WORD PHASE0 ;DATA OUT .WORD PHASE1 ;DATA IN .WORD PHASE2 ;CMD OUT .WORD PHASE3 ;STATUS IN .WORD S_EXIT ;UNUSED .WORD S_EXIT ;UNUSED .WORD PHASE6 ;MESSAGE OUT .WORD PHASE7 ;MESSAGE IN ;------------------------------------------------------------------------------- ;PHASE HANDLERS ;------------------------------------------------------------------------------- ; ;DATA OUT PHASE0: LD L,(IX+6) ;GET POINTER LD H,(IX+7) JP S_WRIT ;WRITE BYTES ; ;DATA IN PHASE1: LD L,(IX+8) ;GET POINTER LD H,(IX+9) JP S_READ ;READ BYTES ; ;CMD OUT PHASE2: LD L,(IX+2) LD H,(IX+3) JP S_WRIT ; ;STATUS IN PHASE3: LD L,(IX+4) LD H,(IX+5) JP S_READ ; ;MSG OUT PHASE6: LD L,(IX+10) LD H,(IX+11) JP S_WRIT ; ;MSG IN PHASE7: LD L,(IX+12) LD H,(IX+13) JP S_READ ;------------------------------------------------------------------------------- ;SCSI WRITE ROUTINE (SEND BYTES TO TARGET) ;BUS PHASE ALREADY SET. RETURN ON PHASE MISMATCH ;------------------------------------------------------------------------------- S_WRIT: LD A,1 ;DRIVE SCSI DATA BUS OUT (SCSI_SR_ICR),A ; ;WAIT FOR REQ WHILE CHECKING BUSY ; S_WWREQ: IN A,(SCSI_SR_CSBS) ;GET CURRENT BUS STAT LD B,A ;SAVE IT AND SCSI_SM_REQ ;REQUEST ACTIVE? JR NZ,S_WNXT ; ; LD A,B ;RECOVER CURRENT BUS STAT AND SCSI_SM_BSY ;STILL BUSY? JP NZ,S_WWREQ ;LOOP IF STILL BUSY JP PHASE ; ; ;REQUEST ACTIVE SO CHECK PHASE ; S_WNXT: IN A,(SCSI_SR_BSR) ;GET STATUS AND SCSI_SM_PHM ;MASK TO PHASE MATCH JP Z,PHASE ;JMP IF PHASE MISMATCH ; ;REQUEST ACTIVE AND PHASE MATCH SO SEND DATA ; LD A,(HL) ;GET BYTE OUT (SCSI_SR_ODR),A ;SEND DATA LD A,$11 ;ACK + DRIVE BUS OUT (SCSI_SR_ICR),A ;SET ACK,DRIVE SCSI BUS INC HL ;ADVANCE BUF POINTER ; ;WAIT FOR REQUEST TO DROP ; S_WNREQ: IN A,(SCSI_SR_CSBS) ;GET CURRENT STATUS AND SCSI_SM_REQ JR NZ,S_WNREQ ;LOOP TILL REQ DROPS ; LD A,$1 ;DROP ACK,ASSERT DATA OUT (SCSI_SR_ICR),A ;DROP ACK JP S_WWREQ ;LOOP FOR NEXT BYTE/PHASE ;------------------------------------------------------------------------------- ;SCSI READ ROUTINE (GET BYTES FROM TARGET) ;BUS PHASE ALREADY SET. RETURN ON PHASE MISMATCH ;------------------------------------------------------------------------------- ; S_READ: ; ;WAIT FOR REQ WHILE CHECKING BUSY ; S_RWREQ: IN A,(SCSI_SR_CSBS) ;GET CURRENT BUS STAT LD B,A ;SAVE IT AND SCSI_SM_REQ ;REQUEST ACTIVE? JR NZ,S_RNXT ; ; LD A,B ;RECOVER CURRENT BUS STAT AND SCSI_SM_BSY ;STILL BUSY? JP NZ,S_RWREQ ;LOOP IF STIL BUSY JP PHASE ; ; ;REQUEST ACTIVE SO CHECK PHASE S_RNXT: IN A,(SCSI_SR_BSR) ;GET STATUS AND SCSI_SM_PHM ;MASK TO PHASE MATCH JP Z,PHASE ;JMP IF PHASE MISMATCH ;REQUEST ACTIVE AND PHASE MATCH SO GET DATA ; IN A, (SCSI_SR_CSD) ;GET DATA LD (HL),A ;SAVE DATA LD A,$10 OUT (SCSI_SR_ICR),A ;SET ACK INC HL ;ADVANCE BUF POINTER ; ;WAIT FOR REQUEST TO DROP ; S_RNREQ: IN A,(SCSI_SR_CSBS) ;GET CURRENT STATUS AND SCSI_SM_REQ JR NZ,S_RNREQ ;LOOP TILL REQ DROPS XOR A OUT (SCSI_SR_ICR),A ;DROP ACK JP S_READ ;LOOP FOR NEXT BYTE/PHASE ; ;============================================================================= ; HARDWARE INTERFACE ROUTINES ;============================================================================= ; ;============================================================================= ; ERROR HANDLING AND DIAGNOSTICS ;============================================================================= ; ; ERROR HANDLERS ; SCSI_NOMEDIA: LD A,SCSI_STNOMEDIA JR SCSI_ERR ; SCSI_IOERR: LD A,SCSI_STIOERR JR SCSI_ERR ; SCSI_TO: LD A,SCSI_STTO JR SCSI_ERR ; SCSI_NOTRDY: LD A,SCSI_STNOTRDY JR SCSI_ERR ; SCSI_ERR: LD (IY+SCSI_STAT),A ; SAVE NEW STATUS ; #IF (SCSITRACE >= 2) CALL SCSI_PRTSTAT #ENDIF OR A ; SET FLAGS RET ; ; ; SCSI_PRTERR: RET Z ; DONE IF NO ERRORS ; FALL THRU TO SCSI_PRTSTAT ; ; PRINT FULL DEVICE STATUS LINE ; SCSI_PRTSTAT: PUSH AF PUSH DE PUSH HL LD A,(IY+SCSI_STAT) CALL SCSI_PRTPREFIX ; PRINT UNIT PREFIX JR SCSI_PRTSTAT3 SCSI_PRTSTAT2: CALL NEWLINE PRTS("SCSI:$") ; NO UNIT NUM IN PREFIX FOR INVALID UNIT SCSI_PRTSTAT3: CALL SCSI_PRTSTATSTR POP HL POP DE POP AF RET ; ; PRINT STATUS STRING ; SCSI_PRTSTATSTR: PUSH AF PUSH DE LD A,(IY+SCSI_STAT) OR A LD DE,SCSI_STR_STOK JR Z,SCSI_PRTSTATSTR1 INC A LD DE,SCSI_STR_STNOMEDIA JR Z,SCSI_PRTSTATSTR1 INC A LD DE,SCSI_STR_STIOERR JR Z,SCSI_PRTSTATSTR1 INC A LD DE,SCSI_STR_STTO JR Z,SCSI_PRTSTATSTR1 INC A LD DE,SCSI_STR_STNOTRDY JR Z,SCSI_PRTSTATSTR1 LD DE,SCSI_STR_STUNK SCSI_PRTSTATSTR1: CALL PC_SPACE ; FORMATTING CALL WRITESTR POP DE POP AF RET ; ; PRINT DIAGNONSTIC PREFIX ; SCSI_PRTPREFIX: PUSH AF CALL NEWLINE PRTS("SCSI$") LD A,(IY+SCSI_DEV) ; GET CURRENT DEVICE NUM CP $FE ; NOT YET ASSIGNED? JR Z,SCSI_PRTPREFIX1 ; SKIP DEV NUM IF SO CALL PRTDECB SCSI_PRTPREFIX1: CALL PC_COLON POP AF RET ; ;============================================================================= ; STRING DATA ;============================================================================= ; SCSI_STR_STOK .TEXT "OK$" SCSI_STR_STNOMEDIA .TEXT "NO MEDIA$" SCSI_STR_STIOERR .TEXT "IO ERROR$" SCSI_STR_STTO .TEXT "TIMEOUT$" SCSI_STR_STNOTRDY .TEXT "NOT READY$" SCSI_STR_STUNK .TEXT "UNKNOWN ERROR$" ; ;============================================================================= ; DATA STORAGE ;============================================================================= ; SCSI_DEVNUM .DB 0 ; TEMP DEVICE NUM USED DURING INIT SCSI_DSKBUF .DW 0 ; ACTIVE DISK BUFFER ; ;---------------------------------------------------------------- ;SCSI COMMAND DESCRIPTOR FOR READ/WRITE ; SCSI_S_CDB: .DB SCSI_CMD_READ ; COMMAND SCSI_CUR_LUN .DB 0 << 5 ; LUN/LBA HI SCSI_CUR_LBN .DB 0 ; LBA MID .DB 0 ; LBA LOW .DB 1 ; COUNT .DB 0 ; CONTROL ; ;---------------------------------------------------------------- ;SCSI COMMAND DESCRIPTOR FOR INQUIRY ; SCSI_S_INQ: .DB SCSI_CMD_INQ ; COMMAND SCSI_INQ_LUN .DB 0 << 5 ; LUN (TOP 3 BITS) .DB 0 ; PAGE CODE (UNUSED) .DB 0 ; RESERVED .DB $FF ; ALLOCATION LENGTH .DB 0 ; CONTROL ; ;---------------------------------------------------------------- ;SCSI COMMAND DESCRIPTOR FOR READ CAPACITY ; SCSI_S_CAP: .DB SCSI_CMD_RDCAP ; COMMAND SCSI_CAP_LUN .DB 0 << 5 ; LUN (TOP 3 BITS) .FILL 4,0 ; LBA (UNUSED) .FILL 3,0 ; RESERVED .DB 0 ; CONTROL ; ;---------------------------------------------------------------- ;SCSI I/O ADDRESS TABLE FOR READ/WRITE ;DONT MESS WITH THIS EITHER SCSI_S_IOT: SCSI_CUR_TID .DB 1 << SCSI_TID ; TARGET .DB 0 ; UNUSED SCSI_CUR_CDB .DW SCSI_S_CDB ; CDB POINTER .DW SCSI_S_STAT ; STATUS POINTER SCSI_BUF_OUT .DW HB_WRKBUF ; DATA OUT POINTER SCSI_BUF_IN .DW HB_WRKBUF ; DATA IN POINTER .DW SCSI_S_MSG ; MSG OUT POINTER .DW SCSI_S_MSG ; MSG IN POINTER ; SCSI_S_STAT .DW 0 ; SCSI ENDING STATUS SCSI_S_MSG .DW 0 ; SCSI MESSAGE ; SCSI_CAP_BUF .FILL 8,0 ; SCSI CAPACITY DATA BUFFER ; ;-------------------------------------------------------------------------------------------------- ; HBIOS MODULE TRAILER ;-------------------------------------------------------------------------------------------------- ; END_SCSI .EQU $ SIZ_SCSI .EQU END_SCSI - ORG_SCSI ; MEMECHO "SCSI occupies " MEMECHO SIZ_SCSI MEMECHO " bytes.\n"