ephraim@wang.UUCP (Ephraim Vishniac) (11/05/86)
Enclosed is SCSI Stop, a shutdown application for use with SCSI devices
on the Mac Plus.
[Binary has been posted to mod.mac.binaries. -RLL]
---
#!/bin/sh
# shar: Shell Archiver
# Run the following text with /bin/sh to create:
# SCSIStop.asm
sed 's/^X//' << 'SHAR_EOF' > SCSIStop.asm
XDEBUG EQU 0
X;
X; SCSIStop.asm: Kill off everything.
X; This program is in the public domain.
X; Ephraim M. Vishniac, October 5th, 1986.
X;
X; The current version of the Finder (5.3) doesn't make any
X; provision for notifying device drivers when the system is
X; being Shut Down. This means that there's no convenient
X; way to do an orderly shutdown of attached peripheral
X; devices.
X; The Finder does the following when shutting down:
X; 1. Deliver a "goodbye kiss" to each device driver
X; that needs it.
X; 2. Ejects and Unmounts every volume.
X; 3. Resets.
X; It would make sense for the Finder to close every device
X; driver between (2) and (3), but it doesn't. Apple Technical
X; Support tells me that "Future system software will have a
X; mechanism for shutdown notification ('future' means 'sometime
X; next year', most likely)." They don't say what the
X; mechanism will be.
X
X; This program does everything that the Finder's
X; Shut Down choice does, plus send a Stop command to each
X; SCSI device. The effect of Stop varies from one SCSI
X; device to another. Some disks "park" the disk heads;
X; some actually spin down the disk. Consult your owner's
X; manual or technical reference.
X
X; Please direct questions or comments to the author:
X
X; uucp: decvax!wanginst!wang!ephraim
X
X; MCI mail: masstech
X
X; US mail: Ephraim Vishniac
X; P.O. Box 1357
X; East Arlington, MA 02174
X
X
X; Includes:
X
X Include MacTraps.D ; Use System and ToolBox traps
X Include SysEqu.D ; Use System equates
X Include FSEqu.D ; Use file system equates
X Include ToolEqu.D ; Use toolbox equates
X Include SysErr.D ; Use system error equates
X Include SCSIEqu.Txt ; Use SCSI-specific equates & macros
X
X; Macros:
X
XMACRO DoAlert AlertNumber =
X ; Alert (AlertNumber:INT, NIL:ProcPtr) : INT;
X Clr.w -(sp) ; space for result
X move.w #{AlertNumber},-(sp) ; alert number
X Clr.l -(sp) ; NIL filter
X _Alert
X move.w (sp)+,d0 ; d0 = button hit
X cmp.w #OKitem,d0 ; standard test
X |
X
X; Literals:
X
XGreeting equ 128 ; Greeting alert number
XOKitem equ 1 ; Item number for OK button
XQuitItem equ 2 ; Item number for Quit button
X
XStopSize equ 6 ; Size of stop command
X
XSecond equ 60 ; number of ticks in a second
XStopTime equ 10*Second ; we're in no hurry
X
X; Global data:
X
XStatWord ds.w 1 ; Status word for _SCSIComplete
XMsgWord ds.w 1 ; Message word for _SCSIComplete
X
XStart
X
X;------------------------------- InitManagers -----------------------------
X; This init code is from one of Apple's example programs.
X
X pea -4(A5) ; Quickdraw's global area
X _InitGraf ; Init Quickdraw
X _InitFonts ; Init Font Manager
X move.l #$FFFF,D0 ; Flush all events
X _FlushEvents
X _InitWindows ; Init Window Manager
X _InitMenus ; Init Menu Manager
X _TEInit ; Init Text Edit
X Clr.l -(SP) ; No restart procedure
X _InitDialogs ; Init Dialog Manager
X _InitCursor ; Turn on arrow cursor
X;--------------------------------------------------------------------------
X
X; Warn the user that this will end it all.
X
X DoAlert Greeting
X beq DropDead
X
X; The user didn't say OK. Go back to the Finder.
X
X _ExitToShell
X
X; The user said it's OK, so let's go.
X
XDropDead
X IF DEBUG
X _Debugger
X ENDIF
X
X ; Detach our code segment for safety.
X ; Remember that files get closed as volumes are dismounted.
X Clr.l -(sp) ; space for handle
X move.l #'CODE',-(sp) ; resource type
X move.w #1,-(sp) ; resource number
X _GetResource ; get our handle
X _DetachResource ; break it off
X
X ; Say goodbye to each driver
X ; This routine is digested from Finder 5.3.
XSayGoodBye
X suba.w #ioFQElSize,sp ; space for I/O parm block
X move.w #-1,csCode(sp) ; goodbye code
X movea.l UTableBase,A1 ; A1 = Unit Table pointer
X move.w UnitNtryCnt,D1 ; D1 = Unit Table size
X@0 move.l (A1)+,D0 ; D0 = DCE handle
X beq.s @1 ; skip if empty slot
X movea.l D0,A0 ; A0 = DCE handle
X movea.l (A0),A0 ; A0 = DCE pointer
X bTst #dNeedGoodbye,dCtlFlags(A0) ; Need goodbye?
X beq.s @1 ; skip if no goodbye needed
X move.w dCtlRefNum(A0),ioRefNum(sp) ; set driver refnum
X movea.l sp,A0 ; A0 = IOPB pointer
X _Control ; say goodbye
X@1 subq.w #1,D1 ; that's one down
X bne.s @0 ; loop through table
X
X ; Eject all volumes
X ; This routine is severely digested from Finder 5.3.
XEjectAll
X move.l vcbQHdr+qHead,D7 ; D7 = head of VCB queue
X move.l sp,A0 ; A0 = I/O parm block pointer
X Clr.l ioFileName(A0) ; clear file name pointer
X bra.s @1 ; hop into ejection loop
X@0 move.l (A4),D7 ; D7 = next VCB pointer
X move.w vcbVRefNum(A4),D0 ; D0 = Volume RefNum
X move.w D0,ioVRefNum(A0) ; Set VRefNum in I/O parm block
X _Eject ; Stick it out
X _UnMountVol ; ditch it
X@1 movea.l D7,A4 ; A4 = VCB pointer
X Tst.l D7 ; nil pointer
X bne.s @0 ; loop if not
X
X ; Stop each SCSI device
X ; This is new code.
XSCSIStop
X move.w #6,D7 ; top SCSI address
X@0 move.l #StopTime,D0 ; completion time for Stop
X move.w #StopSize,D1 ; length of stop command
X move.w D7,D2 ; SCSI address
X lea StopCommand,A0 ; Stop command
X jsr SCSISimple ; Issue the stop command
X
X dbra D7,@0 ; Kill off each device
X
X ; Drop the bomb
X ; This is from Finder 5.3.
XResetMac
X movea.l RomBase,A0
X Reset
X jmp $A(A0)
X
X;_______________________________________________________________________
X;
X; Routine: SCSISimple - Issue SCSI command with no data transfer
X; This routine is very distantly derived from 'SCSICommon'
X; in Apple's sample SCSI driver.
X; Arguments:
X; (A0) (input) -- SCSI command block pointer
X; D0.L (input) -- ticks we're willing to wait for completion
X; D1.W (input) -- SCSI command block size
X; D2.W (input) -- SCSI address
X; StatWord(A5) (output) -- returned status from _SCSIComplete, if no err.
X; MsgWord(A5) (output) -- returned Message from _SCSIComplete, if no err.
X; D0.W (output) -- result code (error if non-0)
X;
X;_______________________________________________________________________
X
XSCSISimple
X MoveM.L D4-D6/A4,-(SP) ; save regs
X Move.L D0,D4 ; D4 = tick count
X Move.W D1,D5 ; D5 = command block size
X Move.W D2,D6 ; D6 = SCSI ID
X Move.L A0,A4 ; A4 = command block pointer
X
X Clr.W -(SP) ; space for result code
X
X ; Get the SCSI bus
X _SCSIGet ; "Hello?"
X Tst.W (SP) ; (did it work?)
X Bne TargetErr ; (no... give up)
X
X ; Select our target
X Move.W D6,-(SP) ; SCSI address
X _SCSISelect ; "Is there anybody out there?"
X Tst.W (SP) ; (did it work?)
X Bne.S TargetErr ; (no... give up)
X
X ; Issue the SCSI command
X Move.L A4,-(SP) ; SCSI command pointer
X Move.W D5,-(SP) ; command length
X _SCSICmd ; do the command
X
X ; Complete the SCSI command.
X Pea StatWord(A5) ; get the status
X Pea MsgWord(A5) ; and message words
X Move.L D4,-(SP) ; tick count we're willing to wait
X _SCSIComplete ; go get 'em
X Tst.W (SP) ; (did it work?)
X Bne.S TargetErr ; (no. Give up.)
X
X ;What were the Status bytes?
X@3 Move.B StatWord+1(A5),D0 ; was there an SCSI error?
X Beq.S SCSIDone ; no error, just exit.
X
X;We got an error in contacting the target, or in SCSIComplete.
XTargetErr
X Move.W #ioErr,(SP) ; if we can't get bus or target.
X
X;Exit, stage left.
XSCSIDone
X Move.W (SP)+,D0 ; pop error code
X MoveM.L (SP)+,D4-D6/A4 ; restore regs
X Tst.W D0 ; test error code
X Rts ; and return
X
X; Static data
X
XStopCommand
X dc.b $1B ; Start/stop command = $1B
X dc.b $01 ; LUN = 0; Reserved = 0; Immed. = 1
X dc.b $00 ; Reserved = 0
X dc.b $00 ; Reserved = 0
X dc.b $00 ; Reserved = 0; Start = 0
X dc.b $00 ; Reserved = 0; Flag = 0; Link = 0
X
X END
SHAR_EOF
exit
---