TweetFollow Us on Twitter

Modifying SCSI
Volume Number:4
Issue Number:1
Column Tag:Advanced Mac'ing

Modifying Apple's SCSI Driver

By Jörg Langowski, MacTutor Editorial Board, Grenoble, France

How to Make Apple’s ‘non-functional’ SCSI Driver, Functional!

Happy New Year and welcome to our fourth volume. We’ll step right in the middle of things with a SCSI driver project that will take us two columns.

You’ve seen several articles on SCSI device handling in MacTutor; Tim Standing’s contributions in V3#2 and V3#6, and my own column in V3#3. We showed you how to hook up the electronics of a generic SCSI disk to the Mac, how to play with SCSI commands and do raw data transfers, and how to format the SCSI disk. One crucial thing has always been missing: the SCSI driver itself.

History

It’s been over a year now that I hooked up my own 80 MByte disk, a Quantum Q280, to my Mac (Plus at that time), and was confronted with all those problems, including getting a driver that would make my disk work. That last part turned out to be the hard one, at that time.

All information that I could then get hold of was the source of a ‘generic’ SCSI driver published by Apple in a Software Supplement, and also available on various bulletin boards. The problem with this driver was that it wouldn’t quite work as promised. In this column I’ll explain the modifications that I had to do to the Apple driver to make it boot and run on the Quantum Q280 disk. I am not claiming that it will drive any SCSI disk, although in theory it should drive many of them; in practice, however, a Seagate ST225N will run with the original code supplied by Apple, but not with my code. However, by describing my implementation and its differences to the original, I hope to give you some hints what can be done to make an arbitrary SCSI disk work with a fully or partially home-brew driver.

Some of you might find this information out of date, since by now the HD SC installer has been released by Apple. Alas: I lost a lot of time backing up some 63 Megabytes to run the HD SC installer on my Q280; only to find out that the drive wasn’t recognized and I had to re-install my old driver. Which, as you’ll see soon, is admittedly some kind of a kludge, but has performed without problems for over one year now.

It is for exactly the reason that, after all, SCSI devices are not that generic, that David Smith asked me to write about my SCSI driver [Apple Expo, Paris Sept 30: “You really have a SCUZZY driver? Well, publish it!”]. Therefore, not much Forth this month. Rather assembler, and general ramblings. Next month I’ll continue with a re-implementation of Apple’s SCSI driver in Forth. Yes, that’s right. Just to get all you assembly/ hardware guys out there to buy your copies of Mach2.

Apple’s ‘generic’ SCSI driver

There are two problems with printing the full, commented source listing of Apple’s driver here (I already mentioned this in the March 87 article). First, although it is almost two years old, it is copyrighted by Apple. Second, the source is quite long, (some 12 pages with comments) and it is available through APDA, Delphi, Compuserve and who knows where. I think it is much simpler that you download a copy of the [heavily commented] driver’s source - I got mine from Delphi - and follow the explanations in this article to understand what it’s doing. The parts of the driver that I modified are printed in the listing. The complete source of a SCSI driver, written in Forth, will follow next month.

[The SCSI driver example is a product of APDA, part # KMSSDP, which sells for $10. The APDA catalog says, and I quote: ‘Contains a heavily commented, but non-functional, sample scsi driver written in Assembly language’. Jörg’s article should help make it functional! We can’t distribute it since APDA is selling it as a product, so please contact them for this source. You’ll also want to make sure you have the 2.0b1 MPW Shell release, which contains the latest assembler equates including the SCSI equates. Included with the scsi example is a eight page handout which says: ‘It is provided to shows how such a driver might be written (by someone with not a lot of time to tell developers how to write drivers!)’. And again, this little gem: ‘Unfortunately, if you happen to have gotten a good deal on an old 370 meg drive that you want to hook up to your Macintosh, we can’t really help you (there are only six of us for all Macintosh development, and four thousand of you!)’. The comments go on to state that the Technical Support Group’s charter is to help developer’s in creating products for market, so I assume any subject that does not appear to lead to product development is given little developer support! I have always disagreed with this narrow view of software development. The amount of Macintosh software developed in-house far exceeds what little commercial “MS Word” type program development that is going on, and this will only increase as the Mac II moves into big-time engineering departments. Computers were tools for problem solving long before they were a means to help Apple sell more computers. -Ed]

The structure of a SCSI driver

Like any driver, the SCSI driver will have a header before the actual driver code. This header looks like the following:

Flags [word]    $4F00   
 ;read, write, control, status, needs lock
        [word]   $0  ;no periodic action
 [word]   $0;no event mask
        [word]   $0   ;no menu
 
; Entry point offset table
 [word] offset to Open routine
 [word] offset to Prime routine
 [word] offset to Control routine
 [word] offset to Status routine
 [word] offset to Close routine
 [counted string]  the driver name

The block number at which the driver can be found on the disk, and its length, are given in the device descriptor map (DDM) on block 0 of the SCSI disk. On bootup, the driver is found (hopefully) at the location given in the DDM, read from the disk, and a jump is made to the beginning of the driver. Therefore, an SCSI driver must contain executable code before the header. Usually, a JMP or BRA instruction is contained here that jumps to a piece of code which does the actual initialization and installation.

SCSI driver installation

The procedure by which the Macintosh will install the driver on bootup is partly described in IM IV-293, partly in the comments to Apple’s SCSI driver source. I’ll summarize the relevant information here.

On bootup, the Macintosh will try to select a device on the SCSI bus by its ID, starting with ID=6 and going downward. In the older systems, the highest ID found was used as the number of the startup device; in the new system releases, the control panel allows you to select where you want to boot from.

The driver descriptor and device partition maps are then read from block 0 and 1 of the startup device. Their signatures are checked; the first word of block 0 must be $4552, and of block 1, $5453. The driver descriptor map (DDM) must contain an entry that corresponds to a driver for the Macintosh (processor type = 1, as explained in V3#3). The driver is read from the blocks given in the DDM and put into memory allocated in the system heap. Then the Macintosh jumps to the beginning of the driver code.

The driver code is supposed to ‘install’ itself. In Apple’s code, the installation routine is located at the very end of the driver. It takes three parameters on entry:

- A0, a pointer to the device partition map

- D5, the SCSI ID of the device for this driver

- D7, default data start area’, not used in the Apple driver.

I’ll explain the steps the installer goes through. First, we have to let the system know that we exist. The table of existing drivers is the unit table (IM II-191), a pointer to which is available through the system global UTableBase ($11C). The unit table contains a handle to the unit’s device control entry at UTableBase+unitnumber*4. By definition, the unit number of the SCSI device is its SCSI ID + 32. The driver reference number for a device is the two’s complement of its unit number.

We therefore know our unit number and reference number when the installation routine is entered. The trap DrvrInstall (Toolbox $A03D, and not documented in IM), called with the driver reference number in D0, will allocate a new device control entry for the driver and put a handle to this DCE into the unit table. The format of a DCE, as given in IM II-190, looks like:

TYPE DCtlEntry = RECORD
      DCtlDriver : Ptr ; 
 {ptr to ROM or handle to RAM driver}
      DCtlFlags : Integer ; {flags}
      DCtlQHdr : QHdr ; {driver’s i/o queue}
      DCtlPosition : LongInt ; 
 {byte pos used by read and write calls}
      DCtlStorage : Handle ; 
 {hndl to RAM drivers private storage}
      DCtlRefNum : Integer ; 
 {driver’s reference number}
      DCtlCurTicks : LongInt ; 
 {long counter for timing system task calls}
      DCtlWindow : Ptr ; 
 {ptr to driver’s window if any}
      DCtlDelay : Integer ; 
 {number of ticks btwn sysTask calls}
      DCtlEMask : Integer ; 
 {desk acessory event mask}
      DCtlMenu : Integer ; 
 {menu ID of menu associated with driver}
      END ;  

After the DCE has been created, some of its fields (DCtlDriver, DCtlFlags, DCtlDelay, DCtlEmask, and DCtlMenu) are filled using the information in the driver header. The driver will be marked “ROM based” (bit 6 of dCtlFlags = 0), because the header contains a pointer to the driver.

Next, the Open trap is called with the driver’s name as its parameter. If the driver cannot be opened for some reason, DrvrRemove (Toolbox $A03E, also undocumented) is called with the reference number in D0, and the memory allocated to the driver is disposed with a call to DisposPtr.

If the driver has been opened correctly, the device partition map is checked for a partition with the file system ID ‘TFS1’. The offset to this partition and its size are remembered in the local variables area of the driver. It is this partition which will be mounted as a Macintosh volume.

Finally, if the install routine has been called at boot time, the dNeedTime flag is set in the DCtlFlags word; this way the driver gets called by the desk manager when the system comes up. This will allow us to post a disk-insert event for this volume at that time. The reason to do this is that on boot-up the system remembers only the drive that was actually used to boot from. Thus, in case the boot was made from another drive (such as a floppy), our SCSI drive will have to be re-mounted, even though the driver has already been installed.

The Open routine

The Open routine will get memory for the driver’s local variables and add the SCSI drive to the drive queue. Entry parameters to this routine are, as for all five driver routines (Open, Control, Prime, Status, Close) a pointer to a parameter block in A0 and to the device control entry in A1.

First, a block is reserved in the system heap for the local variables and its pointer stored in the driver’s DCE. The drive number is initially set to 5, and the drive queue is traversed, starting at its head (contained in the system global DrvQHdr+QHead = $30A), to see whether the drive number is already in use. If it is, it is incremented by 1 and the queue checked again until an unused drive number has been found. This drive number is stored in a local variable. The drive queue element (IM II-127) for our drive is also set up in the local variable space and some of its fields are preset (see TN36, which also describes a routine that adds a drive to the drive queue in a very similar way):

The qType field is set to 1. This indicates that the drive size may be greater than 32 MBytes and that one more 16-bit word is following the dQDriveSize field of the drive queue element; this word indicates the high-order word of a 32-bit block count. With the old definition of the drive size (qType = 0), a 16-bit block count was used, allowing a maximum size of only 32 MBytes. We therefore have to remember that the high- and low-order words of the drive size are reversed when we are working with this variable later. The dqDrvSize is initialized to zero; this field will be filled by the Install routine after the driver is open. The dQFSID field is also set to 0 to indicate a normal HFS volume. The four bytes preceding the drive queue element contain flags (IM II-128); byte 1 of these flags is set to 8 to indicate a non-ejectable disk. The remaining flags are cleared.

The drive is added to the drive queue using the AddDrive trap ($A04E, not documented in IM) with D0 containing the drive number in its high order word and the driver reference number in its low order word, and A0 containing a pointer to the drive queue element.

The last action of the Open routine is to set up an SCSI pseudo program for read/write transfers in the local variable space. We use a very simple one:

 SCNOINCbuffer, #bytes
 SCSTOP

and this is where we first deviate from the Apple driver. Apple’s example uses (and this works with the ST225N):

@1 SCINCbuffer, #bytes
 SCLOOP @1, count
 SCSTOP

which will transfer count blocks of #bytes each starting at address buffer. Our driver, on the contrary, will transfer all bytes requested in one single chunk. The reason for this will be explained later. First, keep yourself content with the fact that one method works on the Q280 and the other on the ST225N.

The Control routine

The SCSI driver must be able to respond to several control calls, distinguished by their csCode parameter; some of them are described in TN28. They are:

KillIo  csCode=1
Verify  csCode=5
Format  csCode=6
Eject   csCode=7
getIcon csCode=21
AccRun  csCode=65
SCSICodecsCode=77

KillIo is ignored (the driver operates synchronously and won’t return before the I/O operation is completed), as are Verify and Format.

Eject must be supported in some way. First, when the ROM code cannot boot off a volume, it will try to eject that volume; the driver code has to return with an error here, otherwise the Macintosh would keep trying to boot from this drive. Also, a disk inserted event is posted, so that later on , when the system comes up, the drive will be re-mounted.

getIcon, will return a pointer to an icon list (ICN#) corresponding to the disk icon, followed by a counted string identifying the driver.

AccRun will post a disk-inserted event (see above); it will be called by the desk manager when the system comes up after boot time. After being called, it will clear thedNeedTime flag in the DCE so that no further calls are made.

Finally, SCSICode is a control call that allows it to issue SCSI commands directly, with the parameters (SCSI command block pointer, its length, completion count, address of pseudo program) in the CSParam field of the parameter block.

Status and Close calls are not supported.

Read and Write

The actual read and write calls pass through the Prime routine. It is mainly this routine, and SCSICommon that handles SCSI commands, that I had to modify to make Apple’s driver work with my Q280. The modified routines are printed in listing one.

Since the SCSI Read and Write commands only take an 8-bit sector count (512 bytes per sector), the author of Apple’s driver decided to transfer the data in chunks of 64K maximum each. Furthermore, each such ‘chunk’ is transferred in 512 byte sub-chunks using the ‘looping’ SCSI pseudo program described above.

When I first tried to set up the Apple driver on the Q280 without any modifications, the routine ‘almost’ seemed to work, at least I could install my drive and see its icon on my desktop, although I couldn’t boot. Nor could I read/write files larger than 64K. Desperate, I looked through Technical Note #96, which describes SCSI handling and known bugs.

The first problem was a well-known one with the Mac Plus ROM boot code: the Q280 was configured to enter the Unit Attention condition after a reset, and thus a read command right after that would fail. Although this problem could be overcome by changing the Unit Attention Enable bit on the drive with a Mode Select command, there was a second problem: The firmware that the Q280 used at that time took 4 seconds to recover after an SCSI bus reset, and since the Macintosh boot code issues resets in one-second intervals, the disk could never get ready for the boot code to read the first blocks. This problem could only be solved by changing the firmware, which the local Quantum distributor eventually did.

But there were other problems, this time in the Apple SCSI driver. The multiple-chunk transfer instruction block seemed to be one of them. TN96 says: “Don’t use multi transfer TIBs. The SCSI Manager has trouble with losing bytes when executing more than one transferring TIB instruction within a single call. Try to code your TIB as simply as possible: SCNoInc followed by SCStop.”

Therefore, the Open routine was modified as described above. Although the problem was supposed to be fixed with System releases 3.2 or later, I found that a multi-transfer TIB wouldn’t work even with more recent systems, and I still use the simple TIB shown above.

The second problem was that the original driver transferred the data from/to the disk by consecutive Read or Write commands if the amount of data exceeded 64K bytes. Even though each of these commands was issued in the proper way, Getting the bus, Selecting the target, sending the command, doing the SCSIRead or SCSIWrite, and a SCSIComplete at the end, the driver seemed to be losing bytes when more than 64K of data were transferred. TN 96 cautions: “Multiple calls to SCSIRead or SCSIRBlind after issuing a command and before calling SCSIComplete may not work.” Although the situation was not quite like this - each Read was in fact completed before the next one was started - I decided to transfer all bytes with one single SCSI command. The 10 byte commands Read Extended and Write Extended can be used for this purpose. They take a 16-bit sector count in their command block, and thus allow the transfer of 512*65536 = 32 Megabytes maximum. So until you’ve upgraded your machine to more than 32 Mbyte, this driver should have no problems.

Third, it seemed like blind transfers would not be accepted by my Q280. Therefore I changed the part of the SCSICommon routine that does the actual read/write so that only non-blind transfers would be made. This slows the driver down somewhat, but the overall performance (Disktimer II) is still about 60% of a Dataframe 40 XP on a Mac+.

Let me quickly summarize the main modifications that have to be made to Apple’s driver to make it run with the Quantum Q280 SCSI disk:

- change the SCSI pseudo program so that only one transfer instruction is done.

- remove the main loop of the Prime routine that reads/writes the data in several pieces. Replace it by a sequence of instructions that uses the SCSI Read/Write Extended commands so that all data is transferred in one block.

- remove the option of doing blind reads. Only non-blind reads should be used.

The modified Prime and SCSICommon routines are printed in Listing 1. The code there makes reference to variables and routines of the Apple SCSI driver, so you should have its source at hand. The modified driver can be assembled with MPW or MDS; if you assemble it into a resource of type ‘SDRV’ and ID=128, the installer written in Mach2 (listing 2) will accept it and write it out to your SCSI drive. The installer code should be self-explanatory after you’ve read the installation strategy in V3#3.

Since this article has made reference to quite a few different sources, I’ll summarize the recommended (or required) reading again:

- Apple example SCSI driver source, version 1.0 (APDA)

- Inside Macintosh:

Vol. II, Device Manager; Vol. IV, SCSI Manager

- Technical Notes:

28, Finders and Foreign Drives

36, Drive Queue Element Format

96, Known SCSI Bugs

- MacTutor:

V3#2 p.67, Tim Standing, Build your own SCSI hard disk

V3#3 p.32, Jörg Langowski, SCSI device introduction

V3#6 p.45, Tim Standing, SCSI formatting program

The full source of a Forth SCSI driver is to follow in the next issue. See you then.

Listing 1: Modification of Apple’s Prime and SCSICommon routines for the 
Quantum Q280
;
; Routine:    DiskPrime
; Arguments:  A0 (input)  -- pointer to request parameter block
;             A1 (input)  -- pointer to disk DCE
;
; The “prime” entry point is used for drive read/write.
;
; Within this routine, we use the following registers:
;   D0-D1: temps
;   D3: Next Sector Number
;   D5: Number of Physical Blocks Left to Xfer
;   D6: Number of blocks to transfer this iteration
;   A2: locals ptr
;   A3: paramblk ptr
;   A4: DCE Ptr
 
DiskPrime 
 BSR.S   CkDrvNum;check for valid drive number,
 ; setup A2 & D1
        SFTickleFlag(A2)  ;Remember that we’ve been 
 ;accessed.
       
 ;Do the transfer. Our DCE ptr is in A4, our locals ptr in A2.
        MOVE.L  A0,A3         ;save the ioparamblk ptr in A3
        ;Calculate sector count (to D5)
        MOVE.L IOByteCount(A3),D5 ;how many bytes does he want?
 BEQ.S   DiskParmErr     ;he doesn’t want any! Ooops!
 LSR.L   #8,D5           ;convert bytes to 512-byte sectors
 LSR.L   #1,D5
@1      AND.L   #$001FFFFF,D5   ;make sure it fits in 21 bits
 ;Calculate starting sector number (to D3)
        MOVE.L  DCtlPosition(A4),D3     ;starting byte position
 LSR.L   #8,D3   ;convert sector # to 512-byte sectors
 LSR.L   #1,D3           
 
     ;Range-check this operation: 
 ;If (starting block number + block count) >= volume size
     ;then return IOErr.
        MOVE.L  D3,D0   ;copy starting sector
 ADD.L   D5,D0   ;add this request sector count
 CMP.L   D1,D0   ;(block after end of request ? 
 ;  block after end of volume)
        BGE     PrimeErr  
        
 ;This request is valid. 
; Offset the starting sector # by the start of the partition
        ADD.L   Offset(A2),D3 ;offset to the partition start
        ;Copy buffer address to NextAddr(A2)
        MOVE.L  IOBuffer(A3),NextAddr(A2)
        
;SCSI transfer is done by extended read or write.
;Therefore no loop, like in the original code, is necessary.
;The maximum # of bytes transferred this way
;will be 65535 sectors, i.e. 32 MBytes. 
;This should be well above the buffer size of the Mac for 
;some years to come. /JL
;
        MOVE.W  D5,D6;Transfer # of sectors requested.
        ; setup SCSI extended R/W block
 ;
        ;Stuff command byte first
@3      LEA     SCmd(A2),A0     ;point at our command block
        MOVE.W  #$2800,D0       ;assume Read command
 CMP.B   #aWrCmd,ioTrap+1(A3) ;are we writing?
 BNE.S   @4          ;  no.
 MOVE.W  #$2A00,D0   ;  yes, do a Write command
@4      MOVE.W  D0,(A0)+    ;  put the command away.
        
     ;Stuff Starting sector number /JL
        MOVE.L  D3,(A0)+  ;put it into SCSI command block
 ; (clears logical unit number, too)
   ;Stuff block count, and clear the reserved byte.
 LSL.L  #8,D6    ;align D6 with cmd block structure
        MOVE.L  D6,(A0)+    ;put it away. 
        CLR.B   (A0)+       ;clear the reserved byte.
        
     ;Set up the SCSI “pseudo-program”. The SCSI manager
 ;will interpret this program during the transfer. 
 ;The program is very simple:
 ;  @1  SCNOINC  buffer, #bytes 
      ; SCSTOP
      ;
        LEA SCSIPseudo(A2),A0 
 ;point at the pseudo-program block
 MOVE.L  NextAddr(A2),SCParam1(A0)       
 ;fill in “buffer” with the start address 
 ;of the caller’s buffer.
 LSL.L  #1,D6  ;convert #sectors*256 (in D6) to #bytes
 MOVE.L  D6,SCParam2(A0)  ;fill in “bytes”: # of bytes
 LSR.L  #1,D6
 LSR.L  #8,D6    ;restore D6
 
        ;Do the SCSI call for this iteration.
        MOVEQ   #1,D1              ;assume we’re reading (>0)
 CMP.B   #aWrCmd,ioTrap+1(A3) ;are we reading?
 BNE.S   @5               ;yes.
 MOVEQ   #-1,D1  ;no, we’re writing. (<0).
@5      LEA     SCSIPseudo(A2),A0  ;point at pseudoprogram
        LEA     SCmd(A2),A1      ;point at SCSI command block
 MOVEQ #60,D0    ;tick count to wait for completion
 MOVEQ   #10,D2  ;length of command block
 BSR.S   SCSICommon       ;do the xfer
 BNE.S   PrimeErr  ;error in transfer.
 
 MOVE.L  D6,D0   ;calculate # sectors  xferred
 ASL.L   #8,D0   ; * 512, for 512 bytes per sector.
 ASL.L   #1,D0           
 ADD.L   D0,NextAddr(A2) ;bump buffer pointer.
        
    ;Let the param block show that we finished.
        MOVE.L  IOByteCount(A3),D0  ;he asked for this many bytes
 MOVE.L  D0,IONumDone(A3)    ;we did this many bytes!
 ADD.L   D0,DCtlPosition(A4) ;bump position pointer, too.
 BRA     DiskOKDone       ;all done!
 
;This is where we get to if we get an SCSI error during Prime.
;A little intelligence here (retry on certain kinds of errors)
; would be nice.

PrimeErr: 
 MOVEQ  #IOErr,D0 ;replace error code with an I/O Error
        BRA    DiskDone  ;and return through our exit routine. 
;
; Routine:      SCSICommon
; Arguments:    OurId(A2)       (input)  -- our SCSI ID.
;(A0)    (input)  -- the SCSI pseudoprogram (all set up)
;(A1)    (input)  -- the SCSI command block (6 bytes)
;(A2)    (input)  -- ptr to our locals
;D0.L    (input)  -- the tick count we’re willing to wait
;                       for completion
;D1.L    (input)  --  sign of byte count we’re transferring
;after the command (0 if none, + if read, - if write).
;  D2.W    (input)  -- Size of the SCSI command block
;StatWord(A2)     (output) -
;- returned status from _SCSIComplete, if no err.
;MsgWord(A2)      (output) -
;- returned Message from _SCSIComplete, if no err.
;  D0.W    (output) -- result code (error if non-0!)
;
; This routine is the common code for an SCSI Operation. 
; We set up the command block and the pseudoprogram, 
; then call this routine to execute it.
; All the SCSIManager routines we’ll be using are stack-based 
; functions which return an integer error code. So we “pre-
; push” result word, test it after each command, and pop it 
; off after we’re done (or, [knock on wood] after an error 
; occurs).

SCSICommon
        MOVEM.L D4-D6/A3-A4,-(SP)    ;save regs
 MOVE.L  D0,D4   ;save tick count in D4
 MOVE.L  D1,D5   ;save byte count in D5
 MOVE.W  D2,D6   ;save command size in D6
 MOVE.L  A0,A3   ;save the pseudocode ptr
 MOVE.L  A1,A4   ;save the cmd block ptr
 CLR.W   -(SP)   ;reserve space for result code.
 ;Arbitrate for the SCSI bus
        _SCSIGet ;”Hello?”
        TST.W   (SP) ;(did it work?)
        BNE.S   TargetErr ;(no... give up)
        
 ;We have the bus... Select our target
        MOVE.W  OurID(A2),-(SP)  ;push our target’s SCSI id
 _SCSISelect;”Is there anybody out there?”
 TST.W   (SP)    ;(did it work?)
 BNE.S   TargetErr ;(no... give up)
        
    ;We’ve reached our target. Issue the SCSI command
        MOVE.L  A4,-(SP)  ;push address of  SCSI command
 MOVE.W  D6,-(SP); the block is this many bytes long
 _SCSICmd ;do the command
 TST.W   (SP)    ;(did it work?)
 BNE.S   Cleanup ;(no... go take care of the error)
 
; If we have to transfer any bytes, execute the 
; pseudo-program to transfer them.
;Since we’re going to do an SCSIComplete right away, 
;we don’t need to check the error
;(because it would only result in a call to SCSIComplete...)
        TST.L   D5 ;any bytes to transfer?
 BEQ.S   Cleanup ; no, skip this.
 MOVE.L  A3,-(SP);yes, push pseudo-program address
 TST.L   D5 ;Are we reading or writing? (- if writing)
 BMI.S   @1 ;br if writing.
 
  _SCSIRead ;normal reads only. May be modified 
 ;for other drives
        BRA.S   Cleanup 
 
 @1  _SCSIWrite    ;Do the Write.
 
;clean up after ourselves, or find out why we got an error.
;(the error so far is in (SP).W -- it might be useful to look
; at it).

Cleanup:  
 PEA     StatWord(A2)  ;get the status
        PEA     MsgWord(A2)   ; and message words
        MOVE.L  D4,-(SP)  ;tick count we’re willing to wait
 _SCSIComplete        ;go get ‘em
 TST.W   (SP)    ;(did it work?)
 BNE.S   TargetErr      ;(no. Give up.)
 
    ;What were the Status bytes?
 MOVE.B  StatWord+1(A2),D0  ;was there an SCSI error?
        BEQ.S   SCSIDone  ;no error, just exit.
 
  ;At this point, we should look at the “check sense status”
  ;bit in the status byte - if it’s set, we could make a
  ;recursive call to SCSICommon to get sense status.
  ;But, since we’d only be returning an I/O error anyway...
  ;
  ;Since this driver always executes fully synchronously,
  ;we’ll probably never see the “busy” bit set, but we
  ;could probably retry in that case.
 
;We got an error in contacting the target, or in SCSIComplete.
TargetErr:
 MOVE.W  #ioErr,(SP) ;if we can’t get bus or target.
        
;Exit, stage left.
SCSIDone: 
 MOVE.W  (SP)+,D0                ;pop error code
        MOVEM.L (SP)+,D4-D6/A3-A4       ;restore regs
        RTS       ;and return (D0 and CCR reflect error).


Listing 2: SCSI drive formatter/installer

\ This program requires the SCSI command definitions
\ printed in V3#3. Only the actual installer code is listed here.
\ © Nov 1987 J. Langowski / MacTutor

only forth definitions
also mac also assembler

variable numstring 20 vallot
variable mydisk

: input-number numstring 1+ 20 expect  
 numstring number? drop ;
 
: yesno
 BEGIN
 pad 32 expect pad c@ 
 CASE ascii y OF 1 0 ENDOF
  ascii Y OF 1 0 ENDOF
  ascii n OF 0 0 ENDOF
  ascii N OF 0 0 ENDOF
 1 ENDCASE
 WHILE cr .” Enter y or n - “
 REPEAT
;
 
: wait { nticks | #ticks -- }
 call tickcount -> #ticks
 BEGIN pause
 call tickcount #ticks -
 nticks >
 UNTIL
;

( SCSI routines follow )
: find.disk ( finds the highest ID SCSI device )
 8 1 do
 SCSIReset drop 60 wait
 SCSIGet drop
 i SCSISelect 0= IF i leave THEN
 loop SCSIReset drop
;

: get.disk find.disk mydisk ! ;

: format 12000 format.blk myDisk @ doscsi 2drop ;

: prep.noattn  ( mode data )
scbuf 20 0 fill
[ hex ] 
00000008 scbuf ! 
00000000 scbuf 4 + !  
00000000 scbuf 8 + ! 
00021000 scbuf C + ! ( page 0; unit attn disable )
[ decimal ]
;

: modenoattn
 prep.noattn
 16 modesel.blk 5 + c!
 120 modesel.blk myDisk @ scbuf 16 doscsi.wb
;

variable ddm 512 vallot
variable dpm 512 vallot
variable driver.block 2048 vallot

: read.cap ( -- #blocks bytes.p.blk )
 120 readcap.blk myDisk @ scbuf 8 doscsi.rb
 abort” Can’t read capacity” drop
 scbuf @ scbuf 4 + @ 
;

: show.cap read.cap
 dup . .”  byte blocks; total capacity is “ 
 1024 */ . .”  K bytes.” cr
;

hex
: create.ddm
 ddm 200 0 fill
 4552 ddm w!
 read.cap ddm 2+ w! ( block size )
  ddm 4 + ! ( # of blocks )
 0 ddm 8 + w! ( device type )
 0 ddm A + w! ( device ID )
 8 ddm C + !  ( first data block )
 1 ddm 10 + w! ( one driver to follow )
 2 ddm 12 + ! ( driver start block )
 4 ddm 16 + w! ( driver is 4 blocks long )
 1 ddm 18 + w! ( and runs on Macintosh =1 )
;

: create.dpm
 dpm 200 0 fill
 5453 dpm w!
 8 dpm 2+ ! ( starting block of partition )
 read.cap drop 8 - dpm 6 + ! ( # of blocks )
 “tfs1 dpm A + !   ( TFS1 signature )
 0 dpm E + !
;
decimal

: read.ddm
 0 read.blk 2+ w! 0 read.blk 4 + c!
 1 read.blk 5 + c!
 120 read.blk myDisk @ ddm 512 doscsi.r
 2drop
;

: read.dpm
 0 read.blk 2+ w! 1 read.blk 4 + c!
 1 read.blk 5 + c!
 120 read.blk myDisk @ dpm 512 doscsi.r
 2drop
;

: write.ddm
 0 write.blk 2+ w! 0 write.blk 4 + c!
 1 write.blk 5 + c!
 120 write.blk myDisk @ ddm 512 doscsi.w
 2drop
;

: write.dpm
 0 write.blk 2+ w! 1 write.blk 4 + c!
 1 write.blk 5 + c!
 120 write.blk myDisk @ dpm 512 doscsi.w
 2drop
;

: get.sdrv 
 “sdrv 128 call getresource
 @ driver.block 2048 cmove
;

: write.sdrv
 0 write.blk 2+ w! 2 write.blk 4 + c!
 4 write.blk 5 + c!
 120 write.blk myDisk @ driver.block 2048 doscsi.w
 2drop
;

 
.TRAP   _newptr,sys     $A51E
hex 144 CONSTANT SysEvtMask 
 308 CONSTANT DQHeader
 6 CONSTANT QTail
 6 CONSTANT DQDrive
decimal

VARIABLE syshp.drvr

: install.driver { | dstart dlength dbytes pointer -- }
 read.ddm 
 ddm 18 +  @ -> dstart
 ddm 22 + w@ -> dlength
 dlength 512 * -> dbytes
 dstart 256 /mod read.blk 2+ w! read.blk 4 + c!
 dlength read.blk 5 + c!
 120 read.blk myDisk @ driver.block 512 dlength * doscsi.r
 2drop
 dbytes MOVE.L (A6)+,D0
      _newptr,sys ( get memory block in system heap )
      MOVE.L A0,-(A6)   -> pointer
 pointer 
 IFdriver.block pointer dbytes cmove
 pointer syshp.drvr !
      ELSE .” Not enough system heap for installation.” cr
      THEN
;

CODE call.driver
 MOVE.L D5,-(A7)
 MOVE.L (A6)+,D5
 MOVE.L (A6)+,A0
 execute
 MOVE.L (A7)+,D5
 RTS
END-CODE
 
: mount.scsi
 install.driver 
 read.dpm
 SysEvtMask @
 0 SysEvtMask !
 syshp.drvr @ dpm myDisk @ call.driver
 SysEvtMask !
;

: zero.scsi
 DQHeader qTail + @ dQDrive + w@ ( drive # found )
 “ JL’s Hard Disk” call DIZero
;
 
NEW.WINDOW Installer
“ SCSI Installer 0.9” Installer TITLE
50 20 300 480 Installer BOUNDS
Document Visible NoCloseBox NoGrowBox Installer ITEMS

1000 6000 TERMINAL Inst

: init.scsi { | fmt -- } activate
 0 -> fmt
 Installer dup CALL selectwindow 
   dup CALL showwindow
   CALL setport
 cr .” Looking for SCSI devices...”
 get.disk
 cr .” SCSI drive found at address “ myDisk @ .
 cr show.cap
 cr .” format disk? “ 
 yesno IF 
 cr .” Do you REALLY want to erase this SCSI disk? “
 yesno IF 1 -> fmt 
  cr .” Reformatting disk... “ 
  format 
   THEN
 THEN
 modenoattn
 create.ddm create.dpm
 write.ddmwrite.dpm
 cr .” Device and partition descriptor maps written. “
 cr .” Reading SDRV resource ... “
 get.sdrv
 cr .” Writing driver ... “
 write.sdrv
 mount.scsi
 fmt if 
 zero.scsi 
 cr .” Directory zeroed.”
 then
 60 wait bye
;

: scsi.go
 Installer ADD
 Installer Inst BUILD
 Inst init.scsi
;

\ use TURNKEY scsi.go filename to create 
\ a turnkey application
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Logic Pro X 10.1.1 - Music creation and...
Apple Logic Pro X is the most advanced version of Logic ever. Sophisticated new tools for professional songwriting, editing, and mixing are built around a modern interface that's designed to get... Read more
VLC Media Player 2.2.0 - Popular multime...
VLC Media Player is a highly portable multimedia player for various audio and video formats (MPEG-1, MPEG-2, MPEG-4, DivX, MP3, OGG, ...) as well as DVDs, VCDs, and various streaming protocols. It... Read more
Sound Studio 4.7.8 - Robust audio record...
Sound Studio lets you easily record and professionally edit audio on your Mac. Easily rip vinyls and digitize cassette tapes, or record lectures and voice memos. Prepare for live shows with live... Read more
LibreOffice 4.4.1.2 - Free, open-source...
LibreOffice is an office suite (word processor, spreadsheet, presentations, drawing tool) compatible with other major office suites. The Document Foundation is coordinating development and... Read more
Freeway Pro 7.0.3 - Drag-and-drop Web de...
Freeway Pro lets you build websites with speed and precision... without writing a line of code! With its user-oriented drag-and-drop interface, Freeway Pro helps you piece together the website of... Read more
Cloud 3.3.0 - File sharing from your men...
Cloud is simple file sharing for the Mac. Drag a file from your Mac to the CloudApp icon in the menubar and we take care of the rest. A link to the file will automatically be copied to your clipboard... Read more
Cyberduck 4.6.5 - FTP and SFTP browser....
Cyberduck is a robust FTP/FTP-TLS/SFTP browser for the Mac whose lack of visual clutter and cleverly intuitive features make it easy to use. Support for external editors and system technologies such... Read more
Firefox 36.0 - Fast, safe Web browser. (...
Firefox for Mac offers a fast, safe Web browsing experience. Browse quickly, securely, and effortlessly. With its industry-leading features, Firefox is the choice of Web development professionals and... Read more
Thunderbird 31.5.0 - Email client from M...
As of July 2012, Thunderbird has transitioned to a new governance model, with new features being developed by the broader free software and open source community, and security fixes and improvements... Read more
VOX 2.4 - Music player that supports man...
VoxIt just sounds better! The beauty is in its simplicity, yet behind the minimal exterior lies a powerful music player with a ton of features & support for all audio formats you should ever need... Read more

Get The Whole Story – Lone Wolf Complete...
Get The Whole Story – Lone Wolf Complete is Now Available and On Sale Posted by Jessica Fisher on February 27th, 2015 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Who Wore it Best? The Counting Dead vs....
Like it or not, the “clicker” genre, popularized by cute distractions like Candy Box and Cookie Clicker, seems like it’s here to stay. So Who Wore it Best? takes a look at two recent examples: The Counting Dead and AdVenture Capitalist. | Read more »
Card Crawl, the Mini Deck Building Game,...
Card Crawl, the Mini Deck Building Game, is Coming Soon Posted by Jessica Fisher on February 27th, 2015 [ permalink ] Tinytouchtales and Mexer have announced their new game, | Read more »
Witness an all new puzzle mechanic in Bl...
Well, BlastBall MAX is not one of those games and is bucking trends such as timers, elements of randomness, and tacked-on mechanics in favor of pure puzzle gameplay. When you first boot up the game you’ll see a grid made up of squares that are each... | Read more »
This Princess Has a Dragon and She isn’t...
This Princess Has a Dragon and She isn’t Afraid to Useit. | Read more »
Mecha Showdown Review
Mecha Showdown Review By Lee Hamlet on February 27th, 2015 Our Rating: :: IN A SPINUniversal App - Designed for iPhone and iPad Mecha Showdown replaces traditional buttons with a slot machine mechanic in this robot fighting game,... | Read more »
Reliance Games and Dreamworks Unveil Rea...
Reliance Games and Dreamworks Unveil Real Steel Champions Posted by Ellis Spice on February 27th, 2015 [ permalink ] Reliance Games and Dreamworks have announced that a third game in | Read more »
Sum Idea Review
Sum Idea Review By Jennifer Allen on February 27th, 2015 Our Rating: :: TAXING NUMBERSUniversal App - Designed for iPhone and iPad Sum Idea is a fairly charming but taxing puzzle game.   | Read more »
A New Badland Update Brings Daydream Lev...
A New Badland Update Brings Daydream Levels to Co-Op Posted by Ellis Spice on February 27th, 2015 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Slashing Demons Review
Slashing Demons Review By Lee Hamlet on February 27th, 2015 Our Rating: :: IT'S A LONG WAY TO THE TOPUniversal App - Designed for iPhone and iPad Slashing Demons lacks the depth or scope to take it beyond the point of being just... | Read more »

Price Scanner via MacPrices.net

Apple CEO Tim Cook to Deliver 2015 George Was...
Apple CEO Tim Cook will deliver the George Washington University’s Commencement address to GWU grads on May 17, at which time he will also be awarded an honorary doctorate of public service from the... Read more
Apple restocks refurbished Mac minis for up t...
The Apple Store has restocked Apple Certified Refurbished 2014 Mac minis, with models available starting at $419. Apple’s one-year warranty is included with each mini, and shipping is free: - 1.4GHz... Read more
Save up to $50 on iPad Air 2s, NY tax only, f...
 B&H Photo has iPad Air 2s on sale for $50 off MSRP including free shipping plus NY sales tax only: - 16GB iPad Air 2 WiFi: $469.99 $30 off - 64GB iPad Air 2 WiFi: $549 $50 off - 128GB iPad Air 2... Read more
16GB iPad Air 2 on sale for $447, save $52
Walmart has the 16GB iPad Air 2 WiFi on sale for $446.99 on their online store for a limited time. Choose free shipping or free local store pickup (if available). Sale price for online orders only,... Read more
iMacs on sale for up to $205 off MSRP
B&H Photo has 21″ and 27″ iMacs on sale for up to $205 off MSRP including free shipping plus NY sales tax only: - 21″ 1.4GHz iMac: $1029 $70 off - 21″ 2.7GHz iMac: $1199 $100 off - 21″ 2.9GHz... Read more
Apple Takes 89 Percent Share of Global Smartp...
According to the latest research from Strategy Analytics, global smartphone operating profit reached US$21 billion in Q4 2014. The Android operating system captured a record-low 11 percent global... Read more
New Travel Health App “My Travel Health” iOS...
Rochester, Minnesota based Travel Health and Wellness LLC has announced that its new iOS app help safeguard the user’s health when traveling abroad — “My Travel Health” is now available on the Apple... Read more
Sale! MacBook Airs for up to $115 off MSRP
B&H Photo has MacBook Airs on sale for up to $100 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 11″ 128GB MacBook Air: $799 100 off MSRP - 11″ 256GB MacBook Air: $999 $100... Read more
15-inch 2.0GHz Retina MacBook Pro (refurbishe...
The Apple Store has Apple Certified Refurbished previous-generation 15″ 2.0GHz Retina MacBook Pros available for $1489 including free shipping plus Apple’s standard one-year warranty. Their price is... Read more
Wither The iPad mini? End Of The Road Imminen...
AppleDailyReport’s Dennis Sellers predicts that the iPad mini is going to be left to wither on the vine, as it were, and then just allowed to fade away — a casualty of the IPhone 6 Plus and other... Read more

Jobs Board

Sr. Technical Services Consultant, *Apple*...
**Job Summary** Apple Professional Services (APS) has an opening for a senior technical position that contributes to Apple 's efforts for strategic and transactional Read more
Event Director, *Apple* Retail Marketing -...
…This senior level position is responsible for leading and imagining the Apple Retail Team's global engagement strategy and team. Delivering an overarching brand Read more
*Apple* Pay - Site Reliability Engineer - Ap...
**Job Summary** Imagine what you could do here. At Apple , great ideas have a way of becoming great products, services, and customer experiences very quickly. Bring Read more
*Apple* Solutions Consultant - Retail Sales...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
*Apple* Solutions Consultant - Retail Sales...
**Job Summary** As an Apple Solutions Consultant (ASC) you are the link between our customers and our products. Your role is to drive the Apple business in a retail Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.