SCSI Device Driver for the Seagate ST-01
Brian Who?
briana at tau-ceti.isc-br.com
Thu Aug 30 12:03:34 AEST 1990
Here is a very simple minded device driver using the ST-01 SCSI
interface card. It is none to fast, and the code is probably not what
it could be, but for my first assembler project on a PC it does work.
Enjoy!
#
# This is a Shell Archive.
# Remove everything above and including the cut line.
# Then run the rest of the file through #! /bin/sh.
# -----cut here-----cut here-----cut here-----cut here-----
#! /bin/sh
# Execute the file with #! /bin/sh (not csh) to create the files:
# Makefile
# Readme.10
# dump.asm
# equ.inc
# ioctl.asm
# scsi.asm
# sformat.c
# struct.inc
# subs.asm
# units.asm
# This Archive created: Wed Aug 29 19:00:19 1990
# By: Brian Who? at I Saute Cats - Barbecue Rats, Spokane, WA
#
export PATH; PATH=/bin:$PATH
echo shar: extracting "'Makefile'" '(388 characters)'
if test -f 'Makefile'
then
echo shar: will not over-write existing file "'Makefile'"
else
sed 's/^XX//' > 'Makefile' << \SHAR_EOF
XX#
XX# SCSI Stuff
XX#
XXall: scsi.sys sformat.exe
XX
XX#
XX# SCSI Disk Device Driver
XX#
XXscsi.sys: scsi.obj
XX link +scsi.obj, scsi ;
XX exe2bin scsi.exe scsi.sys
XX
XXscsi.obj: scsi.asm subs.asm ioctl.asm dump.asm units.asm equ.inc struct.inc
XX masm scsi.asm scsi.obj scsi.lst ;
XX
XX#
XX# SCSI Disk Formatter
XX#
XXsformat.exe: sformat.c
XX cl -G2 -Ox -o sformat.exe sformat.c
XX
XX#
XX# clean
XX#
XXclean:
XX rm -f *.exe *.obj *.lst
SHAR_EOF
if test 388 -ne "`wc -c < 'Makefile'`"
then
echo shar: error transmitting "'Makefile'" '(should have been 388 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Readme.10'" '(2706 characters)'
if test -f 'Readme.10'
then
echo shar: will not over-write existing file "'Readme.10'"
else
sed 's/^XX//' > 'Readme.10' << \SHAR_EOF
XXScsi Version 1.0
XX
XX The code you received with this file is a very simple SCSI device
XXdriver that uses the Seagate ST-01 interface card. As this driver is
XXmy first PC assembler project other then "hello world", please don't
XXsnicker to loudly.
XX
XX The package includes the source for a device driver that will scan
XXthe SCSI bus for disk drives and partition any drives found into chunks
XXof 32Meg plus any leftovers. As soon as I discover a way to get DOS to
XXlet me use > 512 byte sectors, It will just allocate the entire disk to
XXa single logical drive. It also includes a utility to access the low
XXlevel SCSI format function for any disk found. You may specify the
XXinterleave when the low level format is done and the version of the
XXdriver here seems to work fine at 1:1 with my 8Mhz NEC.
XX
XX Some of the things to look out for are:
XX
XX#1 The receive_data and send_data functions in subs.asm use polled I/O
XX to transfer data to/from the card. I would have loved to just use
XX the I/O Channel Ready line that the card is suppose to support, but
XX my NEC does not seem to use that line. Hence the polling of the REQ
XX bit in the status port.
XX
XX#2 I did not know how to do clock speed independent timing loops, so there
XX is a wait100us function in subs.asm that is very processor speed
XX dependent :-(
XX
XX#3 In ioctl.asm there is a commented out call to scsi_verify. This is
XX used by the DOS format utility to scan for errors. You may want to
XX enable the call after you get everything setup. I shut it off while
XX I was testing as I didn't want to wait for the verify everytime I
XX changed the interleave.
XX
XX To bring up the driver. Assemble and link scsi.sys and add it to
XXyour config.sys file. After rebooting, you may optionaly do a low level
XXformat of each disk found using sformat.exe. You then use the DOS format
XXutility on each logical drive. I did figure out just what format needed
XXin the way of ioctl support to get it to do the high level format for me.
XXAt this point you should have fully functional DOS drives. In testing
XXI found that with multi_sector support (subs.asm) enabled, the SCSI drives
XXwere just about as fast as the ST-412 C: that came with the machine. I
XXam sure that the speed problem is basic to the inner loop of the data
XXtransfer routines, but I'm at a loss to figure out how to speed it up.
XX
XX Anyway, maybe someone can find some use for the code. I got the
XXcard for free, so I can't really complain about the speed or cost too
XXmuch :-)
XX
XX Also thanks to the people that sent me samples of other device drivers
XXfor the PC. I lost the names to a disk crash, but here is the result of
XXyour help and my thanks.
XX
XXBrian Antoine
XXAug 29, 1990
SHAR_EOF
if test 2706 -ne "`wc -c < 'Readme.10'`"
then
echo shar: error transmitting "'Readme.10'" '(should have been 2706 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'dump.asm'" '(973 characters)'
if test -f 'dump.asm'
then
echo shar: will not over-write existing file "'dump.asm'"
else
sed 's/^XX//' > 'dump.asm' << \SHAR_EOF
XX;
XX; Convert bin (ax) to ascii (dx => buffer)
XX;
XXbin_ascii proc near
XX pusha
XX push ax
XX mov bx,dx
XX mov cx,6
XXfill_buff: mov byte ptr [bx],' '
XX inc bx
XX loop fill_buff
XX mov si,10
XX or ax,ax
XX jns clr_dvd
XX neg ax
XXclr_dvd: sub dx,dx
XX div si
XX add dx,'0'
XX dec bx
XX mov [bx],dl
XX inc cx
XX or ax,ax
XX jnz clr_dvd
XX pop ax
XX or ax,ax
XX jns no_more
XX dec bx
XX mov byte ptr [bx],'-'
XXno_more: popa
XX ret
XXbin_ascii endp
XX
XX;
XX; Convert Hex to Ascii
XX;
XX; dx = value
XX; di => buffer
XX;
XXhex2asc proc near
XX push cx
XX push ax
XX mov cx,4 ;Do Four Digits
XXh1: push cx
XX mov cl,4
XX rol dx,cl
XX mov al,dl ;Get the Current Digit
XX and al,0Fh
XX cmp al,0Ah ;Is It Hex?
XX jge h2
XX add al,30h ;Normal Digit
XX jmp h3
XXh2: add al,37h ;Hex Digit
XXh3: mov cs:[di],al ;Insert in Buffer
XX inc di
XX pop cx ;Go Do Another
XX loop h1
XX pop ax
XX pop cx
XX ret
XXhex2asc endp
XX
XX;
XX; Print a string
XX;
XX; ds:dx => string
XX;
XXputs proc near
XX pusha
XX mov ah,9 ;DOS print string
XX int 21h
XX popa
XX ret
XXputs endp
SHAR_EOF
if test 973 -ne "`wc -c < 'dump.asm'`"
then
echo shar: error transmitting "'dump.asm'" '(should have been 973 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'equ.inc'" '(3049 characters)'
if test -f 'equ.inc'
then
echo shar: will not over-write existing file "'equ.inc'"
else
sed 's/^XX//' > 'equ.inc' << \SHAR_EOF
XX;
XX; Equates
XX;
XXSCSI_CARD_SEG EQU 0DE00h ;Base Segment of Card
XXSCSI_CMD_PORT EQU 01A00h ;Offset to Command Port
XXSCSI_DATA_PORT EQU 01C00h ;Offset to Data Port
XX
XXSTACK_SIZE EQU 512 ;Our Local Stack
XX
XX;
XX; How the 16 bit sector number is broken down
XX; into a sector and cylinder number.
XX;
XX; x = Cylinder, y = track, always have only 1 head
XX;
XX; xxxx xxxx xxxx yyyy
XX;
XX; SECT_2_FS is computed as: ((unit_bpb.bpb_ts / CLUSTSIZE) * 2) / P_SECT)
XX;
XXSECT_TRACK EQU 16 ;Logical Sectors in a Track
XXSECT_MASK EQU 0000Fh ;Mask for Sector
XXCYL_MASK EQU 0FFF0h ;Mask for Cylinder
XXSECT_2_CYL EQU 4 ;How far to shift to convert
XX ;Sector to Cylinder Number
XXSECT_2_FS EQU 10 ;How far to shift for
XX ;Total Sectors to Fat Sectors
XX
XXMAXUNIT EQU 3 ;Maximum Unit Number
XX
XXP_SECT EQU 512 ;Physical Sector Size
XXCLUSTSIZE EQU 4 ;Number of Sectors to a Cluster
XX
XX;
XX; For multi_sector reads and writes,
XX; set the following to '1'
XX;
XX; CHUNK_MASK is the maximum number of sectors to access in one
XX; SCSI request. It MUST be a power of two, and CHUNK_MASK * P_SECT
XX; MUST be <= 64K to prevent segment wrap problems.
XX;
XXmulti_sector = 1 ;1 = multi sector, 0 = single sector
XXCHUNK_MAX EQU 32
XX
XXCMDENABLE EQU 080h ;Enable the output drivers
XXCMDENINTR EQU 040h ;Enable Interrupt
XXCMDPARITY EQU 020h ;Enable Parity
XXCMDSTARB EQU 010h ;Start Bus Arbitration
XXCMDATTN EQU 008h ;Assert ATTN
XXCMDBSY EQU 004h ;Assert BSY
XXCMDSEL EQU 002h ;Assert SEL
XXCMDRST EQU 001h ;Assert RST
XX
XXCMDBASE EQU CMDPARITY ;Base value of all commands
XX
XXSTARBCOMPL EQU 080h ;Arbitration Complete
XXSTPARERR EQU 040h ;Parity Error
XXSTSEL EQU 020h ;SEL Asserted
XXSTREQ EQU 010h ;REQ Asserted
XXSTCD EQU 008h ;C/D Asserted
XXSTIO EQU 004h ;I/O Asserted
XXSTMSG EQU 002h ;MSG Asserted
XXSTBSY EQU 001h ;BSY Asserted
XX
XXFREE_MASK EQU 03Fh
XX
XXREQ_MASK EQU STMSG or STCD or STIO
XXREQ_DATAOUT EQU 000h ;Data Out Phase
XXREQ_DATAIN EQU STIO ;Data In Phase
XXREQ_CMDOUT EQU STCD ;Command Out Phase
XXREQ_STATIN EQU STCD or STIO ;Status In Phase
XXREQ_MSGOUT EQU STMSG or STCD ;Msg Out Phase
XXREQ_MSGIN EQU STMSG or STCD or STIO ;Msg In Phase
XX
XXCOK EQU 0 ;Command Completed OK
XXCNOCONNECT EQU 1 ;Unable to Connect to Target
XXCBUSBUSY EQU 2 ;Bus Busy
XXCTIMEOUT EQU 3 ;Timeout waiting for Response
XXCERROR EQU 4 ;Target Return Error
XXCBUSY EQU 5 ;Target was Busy
XXCDISCONNECT EQU 6 ;Target Disconnected
XX
XXSCSI_TESTREADY EQU 000h ;Test Unit Ready (6 byte)
XXSCSI_REQSENSE EQU 003h ;Request Sense (6 byte)
XXSCSI_FORMATUNIT EQU 004h ;Format Disk (6 byte)
XXSCSI_INQUIRY EQU 012h ;Inquire (6 byte)
XXSCSI_READSIZE EQU 025h ;Read Drive Capacity (10 byte)
XXSCSI_READBLK EQU 028h ;Read Sectors (10 byte)
XXSCSI_WRITEBLK EQU 02Ah ;Write Sectors (10 byte)
XXSCSI_VERIFYBLK EQU 02Fh ;Verify Blocks (10 byte)
XX
XXMSG_COMPLETE EQU 000h ;Command is Complete
XXMSG_SAVE EQU 002h ;Save Data Pointers
XXMSG_RESTORE EQU 003h ;Restore Data Pointers
XXMSG_ERROR EQU 005h ;Error Detected
XXMSG_ABORT EQU 006h ;Abort the Command
XXMSG_REJECT EQU 007h ;Reject the Command
XXMSG_NOP EQU 008h ;No Operation
XXMSG_IDENTIFY EQU 080h ;Identify Yourself
SHAR_EOF
if test 3049 -ne "`wc -c < 'equ.inc'`"
then
echo shar: error transmitting "'equ.inc'" '(should have been 3049 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'ioctl.asm'" '(1824 characters)'
if test -f 'ioctl.asm'
then
echo shar: will not over-write existing file "'ioctl.asm'"
else
sed 's/^XX//' > 'ioctl.asm' << \SHAR_EOF
XX;
XX; Process an ioctl request for the current unit
XX;
XX; return 'C' on error
XX;
XXscsi_ioctl proc
XX mov al,es:[bx].rh19_minor ;Get the minor number
XX
XX cmp al,40h ;Set Device Params?
XX jnz scsi_i_42h
XX clc
XX jmp scsi_i_exit
XX
XXscsi_i_42h: cmp al,42h ;Format and Verify?
XX jnz scsi_i_60h
XX; call scsi_verify
XX jmp scsi_i_exit
XX
XXscsi_i_60h: cmp al,60h ;Get Device Params?
XX jnz scsi_i_62h
XX mov si,cur_bpb ;Get the Current BPB
XX mov di,es:[bx].rh19_buf_ofs ;Get the Param Buffer
XX mov ax,es:[bx].rh19_buf_seg
XX mov es,ax
XX mov es:[di].dpb_special,05h ;Sect Same/Use Cur BPB
XX mov es:[di].dpb_type,05h ;Fixed Disk
XX mov es:[di].dpb_attr,0001h ;Not Removable
XX mov ax,[si].bpb_ts
XX shr ax,SECT_2_CYL ;Convert Sect to Cyl
XX mov es:[di].dpb_cyl,ax
XX mov es:[di].dpb_media,0 ;????
XX mov es:[di].dpb_sectors,SECT_TRACK ;Sectors per Track
XX
XX push di
XX lea di,es:[di].dpb_bpb ;Copy the bpb into
XX mov cx,size bpb ;the requestors buffer
XX cld
XX rep movsb
XX pop di
XX
XX lea di,es:[di].dpb_track ;Build the Track List
XX mov cx,SECT_TRACK
XX mov ax,0 ;Start with Sector 0
XXscsi_i_t_loop: mov es:[di],ax ;Sector Number
XX inc ax
XX inc di
XX inc di
XX mov word ptr es:[di],P_SECT ;Sector Size
XX inc di
XX inc di
XX loop scsi_i_t_loop
XX clc
XX jmp scsi_i_exit
XX
XXscsi_i_62h: cmp al,62h ;Verify?
XX jnz scsi_i_error
XX call scsi_verify
XX jmp scsi_i_exit
XX
XXscsi_i_error: stc
XXscsi_i_exit: ret
XXscsi_ioctl endp
XX
XXscsi_ioctl_write proc
XX mov di,es:[bx].rh12_buf_ofs
XX mov ax,es:[bx].rh12_buf_seg
XX mov es,ax
XX mov ax,es:[di].ioc_command ;What Command
XX cmp al,'F' ;Format?
XX jnz scsi_i_w_error
XX
XX mov ax,es:[di].ioc_data ;Get Interleave
XX lea di,cmd_format ;Insert into Command
XX mov [di].fmt_cmd_il_b0,al
XX mov [di].fmt_cmd_il_b1,ah
XX call docmd
XX jmp short scsi_i_w_exit
XX
XXscsi_i_w_error: stc
XXscsi_i_w_exit: ret
XXscsi_ioctl_write endp
SHAR_EOF
if test 1824 -ne "`wc -c < 'ioctl.asm'`"
then
echo shar: error transmitting "'ioctl.asm'" '(should have been 1824 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'scsi.asm'" '(8104 characters)'
if test -f 'scsi.asm'
then
echo shar: will not over-write existing file "'scsi.asm'"
else
sed 's/^XX//' > 'scsi.asm' << \SHAR_EOF
XX;
XX; Simple SCSI Device Driver
XX;
XX .286
XX PAGE 76,132
XX
XX INCLUDE equ.inc
XX INCLUDE struct.inc
XX;
XX; Start of Code and Data
XX;
XX_TEXT segment word public 'CODE'
XX assume cs:_TEXT, ds:_TEXT, es:_TEXT
XX
XX org 0
XX
XX;
XX; Device Header Required By DOS
XX;
XXscsi:
XXnext_dev dd -1 ;No other Device Drivers
XXattribute dw 6040h ;Ioctl R/W, Block Device, Non-IBM, Get/Set
XXstrategy dw dev_strategy ;Address of 1st DOS Call
XXinterrupt dw dev_interrupt ;Address of 2nd DOS Call
XXdisk_count db 0 ;Number of Disks Present
XX db 7 dup(?)
XX
XX;
XX; Work Space For Our Device Driver
XX;
XXrh_off dw ? ;Request Header Offset
XXrh_seg dw ? ;Request Header Segment
XX
XXcur_drive db -1
XXvol_id db 'NO NAME ',0
XX
XX;
XX; Define our own personal Stack
XX;
XX even
XXnew_stack db STACK_SIZE-2 dup (?) ;Our Local Stack
XXnew_stack_top dw ?
XX
XXstack_ptr dw ? ;Old Stack Pointer
XXstack_seg dw ? ;Old Stack Segment
XX
XX;
XX; Command Table
XX;
XXcmdtab label byte ;* = Char Only Devices
XX dw INITIALIZATION ;Initialization
XX dw MEDIA_CHECK ;Media Check (Block Only)
XX dw GET_BPB ;Build BPB
XX dw unknown ;IOCTL Read
XX dw READ ;Read Data
XX dw done ;*Non Destructive Read
XX dw done ;*Read Status
XX dw done ;*Flush Read Buffer
XX dw WRITE ;Write Data
XX dw WRITE_VERIFY ;Write With Verify
XX dw done ;*Write Status
XX dw done ;*Flush Write Buffer
XX dw WRITE_IOCTL ;IOCTL Write
XX dw done ;Device Open
XX dw done ;Device Close
XX dw busy ;Removable Check
XX dw unknown ;*Write Until Busy
XX dw unknown ;Unknown Call
XX dw unknown ;Unknown Call
XX dw IOCTL ;Generic Ioctl
XX dw unknown ;Unknown Call
XX dw unknown ;Unknown Call
XX dw unknown ;Unknown Call
XX dw GET_DEV ;Get Device
XX dw SET_DEV ;Set Device
XX
XX;
XX; Strategy Procedure
XX;
XXdev_strategy proc far
XX mov cs:rh_seg,es ;Save Request Header Ptr Segment
XX mov cs:rh_off,bx ;Save Request Header Ptr Offset
XX ret
XXdev_strategy endp
XX
XX;
XX; Interrupt Procedure
XX;
XXdev_interrupt proc far
XX cli ;Save Machine State On Entry
XX push ds
XX push es
XX push ax
XX push bx
XX push cx
XX push dx
XX push si
XX push di
XX push bp
XX pushf
XX
XX mov cs:stack_seg,ss ;Save Old Stack
XX mov cs:stack_ptr,sp
XX
XX mov ax,cs ;Save us the Segment Override Crap
XX mov ds,ax
XX mov es,ax
XX
XX mov ss,ax ;Setup Our Local Stack
XX lea ax,new_stack_top
XX mov sp,ax
XX sti ;We're Safe Now
XX
XX;
XX; Perform branch based on the command passed in the Request Header
XX;
XX mov es,rh_seg ;Point us at the Request Header
XX mov bx,rh_off
XX
XX mov al,es:[bx].rh_cmd ;Get Command Code
XX rol al,1 ;Get offset into table
XX lea di,cmdtab ;Get address of command table
XX mov ah,0 ;Clear hi order byte
XX add di,ax ;Add offset
XX jmp word ptr [di] ;Jump Indirect
XX
XX;
XX; Command Procedures
XX;
XXINITIALIZATION: mov al,es:[bx].rh0_drv_ltr ;Save the starting Drive
XX add al,041h
XX mov cur_drive,al
XX call initial ;Setup
XX mov bx,rh_off
XX mov es,rh_seg
XX lea ax,initial ;Set The Break Address
XX mov es:[bx].rh0_brk_ofs,ax
XX mov es:[bx].rh0_brk_seg,cs
XX mov al,disk_count ;Number of Disk Devices Supported
XX mov es:[bx].rh0_nunits,al
XX lea dx,bpb_array ;BPB Array
XX mov es:[bx].rh0_bpb_tbo,dx
XX mov es:[bx].rh0_bpb_tbs,cs
XX jmp done
XX
XXMEDIA_CHECK: call find_unit
XX jc bad_unit
XX mov di,cur_unit
XX mov al,[di].unit_mcheck ;Get Initial Status
XX mov [di].unit_mcheck,1 ;Always OK from then on
XX mov es:[bx].rh1_md_stat,al
XX lea dx,vol_id ;Address of Volume ID
XX mov es:[bx].rh1_volid_ofs,dx
XX mov es:[bx].rh1_volid_seg,cs
XX jmp done
XX
XXGET_BPB: call find_unit
XX jc bad_unit
XX mov dx,cur_bpb ;Address of BPB
XX mov es:[bx].rh2_pbpbo,dx
XX mov es:[bx].rh2_pbpbs,cs
XX jmp done
XX
XX;
XX; Read some data from the disk
XX;
XXREAD: call find_unit
XX jc bad_unit
XX call scsi_read
XX jc bad_read
XX jmp done
XX
XX;
XX; Write some data to the disk
XX;
XXWRITE equ $
XXWRITE_VERIFY: call find_unit
XX jc bad_unit
XX call scsi_write
XX jc bad_write
XX jmp done
XX
XX;
XX; Write Ioctl Packet
XX;
XXWRITE_IOCTL: call find_unit
XX jc bad_unit
XX call scsi_ioctl_write
XX jc unknown
XX jmp done
XX
XX;
XX; Special Control Functions
XX;
XXIOCTL: call find_unit
XX jc bad_unit
XX call scsi_ioctl
XX jc unknown
XX jmp done
XX
XXGET_DEV: mov es:[bx].rh_unit,0
XX jmp done
XX
XXSET_DEV: jmp done
XX
XXbad_unit: mov es,rh_seg ;Point us at the Request Header
XX mov bx,rh_off
XX or es:[bx].rh_status,8001h
XX jmp short done
XX
XXunknown: mov es,rh_seg ;Point us at the Request Header
XX mov bx,rh_off
XX or es:[bx].rh_status,8003h
XX jmp short done
XX
XXbad_write: mov es,rh_seg ;Point us at the Request Header
XX mov bx,rh_off
XX or es:[bx].rh_status,800Ah
XX jmp short done
XX
XXbad_read: mov es,rh_seg ;Point us at the Request Header
XX mov bx,rh_off
XX or es:[bx].rh_status,800Bh
XX jmp short done
XX
XXbusy: mov es,rh_seg ;Point us at the Request Header
XX mov bx,rh_off
XX or es:[bx].rh_status,0200h
XX
XXdone: mov es,rh_seg ;Point us at the Request Header
XX mov bx,rh_off
XX or es:[bx].rh_status,0100h
XX
XX cli ;Make sure we're left alone
XX mov ax,cs:stack_seg ;Restore DOS Stack
XX mov ss,ax
XX mov ax,cs:stack_ptr
XX mov sp,ax
XX
XX popf ;Restore All Registers
XX pop bp
XX pop di
XX pop si
XX pop dx
XX pop cx
XX pop bx
XX pop ax
XX pop es
XX pop ds
XX sti ;We're Safe Now
XX ret
XX
XX INCLUDE units.asm
XX INCLUDE subs.asm
XX INCLUDE ioctl.asm
XX INCLUDE dump.asm
XX;
XX; End of Program
XX; Stuff Placed Here Gets Handed Back To DOS For Re-use
XX;
XXinitial proc near
XX lea dx,hello_msg ;Tell them the driver version
XX call puts
XX push cs
XX pop dx
XX lea di,seg_msg_value
XX call hex2asc
XX lea dx,seg_msg ;And Were We Loaded
XX call puts
XX
XX call scsi_reset ;Reset the bus
XX
XX mov cx,0 ;Scan for devices
XXscan: mov ax,cx
XX add al,030h
XX mov scan_dev,al
XX mov ax,1 ;Create Select Bit
XX shl ax,cl
XX mov di,cur_unit
XX mov [di].unit_select,al
XX mov [di].unit_num_drv,0 ;No Drives to start with
XX mov al,disk_count ;We will start with
XX mov [di].unit_1st_drv,al ;Drive Number if any
XX
XX lea dx,scan_dev ;Print the device number
XX call puts
XX call scsi_inquire ;Inquire as to its type
XX jnc scan_inq_ok
XX jmp scan_err
XX
XXscan_inq_ok: mov di,cur_unit
XX lea dx,[di].unit_inq_buf.inq_manufact
XX mov [di].unit_inq_term,'$'
XX mov al,[di].unit_inq_buf.inq_dev_type
XX or al,al ;Look at device type
XX jz scan_is_drv
XX jmp scan_puts ;Must be a Tape Drive
XX
XXscan_is_drv: call puts ;Output the Device String
XX call scsi_capacity ;Inquire as to its size
XX lea dx,err_size
XX jc scan_puts ;Do not use unknown drives
XX lea dx,crlf
XX call puts
XX
XXscan_next_drv: mov di,cur_unit
XX mov al,disk_count ;Number Of Drives Found
XX inc al
XX mov disk_count,al
XX mov al,[di].unit_num_drv ;We have a valid Drive
XX inc al
XX mov [di].unit_num_drv,al
XX mov al,cur_drive ;Get Current Drive Letter
XX mov drv_msg_let,al ;Insert it in message
XX inc al ;Bump Drive Letter
XX mov cur_drive,al
XX call make_bpb ;Setup the BPB for this drive
XX mov di,cur_bpb ;Current Working BPB
XX mov ax,[di].bpb_ts
XX shr ax,11
XX inc ax
XX lea dx,drv_msg_size
XX call bin_ascii
XX mov bx,bpb_hw_mark ;Get the BPB High Water Mark
XX inc bx ;Bump HW Mark for next time
XX inc bx
XX mov ax,[bx] ;Get the BPB
XX mov cur_bpb,ax ;Make it the current BPB
XX mov bpb_hw_mark,bx
XX lea dx,drv_msg
XX call puts
XX mov bx,cur_unit
XX mov ah,0
XX mov al,[bx].unit_num_drv ;Insert Drive Offset
XX dec al ;Into BPB for this Drive
XX mov [di].bpb_hs_msw,ax
XX mov al,[bx].unit_cap_buf.cap_sectors_b3
XX or al,[bx].unit_cap_buf.cap_sectors_b2
XX or al,[bx].unit_cap_buf.cap_sectors_b1
XX or al,[bx].unit_cap_buf.cap_sectors_b0
XX jnz scan_next_drv ;Room left for another Drive
XX jmp short scan_next
XX
XXscan_err: lea dx,no_dev
XX cmp al,CNOCONNECT
XX jz scan_puts
XX lea dx,err_dev
XXscan_puts: call puts
XX lea dx,crlf
XX call puts
XX
XXscan_next: inc cx
XX cmp cx,MAXUNIT ;End of devices?
XX jg scan_exit
XX mov bx,cx ;Bump to next unit
XX shl bx,1
XX mov ax,word ptr unit_array[bx]
XX mov cur_unit,ax
XX jmp scan
XX
XXscan_exit: ret
XXinitial endp
XX
XX;
XX; Data Area Used Only During Initialization
XX;
XXhello_msg db 0dh,0ah,'SCSI Device Driver Version 1.0',0Dh,0Ah,'$'
XXseg_msg db 'Driver Loaded At Segment '
XXseg_msg_value db '0000',0dh,0ah,'$'
XXscan_dev db 'X - ','$'
XXno_dev db '(No Installed Device)$'
XXerr_dev db '(Error On Device)$'
XXerr_size db 'unknown size$'
XXdrv_msg db ' - Drive '
XXdrv_msg_let db 'X: '
XXdrv_msg_size db 'XXXXXX Meg',0dh,0ah,'$'
XXcrlf db 0dh,0ah,'$'
XX
XXdev_interrupt endp
XX_TEXT ends
XX end scsi
SHAR_EOF
if test 8104 -ne "`wc -c < 'scsi.asm'`"
then
echo shar: error transmitting "'scsi.asm'" '(should have been 8104 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'sformat.c'" '(1842 characters)'
if test -f 'sformat.c'
then
echo shar: will not over-write existing file "'sformat.c'"
else
sed 's/^XX//' > 'sformat.c' << \SHAR_EOF
XX/*
XX** SCSI Disk Formatter (Low Level)
XX**
XX** usage: sformat drive: [interleave]
XX**
XX** Revision History:
XX**
XX** Version 1.0 08/03/90 Initial Release
XX**
XX** Version 1.1 08/20/90 Add verification message.
XX*/
XX#include <stdio.h>
XX#include <dos.h>
XX
XX#define TRUE (1)
XX#define FALSE (0)
XX#define VERSION "sformat Version 1.1 BWA"
XX
XXextern int _doserrno;
XX
XXstruct cmd {
XX short command; /* command type */
XX short args; /* command args */
XX} ioctl_data;
XXunion REGS inregs, outregs;
XXstruct SREGS segregs;
XXunsigned short interleave = 0;
XXunsigned char drive;
XXchar far *cp;
XX
XXmain(argc, argv)
XXint argc;
XXchar *argv[];
XX{
XX /*
XX ** say hello
XX */
XX puts(VERSION);
XX
XX /*
XX ** figure out who to format
XX */
XX switch (argc)
XX {
XX case 3:
XX interleave = atoi(argv[2]);
XX case 2:
XX if (argv[1][1] != ':') usage();
XX drive = argv[1][0];
XX drive = toupper(drive);
XX drive -= '@';
XX break;
XX
XX default:
XX usage();
XX break;
XX }
XX
XX /*
XX ** verify that this is what the user really wants to do
XX */
XX printf("Do you really wish to format the SCSI\n");
XX printf("device that contains drive %c: (y,n)? ", argv[1][0]);
XX fflush(stdout);
XX if ( getchar() != 'y' )
XX {
XX puts("Aborting low level format ....");
XX exit(1);
XX }
XX
XX /*
XX ** put together the command
XX */
XX inregs.h.ah = 0x44; /* ioctl */
XX inregs.h.al = 0x05; /* write */
XX inregs.h.bl = drive; /* unit */
XX inregs.x.cx = sizeof(struct cmd);
XX cp = (char *) &ioctl_data;
XX inregs.x.dx = FP_OFF(cp);
XX segregs.ds = FP_SEG(cp);
XX ioctl_data.command = 'F';
XX ioctl_data.args = interleave;
XX
XX /*
XX ** start the format
XX */
XX puts("Now formating ....");
XX puts("Please wait ....");
XX intdosx(&inregs, &outregs, &segregs);
XX
XX /*
XX ** see what happened
XX */
XX if ( outregs.x.cflag )
XX printf("DOS error %d occured during format.\n", _doserrno);
XX else
XX puts("Formating complete.");
XX exit(0);
XX}
XX
XXusage()
XX{
XX puts("usage: sformat drive: [interleave]");
XX exit(1);
XX}
SHAR_EOF
if test 1842 -ne "`wc -c < 'sformat.c'`"
then
echo shar: error transmitting "'sformat.c'" '(should have been 1842 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'struct.inc'" '(5738 characters)'
if test -f 'struct.inc'
then
echo shar: will not over-write existing file "'struct.inc'"
else
sed 's/^XX//' > 'struct.inc' << \SHAR_EOF
XX;
XX; Structures for SCSI commands
XX;
XXio_cmd struc
XXio_cmd_op db ? ;Opcode
XXio_cmd_lun db ?
XXio_cmd_lba_b3 db ? ;Logical Block Address
XXio_cmd_lba_b2 db ?
XXio_cmd_lba_b1 db ?
XXio_cmd_lba_b0 db ?
XXio_cmd_dummy1 db ?
XXio_cmd_cnt_b1 db ? ;Block Count
XXio_cmd_cnt_b0 db ?
XXio_cmd_dummy2 db ?
XXio_cmd ends
XX
XX;
XX; Format the Unit
XX;
XXfmt_cmd struc
XXfmt_cmd_op db ? ;Opcode
XXfmt_cmd_type db ? ;Format Type
XXfmt_cmd_dummy1 db ?
XXfmt_cmd_il_b1 db ? ;Interleave (MSB)
XXfmt_cmd_il_b0 db ? ;Interleave (LSB)
XXfmt_cmd_dummy3 db ?
XXfmt_cmd ends
XX
XX;
XX; Verify Sectors
XX;
XXver_cmd struc
XXver_cmd_op db ? ;Opcode
XXver_cmd_lun db ? ;Lun
XXver_cmd_lba_b3 db ? ;Logical Block Address MSB
XXver_cmd_lba_b2 db ?
XXver_cmd_lba_b1 db ?
XXver_cmd_lba_b0 db ? ;Logical Block Address LSB
XXver_cmd_dummy1 db ?
XXver_cmd_len_b1 db ? ;Length MSB
XXver_cmd_len_b0 db ? ;Length LSB
XXver_cmd_dummy2 db ?
XXver_cmd ends
XX
XX;
XX; Structure returned by the unit inquiry command
XX;
XXinq struc
XXinq_dev_type db ? ;Device Type
XXinq_dev_qual db ? ;Device Qualifier
XXinq_stand_rev db ? ;Standard Revision Level
XXinq_format db ? ;Response Format
XXinq_length db ? ;Length of Extra Data
XXinq_reserv1 db ?
XXinq_reserv2 db ?
XXinq_reserv3 db ?
XXinq_manufact db 8 dup (?) ;Manufacture
XXinq_product db 16 dup (?) ;Product
XXinq ends
XX
XX;
XX; Structure returned by the read drive capacity command
XX;
XXcap struc
XXcap_sectors_b3 db ? ;MSB of sector count
XXcap_sectors_b2 db ?
XXcap_sectors_b1 db ?
XXcap_sectors_b0 db ? ;LSB of sector count
XXcap_size_b3 db ? ;MSB of sector size
XXcap_size_b2 db ?
XXcap_size_b1 db ?
XXcap_size_b0 db ? ;LSB of sector size
XXcap ends
XX
XX;
XX; Structure Definitions For Our Device Driver
XX;
XXbpb struc
XXbpb_ss dw ? ;Sector Size
XXbpb_au db ? ;Cluster Size in Sectors
XXbpb_rs dw ? ;Reserved Sectors
XXbpb_nf db ? ;Number of Fats
XXbpb_de dw ? ;Number of Root Directory Entries
XXbpb_ts dw ? ;Total Number Of Sectors
XXbpb_md db ? ;Media Descriptor
XXbpb_fs dw ? ;Number of Sectors in each Fat
XXbpb_st dw ? ;Number of Sectors per Track
XXbpb_nh dw ? ;Number of Heads
XXbpb_hs_lsw dw ? ;Hidden Sectors (Least Sig Word)
XXbpb_hs_msw dw ? ;Hidden Sectors (Most Sig Word)
XXbpb_ts_large dd ? ;Large Total Sector Count
XXbpb_res db 6 dup (?) ;Reserved
XXbpb ends
XX
XX;
XX; ioctl function 42h
XX;
XXioctl_fmt struc
XXioctl_fmt_spec db ? ;Special Flags
XXioctl_fmt_head dw ? ;Head to Format
XXioctl_fmt_cyl dw ? ;Cylinder to Format
XXioctl_fmt ends
XX
XX;
XX; ioctl function 60h
XX;
XXdpb struc
XXdpb_special db ? ;Special Flags
XXdpb_type db ? ;Device Type
XXdpb_attr dw ? ;Device Attributes
XXdpb_cyl dw ? ;Device Cylinder Count
XXdpb_media db ? ;Device Media Type if Diskette
XXdpb_bpb db size bpb dup (?)
XXdpb_sectors dw ? ;Sectors in Track
XXdpb_track dd SECT_TRACK dup (?)
XXdpb ends
XX
XX;
XX; The internal control structure for a SCSI device
XX;
XXunit struc
XXunit_1st_drv db ? ;DOS Drive Numbers
XXunit_num_drv db ? ;DOS Drive Count
XXunit_select db ? ;SCSI Select Bit
XXunit_mcheck db ? ;Media Check Byte
XXunit_inq_buf db size inq dup (?)
XXunit_inq_term db ?
XXunit_cap_buf db size cap dup (?)
XXunit ends
XX
XX;
XX; Ioctl Commands
XX;
XXioc struc
XXioc_command dw ? ;Command
XXioc_data dw ? ;Command Dependent Data
XXioc ends
XX
XX;
XX; DOS requests
XX;
XXrh struc
XXrh_len db ? ;Length of Packet
XXrh_unit db ? ;Unit Code (Block Only)
XXrh_cmd db ? ;Command Code
XXrh_status dw ? ;Returned Status
XXrh_res db 8 dup (?) ;Reserved
XXrh ends
XX
XXrh0 struc ;INITIALIZATION
XXrh0_rh db size rh dup (?) ;Fixed Portion
XXrh0_nunits db ? ;Number of units (Block Only)
XXrh0_brk_ofs dw ? ;Break Address (Offset)
XXrh0_brk_seg dw ? ;Break Address (Segment)
XXrh0_bpb_tbo dw ? ;Pointer to BPB Array (Offset)
XXrh0_bpb_tbs dw ? ;Pointer to BPB Array (Segment)
XXrh0_drv_ltr db ? ;First Available Drive (DOS 3+, Block Only)
XXrh0 ends
XX
XXrh1 struc ;MEDIA CHECK
XXrh1_rh db size rh dup (?) ;Fixed Portion
XXrh1_media db ? ;Media Descriptor from DPB
XXrh1_md_stat db ? ;Media Status returned by Device Driver
XXrh1_volid_ofs dw ? ;Offset of Volume ID String (DOS 3+)
XXrh1_volid_seg dw ? ;Segment of Volume ID String (DOS 3+)
XXrh1 ends
XX
XXrh2 struc ;GET BPB
XXrh2_rh db size rh dup (?) ;Fixed Portion
XXrh2_media db ? ;Media Descriptor from DPB
XXrh2_buf_ofs dw ? ;Offset of Data Transfer Area
XXrh2_buf_seg dw ? ;Segment of Data Transfer Area
XXrh2_pbpbo dw ? ;Offset of Pointer to BPB
XXrh2_pbpbs dw ? ;Segment of Pointer to BPB
XXrh2 ends
XX
XXrh4 struc ;INPUT
XXrh4_rh db size rh dup (?) ;Fixed Portion
XXrh4_media db ? ;Media Descriptor from DPB
XXrh4_buf_ofs dw ? ;Offset of Data Transfer Area
XXrh4_buf_seg dw ? ;Segment of Data Transfer Area
XXrh4_count dw ? ;Transfer Count (Sectors)
XXrh4_start dw ? ;Start Sector Number
XXrh4 ends
XX
XXrh8 struc ;OUTPUT
XXrh8_rh db size rh dup (?) ;Fixed Portion
XXrh8_media db ? ;Media Descriptor from DPB
XXrh8_buf_ofs dw ? ;Offset of Data Transfer Area
XXrh8_buf_seg dw ? ;Segment of Data Transfer Area
XXrh8_count dw ? ;Transfer Count (Sectors)
XXrh8_start dw ? ;Start Sector Number
XXrh8 ends
XX
XXrh9 struc ;OUTPUT VERIFY
XXrh9_rh db size rh dup (?) ;Fixed Portion
XXrh9_media db ? ;Media Descriptor from DPB
XXrh9_buf_ofs dw ? ;Offset of Data Transfer Area
XXrh9_buf_seg dw ? ;Segment of Data Transfer Area
XXrh9_count dw ? ;Transfer Count (Sectors)
XXrh9_start dw ? ;Start Sector Number
XXrh9 ends
XX
XXrh12 struc ;OUTPUT IOCTL
XXrh12_rh db size rh dup (?) ;Fixed Portion
XXrh12_media db ? ;Media Descriptor from DPB
XXrh12_buf_ofs dw ? ;Offset of Data Transfer Area
XXrh12_buf_seg dw ? ;Segment of Data Transfer Area
XXrh12_count dw ? ;Transfer Count (Sectors)
XXrh12_start dw ? ;Start Sector Number
XXrh12 ends
XX
XXrh19 struc ;IOCTL
XXrh19_rh db size rh dup (?) ;Fixed Portion
XXrh19_major db ? ;Major Code
XXrh19_minor db ? ;Minor Code
XXrh19_si dw ? ;Caller SI Register
XXrh19_di dw ? ;Caller DI Register
XXrh19_buf_ofs dw ? ;Caller Buffer Offset
XXrh19_buf_seg dw ? ;Caller Buffer Segment
XXrh19 ends
SHAR_EOF
if test 5738 -ne "`wc -c < 'struct.inc'`"
then
echo shar: error transmitting "'struct.inc'" '(should have been 5738 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'subs.asm'" '(11083 characters)'
if test -f 'subs.asm'
then
echo shar: will not over-write existing file "'subs.asm'"
else
sed 's/^XX//' > 'subs.asm' << \SHAR_EOF
XX;
XX; Data storage for local subroutines
XX;
XXcmd_ready db SCSI_TESTREADY,0,0,0,0,0
XXcmd_format db SCSI_FORMATUNIT,0,0,0,0,0
XXcmd_read db SCSI_READBLK,0,0,0,0,0,0,0,1,0
XXcmd_write db SCSI_WRITEBLK,0,0,0,0,0,0,0,1,0
XXcmd_inquire db SCSI_INQUIRY,0,0,0,size inq,0
XXcmd_capacity db SCSI_READSIZE,0,0,0,0,0,0,0,0,0
XXcmd_verify db SCSI_VERIFYBLK,0,0,0,0,0,0,0,SECT_TRACK,0
XX
XX even
XXdocmd_cmd dw ?
XXdocmd_buf dw ?
XXdocmd_buf_seg dw ?
XXdocmd_len dw ?
XXdocmd_unit_sel db ?
XXdocmd_status db ?
XX
XX;
XX; Reset the SCSI Bus
XX;
XXscsi_reset proc near
XX pusha
XX
XX mov ax,SCSI_CARD_SEG ;Point at the command port
XX mov es,ax
XX mov si,SCSI_CMD_PORT
XX
XX mov al,CMDBASE or CMDENABLE or CMDRST
XX mov es:[si],al ;Reset the bus
XX call wait1ms
XX mov al,CMDBASE
XX mov es:[si],al ;All done
XX mov cx,250 ;Wait 250ms
XXreset_loop: call wait1ms
XX loop reset_loop
XX
XX popa
XX ret
XXscsi_reset endp
XX
XX;
XX; Test the Ready Status of a unit
XX;
XX; al = return code, 'C' error
XX;
XXscsi_ready proc near
XX lea di,cmd_ready ;Command
XX call docmd
XX ret
XXscsi_ready endp
XX
XX;
XX; Inquire about the type of a unit
XX;
XX; 'C' error indicates an error
XX;
XXscsi_inquire proc near
XX push cx
XX mov di,cur_unit ;Unit
XX lea bx,[di].unit_inq_buf ;Buffer Offset
XX push ds ;Buffer Segment
XX pop es
XX mov cx,size inq ;Buffer Size
XX lea di,cmd_inquire ;Command
XX call docmd
XX pop cx
XX ret
XXscsi_inquire endp
XX
XX;
XX; Determine the size of a disk
XX;
XX; 'C' error indicates an error
XX;
XXscsi_capacity proc near
XX push cx
XX mov di,cur_unit ;Unit
XX lea bx,[di].unit_cap_buf ;Buffer Offset
XX push ds ;Buffer Segment
XX pop es
XX mov cx,size cap ;Buffer Size
XX lea di,cmd_capacity ;Command
XX call docmd
XX pop cx
XX ret
XXscsi_capacity endp
XX
XX;
XX; Verify the Track given in an IOCTL Request
XX;
XX; 'C' indicates an error
XX;
XXscsi_verify proc near
XX mov di,es:[bx].rh19_buf_ofs ;Command Offset
XX mov ax,es:[bx].rh19_buf_seg ;Command Segment
XX mov es,ax
XX mov ax,es:[di].ioctl_fmt_cyl ;Track
XX shl ax,SECT_2_CYL ;Convert to Sector
XX
XX mov di,cur_bpb ;Add to Drive Offset
XX mov dx,[di].bpb_hs_msw
XX
XX lea di,cmd_verify ;Command
XX mov [di].ver_cmd_lba_b3,dh ;Insert Sector
XX mov [di].ver_cmd_lba_b2,dl ; into Command
XX mov [di].ver_cmd_lba_b1,ah ;Insert Sector
XX mov [di].ver_cmd_lba_b0,al ; into Command
XX call docmd
XX ret
XXscsi_verify endp
XX
XX;
XX; Read Some Blocks from the disk given
XX; the request header in es:bx
XX;
XX; al = return code, 'C' indicates an error
XX;
XXscsi_read proc near
XX mov di,bx
XX mov cx,es:[di].rh4_count ;Sector Count
XX mov dx,es:[di].rh4_start ;Starting Sector
XX mov bx,es:[di].rh4_buf_ofs ;Buffer Offset
XX mov ax,es:[di].rh4_buf_seg ;Buffer Segment
XX mov es,ax
XX
XX mov si,cur_bpb
XX lea di,cmd_read ;Command
XX mov ax,[si].bpb_hs_msw ;Drive Sector Offset
XX mov [di].io_cmd_lba_b3,ah ;Insert Sector
XX mov [di].io_cmd_lba_b2,al ;Into the Command
XX
XX if multi_sector
XX mov ax,cx ;Get Sector Count
XX and ax,CHUNK_MAX-1 ;Mask Off the I/O Chunk
XX jnz scsi_r_cok1 ;Check for Boundary
XX mov ax,CHUNK_MAX
XXscsi_r_cok1: shl ax,9 ;Convert to Buffer Size
XX add ax,bx ;Check for Wrap
XX else
XX mov ax,bx ;Check for Wrap
XX add ax,P_SECT ;The First Time
XX endif
XXscsi_r_loop: jnc scsi_r_nowrap
XX mov ax,bx ;Normalize the
XX shr ax,4 ;Segment and
XX mov si,es ;Offset so that
XX add si,ax ;It dosn't Wrap
XX mov es,si
XX and bx,000Fh
XXscsi_r_nowrap: push cx
XX mov [di].io_cmd_lba_b1,dh ;Insert Sector
XX mov [di].io_cmd_lba_b0,dl ;Into the Command
XX if multi_sector
XX and cx,CHUNK_MAX-1 ;Mask Off the I/O Chunk
XX jnz scsi_r_cok2 ;Check for Boundary
XX mov cx,CHUNK_MAX
XXscsi_r_cok2: mov [di].io_cmd_cnt_b1,ch ;Insert Sector Count
XX mov [di].io_cmd_cnt_b0,cl ;Into the Command
XX shl cx,9 ;Convert to Buffer Size
XX else
XX mov cx,P_SECT ;Buffer Size
XX endif
XX call docmd
XX pop cx
XX jc scsi_r_exit
XX if multi_sector
XX mov ax,cx ;Get Sector Count
XX and ax,CHUNK_MAX-1 ;Mask Off the I/O Chunk
XX jnz scsi_r_cok3 ;Check for Boundary
XX mov ax,CHUNK_MAX
XXscsi_r_cok3: sub cx,ax ;Dec Sector Count
XX jz scsi_r_exit
XX add dx,ax ;Bump to next Sector
XX shl ax,9 ;Convert to Buffer Size
XX add bx,ax
XX jmp short scsi_r_loop
XX else
XX inc dx ;Bump to next Sector
XX add bx,P_SECT
XX loop scsi_r_loop
XX clc
XX endif
XXscsi_r_exit: mov es,rh_seg
XX mov bx,rh_off
XX pushf
XX mov ax,es:[bx].rh4_count ;Update the Count
XX sub ax,cx
XX mov es:[bx].rh4_count,ax
XX popf
XX ret
XXscsi_read endp
XX
XX;
XX; Write Some Blocks from the disk given
XX; the request header in es:bx
XX;
XX; al = return code, 'C' indicates an error
XX;
XXscsi_write proc near
XX mov di,bx
XX mov cx,es:[di].rh8_count ;Sector Count
XX mov dx,es:[di].rh8_start ;Starting Sector
XX mov bx,es:[di].rh8_buf_ofs ;Buffer Offset
XX mov ax,es:[di].rh8_buf_seg ;Buffer Segment
XX mov es,ax
XX
XX mov si,cur_bpb
XX lea di,cmd_write ;Command
XX mov ax,[si].bpb_hs_msw ;Drive Sector Offset
XX mov [di].io_cmd_lba_b3,ah ;Insert Sector
XX mov [di].io_cmd_lba_b2,al ;Into the Command
XX
XX if multi_sector
XX mov ax,cx ;Get Sector Count
XX and ax,CHUNK_MAX-1 ;Mask Off the I/O Chunk
XX jnz scsi_w_cok1 ;Check for Boundary
XX mov ax,CHUNK_MAX
XXscsi_w_cok1: shl ax,9 ;Convert to Buffer Size
XX add ax,bx ;Check for Wrap
XX else
XX mov ax,bx ;Check for Wrap
XX add ax,P_SECT ;The First Time
XX endif
XXscsi_w_loop: jnc scsi_w_nowrap
XX mov ax,bx ;Normalize the
XX shr ax,4 ;Segment and
XX mov si,es ;Offset so that
XX add si,ax ;It dosn't Wrap
XX mov es,si
XX and bx,000Fh
XXscsi_w_nowrap: push cx
XX mov [di].io_cmd_lba_b1,dh ;Insert Sector
XX mov [di].io_cmd_lba_b0,dl ;Into the Command
XX if multi_sector
XX and cx,CHUNK_MAX-1 ;Mask Off the I/O Chunk
XX jnz scsi_w_cok2 ;Check for Boundary
XX mov cx,CHUNK_MAX
XXscsi_w_cok2: mov [di].io_cmd_cnt_b1,ch ;Insert Sector Count
XX mov [di].io_cmd_cnt_b0,cl ;Into the Command
XX shl cx,9 ;Convert to Buffer Size
XX else
XX mov cx,P_SECT ;Buffer Size
XX endif
XX call docmd
XX pop cx
XX jc scsi_w_exit
XX if multi_sector
XX mov ax,cx ;Get Sector Count
XX and ax,CHUNK_MAX-1 ;Mask Off the I/O Chunk
XX jnz scsi_w_cok3 ;Check for Boundary
XX mov ax,CHUNK_MAX
XXscsi_w_cok3: sub cx,ax ;Dec Sector Count
XX jz scsi_w_exit
XX add dx,ax ;Bump to next Sector
XX shl ax,9 ;Convert to Buffer Size
XX add bx,ax
XX jmp short scsi_w_loop
XX else
XX inc dx ;Bump to next Sector
XX add bx,P_SECT
XX loop scsi_w_loop
XX clc
XX endif
XXscsi_w_exit: mov es,rh_seg
XX mov bx,rh_off
XX pushf
XX mov ax,es:[bx].rh8_count ;Update the Count
XX sub ax,cx
XX mov es:[bx].rh8_count,ax
XX popf
XX ret
XXscsi_write endp
XX
XX;
XX; Do a command
XX;
XX; bx => buffer for returned information
XX; cx = buffer len
XX; di => command string
XX; es = buffer segment for returned information
XX;
XX; al = return code, 'C' indicates an error
XX;
XXdocmd proc near
XX pusha
XX push es
XX
XX mov docmd_buf,bx ;Save our arguments
XX mov docmd_buf_seg,es
XX mov docmd_len,cx
XX mov docmd_cmd,di
XX
XX mov ax,SCSI_CARD_SEG ;Point at the Card
XX mov es,ax
XX mov si,SCSI_CMD_PORT ;Command Port
XX
XX;
XX; Wait for the Bus to become free
XX;
XX mov cx,65535
XXidle_loop: mov al,es:[si] ;Get the Status
XX and al,FREE_MASK
XX jz try_sel
XX loop idle_loop
XX
XX call scsi_reset
XX mov al,CBUSBUSY ;Bus still BUSY?
XX stc
XX jmp docmd_exit
XX
XXtry_sel: mov al,CMDBASE ;Try to select target
XX mov es:[si],al
XX
XX mov di,cur_unit
XX mov al,[di].unit_select ;Get our Select Bit
XX mov di,SCSI_DATA_PORT ;Data Port
XX mov es:[di],al
XX
XX mov al,CMDBASE or CMDENABLE or CMDSEL
XX mov es:[si],al
XX
XX;
XX; Wait 250 ms for the Target to be SELected
XX;
XX mov cx,2500
XXsel_loop: test byte ptr es:[si],STBSY ;Look for BSY bit
XX jnz cmd_xfer
XX call wait100us
XX loop sel_loop
XX
XX mov al,CNOCONNECT ;Nothing Answered
XX stc
XX jmp docmd_exit
XX
XX;
XX; Start the Command
XX;
XXcmd_xfer: mov al,CMDBASE or CMDENABLE
XX mov es:[si],al
XXxfer_loop: mov al,es:[si]
XX test al,STBSY ;Look for BSY bit
XX jz xfer_error
XX test al,STREQ ;And REQ bit
XX jz xfer_loop
XX
XX and al,REQ_MASK ;Look at REQ type
XX
XX cmp al,REQ_DATAOUT ;Is it Data Out?
XX jnz try_datain
XX call send_data
XX jmp short xfer_loop
XX
XXtry_datain: cmp al,REQ_DATAIN ;Is it Data In?
XX jnz try_cmdout
XX call receive_data
XX jmp short xfer_loop
XX
XXtry_cmdout: cmp al,REQ_CMDOUT ;Is it Command Out?
XX jnz try_statin
XX call send_cmd
XX jmp short xfer_loop
XX
XXtry_statin: cmp al,REQ_STATIN ;Is it Status In?
XX jnz try_msgout
XX mov al,es:[di] ;Get the Status Byte
XX mov docmd_status,al
XX jmp short xfer_loop
XX
XXtry_msgout: cmp al,REQ_MSGOUT ;Is it Message Out?
XX jnz try_msgin
XX call send_nop
XX jmp short xfer_loop
XX
XXtry_msgin: cmp al,REQ_MSGIN ;Is it Message In?
XX jnz xfer_error
XX
XX mov al,es:[di] ;Get Message Byte
XX cmp al,MSG_COMPLETE ;Are We All Done?
XX jnz short xfer_loop
XX mov al,docmd_status
XX cmp al,0
XX jnz xfer_error
XX mov al,COK
XX clc
XX jmp docmd_exit
XX
XXxfer_error: call scsi_reset
XX mov al,CERROR
XX stc
XX
XXdocmd_exit: mov docmd_status,al
XX mov al,CMDBASE
XX mov es:[si],al
XX pop es
XX popa
XX mov al,docmd_status
XX ret
XXdocmd endp
XX
XX;
XX; Receive a Data Stream from the card
XX; On entry es:[di] points at the data port
XX; es:[si] points at the command port
XX;
XXreceive_data proc near
XX mov dx,es ;Save ES
XX
XX mov bx,si
XX mov ax,es
XX mov cx,docmd_len ;Length
XX mov di,docmd_buf ;Dest Offset
XX mov es,docmd_buf_seg ;Dest Segment
XX mov si,SCSI_DATA_PORT ;Source Offset
XX mov ds,ax ;Source Segment
XX mov al,STREQ
XX cld
XX
XXreceive_loop: movsb
XX dec si ;Don't blow the card buffer
XX dec cx
XX jz receive_exit
XXreceive_wait: test byte ptr [bx],al ;Ready?
XX jnz receive_loop
XX jmp short receive_wait
XX
XXreceive_exit: mov si,SCSI_CMD_PORT ;Restore the Environment
XX mov di,SCSI_DATA_PORT
XX mov ax,cs
XX mov ds,ax
XX mov es,dx
XX ret
XXreceive_data endp
XX
XX;
XX; Send a Command to the card
XX; On entry es:[di] points at the data port
XX; es:[si] points at the command port
XX;
XXsend_cmd proc near
XX mov bx,docmd_cmd ;Get Command Pointer
XX mov al,[bx] ;Get a Command Byte
XX mov es:[di],al ;Send it to Card
XX inc bx ;Bump for Next Time
XX mov docmd_cmd,bx
XX ret
XXsend_cmd endp
XX
XX;
XX; Send a Data Stream to the card
XX; On entry es:[di] points at the data port
XX; es:[si] points at the command port
XX;
XXsend_data proc near
XX mov bx,si
XX mov cx,docmd_len ;Get the Data Count
XX mov si,docmd_buf ;Source Offset
XX mov ds,docmd_buf_seg ;Source Segment
XX mov al,STREQ
XX cld
XX
XXsend_loop: movsb
XX dec di ;Don't blow the card buffer
XX dec cx
XX jz send_exit
XXsend_wait: test byte ptr es:[bx],al ;Ready?
XX jnz send_loop
XX jmp short send_wait
XX
XXsend_exit: mov si,SCSI_CMD_PORT ;Restore the Environment
XX mov di,SCSI_DATA_PORT
XX mov ax,cs
XX mov ds,ax
XX ret
XXsend_data endp
XX
XX;
XX; Send a NOP Message
XX;
XXsend_nop proc near
XX mov al,MSG_NOP ;Oops, send a nop
XX mov es:[di],al
XX mov al,CMDBASE or CMDENABLE
XX mov es:[si],al
XX ret
XXsend_nop endp
XX
XX;
XX; Wait One Milli second
XX;
XX; The value of 'cx' is computed for an 8 Mhz Clock
XX;
XXwait1ms proc near
XX push cx ; (3) = 375ns
XX mov cx,798 ; (2) = 250ns
XXwait_m_loop: loop wait_m_loop ; (10) = 1250ns * X
XX pop cx ; (5) = 625ns
XX ret ; (11+) = 1375ns
XXwait1ms endp
XX
XX;
XX; Wait One Hundred Micros Seconds
XX;
XX; The value of 'cx' is computed for an 8 Mhz Clock
XX;
XXwait100us proc near
XX push cx ; (3) = 375ns
XX mov cx,78 ; (2) = 250ns
XXwait_u_loop: loop wait_u_loop ; (10) = 1250ns * X
XX pop cx ; (5) = 625ns
XX ret ; (11+) = 1375ns
XXwait100us endp
SHAR_EOF
if test 11083 -ne "`wc -c < 'subs.asm'`"
then
echo shar: error transmitting "'subs.asm'" '(should have been 11083 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'units.asm'" '(3252 characters)'
if test -f 'units.asm'
then
echo shar: will not over-write existing file "'units.asm'"
else
sed 's/^XX//' > 'units.asm' << \SHAR_EOF
XX;
XX; target information/control structures
XX;
XX even
XXunit0 db size unit dup (-1)
XX even
XXunit1 db size unit dup (-1)
XX even
XXunit2 db size unit dup (-1)
XX even
XXunit3 db size unit dup (-1)
XX even
XXunit4 db size unit dup (-1)
XX even
XXunit5 db size unit dup (-1)
XX even
XXunit6 db size unit dup (-1)
XX even
XXunit7 db size unit dup (-1)
XX
XX even
XXbpb0 db size bpb dup (-1)
XX even
XXbpb1 db size bpb dup (-1)
XX even
XXbpb2 db size bpb dup (-1)
XX even
XXbpb3 db size bpb dup (-1)
XX even
XXbpb4 db size bpb dup (-1)
XX even
XXbpb5 db size bpb dup (-1)
XX even
XXbpb6 db size bpb dup (-1)
XX even
XXbpb7 db size bpb dup (-1)
XX even
XXbpb8 db size bpb dup (-1)
XX even
XXbpb9 db size bpb dup (-1)
XX even
XXbpbA db size bpb dup (-1)
XX even
XXbpbB db size bpb dup (-1)
XX even
XXbpbC db size bpb dup (-1)
XX even
XXbpbD db size bpb dup (-1)
XX even
XXbpbE db size bpb dup (-1)
XX even
XXbpbF db size bpb dup (-1)
XX
XX even
XXunit_array dw unit0
XX dw unit1
XX dw unit2
XX dw unit3
XX dw unit4
XX dw unit5
XX dw unit6
XX dw unit7
XX
XX even
XXbpb_array dw bpb0 ;BPB Array for DOS
XX dw bpb1
XX dw bpb2
XX dw bpb3
XX dw bpb4
XX dw bpb5
XX dw bpb6
XX dw bpb7
XX dw bpb8
XX dw bpb9
XX dw bpbA
XX dw bpbB
XX dw bpbC
XX dw bpbD
XX dw bpbE
XX dw bpbF
XXbpb_hw_mark dw bpb_array
XX
XXcur_unit dw unit0
XXcur_bpb dw bpb0
XX
XX;
XX; Given the request header in es:bx
XX; Return a pointer in ds:di to the unit entry
XX; or 'C' if no such unit exists.
XX;
XX; Do not destroy es:bx !!!
XX;
XXfind_unit proc near
XX pusha
XX mov ah,es:[bx].rh_unit ;What drive did they want
XX lea di,unit_array
XX lea si,bpb_array
XX mov cx,MAXUNIT ;How many to search
XXfind_loop: mov bx,[di] ;Point at a unit
XX mov al,[bx].unit_num_drv ;Does this SCSI device
XX or al,al ;Have any Drives Defined?
XX jz find_next
XX mov dh,[bx].unit_1st_drv ;Get First Drive Number
XXfind_unit_loop: cmp ah,dh ;Is this the correct drive?
XX jz find_match
XX inc si ;Bump to next BPB
XX inc si
XX inc dh ;Bump Drive Number
XX dec al ;Dec Drive count
XX jnz find_unit_loop ;Try next Drive
XX jmp short find_next ;Try next SCSI device
XXfind_match: mov cur_unit,bx ;Found a match
XX mov ax,[si]
XX mov cur_bpb,ax
XX clc
XX jmp find_exit
XXfind_next: inc di
XX inc di
XX loop find_loop
XX stc ;No More units, Error
XXfind_exit: popa
XX ret
XXfind_unit endp
XX
XX;
XX; Given the data in a unit entry,
XX; create the bpb for the unit.
XX;
XXmake_bpb proc near
XX mov di,cur_bpb ;Get the current BPB
XX mov bx,cur_unit ;Get the current Unit
XX mov [di].bpb_ss,P_SECT
XX mov [di].bpb_au,CLUSTSIZE
XX mov [di].bpb_rs,1
XX mov [di].bpb_nf,2
XX mov [di].bpb_de,512
XX mov ah,[bx].unit_cap_buf.cap_sectors_b3
XX mov al,[bx].unit_cap_buf.cap_sectors_b2
XX or ax,ax
XX jz make_bpb_last ;Use up the last few sectors
XX dec ax ;Use up 65536 Sectors
XX mov [bx].unit_cap_buf.cap_sectors_b3,ah
XX mov [bx].unit_cap_buf.cap_sectors_b2,al
XX mov dx,65535 ;Max of 32 Meg
XX jmp short make_bpb_ts
XXmake_bpb_last: mov dh,[bx].unit_cap_buf.cap_sectors_b1
XX mov [bx].unit_cap_buf.cap_sectors_b1,0
XX mov dl,0 ;Round to nearest Cyl
XX mov [bx].unit_cap_buf.cap_sectors_b0,0
XX dec dx ;Make it zero relative
XXmake_bpb_ts: mov [di].bpb_ts,dx
XX mov [di].bpb_md,0F8h
XX shr dx,SECT_2_FS
XX inc dx ;Allow for round-off
XX mov [di].bpb_fs,dx
XX mov [di].bpb_st,SECT_TRACK
XX mov [di].bpb_nh,1
XX mov [di].bpb_hs_lsw,0
XX mov [di].bpb_hs_msw,0
XX ret
XXmake_bpb endp
SHAR_EOF
if test 3252 -ne "`wc -c < 'units.asm'`"
then
echo shar: error transmitting "'units.asm'" '(should have been 3252 characters)'
fi
fi # end of overwriting check
#
# End of shell archive
#
exit 0
More information about the Alt.sources
mailing list