*===================================================================*
*                                                                   *
* Example program demonstrating the various methods of talking to   *
* the SCRAM 500 device driver.                                      *
*                                                                   *
* Both standard and SCSI-Direct methods are demonstrated.           *
*                                                                   *
* The code is verbosely commented to make it simple to understand   *
* but some knowledge of 68000 assembler programming on the part of  *
* the reader is assumed.                                            *
*                                                                   *
* All code by Will McGovern.  (yes, I wrote the driver as well !!)  *
*                                                                   *
* BLATENT AD ==> For a custom written driver for your hardware,     *
*                send inquiries to :                                *
*                                                                   *
*                         Will McGovern                             *
*                         PO Box 247,                               *
*                         NEW LABTON,                               *
*                         NSW 2289                                  *
*                         AUSTRALIA                                 *
*                                                                   *
* The code is written to be assembled with Macro68 from DigiSoft    *
* but can be converted to other formats with ease.  Any Macro68     *
* specific directives are explained.                                *
*                                                                   *
* The 2.0 include files are used for all symbols and equates.       *
*                                                                   *
* THIS CODE IS COMPLETELY PUBLIC DOMAIN. USE IT HOWEVER YOU WANT !! *
*===================================================================*

 Macro68 assembler directives

                mc68000                     ;68000 mode
                strict                      ;strict syntax mode
                exeobj                      ;executable object file
                objfile    'example'        ;object filename

 SYS : Call system vector macro

sys             macro
                jsr(_LVO\1,a6)
                endm

*------------------------------------------------------------------

EXAMPLE_UNIT     equ      0                 ;scsi unit to talk to
BLOCK_SIZE       equ      $200              ;size of 512 byte block
MAXAUTO_SIZE     equ      $fe               ;maximum autosense size
MAXINQUIRY_SIZE  equ      $fe               ;maximum # of inquiry bytes

*------------------------------------------------------------------

            section  excode,code

 Find this task and see if we started from workbench or from a CLI

start       movea.l  (4).w,a6            ;exec library base
            suba.l   a1,a1               ;this task
            sys      FindTask            ;find this task
            movea.l  d0,a4               ;save task pointer
            tst.l    (pr_CLI,a4)         ;did we come from a CLI ?
            bne.s    clistartup          ;branch if CLI entry

 Discard the workbench startup msg

            lea     (pr_MsgPort,a4),a0  ;this task's message port
            sys     WaitPort            ;wait for WB startup message
            lea     (pr_MsgPort,a4),a0  ;this task's message port
            sys     GetMsg              ;fetch the startup message

 Initialise a message port (MP) for use with my IORequest structure

clistartup   movea.l  #mymp,a2              ;my message port
             move.l   a4,(MP_SIGTASK,a2)    ;save pointer to this task
             moveq    #-1,d0                ;any signal will do
             sys      AllocSignal           ;allocate a signal for MP
             move.b   d0,(MP_SIGBIT,a2)     ;save signal # in MP
             bmi      nosignal              ;branch if error
             movea.l  a2,a1                 ;copy MP pointer
             sys      AddPort               ;add my MP to the system
 Open scram.device for EXAMPLEUNIT

             movea.l  #scramname,a0         ;scram.device name
             movea.l  #myior,a1             ;my IORequest structure
             move.l   a2,(MN_REPLYPORT,a1)  ;init MP pointer in IOR
             moveq    #EXAMPLE_UNIT,d0      ;scsi unit to talk to
             moveq    #0,d1                 ;no flags
             sys      OpenDevice            ;open scram.device
             tst.l    d0                    ;any errors ?
             bne.b    noscramdevice         ;branch if error

* Now we can talk to the scram.device through the standard 
* device commands such as CMD_READ or use the HD_SCSICMD command 
* for SCSI-Direct mode.

 Here are some examples of normal and SCSI-Direct mode access.


 Read block 0 from the unit into blockbuffer using CMD_READ command

             movea.l #myior,a1                    ;IORequest pointer
             move.w  #CMD_READ,(IO_COMMAND,a1)    ;CMD_READ command
             move.l  #blockbuffer,(IO_DATA,a1)    ;buffer for data
             clr.l   (IO_OFFSET,a1)               ;block 0
             move.l  #BLOCK_SIZE,(IO_LENGTH,a1)   ;one block to read
             sys     DoIO                         ;read the block
             tst.b   d0                           ;any error ?
             bne.b   cmdreaderror                 ;error if d0 not zero

 Now do the same as above in SCSI-Direct mode

             movea.l #myior,a1                    ;IORequest pointer
             move.w  #HD_SCSICMD,(IO_COMMAND,a1)  ;CMD_READ command
             move.l  #scsireadcmd,(IO_DATA,a1)    ;pointer to SCSICmd
             sys     DoIO                         ;read the block
             tst.b   d0                           ;any error ?
             bne.b   scsireaderror                ;error if d0 not zero

 Perform a SCSI INQUIRY command on the EXAMPLE_UNIT

             movea.l #myior,a1                    ;IORequest pointer
             move.w  #HD_SCSICMD,(IO_COMMAND,a1)  ;HD_SCSICMD command
             move.l  #scsiinquirycmd,(IO_DATA,a1) ;pointer to SCSICmd
             sys     DoIO                         ;perform inquiry
             tst.b   d0                           ;any error ?
             beq.b   exitexample                  ;error if d0 not zero

 This is where an error handler would be placed if this was serious code

cmdreaderror:
scsireaderror  nop

 Clean up our mess and return to DOS

exitexample    movea.l  #myior,a1           ;pointer to my IORequest
               sys      CloseDevice         ;close scram.device
noscramdevice  movea.l  #mymp,a1            ;pointer to my MP
               sys      RemPort             ;remove my message port
               moveq    #0,d0               ;prepare D0 for byte load
               move.b   (mymp+MP_SIGBIT),d0 ;get signal # we allocated
               sys      FreeSignal          ;free the allocated signal
nosignal       moveq    #0,d0               ;clear return code
               rts                          ;return to DOS

*--------------------------------------------------------------------

	section	exdata,data


Note: The SCSICmd structure used in this example did not appear in the
      early 1.3 include files in its entirety.  C= omitted the autosense
      information.  See the 2.0 include file "devices/scsidisk.i" for a
      full description of the SCSI-Direct protocol.

      Also note that the SCSIF_AUTOSENSE (4 byte sense length) has 
      become SCSIF_OLDAUTOSENSE in the 2.0 implementation.

      The new SCSIF_AUTOSENSE supports sense data lengths of 4 to 255
      bytes.  The sense length is specified in scsi_SenseLength field.

The SCSIF_READ/SCSIF_WRITE flags are NOT required by the scram.device as
the data direction is determined automatically by the driver.


 SCSICmd structure for reading block 0

scsireadcmd    dc.l     blockbuffer           ;data buffer address
               dc.l     BLOCK_SIZE            ;number of bytes to read
               dc.l     0                     ;actual bytes read
               dc.l     readcmd               ;pointer to scsi CDB
               dc.w     10                    ;# of command bytes
               dc.w     0                     ;actual cmd bytes sent
               dc.b     SCSIF_AUTOSENSE       ;automatic sense
               dc.b     0                     ;status byte
               dc.l     sensebuffer           ;buffer for sense data
               dc.w     MAXAUTO_SIZE          ;size of my sense buffer
               dc.w     0                     ;actual sense bytes read

 SCSICmd structure for an INQUIRY command

scsiinquirycmd dc.l     inquirybuffer         ;data buffer address
               dc.l     MAXINQUIRY_SIZE       ;number of bytes to read
               dc.l     0                     ;actual bytes read
               dc.l     inquirycmd            ;pointer to scsi CDB
               dc.w     6                     ;# of command bytes
               dc.w     0                     ;actual cmd bytes sent
               dc.b     SCSIF_AUTOSENSE       ;automatic sense
               dc.b     0                     ;status byte
               dc.l     sensebuffer           ;buffer for sense data
               dc.w     MAXAUTO_SIZE          ;size of my sense buffer
               dc.w     0                     ;actual sense bytes read

* Here are the actual command desciptor blocks (CDB's) sent to the 
* selected scsi unit.
*
* For more information on these consult the SCSI specifications or the 
* manual for your scsi device.

readcmd        dc.w   $2800,$0000,$0000,$0000,$0100  ;extended read
inquirycmd     dc.w   $1200,$0000,MAXINQUIRY_SIZE<<8

 Text and byte data

scramname      cstr     'scram.device'        ;null terminated name
               even

*--------------------------------------------------------------------

section        exbss,data

mymp           ds.b     MP_SIZE               ;my message port structure
               even
myior          ds.b     IOSTD_SIZE            ;my IORequest structure
               even
inquirybuffer  ds.b     MAXINQUIRY_SIZE       ;inquiry data buffer
               even
sensebuffer    ds.b     MAXAUTO_SIZE          ;autosense data buffer
               even
blockbuffer    ds.b     BLOCK_SIZE            ;block data buffer
               even

*--------------------------------------------------------------------

               end

