home *** CD-ROM | disk | FTP | other *** search
- ;
- ; Data storage for local subroutines
- ;
- cmd_ready db SCSI_TESTREADY,0,0,0,0,0
- cmd_rewind db SCSI_REWIND,0,0,0,0,0
- cmd_sense db SCSI_REQSENSE,0,0,0,size sense,0
- cmd_e_sense db SCSI_REQSENSE,0,0,0,size e_sense,0
- cmd_format db SCSI_FORMATUNIT,FORMAT_NORMAL,0,0,0,0
- cmd_remap db SCSI_REASSIGN,0,0,0,0,0
- cmd_space db SCSI_SPACE,1,0,0,0,0
- if extended_io
- cmd_read db SCSI_READBLK,0,0,0,0,0,0,0,1,0
- cmd_write db SCSI_WRITEBLK,0,0,0,0,0,0,0,1,0
- else
- cmd_read db SCSI_READBLK,0,0,0,1,0
- cmd_write db SCSI_WRITEBLK,0,0,0,1,0
- endif
- cmd_tread db SCSI_READBLK,1,0,0,0,0
- cmd_twrite db SCSI_WRITEBLK,1,0,0,0,0
- cmd_twritefm db SCSI_WRITEFM,0,0,0,CLOSE_FM_CNT,0
- cmd_inquire db SCSI_INQUIRY,0,0,0,size inq,0
- cmd_erase db SCSI_ERASE,1,0,0,0,0
- cmd_load db SCSI_LOAD,0,0,0,0,0
- cmd_capacity db SCSI_READSIZE,0,0,0,0,0,0,0,0,0
- cmd_verify db SCSI_VERIFYBLK,0,0,0,0,0,0,0,SECT_TRACK,0
-
- if large_drives
- even
- lsect_lsw dw ?
- lsect_msw dw ?
- endif
-
- even
- docmd_cmd dw ?
- docmd_buf dw ?
- docmd_buf_seg dw ?
- docmd_len dw ?
- docmd_ustatus db ?
- docmd_estatus db ?
- docmd_message db ?
-
- sense_ustatus db ?
- sense_estatus db ?
- sense_message db ?
-
- retry_cnt db ?
-
- if dump_sense
- sense_msg1 db 0dh,07h,'Unit '
- sense_unit db 'xxh, Err '
- sense_err db 'xxh, Stat '
- sense_ustat db 'xxh, Msg '
- sense_msg db 'xxh, Retry '
- sense_retry db 'xxh$'
- sense_msg2 db ', Sense '
- sense_code db 'xxh, Addr '
- sense_addr3 db 'xx'
- sense_addr2 db 'xx'
- sense_addr1 db 'xx'
- sense_addr0 db 'xxh$'
- ife monitor
- sense_msg3 db 0dh,0ah,'$'
- endif
- endif
-
- ;
- ; Reset the SCSI Bus
- ;
- scsi_reset proc near
- pusha
-
- mov ax,SCSI_CARD_SEG ;Point at the command port
- mov es,ax
- mov si,SCSI_CMD_PORT
-
- mov byte ptr es:[si],CMDBASE or CMDRST
- call wait100us
- mov byte ptr es:[si],CMDBASE
- call wait100us
-
- popa
- ret
- scsi_reset endp
-
- ;
- ; Request Sense data from a unit and display the result
- ; Called after every SCSI command with the exit code in 'al'
- ;
- scsi_sense proc near
- pushf
- pusha
- push es
-
- if dump_sense
- ;
- ; Print out the first part even if we can't retrieve any sense status
- ;
- mov al,docmd_estatus ;Save for printing
- mov sense_estatus,al
- mov al,docmd_ustatus
- mov sense_ustatus,al
- mov al,docmd_message
- mov sense_message,al
- mov di,cur_unit
- mov dl,[di].unit_select
- lea bx,sense_unit ;Unit
- call hex2asc2
- mov dl,sense_estatus ;Error (from docmd)
- lea bx,sense_err
- call hex2asc2
- mov dl,sense_ustatus ;Status (from unit)
- lea bx,sense_ustat
- call hex2asc2
- mov dl,sense_message ;Msg (from unit)
- lea bx,sense_msg
- call hex2asc2
- mov dl,retry_cnt ;Retry
- lea bx,sense_retry
- call hex2asc2
- lea dx,sense_msg1
- call puts
- endif
-
- ;
- ; Try to retrieve sense status
- ;
- mov di,cur_unit ;Unit
- lea bx,[di].unit_sense ;Buffer Offset
- mov cx,size sense ;Buffer Size
- lea dx,cmd_sense ;Command
- cmp [di].unit_sense.sense_sense,SENSE_CCS
- jnz no_e_sense
- lea bx,[di].unit_e_sense ;Buffer Offset
- mov cx,size e_sense ;Buffer Size
- lea dx,cmd_e_sense ;Command
- no_e_sense: push ds ;Buffer Segment
- pop es
- mov di,dx
- call docmd
-
- if dump_sense
- ;
- ; If we got something, print it
- ;
- jnc sense_dump
- jmp sense_exit
-
- sense_dump: mov di,cur_unit
- cmp [di].unit_sense.sense_sense,SENSE_CCS
- jz dump_e_sense
-
- mov dl,[di].unit_sense.sense_sense
- lea bx,sense_code ;Sense
- call hex2asc2
- mov dl,0
- lea bx,sense_addr3
- call hex2asc2
- mov dl,[di].unit_sense.sense_lba_b2
- lea bx,sense_addr2
- call hex2asc2
- mov dl,[di].unit_sense.sense_lba_b1
- lea bx,sense_addr1
- call hex2asc2
- mov dl,[di].unit_sense.sense_lba_b0
- lea bx,sense_addr0
- call hex2asc2
- jmp short sense_print
-
- dump_e_sense: mov dl,[di].unit_e_sense.e_sense_sense
- lea bx,sense_code ;Sense
- call hex2asc2
- mov dl,[di].unit_e_sense.e_sense_lba_b3
- lea bx,sense_addr3 ;Address
- call hex2asc2
- mov dl,[di].unit_e_sense.e_sense_lba_b2
- lea bx,sense_addr2
- call hex2asc2
- mov dl,[di].unit_e_sense.e_sense_lba_b1
- lea bx,sense_addr1
- call hex2asc2
- mov dl,[di].unit_e_sense.e_sense_lba_b0
- lea bx,sense_addr0
- call hex2asc2
-
- sense_print: lea dx,sense_msg2
- call puts
- endif
-
- sense_exit: if dump_sense
- if monitor
- mov cx,20000
- sense_wait: call wait100us
- loop sense_wait
- else
- lea dx,sense_msg3 ;Terminate the Message
- call puts
- endif
- endif
-
- pop es
- popa
- popf
- ret
- scsi_sense endp
-
- ;
- ; Get the Extended Sense Status from the current Unit
- ;
- get_sense proc near
- mov di,cur_unit ;Unit
- lea bx,[di].unit_e_sense ;Buffer Offset
- push ds ;Buffer Segment
- pop es
- mov cx,size e_sense ;Buffer Size
- lea di,cmd_e_sense ;Command
- call docmd ;Always ask first
- ret
- get_sense endp
-
- ;
- ; Inquire about the type of a unit
- ;
- ; This MUST be the first call to a unit after the reset is done!
- ;
- ; al = return code, 'C' error indicates an error
- ;
- scsi_inquire proc near
- push cx
-
- ;
- ; First thing we should do is wait for the unit to be ready
- ; as it takes some drives a while to spin up.
- ;
- mov retry_cnt,READY_RETRY
- ready_loop1: lea di,cmd_ready ;Command
- call docmd
- jnc unit_is_ready
- cmp al,CNOCONNECT ;No such unit?
- jz ready_error
- push cx
- mov cx,10000 ;Wait 1 Second
- ready_loop2: call wait100us
- loop ready_loop2
- pop cx
- dec retry_cnt ;RETRY Times
- jns ready_loop1
- jmp short unit_is_ready ;Still Try the Inquire
- ready_error: stc
- jmp short inquire_exit
-
- ;
- ; Then requests its sense status.
- ; This gives us a chance to find out if the
- ; device supports the Command Command Set (CCS)
- ;
- unit_is_ready: call get_sense
- jc inquire_exit
-
- ;
- ; Ok, Now find out what kind of device it is
- ;
- mov di,cur_unit ;Unit
- lea bx,[di].unit_inq_buf ;Buffer Offset
- push ds ;Buffer Segment
- pop es
- mov cx,size inq ;Buffer Size
- lea di,cmd_inquire ;Command
- call docmd
-
- inquire_exit: pop cx
- ret
- scsi_inquire endp
-
- ;
- ; Determine the size of a disk
- ;
- ; al = return code, 'C' error indicates an error
- ;
- scsi_capacity proc near
- push cx
- mov retry_cnt,MAX_RETRY
-
- capacity_retry: mov di,cur_unit ;Unit
- lea bx,[di].unit_cap_buf ;Buffer Offset
- push ds ;Buffer Segment
- pop es
- mov cx,size cap ;Buffer Size
- lea di,cmd_capacity ;Command
- call docmd
- jnc capacity_exit
- call scsi_sense
- dec retry_cnt
- jns capacity_retry
- stc
-
- capacity_exit: pop cx
- ret
- scsi_capacity endp
-
- ;
- ; Verify (cx) Sectors starting with (dx:ax)
- ;
- ; al = return code, 'C' indicates an error
- ;
-
- scsi_verify proc near
- mov retry_cnt,0 ;Don't do retrys
- lea di,cmd_verify ;Command
- mov [di].ver_cmd_lba_b3,dh ;Insert Sector
- mov [di].ver_cmd_lba_b2,dl ; into Command
- mov [di].ver_cmd_lba_b1,ah ;Insert Sector
- mov [di].ver_cmd_lba_b0,al ; into Command
- mov [di].ver_cmd_len_b1,ch ;Insert Length
- mov [di].ver_cmd_len_b0,cl ; into Command
- call docmd
- jnc verify_exit
- call scsi_sense
-
- verify_exit: ret
- scsi_verify endp
-
- ;
- ; Read Some Blocks from the disk given
- ; the request header in es:bx
- ;
- ; al = return code, 'C' indicates an error
- ;
- disk_read proc near
- mov retry_cnt,MAX_RETRY
-
- mov di,bx
- mov cx,es:[di].rh4_count ;Sector Count
- if large_drives
- mov dx,es:[di].rh4_lsect_lsw ;Starting Sector
- mov lsect_lsw,dx
- mov dx,es:[di].rh4_lsect_msw
- mov lsect_msw,dx
- else
- mov dx,es:[di].rh4_sector ;Starting Sector
- endif
- mov bx,es:[di].rh4_buf_ofs ;Buffer Offset
- mov ax,es:[di].rh4_buf_seg ;Buffer Segment
- mov es,ax
-
- mov si,cur_bpb
- lea di,cmd_read ;Command
- ife large_drives
- mov ax,[si].bpb_hs_msw ;Drive Sector Offset
- if extended_io
- mov [di].io_cmd_lba_b3,ah ;Insert Sector
- endif
- mov [di].io_cmd_lba_b2,al ;Into the Command
- endif
-
- if multi_sector
- mov ax,cx ;Get Sector Count
- and ax,CHUNK_MAX-1 ;Mask Off the I/O Chunk
- jnz disk_r_cok1 ;Check for Boundary
- mov ax,CHUNK_MAX
- if oldcode
- disk_r_cok1: shl ax,1 ;Convert to Buffer Size
- shl ax,1
- shl ax,1
- shl ax,1
- shl ax,1
- shl ax,1
- shl ax,1
- shl ax,1
- shl ax,1
- else
- disk_r_cok1: shl ax,9 ;Convert to Buffer Size
- endif
- add ax,bx ;Check for Wrap
- else
- mov ax,bx ;Check for Wrap
- add ax,P_SECT ;The First Time
- endif
- disk_r_loop: jnc disk_r_nowrap
- mov ax,bx ;Normalize the
- if oldcode
- shr ax,1 ;Segment and
- shr ax,1
- shr ax,1
- shr ax,1
- else
- shr ax,4 ;Segment and
- endif
- mov si,es ;Offset so that
- add si,ax ;It dosn't Wrap
- mov es,si
- and bx,000Fh
- disk_r_nowrap: push cx
- if large_drives
- mov dx,lsect_msw
- if extended_io
- mov [di].io_cmd_lba_b3,dh
- mov [di].io_cmd_lba_b2,dl
- else
- and dl,01Fh
- mov [di].io_cmd_lba_b2,dl
- endif
- mov dx,lsect_lsw
- endif
- mov [di].io_cmd_lba_b1,dh ;Insert Sector
- mov [di].io_cmd_lba_b0,dl ;Into the Command
- if multi_sector
- and cx,CHUNK_MAX-1 ;Mask Off the I/O Chunk
- jnz disk_r_cok2 ;Check for Boundary
- mov cx,CHUNK_MAX
- disk_r_cok2:
- if extended_io
- mov [di].io_cmd_cnt_b1,ch ;Insert Sector Count
- endif
- mov [di].io_cmd_cnt_b0,cl ;Into the Command
- if oldcode
- shl cx,1 ;Convert to Buffer Size
- shl cx,1
- shl cx,1
- shl cx,1
- shl cx,1
- shl cx,1
- shl cx,1
- shl cx,1
- shl cx,1
- else
- shl cx,9 ;Convert to Buffer Size
- endif
- else
- mov cx,P_SECT ;Buffer Size
- endif
- disk_r_retry: call docmd
- jnc disk_r_cok3
- call scsi_sense
- dec retry_cnt
- jns disk_r_retry ;Already Setup
- pop cx
- stc
- jmp short disk_r_exit
- if multi_sector
- disk_r_cok3: pop cx
- mov ax,cx ;Get Sector Count
- and ax,CHUNK_MAX-1 ;Mask Off the I/O Chunk
- jnz disk_r_cok4 ;Check for Boundary
- mov ax,CHUNK_MAX
- disk_r_cok4: sub cx,ax ;Dec Sector Count
- jz disk_r_exit
- if large_drives
- add lsect_lsw,ax ;Bump to next Sector
- adc lsect_msw,0
- else
- add dx,ax ;Bump to next Sector
- endif
- if oldcode
- shl ax,1 ;Convert to Buffer Size
- shl ax,1
- shl ax,1
- shl ax,1
- shl ax,1
- shl ax,1
- shl ax,1
- shl ax,1
- shl ax,1
- else
- shl ax,9 ;Convert to Buffer Size
- endif
- add bx,ax
- jmp disk_r_loop
- else
- disk_r_cok3: pop cx
- if large_drives
- add lsect_lsw,1 ;Bump to next Sector
- adc lsect_msw,0
- else
- inc dx ;Bump to next Sector
- endif
- add bx,P_SECT
- loop disk_r_loop
- clc
- endif
-
- disk_r_exit: mov es,rh_seg
- mov bx,rh_off
- pushf
- mov ax,es:[bx].rh4_count ;Update the Count
- sub ax,cx
- mov es:[bx].rh4_count,ax
- popf
- ret
- disk_read endp
-
- ;
- ; Write Some Blocks to the disk given
- ; the request header in es:bx
- ;
- ; al = return code, 'C' indicates an error
- ;
- disk_write proc near
- mov retry_cnt,MAX_RETRY
-
- mov di,bx
- mov cx,es:[di].rh8_count ;Sector Count
- if large_drives
- mov dx,es:[di].rh8_lsect_lsw ;Starting Sector
- mov lsect_lsw,dx
- mov dx,es:[di].rh8_lsect_msw
- mov lsect_msw,dx
- else
- mov dx,es:[di].rh8_sector ;Starting Sector
- endif
- mov bx,es:[di].rh8_buf_ofs ;Buffer Offset
- mov ax,es:[di].rh8_buf_seg ;Buffer Segment
- mov es,ax
-
- mov si,cur_bpb
- lea di,cmd_write ;Command
- ife large_drives
- mov ax,[si].bpb_hs_msw ;Drive Sector Offset
- if extended_io
- mov [di].io_cmd_lba_b3,ah ;Insert Sector
- endif
- mov [di].io_cmd_lba_b2,al ;Into the Command
- endif
-
- if multi_sector
- mov ax,cx ;Get Sector Count
- and ax,CHUNK_MAX-1 ;Mask Off the I/O Chunk
- jnz disk_w_cok1 ;Check for Boundary
- mov ax,CHUNK_MAX
- if oldcode
- disk_w_cok1: shl ax,1 ;Convert to Buffer Size
- shl ax,1
- shl ax,1
- shl ax,1
- shl ax,1
- shl ax,1
- shl ax,1
- shl ax,1
- shl ax,1
- else
- disk_w_cok1: shl ax,9 ;Convert to Buffer Size
- endif
- add ax,bx ;Check for Wrap
- else
- mov ax,bx ;Check for Wrap
- add ax,P_SECT ;The First Time
- endif
- disk_w_loop: jnc disk_w_nowrap
- mov ax,bx ;Normalize the
- if oldcode
- shr ax,1 ;Segment and
- shr ax,1
- shr ax,1
- shr ax,1
- else
- shr ax,4 ;Segment and
- endif
- mov si,es ;Offset so that
- add si,ax ;It dosn't Wrap
- mov es,si
- and bx,000Fh
- disk_w_nowrap: push cx
- if large_drives
- mov dx,lsect_msw
- if extended_io
- mov [di].io_cmd_lba_b3,dh
- mov [di].io_cmd_lba_b2,dl
- else
- and dl,01Fh
- mov [di].io_cmd_lba_b2,dl
- endif
- mov dx,lsect_lsw
- endif
- mov [di].io_cmd_lba_b1,dh ;Insert Sector
- mov [di].io_cmd_lba_b0,dl ;Into the Command
- if multi_sector
- and cx,CHUNK_MAX-1 ;Mask Off the I/O Chunk
- jnz disk_w_cok2 ;Check for Boundary
- mov cx,CHUNK_MAX
- disk_w_cok2:
- if extended_io
- mov [di].io_cmd_cnt_b1,ch ;Insert Sector Count
- endif
- mov [di].io_cmd_cnt_b0,cl ;Into the Command
- if oldcode
- shl cx,1 ;Convert to Buffer Size
- shl cx,1
- shl cx,1
- shl cx,1
- shl cx,1
- shl cx,1
- shl cx,1
- shl cx,1
- shl cx,1
- else
- shl cx,9 ;Convert to Buffer Size
- endif
- else
- mov cx,P_SECT ;Buffer Size
- endif
- disk_w_retry: call docmd
- jnc disk_w_cok3
- call scsi_sense
- dec retry_cnt
- jns disk_w_retry ;Already Setup
- pop cx
- stc
- jmp short disk_w_exit
- if multi_sector
- disk_w_cok3: pop cx
- mov ax,cx ;Get Sector Count
- and ax,CHUNK_MAX-1 ;Mask Off the I/O Chunk
- jnz disk_w_cok4 ;Check for Boundary
- mov ax,CHUNK_MAX
- disk_w_cok4: sub cx,ax ;Dec Sector Count
- jz disk_w_exit
- if large_drives
- add lsect_lsw,ax ;Bump to next Sector
- adc lsect_msw,0
- else
- add dx,ax ;Bump to next Sector
- endif
- if oldcode
- shl ax,1 ;Convert to Buffer Size
- shl ax,1
- shl ax,1
- shl ax,1
- shl ax,1
- shl ax,1
- shl ax,1
- shl ax,1
- shl ax,1
- else
- shl ax,9 ;Convert to Buffer Size
- endif
- add bx,ax
- jmp disk_w_loop
- else
- disk_w_cok3: pop cx
- if large_drives
- add lsect_lsw,1 ;Bump to next Sector
- adc lsect_msw,0
- else
- inc dx ;Bump to next Sector
- endif
- add bx,P_SECT
- loop disk_w_loop
- clc
- endif
-
- disk_w_exit: mov es,rh_seg
- mov bx,rh_off
- pushf
- mov ax,es:[bx].rh8_count ;Update the Count
- sub ax,cx
- mov es:[bx].rh8_count,ax
- popf
- ret
- disk_write endp
-
- ;
- ; Read Some Blocks from the Tape
- ;
- tape_read proc near
- mov read_flag,TRUE ;Data Read from Tape
- mov di,bx
- mov cx,es:[di].rh4_count ;Byte Count
- mov ax,cx ;Test for invalid
- and ax,P_SECT-1 ;Byte Count
- jz tape_r_valid
- mov error_flag,TRUE
- mov es:[di].rh4_count,0 ;Nothing Read
- stc ;Oops
- ret
- tape_r_valid: mov bx,es:[di].rh4_buf_ofs ;Buffer Offset
- mov ax,es:[di].rh4_buf_seg ;Buffer Segment
- mov es,ax
- mov ax,bx ;Normalize the
- if oldcode
- shr ax,1 ;Segment and
- shr ax,1
- shr ax,1
- shr ax,1
- else
- shr ax,4 ;Segment and
- endif
- mov si,es ;Offset so that
- add si,ax ;It dosn't Wrap
- mov es,si
- and bx,000Fh
- lea di,cmd_tread
- mov ax,cx ;Convert Bytes
- if oldcode
- shr ax,1 ;to Blocks
- shr ax,1
- shr ax,1
- shr ax,1
- shr ax,1
- shr ax,1
- shr ax,1
- shr ax,1
- shr ax,1
- else
- shr ax,9 ;to Blocks
- endif
- mov [di].tio_cmd_cnt_b1,ah ;Insert into Command
- mov [di].tio_cmd_cnt_b0,al
- call docmd
- jnc tape_r_ok
- ;
- ; Get the Extended Sense Status to check for reading FileMark
- ;
- call get_sense ;Get Extended Sense
- jc tape_r_kaboom
- mov di,cur_unit ;Unit
- cmp [di].unit_e_sense.e_sense_sense,80h
- jnz tape_r_eom
- tape_r_kaboom: mov error_flag,TRUE ;Real Error Occured
- stc
- ret
- tape_r_eom: mov es,rh_seg
- mov bx,rh_off
- mov es:[bx].rh4_count,0 ;Nothing Read
- clc
- tape_r_ok: ret
- tape_read endp
-
- ;
- ; Write Some Blocks to the Tape
- ;
- tape_write proc near
- mov write_flag,TRUE ;Data Written to Tape
- mov di,bx
- mov cx,es:[di].rh8_count ;Byte Count
- mov ax,cx ;Test for invalid
- and ax,P_SECT-1 ;Byte Count
- jz tape_w_valid
- mov es:[di].rh8_count,0 ;Nothing Written
- mov error_flag,TRUE ;ERROR!
- stc ;Oops
- ret
- tape_w_valid: mov cx,es:[di].rh8_count ;Byte Count
- mov bx,es:[di].rh8_buf_ofs ;Buffer Offset
- mov ax,es:[di].rh8_buf_seg ;Buffer Segment
- mov es,ax
- mov ax,bx ;Normalize the
- if oldcode
- shr ax,1 ;Segment and
- shr ax,1
- shr ax,1
- shr ax,1
- else
- shr ax,4 ;Segment and
- endif
- mov si,es ;Offset so that
- add si,ax ;It dosn't Wrap
- mov es,si
- and bx,000Fh
- lea di,cmd_twrite
- mov ax,cx ;Convert Bytes
- if oldcode
- shr ax,1 ;to Blocks
- shr ax,1
- shr ax,1
- shr ax,1
- shr ax,1
- shr ax,1
- shr ax,1
- shr ax,1
- shr ax,1
- else
- shr ax,9 ;to Blocks
- endif
- mov [di].tio_cmd_cnt_b1,ah ;Insert into Command
- mov [di].tio_cmd_cnt_b0,al
- call docmd
- jnc tape_w_ok
- ;
- ; Get the Sense Status and see if we hit EOM.
- ; This is to allow the FileMark to still be written
- ; during the close processing.
- ;
- call get_sense ;Get Extended Sense
- jc tape_w_kaboom
- mov di,cur_unit ;Unit
- cmp [di].unit_e_sense.e_sense_sense,40h
- jz tape_w_eom
- tape_w_kaboom: mov error_flag,TRUE ;Real Error Occured
- mov es,rh_seg
- mov bx,rh_off
- mov es:[bx].rh8_count,0 ;Nothing Written
- tape_w_eom: stc
- tape_w_ok: ret
- tape_write endp
-
- ;
- ; Do a command
- ;
- ; bx = buffer offset
- ; es = buffer segment
- ; cx = buffer len
- ; di => command string
- ;
- ; al = return code, 'C' indicates an error
- ;
- docmd proc near
- pusha
- push es
-
- mov docmd_buf,bx ;Save our arguments
- mov docmd_buf_seg,es
- mov docmd_len,cx
- mov docmd_cmd,di
- mov docmd_ustatus,0FFh
-
- if monitor
- mov ax,'F' ;Arbitrate for Bus
- call show_phase
- endif
-
- mov ax,SCSI_CARD_SEG ;Point at the Card
- mov es,ax
- mov si,SCSI_CMD_PORT ;Command Port
- mov di,SCSI_DATA_PORT ;Data Port
- mov bx,cur_unit
- mov al,[bx].unit_select ;Get our Select Bit
-
- if reserve_addr
- ;
- ; Get us control of the BUS by starting Arbitration
- ; Wait a maximum of 250ms for Control of the Bus
- ;
- or al,080h ;Add our Address
- mov byte ptr es:[si],CMDBASE
- nop
- mov byte ptr es:[di],080h ;Our Address
- nop
- mov byte ptr es:[si],CMDBASE or CMDSTARB
- mov cx,2500
- arb_loop: test byte ptr es:[si],STARBCOMPL
- jnz try_sel
- call wait100us
- loop arb_loop
- else
- ;
- ; Wait 250ms for the Bus to become free
- ;
- mov cx,2500
- idle_loop: test byte ptr es:[si],STBSY ;Busy?
- jz try_sel
- call wait100us
- loop idle_loop
- endif
-
- call scsi_reset
- mov al,CBUSBUSY ;Bus still BUSY?
- jmp docmd_exit
-
- try_sel: mov byte ptr es:[di],al ;Select Bit
- nop
- mov byte ptr es:[si],CMDBASE or CMDENABLE or CMDSEL
-
- if monitor
- mov ax,'S' ;Select Target
- call show_phase
- endif
-
- ;
- ; Wait 250 ms for the Target to be SELected
- ;
- mov cx,2500
- sel_loop: test byte ptr es:[si],STBSY ;Wait for BSY
- jnz cmd_xfer
- call wait100us
- loop sel_loop
-
- if monitor
- mov ax,'A' ;Abort Selection
- call show_phase
- endif
-
- mov byte ptr es:[si],CMDBASE or CMDSEL
- call wait100us ;Spec says wait 200us
- call wait100us ;to abort selection phase
- test byte ptr es:[si],STBSY ;Look one final time
- jnz cmd_xfer ;Device did answer
- mov al,CNOCONNECT ;Nothing Answered
- jmp docmd_exit
-
- ;
- ; Start the Command, (al) contains last known status
- ;
- cmd_xfer: mov byte ptr es:[si],CMDBASE or CMDENABLE
- nop
- xfer_loop: mov al,es:[si] ;Get Status Byte
- test al,STBSY ;Look for BSY bit
- jnz still_busy
- jmp xfer_offline
- if scsi_parity
- still_busy: test al,STPARERR ;Parity Error?
- jz still_good
- jmp xfer_parerr
- still_good: test al,STREQ ;Request?
- jz xfer_loop
- else
- still_busy: test al,STREQ ;Request?
- jz xfer_loop
- endif
-
- ;
- ; Figure out what type of request it is
- ;
- and al,REQ_MASK
- cmp al,REQ_CMDOUT ;Is it Command Out?
- jnz try_dataout
-
- if monitor
- mov ax,'C' ;Command
- call show_phase
- endif
-
- mov si,docmd_cmd ;Get Command Pointer
- movsb ;Send Byte to Card
- mov docmd_cmd,si
- mov si,SCSI_CMD_PORT ;Restore Command Port
- mov di,SCSI_DATA_PORT ;Restore Data Port
- jmp xfer_loop
-
- try_dataout: cmp al,REQ_DATAOUT ;Is it Data Out?
- jnz try_datain
-
- if monitor
- mov ax,'W' ;Write
- call show_phase
- endif
-
- mov bx,si
- mov cx,docmd_len ;Get the Data Count
- mov si,docmd_buf ;Source Offset
- mov ds,docmd_buf_seg ;Source Segment
- cld
-
- dataout_loop: test byte ptr es:[bx],STBSY ;Must be BUSY
- jz dataout_exit
- test byte ptr es:[bx],STREQ ;Wait for REQ
- jz dataout_loop
- movsb ;Transfer a Byte
- dec di ;Keep in Valid
- loop dataout_loop ;Done Yet?
-
- dataout_exit: mov si,bx ;Restore the Environment
- mov ax,cs
- mov ds,ax
- jmp xfer_loop
-
- try_datain: cmp al,REQ_DATAIN ;Is it Data In?
- jnz try_statin
-
- if monitor
- mov ax,'R' ;Read
- call show_phase
- endif
-
- mov bx,si
- mov si,di ;Source Offset
- mov ax,es
- mov cx,docmd_len ;Length
- mov di,docmd_buf ;Dest Offset
- mov es,docmd_buf_seg ;Dest Segment
- mov ds,ax ;Source Segment
- cld
-
- datain_loop: test byte ptr [bx],STBSY ;Must be BUSY
- jz datain_exit
- test byte ptr [bx],STREQ ;Wait for REQ
- jz datain_loop
- movsb ;Transfer a Byte
- dec si ;Keep in Valid
- loop datain_loop ;Done Yet?
-
- datain_exit: mov ax,ds ;Restore the Environment
- mov es,ax
- mov ax,cs
- mov ds,ax
- mov di,si
- mov si,bx
- jmp xfer_loop
-
- try_statin: cmp al,REQ_STATIN ;Is it Status In?
- jnz try_msgout
-
- if monitor
- mov ax,'s' ;Status
- call show_phase
- endif
-
- mov al,es:[di] ;Get the Status Byte
- mov docmd_ustatus,al
- jmp xfer_loop
-
- try_msgout: cmp al,REQ_MSGOUT ;Is it Message Out?
- jnz try_msgin
-
- if monitor
- mov ax,'M' ;Message Out
- call show_phase
- endif
-
- mov byte ptr es:[di],MSG_REJECT
- jmp xfer_loop
-
- try_msgin: cmp al,REQ_MSGIN ;Is it Message In?
- jnz kaboom
-
- if monitor
- mov ax,'m' ;Message In
- call show_phase
- endif
-
- mov al,es:[di] ;Get the MSG Byte
- mov docmd_message,al ;And Save it
- cmp al,MSG_COMPLETE ;Are We All Done?
- jnz xfer_error
- cmp docmd_ustatus,0 ;Did we have an error?
- mov al,COK ;Preload OK code
- jz docmd_exit
- jmp xfer_error ;Oops
-
- kaboom: call scsi_reset ;Reset the BUS
-
- if monitor
- mov ax,'?' ;Message In
- call show_phase
- endif
-
- xfer_error: mov al,CERROR ;Command Failed with Bad Status
- jmp short docmd_exit
- xfer_offline: mov al,COFFLINE ;Unit went OffLine
- jmp short docmd_exit
- xfer_parerr: mov al,CPARERR ;Parity Error Detected
- jmp short docmd_exit
- xfer_selerr: mov al,CSELERR ;Re-Select?
-
- docmd_exit: mov docmd_estatus,al
- mov byte ptr es:[si],CMDBASE
- pop es
- popa
- mov al,docmd_estatus
- cmp al,COK
- jz docmd_exit_ok
- stc
- docmd_exit_ok: ret
- docmd endp
-
- ;
- ; Wait One Hundred Micros Seconds
- ;
- ; The value of 'cx' is computed for an 8 Mhz Clock
- ;
- wait100us proc near
- push cx ; (3) = 375ns
- mov cx,79 ; (2) = 250ns
- wait_u_loop: loop wait_u_loop ; (10) = 1250ns * X
- pop cx ; (5) = 625ns
- ret ; (11+) = 1375ns
- wait100us endp
-
- ;
- ; Monitor the Bus Phase on the Video Screen
- ;
- if monitor
- show_phase proc
- push es
- push di
- or ax,VIDEO_COLOR
- mov di,VIDEO_SEG
- mov es,di
- mov di,VIDEO_OFS
- stosw
- pop di
- pop es
- ret
- show_phase endp
- endif
-