Mercurial > hg > Members > kono > nitros9-code
view level1/modules/llscsi.asm @ 2730:6bd6e348665d
Working on cloned default branch, pulled 2012/11/03
user: gheskett@wdtv.com
branch 'default'
changed ChangeLog
changed ReadMe
changed defs/rbf.d
changed defs/rbsuper.d
changed defs/scsi.d
changed level1/atari/cmds/fuji.asm
changed level1/coco/modules/makefile
changed level1/modules/boot_scsi.asm
changed level1/modules/superdesc.asm
changed level2/coco3/bootfiles/makefile
changed level2/coco3/modules/makefile
changed level2/coco3_6309/bootfiles/makefile
changed level2/modules/joydrv_6551L.asm
changed rules.mak
author | gheskett@wdtv.com |
---|---|
date | Sat, 10 Nov 2012 11:55:48 -0500 |
parents | 17d43fd29ee2 |
children |
line wrap: on
line source
******************************************************************** * llscsi - Low-level SCSI driver * * $Id$ * * Drives tested with this driver: * ------------------------------- * Conner DCP30200 Hard Drive - Sends out a SDTR message immediately, * which confused the driver. The driver now handles the receipt * of SCSI messages from the target. * * IBM DPES-31080 Hard Drive - Works, but seizes the bus if a * device ID is referenced on the bus that doesn't exist. * * Sony CDU415 2X CD-ROM - Works fine. * * Toshiba XM-4101BME 12X CD-ROM - Works fine. * * NOTE: A full dsave from the Sony to the IBM was done on 300+ MB * of data (RTSI RBF CD-ROM) on June 7, 2004 with no problems. * * * Edt/Rev YYYY/MM/DD Modified by * Comment * ------------------------------------------------------------------ * 2004/04/?? Boisy G. Pitre * Created. * * 2004/??/?? Boisy G. Pitre * RELEASED WITH SUPERDRIVERS 1.0 * * 2005/12/02 Boisy G. Pitre * Now detects MESSAGE IN phase and reads in message codes (ignoring * the data). The Conner DCP30200 Hard Drive sends out a SDTR message * immediately, which confused the driver. The driver now handles the * receipt of messages from the target. * * 2005/12/11 Boisy G. Pitre * Added SS.SQD and SS.DCmd support. * * 2005/12/13 Boisy G. Pitre * Moved SS.VarSect code into RBSuper for performance. * * 2006/03/22 Boisy G. Pitre * Moved SS.VarSect code into RBSuper for performance. * * 2008/01/21 Boisy G. Pitre * Fixed issue in DCmd where Y was not being saved when os9 F$ID was being called. NAM llscsi TTL Low-level SCSI driver IFP1 USE defsfile USE rbsuper.d USE scsi.d ENDC tylg SET Sbrtn+Objct atrv SET ReEnt+rev rev SET 0 * * SCSI Delay Constants * IFGT Level-1 BUSYDELAY EQU $FFFF ELSE BUSYDELAY EQU $FFFF/2 ENDC NUMTRIES EQU 8 MOD eom,name,tylg,atrv,start,0 ORG V.LLMem * Low-level driver static memory area * SCSI Command Packet * SCSI packet length is 14 bytes V.SCSICMD RMB 1 V.SCSILUN RMB 1 V.SCSIPrm0 RMB 1 V.SCSIPrm1 RMB 1 V.SCSIPrm2 RMB 1 V.SCSIPrm3 RMB 1 V.SCSIPrm4 RMB 1 V.SCSIPrm5 RMB 1 V.SCSIPrm6 RMB 1 V.SCSIPrm7 RMB 1 RMB 4 SCSIPkLn EQU .-V.SCSICMD V.Retries RMB 1 SCSI command retry counter V.OS9Err RMB 1 (0 = return OS-9 error code, 1 = return SCSI error code) V.Turbo RMB 1 turbo flag (0 = regular read, 1 = turbo read) V.TfrBuf RMB 2 transfer buffer pointer V.RetryVct RMB 2 retry vector V.ReadVct RMB 2 normal/turbo read vectoor V.WriteVct RMB 2 normal/turbo write vector V.DnsByte RMB 1 copy of PD.DNS from last accessed drive IFNE D4N1+HDII V.MPISlot RMB 1 MPI slot V.MPISave RMB 1 contents of original MPI slot ENDC * The Request Sense Packet and Read Capacity return data share the same space ReqSnPkt EQU . V.TxBuf EQU . used by DSize V.R$Err RMB 2 SCSI error code return value V.UTxBuf EQU . V.R$Err2 RMB 10 V.R$AdSns RMB 1 ReqPkL EQU .-ReqSnPkt length of packet RMB 3 makes V.TxBuf 16 bytes name FCC /ll/ IFNE TC3 FCS /tc3/ ELSE IFNE KTLR FCS /ktlr/ ELSE IFNE D4N1+HDII FCS /disto/ ENDC ENDC ENDC start bra ll_init nop lbra ll_read lbra ll_write bra ll_getstat nop lbra ll_setstat * lbra ll_term * ll_term * * Entry: * Y = address of device descriptor * U = address of device memory area * * Exit: * CC = carry set on error * B = error code * ll_term clrb rts * ll_init * * Entry: * Y = address of device descriptor * U = address of device memory area * * Exit: * CC = carry set on error * B = error code * ll_init IFNE D4N1+HDII * Disto 4-N-1 and HD-II: Get MPI slot select value from descriptor * and save it in our static storage. lda IT.MPI,y anda #$0F preserve *SCS bits only sta V.MPISlot,u ENDC clrb rts * ll_getstat * * Entry: * Y = address of path descriptor * U = address of device memory area * * Exit: * CC = carry set on error * B = error code * ll_getstat ldx PD.RGS,y lda R$B,x cmpa #SS.DSize beq SSDSize ldb #E$UnkSvc coma rts * SS.DSize - Return size information about a device * * Entry: B = SS.DSize * Exit: Carry = 1; error with code in B * Carry = 0: * IF B = 0 * A = Sector Size (1 = 256, 2 = 512, 4 = 1024, 8 = 2048) * X = Number of Sectors (bits 31-16) * Y = Number of Sectors (Bits 15-0) * IF B != 0 * A = Sector Size (1 = 256, 2 = 512, 4 = 1024, 8 = 2048) * X = Number of Logical Cylinders * B = Number of Logical Sides * Y = Number of Logical Sectors/Track * SSDSize pshs u,y bsr DSize bcs ex@ ldu ,s get path desc in U ldu PD.RGS,u std R$D,u stx R$X,u sty R$Y,u clrb ex@ puls y,u,pc * DSize - Get SCSI disk size * * Exit: Carry = 1; error with code in B * Carry = 0: * IF B = 0 * A = Sector Size (1 = 256, 2 = 512, 4 = 1024, 8 = 2048) * X = Number of Sectors (bits 31-16) * Y = Number of Sectors (Bits 15-0) * IF B != 0 * A = Sector Size (1 = 256, 2 = 512, 4 = 1024, 8 = 2048) * X = Number of Logical Cylinders * B = Number of Logical Sides * Y = Number of Logical Sectors/Track DSize lbsr SCSIPrep do SCSI prep stuff lda #S$RCAP sta V.SCSICMD,u leax V.TxBuf,u stx V.TfrBuf,u IFNE D4N1+HDII lbsr MPIIn ENDC lbsr SCSIXfer bcs ex@ ldd V.TxBuf+2,u get bits 15-0 of block count addd #$0001 add 1 to count std V.TxBuf+2,u resave bcc b@ ldd V.TxBuf,u get bits 31-16 addd #$0001 add 1 std V.TxBuf,u resave b@ lda V.TxBuf+6,u clrb ldx V.TxBuf,u ldy V.TxBuf+2,u ex@ IFNE D4N1+HDII lbra MPIOut ELSE rts ENDC * ll_setstat * * Entry: * Y = address of path descriptor * U = address of device memory area * * Exit: * CC = carry set on error * B = error code * ll_setstat ldx PD.RGS,y lda R$B,x cmpa #SS.SQD beq StopUnit cmpa #SS.DCmd bne n@ pshs x save pointer to caller registers bsr DCmd call DCmd puls x get pointer to caller registers sta R$A,x save status byte in A n@ clrb ex rts * Entry: * R$B = SS.SQD StopUnit lbsr SCSIPrep do SCSI prep stuff lda #S$UNIT sta V.SCSICMD,u clr V.SCSIPrm2,u we want to STOP unit s@ IFNE D4N1+HDII lbsr MPIIn ENDC lbra SCSIXfer noperms comb ldb #E$FNA rts * Entry: * X = caller regs * Y = path descriptor * * R$B = SS.DCmd * R$X = Transfer buffer * R$Y = SCSI command packet DCmd * Fixed bug where Y was not being saved when doing os9 F$ID pshs y os9 F$ID get the user ID of the calling process cmpy #$0000 is it 0 (superuser)? puls y bne noperms no, don't allow the call lbsr SCSIPrep ldy R$X,x get caller's transfer buffer sty V.UTxBuf,u save off in mem for later ldx R$Y,x get ptr to caller's SCSI command buffer IFGT Level-1 ldy D.Proc get current process ptr lda P$Task,y get task # for current process ldb D.SysTsk get system task # ldy #SCSIPkLn max size of SCSI command pshs u save on stack leau V.SCSICMD,u point to SCSI command buffer in our statics os9 F$Move copy from caller to temporary task puls u bcs ex error copying, exit ELSE ldb #SCSIPkLn leay V.SCSICMD,u cl@ lda ,x+ sta ,y+ decb bne cl@ ENDC ldy V.PORT-UOFFSET,u get hw address (because we overwrite Y earlier) IFNE D4N1+HDII lbsr MPIIn ENDC inc V.OS9Err,u we want real SCSI errors returned inc V.CchDirty,u and make cache dirty leax retry@,pcr stx V.RetryVct,u retry@ lbsr SCSISend IFNE D4N1+HDII lbcs MPIOut ELSE bcs ex ENDC IFGT Level-1 ldx D.Proc get current process ptr ldb P$Task,x get task # for current process ENDC ldx V.UTxBuf,u msgloop@ lbsr Wait4REQ wait for REQ to be asserted bita #CMD command phase? lbne PostXfr yes, return io@ bita #INOUT data coming in or going out? bne in@ branch if coming in... IFGT Level-1 os9 F$LDABX leax 1,x ELSE lda ,x+ ENDC sta SCSIDATA,y bra msgloop@ in@ lda SCSIDATA,y IFGT Level-1 os9 F$STABX leax 1,x ELSE sta ,x+ ENDC bra msgloop@ * ll_read * * Entry: * Y = address of path descriptor * U = address of device memory area * * Static memory referenced: * V.CchPSpot = address of spot in cache where physical sector data will go * sectsize = sector size (0=256,1=512,2=1024,3=2048) * V.SectCnt = sectors to read * V.PhysSect = physical sector to start read from ll_read IFNE D4N1+HDII lbsr MPIIn ENDC IFNE SIZEMATTERS bsr SCSIPrep do SCSI prep stuff bsr MakeRead make read command packet ldx V.CchPSpot,u stx V.TfrBuf,u lbra SCSIXfer ELSE leax SCSIReadRetry,pcr stx V.RetryVct,u lbsr SCSIPrep do SCSI prep stuff lbsr MakeRead make read command packet SCSIReadRetry lbsr SCSISend bcs mpiex bita #CMD lbne PostXfr ldb V.SectCnt,u pshs b * Set up appropriate read call (regular or turbo) tst V.Turbo,u beq reg@ leax TurboRead,pcr bra do@ reg@ leax RegRead256,pcr do@ stx V.ReadVct,u ldx V.CchPSpot,u get pointer to physical sector in cache for data in again@ ldb V.Log2Phys,u pshs b loop@ jsr [V.ReadVct,u] dec ,s bne loop@ puls b dec ,s bne again@ puls a lbra PostXfr mpiex IFNE D4N1+HDII lbra MPIOut ELSE rts ENDC TurboRead IFNE H6309 * 6309 Turbo READ ldw #256 orcc #IntMasks we have to mask interrupts for Level 1 tfm y,x+ do the transfer andcc #^IntMasks we have to unmask interrupts for Level 1 lbsr DeauxDeaux rts ELSE * 6809 Turbo READ lda #16 pshs a l2@ lda SCSIDATA,y ldb SCSIDATA,y std ,x lda SCSIDATA,y ldb SCSIDATA,y std $02,x lda SCSIDATA,y ldb SCSIDATA,y std $04,x lda SCSIDATA,y ldb SCSIDATA,y std $06,x lda SCSIDATA,y ldb SCSIDATA,y std $08,x lda SCSIDATA,y ldb SCSIDATA,y std $0A,x lda SCSIDATA,y ldb SCSIDATA,y std $0C,x lda SCSIDATA,y ldb SCSIDATA,y std $0E,x leax 16,x dec ,s decrement counter bne l2@ puls a,pc ENDC RegRead256 clrb * * "Non-Turbo" Read Data from controller * * Passed: B = bytes to read * X = Address of buffer * Y = Controller Address * RegRead * We wait for REQ in an infinite, faster loop here lda SCSISTAT,y get SCSI status byte bita #REQ REQ? beq RegRead lda SCSIDATA,y sta ,x+ decb bne RegRead rts ENDC * Make Read/Write Packet * Entry: * A = SCSI command * V.PhysSect = 3 byte physical sector to read/write MakeWrite lda #S$WRITEX fcb $8C skip next two bytes MakeRead lda #S$READEX MakeRW sta V.SCSICMD,u put passed SCSI command lda V.SectCnt,u 'V.SectCnt' logical blocks * Make SCSI Read/Write 6 byte CDB here * sta V.SCSIPrm2,u * lda V.PhysSect,u * sta V.SCSILUN,u * ldd V.PhysSect+1,u * std V.SCSIPrm0,u * rts * Make SCSI Read/Write Extended 10 byte CDB here sta V.SCSIPrm6,u lda V.PhysSect,u sta V.SCSIPrm1,u ldd V.PhysSect+1,u std V.SCSIPrm2,u rts * Prep for SCSI transfer * Preserves all regs * Entry: Y = path descriptor * Exit: Y = hardware address SCSIPrep pshs x,d leax V.SCSICMD,u ldb #SCSIPkLn l@ clr ,x+ decb bne l@ ldb PD.DNS,y and DNS byte stb V.DnsByte,u save in our statics andb #DNS.TURBO mask out all but turbo bit stb V.Turbo,u and save state lda #NUMTRIES get retry count sta V.Retries,u and reset retry counter clr V.OS9Err,u we want real SCSI errors returned ldy V.PORT-UOFFSET,u get hw address puls x,d,pc * Check Transfer Status * This routine is passed the address of another routine to call in case * the device is busy or there is an error returned. * * Passed: V.RetryVct,u = address of routine to call if SCSI device is busy PostXfr lbsr GetStatB get transfer status byte bita #X$BUSY device BUSY? bne retry@ attempt a retry if so... chkerr@ bita #X$ERROR error? beq ok@ branch if not... * Error occurred.. retry retry@ dec V.Retries,u decrement retry count bne jmp@ try again if not at end IFNE D4N1+HDII lbsr SCSIErr lbra MPIOut ELSE lbra SCSIErr ENDC jmp@ jmp [V.RetryVct,u] ok@ clrb IFNE D4N1+HDII lbra MPIOut ELSE rts ENDC * ll_write * * Entry: * Y = address of path descriptor * U = address of device memory area * * Static memory referenced: * V.CchPSpot = address of spot in cache where physical sector data is * sectsize = sector size (0=256,1=512,2=1024,3=2048) * V.SectCnt = sectors to read * V.PhysSect = physical sector to start read from ll_write IFNE D4N1+HDII lbsr MPIIn ENDC IFNE SIZEMATTERS bsr SCSIPrep do SCSI prep stuff bsr MakeWrite make read command packet ldx V.CchPSpot,u stx V.TfrBuf,u ELSE leax SCSIWriteRetry,pcr stx V.RetryVct,u bsr SCSIPrep do SCSI prep stuff lbsr MakeWrite SCSIWriteRetry lbsr SCSISend lbcs mpiex bita #CMD bne PostXfr ldb V.SectCnt,u pshs b * Set up appropriate write call (regular or turbo) tst V.Turbo,u beq reg@ leax TurboWrite,pcr bra do@ reg@ leax RegWrite,pcr do@ stx V.WriteVct,u ldx V.CchPSpot,u again@ ldb V.Log2Phys,u pshs b loop@ jsr [V.WriteVct,u] dec ,s bne loop@ puls b dec ,s bne again@ puls a bra PostXfr TurboWrite IFNE H6309 * 6309 Turbo WRITE loop@ orcc #IntMasks we have to mask interrupts for Level 1 ldw #256 tfm x+,y andcc #^IntMasks we have to unmask interrupts for Level 1 lbsr DeauxDeaux rts ELSE * 6809 Turbo WRITE lda #16 pshs a l2@ ldd ,x sta SCSIDATA,y stb SCSIDATA,y ldd $02,x sta SCSIDATA,y stb SCSIDATA,y ldd $04,x sta SCSIDATA,y stb SCSIDATA,y ldd $06,x sta SCSIDATA,y stb SCSIDATA,y ldd $08,x sta SCSIDATA,y stb SCSIDATA,y ldd $0A,x sta SCSIDATA,y stb SCSIDATA,y ldd $0C,x sta SCSIDATA,y stb SCSIDATA,y ldd $0E,x sta SCSIDATA,y stb SCSIDATA,y leax 16,x dec ,s decrement counter bne l2@ puls a,pc ENDC * * "Non-Turbo" Write Data to controller * * Passed: X = Address of data to write * Y = Controller Address * RegWrite clrb loop@ lda SCSISTAT,y bita #REQ beq loop@ lda ,x+ sta SCSIDATA,y decb bne loop@ rts ENDC IFNE D4N1+HDII * Disto 4-N-1/HD-II: Map in MPI HERE MPIIn pshs cc,a lda MPI.Slct get MPI value sta V.MPISave,u save off in our statics anda #$F0 preserve CTS slot bits (%1111000) ora V.MPISlot,u OR in MPI slot of our HW MPIWrite sta MPI.Slct write out to MPI puls a,cc,pc MPIOut pshs cc,a lda V.MPISave,u bra MPIWrite ENDC * SCSIXfer * * Entry: * Y = hardware address * U = address of device memory area * * Static memory referenced: * V.TfrBuf,u = address of transfer/receive buffer SCSIXfer leax retry@,pcr stx V.RetryVct,u retry@ bsr SCSISend bcs sr@ ldx V.TfrBuf,u tfr@ lbsr Wait4REQ wait for REQ to be asserted bita #CMD lbne PostXfr COMMAND phase... * If here, we're in DATA PHASE bita #INOUT data coming in or going out? bne in@ branch if coming in... out@ lda ,x+ sta SCSIDATA,y bra tfr@ in@ lda SCSIDATA,y sta ,x+ bra tfr@ sr@ rts * Give up timeslice several times unless this is the system DeauxDeaux pshs x IFGT Level-1 ldx D.Proc get proc descriptor cmpx D.SysPrc system? beq WaitDone yep, system cannot sleep ENDC * ldx D.AProcQ get active proc queue * beq WaitDone if empty, return * ldx #$0001 * os9 F$Sleep give up timeslice * ldx D.AProcQ get active proc queue * beq WaitDone if empty, return ldx #$0001 os9 F$Sleep give up timeslice WaitDone puls x,pc return to caller * Get Status Byte from SCSI controller * Exit: A = status byte GetStatB bsr Wait4REQ lda SCSIDATA,y pshs a bsr Wait4REQ clr SCSIDATA,y puls pc,a * SCSI ID table with hi-bit set for SCSI-3 compliance IDTBL FCB $80+1,$80+2,$80+4,$80+8,$80+16,$80+32,$80+64,128 * * SCSI Packet Send Routine * * Sets LUN for SCSI Packet, then sends command packet to controller * * Passed: Y = Device Address * * Returns: A = SCSI Status byte * * Destroys: X * SCSISend ldb V.SCSILUN,u get SCSI LUN andb #%00011111 mask out LUN stb V.SCSILUN,u ldb V.DnsByte,u get DNS byte andb #%11100000 get SCSI LUN from byte orb V.SCSILUN,u OR with SCSI LUN byte stb V.SCSILUN,u save off ldd #BUSY*256 we want /BUSY bsr StatusWait bcs ex4 * BUSY is clear, put initiator/target IDs on bus lda V.DnsByte,u get DNS byte anda #$07 mask out all but SCSI IDs leax IDTBL,pcr point to device ID table lda a,x get ID value sta SCSIDATA,y write out to controller sta SCSISEL,y here too... ldd #BUSY*256+BUSY we want BUSY bsr StatusWait bcs ex4 * BUSY is set * Here we send the packet to the controller. chkok@ leax V.SCSICMD,u point X to SCSI command packet tfrloop@ bsr Wait4REQ wait for REQ bita #CMD SCSI CMD bit set? beq ex4 branch if not... bita #INOUT INOUT set? bne ckmsg@ branch if target->initiator lda ,x+ get byte from SCSI CMD packet sta SCSIDATA,y write to controller bra tfrloop@ ckmsg@ bita #MSG MESSAGE IN (target->initiator) beq ex4 * * MESSAGE IN phase code * MSGIn lda SCSIDATA,y extended message? deca bne SCSISend nope, restart target initiation ldb SCSIDATA,y get extended message length * Note: We ignore extended messages l@ tst SCSIDATA,y read extended message data decb bne l@ bra SCSISend message read, restart target initiation ex4 rts * * Loop until REQ bit is set * * Passed: Y = Device Address * * Returns: A = SCSI Status byte * Wait4REQ loop@ lda SCSISTAT,y get SCSI status byte bita #REQ REQ? beq sleep@ + rts + sleep@ lbsr DeauxDeaux bra loop@ * Wait for a set of conditions in the status register to be TRUE * This yields a delay of about 5 seconds. * * Entry: Y = HW address * A = flip (if bit set, that bit is tested) * B = mask (result must match this byte) StatusWait pshs x,d IFEQ Level-1 ldb #$02 ldx #$0000 ELSE ldb #$04 ldx #$0000 ENDC l@ lda SCSISTAT,y anda ,s apply flip cmpa 1,s compare to mask bne dec@ branch if not equal (not what we want) lda SCSISTAT,y clrb clear carry bra ok@ dec@ leax -1,x count down bne l@ decb decrement bits 23-16 bpl l@ if >=0, keep going comb set carry ldb #E$NotRdy ok@ leas 2,s puls x,pc * * Send a REQSENSE message to the SCSI controller * SndMSG lbsr Wait4REQ wait for REQ to be asserted bita #CMD command phase? bne ex4 yes, return beq INorOUT no, check for in/out rts INorOUT bita #INOUT data coming in or going out? bne ComingIn branch if coming in... lda ,x+ sta SCSIDATA,y bra SndMSG ComingIn lda SCSIDATA,y sta ,x+ bra SndMSG * SCSIErr - Attemps a REQUEST SENSE to find a SCSI error * * Entry: * Y = address of hardware * U = address of device memory area * * Exit: * CC = carry set * B = error code * SCSIErr lda #S$REQSEN REQUEST SENSE command sta V.SCSICMD,u clra clrb sta V.SCSILUN,u std V.SCSIPrm0,u lda #ReqPkL set allocation length std V.SCSIPrm2,u lbsr SCSISend send command bcs ex4 branch if error leax V.R$Err,u point to return data buffer bsr SndMSG get response data lbsr GetStatB clra pshs a lda V.R$Err,u get error code anda #$7F wipe out hi bit cmpa #$70 "current" error? bne L05A3 branch if not... lda V.R$Err2,u get more detailed error anda #%00001111 sta ,s save off stack lda V.R$AdSns,u get additional sense code L05A3 tst V.OS9Err,u send OS-9 error? L05A7 beq L05AD branch if so... tfr a,b else put SCSI error in B clr V.OS9Err,u and clear SCSI error flag bra ErrErr and return with error * Walk error table to find OS-9 error L05AD leax >ErrTbl,pcr ldb #E$Unit L05B3 tst ,x beq ErrErr cmpa ,x++ blt L05B3 ldb -1,x ErrErr coma puls pc,a * Error Table - Maps SCSI errors to OS-9 errors * This table is contructed so that gaps are actually continuations of * the previous entry. For example, $14 maps to E$Seek, and so does $15 and * $16. ErrTbl FCB $01,E$NotRdy FCB $02,E$Seek FCB $03,E$Write FCB $04,E$NotRdy FCB $06,E$Seek FCB $10,E$CRC FCB $11,E$Read FCB $14,E$Seek FCB $17,E$CRC FCB $19,E$IllArg FCB $1C,E$Read FCB $1E,E$CRC FCB $20,E$IllCmd FCB $21,E$Sect FCB $25,E$IllArg FCB $29,E$NotRdy FCB $00 EMOD eom EQU * END