[mod.mac.sources] SCSIStop

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