Mercurial > hg > Members > kono > nitros9-code
view 3rdparty/drivers/burke/hdcmd.src @ 1366:770c350f4c15
More changes
author | boisy |
---|---|
date | Fri, 26 Sep 2003 12:43:30 +0000 |
parents | c10820aa211b |
children |
line wrap: on
line source
******************************************* *** *** *** HDCMD.SRC *** *** *** *** COPYRIGHT BURKE & BURKE 1987 *** *** ALL RIGHTS RESERVED *** *** *** *** COPYRIGHT BURKE & BURKE 1992 *** *** ALL RIGHTS RESERVED *** *** *** ******************************************* * * This is the routine that executes controller commands, and * its support routines. * * Modification History * -------------------- * * Date Who Description * -------- --- ------------------------------------ * 12/20/87 CJB Modified GetDat and PutDat to call * SNOOZE routine if not ready for data. * This causes the driver to sleep * during disk seeks. * Modified s25flg stuff for generic * 32x4x?? drives. * 02/07/88 CJB Added CMEXIN to process special drive * parameters during formatting * * 04/17/88 cjb Added WaitIdl, which waits for controller * ready to receive a command. * Added call to Snooze in WaitIdl. * 04/21/88 cjb Added code to OR RetryEn into step rate * byte. This allows retries to be disabled * by RetryEn = $80. * 05/18/88 cjb Checked all paths for proper handling of * premature command termination * 06/12/88 cjb Added WaitId2 to assure sleep for at least * one tick. * Fixed DrvCmd to check for WX$XIN opcode * if formatting enabled. * 07/01/88 cjb Fixed bug in CMESTS -- changed "<" to ">" * 10/10/88 cjb Modified to save error track if format enabled * 02/01/89 cjb Fixed bug in error routine -- now dumps * cache on any uncorrectable error * Fixed bug in error routine to save * error track # correctly * 05/05/90 cjb Added kludge for ST11R in WAIRDY * Added support for drives in multiple slots * 04/15/92 cjb Fixed bug in location of DBLRDD - caused * driver to hang up on an error message. * Lenghtened a bit for speed, and to allow * easy 6309E overlays. * page * * Byte saver. * * Call here to send command in Reg-A to drive in Reg-B, * with 0's as the rest of the command. * * Note that this command sets the step rate to 3 ms! * DrvCmd pshs y,x,a ;Save registers same as CmExec sts AbtStk,U ;Save stack pointer for error recovery * Enter here to send WX$STS -- stack etc. already set up DrvCm2 bsr WAIRDY ;Wait for ready for command -- preserves B lda ,S ; recover reg-A ifne fmtflg bsr ChkCmd ; translate cmd. if necessary endc ifne (Drives-1) ;If multiple drives, andb #$01 ; 2 drives per controller, different slots aslb aslb aslb ;convert drive # to controller's format aslb aslb else clrb ;drive # is always 0 endc bsr PutCm2 ;Send command & drive # * Send the rest of the command as 0's (including step rate . . . 3ms) * Note that RetryEn is ignored here. clra clrb bsr PutCm2 bsr PutCm2 ;Send 4 zeros for rest of command * Pass control to dispatch routine, and wait for end when done bra CmDisp page * * Put Reg-D to controller as command bytes * * Assumes AbtStk is valid. * ifne icdflg ;If ignoring C/D status bit PutCm2 lbra PutDt2 else PutCm2 bsr PutCmd tfr B,A ;Fall through to PutCm2 endc * * Wait for controller to indicate it is ready to receive * a command byte, then send it from Reg-A. * * Assumes AbtStk,U has been set to the error recovery * stack pointer. * If the command aborts, the stack is cleaned and control * passed to CmdDun. * ifne icdflg ;If ignoring C/D status bit PutCmd lbra PutDat else PutCmd pshs A PCM0 bsr ChkAbt ;Get status, check for abort cmpa #%00001101 ;Check for command request bne PCM0 * Ready. Put the data puls A sta >HDDATA rts endc * * Get status of hard disk controller, and abort command in * progress if controller says so. * * Assumes AbtStk,U has been set to the error recovery * stack pointer. * If the command aborts, the stack is cleaned and control * passed to CmdDun. * ChkAbt lda >HDSTAT cmpa >HDSTAT ;Data must be stable bne ChkAbt anda #%00001111 cmpa #%00001111 ;Check for abort bne CKA9 * Well, the command is complete. This normally means it * aborted. Pass control to CmdDun lds AbtStk,U ;Clean stack bra CmdDun * Not done yet. Return current status to caller CKA9 rts ifne fmtflg ;If formatting allowed, * * Convert command op-code before transmission to controller * if necessary. * * The special initialization code WX$XIN is not a real controller * op-code. * ChkCmd cmpa #WX$XIN ;Check for bogus INITIALIZE PARAMETERS bne CCM9 lda #WX$INI ; convert to real INITIALIZE PARAMETERS CCM9 rts endc * * Wait for controller ready to receive a command, then * get its attention. Blows away Reg-A. * * Does not time out. * WAIRDY bsr WaitIdl ;Wait for controller idle clr >HDATTN ;Get attention of controller rts * Wait for controller ready to receive a command WaitIdl lda >HDSTAT * anda #%00001111 anda #%00001001 ;Special mask works for ST11R, too cmpa #%00000000 ; (all bits must be clear if ready) beq WaitId9 * Enter here to sleep for at least one tick. * Waste time while waiting for HD. WaitId2 lbsr Snooze ;Give up slot, sleep. bra WaitIdl WaitId9 rts page * * Command execution module for CoCo XT. * * Enter with: * * Command op-code in Reg-A * Buffer pointer in Reg-X (points to buffer for data part of cmd) * Command image set up at IMAGE,U * Reg-Y points to real or bogus path descriptor (for drive # and * step rate). * Slot 3 is assumed to be selected, with interrupts disabled. * * Exits w/ carry clear if success, otherwise carry set and * error code in Reg-B. * CMEXEC pshs y,x,a ;Save caller's registers sts AbtStk,U ;Save stack pointer for error recovery * Wait for drive ready to accept a command bsr WaiRdy * Point to the command block leax IMAGE,U * Issue the command . . . op-code 1st * PutCmd and PutCm2 will automatically abort the command * if the controller indicates that this is necessary. lda 0,S ;Recover command op-code ifne fmtflg bsr ChkCmd ;Translate command op-code if needed endc CMX1 bsr PutCmd ldd ,X++ ; (send head & sector) bsr PutCm2 ldd ,X++ ; (send cylinder & block count) bsr PutCm2 lda PD.STP,Y ; (send step rate) ora RetryEn,U ; (and send retry flag) bsr PutCmd * Now dispatch the command based on it's op-code. If a command * isn't explicitly checked for in this loop, it is assumed that * the command has no data arguments and is now executing. CmDisp equ * * Command in progress. Dispatch to service routine. * Note that the service routine must check for premature * command termination via CHKABT. ldx 1,S ;Recover possible data pointer lda 0,S ;Recover op-code cmpa #WX$RDD ;READ SECTOR beq CMERDD cmpa #WX$WRT ;WRITE SECTOR beq CMEWRT cmpa #WX$INI ;SET DRIVE PARAMETERS lbeq CMEINI ifne fmtflg cmpa #WX$WBF ;WRITE SECTOR BUFFER (for format) lbeq CMEWBF cmpa #WX$XIN ;Bogus SET DRIVE PARAMETERS lbeq CMEXIN endc cmpa #WX$STS ;DETAILED STATUS REQUEST lbeq CMESTS * Wait for end of command execution. Then get completion status * byte and decode any errors encountered. WaiEnd bsr ewait ;Wait for command done * Get completion status byte * Stack pointer and ABTSTK,U match CmdDun clrb ;Clear carry, assume no error lda >HDDATA bita #%00000010 beq NoErr * Error bit is set -- note this could still be a "null" error * or a correctable error, so we have to get the status packet. lda 0,S ;Check op-code cmpa #WX$STS ;Was it an error status request? bne GetErr * Unknown error, or error while trying to determine error. NotRdy comb ldb #E$Read ;Report it as a "read" error * Generic exit NoErr equ * CMEXIT puls a,x,y,pc * Issue command to read error from controller. This command * will return the error code in Reg-B w/ carry set. GetErr lda #WX$STS ;Recurse to get detailed status (implicit bfr) ifne Drives-1 ;If more than 1 drive, ldb PD.DRV,Y endc lds AbtStk,U ;Recover stack pointer sta 0,S ;Put command on stack lbra DrvCm2 ;Go try again. * Wait for command to terminate ewait lda >HDSTAT anda #%00000111 ;NOTE: IGNORE BUSY BIT cmpa #%00000111 ; (all bits set for command completion byte) beq ewx * Not done. Sleep for the rest of this tick, then try again. lbsr Snooze ;Give up slot, sleep, get back slot bra ewait * Exit ewx rts page * * Handle tail end of sector read. * Get the data to the caller's buffer. * CMERDD lda secnum,u bita #1 bne CMRODD * Read even logical sector on track -- 1st half of physical sector * Save 2nd half if necessary. bsr keep256 ifne cchflg ;If read cache supported, tst BFRFLG,U beq CMRE1 * Copy 2nd half of sector to verify buffer (possible cache) leax vrfbuf,U bsr keep256 bra WaiEnd endc * Discard 2nd half of sector CMRE1 bsr dump256 bra WAIEND * Read odd logical sector on track -- 2nd half of physical sector * Throw away the 1st half CMRODD bsr dump256 bsr keep256 bra WAIEND page * * Handle tail end of sector write. * Get the data from the caller's buffer. * CMEWRT lda secnum,u bita #1 bne CMWODD * Write even lsn on track -- uses 1st half, get 2nd half from verify bfr bsr writ256 bsr copy256 bra WAIEND * Write odd lsn on track -- uses 2nd half, get 1st half from verify bfr CMWODD bsr copy256 bsr writ256 bra WAIEND ifne fmtflg ;If hard formatting enabled, page * * Process command to fill sector buffer with (A). * * This is only used at the beginning of a FORMAT command. * CMEWBF ldd #$E600 ; ($00 -> 256 iterations) bsr CMF0 bsr CMF0 ; Reg-B is still 0 from previous iteration lbra WAIEND CMF0 bsr PutDat ;Fill 256 bytes of sector buffer with (A) decb bne CMF0 rts endc page * * Copy 256 bytes from sector buffer to (X) * ifne fstflg ;If fast transfers, Keep256 bsr GetDat ;Full handshake on 1st byte sta ,X+ ifne tboflg ;If 2 MHz for transfers, clr >$FFD9 endc bsr GetDat ;Get 2nd (quick move goes in pairs) sta ,X+ ldb #$7F ;pair count pshs B RDD1 lda >HDDATA ;Read the rest of the block w/o handshake ldb >HDDATA std ,X++ dec ,S bne RDD1 ifne tboflg ;If 2 MHz for transfers, clr >$FFD8 endc puls A,PC ;Flush counter else ;If slow transfers, Keep256 clrb ;Copy 256 bytes ifne tboflg ;If 2 MHz for transfers, clr >$FFD9 endc RDD1 bsr GetDat ;Full handshake on every byte sta ,X+ decb bne RDD1 ifne tboflg ;If 2 MHz for transfers, clr >$FFD8 endc rts endc * * Copy 256 bytes from sector buffer to bit bucket * ifne fstflg ;If fast transfers, Dump256 bsr GetDat ;Full handshake on 1st byte ifne tboflg ;If 2 MHz for transfers, clr >$FFD9 endc bsr GetDat ;Quick dump goes in pairs ldb #$7F RDD2 lda >HDDATA ;Read the rest of the block w/o handshake lda >HDDATA decb bne RDD2 ifne tboflg ;If 2 MHz for transfers, clr >$FFD8 endc rts else ;If slow transfers, Dump256 clrb ;Copy 256 bytes ifne tboflg ;If 2 MHz for transfers, clr >$FFD9 endc RDD2 bsr GetDat ;Full handshake on every byte decb bne RDD2 ifne tboflg ;If 2 MHz for transfers, clr >$FFD8 endc rts endc * * Wait for controller to indicate it is ready to transmit * a data byte, then get it to Reg-A. * * Assumes AbtStk,U has been set to the error recovery * stack pointer. * If the command aborts, the stack is cleaned and control * passed to CmdDun. * GetDat equ * GDT0 lbsr ChkAbt ;Get status, check for abort ifne icdflg ;If ignoring C/D bit, anda #%00001011 endc cmpa #%00001011 ;Check for data request beq GDT1 ; (branch if request present) * New -- sleep if controller not ready (D.DMAReq only) lbsr Snooze bra GDT0 * Ready. Get the data GDT1 lda >HDDATA rts page * * Copy 256 bytes from (X) to sector buffer * ifne fstflg ;If fast transfers, Writ256 ldd ,X++ bsr PutDt2 ;Full handshake on 1st byte pair ifne tboflg ;If 2 MHz for transfers, clr >$FFD9 endc ldb #$7F pshs B WRT1 ldd ,X++ sta >HDDATA ;Write the rest of the block w/o handshake stb >HDDATA dec ,S bne WRT1 ifne tboflg ;If 2 MHz for transfers, clr >$FFD8 endc puls A,PC ;clean up counter else ;If slow transfers, Writ256 clrb ;Copy 256 bytes ifne tboflg ;If 2 MHz for transfers, clr >$FFD9 endc WRT1 lda ,X+ bsr PutDat ;Full handshake on every byte decb bne WRT1 ifne tboflg ;If 2 MHz for transfers, clr >$FFD8 endc rts endc * * Copy 256 bytes from verify buffer to sector buffer * copy256 pshs X leax vrfbuf,u ;Get verify buffer pointer bsr writ256 puls X,PC * * Put Reg-D to controller as data bytes * * Assumes AbtStk is valid. * PutDt2 bsr PutDat tfr B,A ;Fall through to PutCm2 * * Wait for controller to indicate it is ready to receive * a data byte, then send it from Reg-A. * * Assumes AbtStk,U has been set to the error recovery * stack pointer. * If the command aborts, the stack is cleaned and control * passed to CmdDun. * PutDat pshs A PDT0 lbsr ChkAbt ;Get status, check for abort ifne icdflg ;If ignoring C/D bit, anda #%00001011 endc cmpa #%00001001 ;Check for data request beq PDT1 ; (branch if request present) * New -- sleep if controller not ready (D.DMAReq only) lbsr Snooze bra PDT0 * Ready. Put the data PDT1 puls A sta >HDDATA rts page * * Process detailed status request command. * This routine performs the status request, then * translates the controller's error code and returns * it as the error status of the operation w/ C-bit set. * "Null" and correctable errors do not cause C-bit set. * CMESTS equ * * Recover error status from controller bsr GetDat ;Read result of last disk command pshs a ; (save) ifne FMTFLG bsr GetDat ; (dump head #) bsr GetDat ;Get shifted cyl # MS byte tfr A,B bsr GetDat ;Get shifted cyl # LS byte exg A,B std ERRHCYL,U ;Save cylinder # of error for FORMAT else bsr DBLRDD ;Dump last 3 response bytes bsr GetDat ; (dump last response byte) endc lbsr ewait ; Wait for command complete lda >HDDATA ; and dump completion byte puls a ; (recover error code) * Look up error code in Reg-A -> Reg-B anda #$3F ;Keep only error bits beq NULERR cmpa #WE$CER ;Correctable error bne EL0 * Special processing for correctable errors. * If formatting (RetryEn,U != 0), report these * as READ ERRORS tst RetryEn,U ;If retries disabled, error out. beq NULERR ; (retries enabled -- ignore error) EL0 equ * ifne cchflg ;If read cache supported, clr BFRFLG,U ;Dump cache on any error endc ifne errflg ;If good error messages enabled, leax ERRTBL,PCR ;Point to lookup table * Search error list. Error code is in Reg-A EL1 tst ,X bmi XXXERR cmpa ,X++ bne EL1 * Found error code comb ;Set carry ldb -1,X ;Fetch error code bra XCMXIT endc * Didn't find error code. Note that errors that translate * to E$Read are not in the table -- we just let them default * to here. XXXERR comb ldb #E$Read bra XCMXIT ;Return status to caller NULERR clrb ;Force carry clear XCMXIT lbra CMEXIT ;Return status to caller * Byte saver DBLRDD lbsr GetDat ;Read 1 byte lbra GetDat page ifne fmtflg ;If formatting allowed, * * Process special drive parameters command. * * This command sends the legal track count rather * than the park track count. * CMEXIN ldd PD.CYL,Y ;get track count bra CMIN01 endc * * Process command to send drive parameters to controller. * Assumes Reg-Y points to real or bogus *PATH* descriptor. * * This routine fetches the drive parameters from the descriptor, * and sends them to the controller. * CMEINI equ * * Send # of cylinders. We send the park track, since it * is the largest track # that will be used. ifne (Drives-1) ;if 2 drives, ifne trsflg ; if optimized for 32 SPT, 4 heads, bsr GtPkLSN ;Get park LSN to B:X pshs X,B ldd ,S addd ,S leas 3,S ;Convert to track by dividing by 128 else bsr GtPkLSN ;Get park LSN to B:X lbsr LSNDIV tfr X,D ;Calculate track and get to D endc else ;if 1 drive, ifne trsflg ; if optimized for 32 SPT, 4 heads, ldd PRKLSN,U addd PRKLSN,U ;park track = park LSN/128 else ldb (PRKLSN+0),U ldx (PRKLSN+1),U ;get park LSN lbsr LSNDIV tfr X,D ;Calculate track and get to D endc endc * Enter here w/ track count in Reg-D CMIN01 addd #1 ; (advance track count by 1) bsr PutDt2 ;Send last legal track to controller * Send # of heads lda PD.SID,Y bsr PutDat * Send (bogus) reduced write current cylinder ldd PD.CYL,Y lbsr PutDt2 * Send write pre-comp cylinder (DD had wpc/4) ifne (Drives-1) ;if 2 drives, pshs Y ldb PD.DRV,Y ;Get drive # lbsr GOBPtr ;Get option pointer for this drive ldb (PCCYL-OBSTART),Y puls Y else ldb PCCYL,U ;Get precomp cylinder / 4 endc lda #4 mul ;Convert to real cyl # in D lbsr PutDt2 * Send maximum error correction burst length (WD recommends 4) lda #4 lbsr PutDat * Wait for end of command, etc. lbra WaiEnd ifne (Drives-1) page * * Utility to get park lsn to B:X for systems with 2 drives. * GtPkLSN pshs Y ldb PD.DRV,Y ;Get drive # lbsr GOBPtr ;Get option pointer for this drive ldb (PRKLSN+0-OBSTART),Y ldx (PRKLSN+1-OBSTART),Y puls Y,PC endc ifne errflg ;If good errors enabled, page * * Table of error code followed by OS9 error code * This translation is somewhat arbitrary. * Remember, E$Read errors are not in the table. * ERRTBL fcb WE$NSC,E$Seek,WE$WRF,E$Write,WE$NRD,E$NotRdy,WE$NT0,E$Seek fcb WE$DSS,E$Seek,WE$SIK,E$Seek,WE$BTK,E$Read,WE$CMD,E$Unit fcb WE$ISA,E$Sect fcb -1 endc * * End of hdcmd.src *