; ;============================================================================= ; SCSI DISK DRIVER FOR 5380 ;============================================================================= ; ; DISK DEVICE DRIVER FOR THE 5380 SCSI CHIP. ; DERIVED FROM CODE PROVIDED BY JAY COTTON. ; ; TODO: ; - IMPLEMENT BUS SCANNING FOR DEVICES AT STARTUP ; - USE TEST UNIT READY TO WAIT FOR SPINUP? ; ; 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_TGT .EQU 2 ; TARGET DEVICE ID SCSI_TID .EQU 3 ; TARGET DEVICE BIT PATTERN SCSI_LUN .EQU 4 ; TARGET LUN SCSI_STAT .EQU 5 ; LAST STATUS (BYTE) SCSI_MEDCAP .EQU 6 ; MEDIA CAPACITY (DWORD) SCSI_LBA .EQU 10 ; OFFSET OF LBA (DWORD) ; SCSI_CFGSIZ .EQU 14 ; SIZE OF CFG TBL ENTRIES ; ;-------------------------------------------------------------------------------------------------- ; 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_CFGTBL: ; #IF (SCSICNT >= 1) ; SCSI0_CFG: .DB $FE ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY) .DB SCSIBASE ; IO BASE ADDRESS .DB SCSI0_TGT ; TARGT DEVICE ID .DB 1 << SCSI0_TGT ; TARGET DEVICE BIT PATTERN .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=" DEVECHO SCSI0_TGT 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_TGT ; TARGT DEVICE ID .DB 1 << SCSI1_TGT ; TARGET DEVICE BIT PATTERN .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=" DEVECHO SCSI1_TGT DEVECHO ", LUN=" DEVECHO SCSI1_LUN DEVECHO "\n" #ENDIF ; #IF (SCSICNT >= 3) .DB $FE ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY) .DB SCSIBASE ; IO BASE ADDRESS .DB SCSI2_TGT ; TARGT DEVICE ID .DB 1 << SCSI2_TGT ; TARGET DEVICE BIT PATTERN .DB SCSI2_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=" DEVECHO SCSI2_TGT DEVECHO ", LUN=" DEVECHO SCSI2_LUN DEVECHO "\n" #ENDIF ; #IF (SCSICNT >= 4) .DB $FE ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY) .DB SCSIBASE ; IO BASE ADDRESS .DB SCSI3_TGT ; TARGT DEVICE ID .DB 1 << SCSI3_TGT ; TARGET DEVICE BIT PATTERN .DB SCSI3_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=" DEVECHO SCSI3_TGT DEVECHO ", LUN=" DEVECHO SCSI3_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: 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(" TGT=$") ; LABEL FOR TARGET DEVICE LD A,(IY+SCSI_TGT) ; GET TARGET DEVICE CALL PRTDEC8 ; DISPLAY IT ; 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 CAP 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 LD A,(IY+SCSI_TID) ; GET TARGET ID LD (IX),A ; PUT IN IOT 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 0 ; TARGET (FILLED DYNAMICALLY) .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"