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 ---