briana@tau-ceti.isc-br.com (Brian Who?) (08/30/90)
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