Source to bsd/dev/ppc/drvApple96_SCSI/Apple96Types.h


Enter a symbol's name here to quickly find it.

/*
 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
 *
 * @[email protected]
 * 
 * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
 * Reserved.  This file contains Original Code and/or Modifications of
 * Original Code as defined in and that are subject to the Apple Public
 * Source License Version 1.0 (the 'License').  You may not use this file
 * except in compliance with the License.  Please obtain a copy of the
 * License at http://www.apple.com/publicsource and read it before using
 * this file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License."
 * 
 * @[email protected]
 */

/**
 * Copyright (c) 1994-1996 NeXT Software, Inc.  All rights reserved. 
 * Copyright 1997 Apple Computer Inc. All Rights Reserved.
 * @author  Martin Minow    mailto:[email protected]
 * @revision	1997.02.13  Initial conversion from AMDPCSCSIDriver sources.
 *
 * Private structures and definitions for Apple 53C96 SCSI driver.
 * Apple96SCSI is closely based on Doug Mitchell's AMD 53C974/79C974 driver.
 *
 * Edit History
 * 1997.02.13	MM		Initial conversion from AMDPCSCSIDriver sources.
 * 1997.03.24	MM		Partially normalized against AppleMeshTypes.h
 * 1997.04.17	MM		Removed SCS_PHASECHANGE (not needed)
 */
#include <machdep/ppc/proc_reg.h>
#include <machdep/ppc/powermac.h>
#include <machdep/ppc/interrupts.h>
#ifndef TIMESTAMP
#define TIMESTAMP   1
#endif
#import <driverkit/scsiTypes.h>
#import <driverkit/IOMemoryDescriptor.h>
#import <machkit/NXLock.h>
#import <kernserv/queue.h>
#import <driverkit/debugging.h>
#import "bringup.h"

/*
 * These types will ultimately be moved to an implementation-wide header file.
 */
#ifndef __APPLE_TYPES_DEFINED__
#define __APPLE_TYPES_DEFINED__ 1
typedef unsigned char	UInt8;		/* An unsigned 8-bit value	*/
typedef unsigned int	UInt32;		/* An unsigned integer		*/
typedef signed int  SInt32;		/* An explicitly signed int	*/
typedef void	    *LogicalAddress;	/* A virtual address		*/
typedef UInt32	    PhysicalAddress;	/* A hardware address		*/
typedef UInt32	    ByteCount;		/* A transfer length count	*/
typedef UInt32	    ItemCount;		/* An index or counter		*/
typedef UInt32	    Boolean;		/* A true/false value		*/
#ifndef TRUE
#define TRUE	    1
#define FALSE	    0
#endif
#endif /* __APPLE_TYPES_DEFINED__ */

/**
 * Macros to access DBDMA Registers
 */
#ifndef SynchronizeIO
#define SynchronizeIO()	    eieio()	/* TEMP */
#endif /* SynchronizeIO */

/*
 * Operation flags and options.
 */
typedef enum BusPhase	/* These are the real SCSI bus phases			    :	*/
{
    kBusPhaseDATO	    = 0,
    kBusPhaseDATI,
    kBusPhaseCMD,
    kBusPhaseSTS,
    kBusPhaseReserved1,
    kBusPhaseReserved2,
    kBusPhaseMSGO,
    kBusPhaseMSGI,
    kBusPhaseBusFree
} BusPhase;

/*
 * Command to be executed by I/O thread. These are ultimately derived from ioctl
 * control values.
 */
typedef enum  { 
    kCommandExecute,		/* Execute IOSCSIRequest    */
    kCommandResetBus,		/* Reset bus		    */
    kCommandAbortRequest	/* Abort I/O thread	    */
} CommandOperation;

/*
 * We read target messages using a simple state machine. On entrance
 * to MSGI phase, gMsgInState = kMsgInIdle. Continue reading messages
 * until either gMsgInState == kMsgInReady or the target changes
 * phase (which is an error).
 */
typedef enum MsgInState {
    kMsgInIdle = 0,	/*  0 Not reading a message (must be zero)	*/
    kMsgInReading,	/*  1 MSG input state: reading counted data	*/
    kMsgInCounting,	/*  2 MSG input state: reading count byte	*/
    kMsgInReady		/*  3 MSG input state: a msg is now available	*/
} MsgInState;

/*
 * This is the maximum number of bytes to be transferred in an autosense
 * request. It should be equal to 255. 
 */
enum {
	kMaxAutosenseByteCount  = (sizeof (esense_reply_t) > 255)
		? sizeof (esense_reply_t) : 255
};

/*
 * gMaxDMATransfer is set so that we don't have to worry about the ambiguous
 * "zero" value in the MESH and DBDMA transfer registers that can mean either
 * 65536 bytes or zero bytes.
 */
enum {
	kMaxDMATransfer = (65536 - 4096)
};

/*
 * These values are stored in gCurrentTarget and gCurrentLUN when
 * there is no active request.
 */
enum {
    kInvalidTarget	    = 0xFFFF,
    kInvalidLUN		    = 0xFFFF,
/*
 * The default initiator bus ID (needs to be fetched from NVRAM).
 */
    kInitiatorIDDefault	    = 7
};
#define APPLE_SCSI_RESET_DELAY	(250)	/* Msec */

/*
 * Command struct passed to I/O thread.
 */
typedef struct CommandBuffer {

    /*
     * Fields valid when commandBuf is passed to I/O thread.
     */
    CommandOperation	op;	/* kCommandExecute, etc.		*/
    
    /*
     * The following 3 fields are only valid if op == CO_Execute.
     */
    IOSCSIRequest   *scsiReq;	/* -> The SCSI command parameter block	*/
    IOMemoryDescriptor *mem;	/* -> Memory to transfer, if any    */
    
    /*
     * These fields are used by the I/O thread to manage the I/O request.
     *	cmdLock		Wait for the command to complete
     *	link		Queue link for the command, disconnect, and
     *			pending queues.
     *	timeoutPort	Port for timeout messages
     *	queueTag	SCSI tagged request if not QUEUE_TAG_NONTAGGED
     */
    NXConditionLock *cmdLock;	    /* client waits on this		*/
    queue_chain_t   link;	    /* for enqueueing on commandQ	*/
    port_t	    timeoutPort;    /* for timeout messages		*/
    UInt8	    queueTag;	    /* QUEUE_TAG_NONTAGGED or queue tag */ 
    UInt8	    cdbLength;	    /* Actual length of this command	*/
    
    /*
     * SCSI bus state variables. Note that currentDataIndex can exceed
     * scsiReq->maxTransfer if the device sends (receives) more data than
     * we can receive (send). This values are NOT used for autosense. The
     * position in the transfer itself is in the IOMemoryDescriptor.
     */
    UInt32	    currentDataIndex;	/* Where we are in the DATA transfer	*/
    UInt32	    savedDataIndex;	/* Where we were at bus disconnect  */
    IOMemoryDescriptorState savedDataState; /* saved index for IOMemoryDescriptor	*/
    UInt32	    thisTransferLength; /* Current Data Phase transfer length	*/
    /*
     * Request management flags
     *	flagActive	    Set if we're in the active array and active count
     *			    reflects our existance. Managed by [self activateCmd]
     *			    and [self deactivateCmd : cmdBuf].
     *			    and that IOScheduleFunc() has been called.
     *	flagIsAutosense	    Set if we are executing an internally-generated
     *			    Request Sense command. If this is an autosense,
     *			    the operation is modified as follows:
     *			Arb/Select:	Disable disconnects. Re-establish
     *					synchronous and fast for this target,
     *					use the current tag, if any.
     *			Command:	Use an internally-generated Request Sense.
     *			Data:		Read into our wired-down sense buffer.
     *					Do not touch the data index and transfer
     *					count variables. On completion, copy
     *					from our wired-down buffer to the caller's
     *					sense array.
     *			Completion:	Good status, return SR_IOST_CHKSV to client.
     *					Bad status: never set isAutosense. Driver
     *					return SR_IOST_CHKSNV.
     */
    unsigned	    flagActive:1,	    /* We're in activeArray and activeCount */
		    flagIsAutosense:1,	    /* Set if THIS is an autosense command  */
					pad:30;
    /*
     * This is set by autosense Status phase.
     */
    UInt8	    autosenseStatus;	/* Did autosense complete ok?		*/ 
    /*
     * Statistics support.
     */
    ns_time_t	    startTime;		/* time cmd started			*/
    ns_time_t	    disconnectTime;	/* time of last disconnect		*/
    
} CommandBuffer;

/*
 * Condition variable states for commandBuf.cmdLock.
 */
#define CMD_PENDING		0
#define CMD_COMPLETE	1

/*
 * Dimension the message in/out buffers.
 */
enum {
    kMessageInBufferLength  = 16,
    kMessageOutBufferLength = 16
};

/*
 * Value of queueTag for nontagged commands. This value is never used for 
 * the tag for tagged commands.
 */
enum {
    QUEUE_TAG_NONTAGGED = 0
};

/*
 * Per-target info.
 * 
 * maxQueue is set to a non-zero value when we reach a target's queue size
 * limit, detected by a STAT_QUEUE_FULL status. A value of zero means we
 * have not reached the target's limit and we are free to queue additional
 * commands (if allowed by the overall cmdQueueEnable flag).
 *
 * syncXferPeriod and syncXferOffset are set to non-zero during sync  
 * transfer negotiation. Units of syncXferPeriod is NANOSECONDS, which
 * differs from both the chip's register format (dependent on clock 
 * frequency and fast SCSI/fast clock enables) and the SCSI bus's format
 * (which is 4 ns per unit).
 *
 * cmdQueueDisable has a default (initial) value of zero regardless of the
 * driver's overall cmdQueueEnable flag. It is set to one when a target
 * explicitly tells us that the indicated feature is unsupported. It is
 * not set to zero after bus reset.
 *
 * selectATNDisable has a default (initial) value of zero. It is set to
 * one when a target does not go to MSGO phase after a select with ATN.
 * It is not set to zero after bus reset.
 */
typedef struct PerTargetData {
	UInt8		maxQueue;	/* Max queue depth for this target	*/
	unsigned	cmdQueueDisable:1, /* No command queue for this target	*/
			selectATNDisable:1, /* No select with ATN for this target */
		pad:6;
	UInt8		inquiry_7;	/* 7th byte peeked fm Inquiry data	*/
} PerTargetData;

/*
 * Values for the finite-state automaton, stored in the gBusState instance
 * variable. See Statemachines.m for documentation. This state machine
 * operates when the bus is busy.
 *
 *	SCS_UNINITIALIZED	Initial power-up state. Illegal in the
 *				finite-state automaton (an interrupt arrived
 *				before we were completely initialized).
 *	SCS_DISCONNECTED	Normal "bus free" state (we're not processing
 *				any commands).
 *	SCS_SELECTING		Just tried to select a remote target.
 *	SCS_RESELECTING		Reselection transistion state
 *	SCS_INITIATOR		Normal "processing bus phases" state. Set
 *				after correctly responding to an interrupt.
 *				Changed to an in-progress state.
 *	SCS_COMPLETING		In command-complete sequence
 *	SCS_WAIT_FOR_BUS_FREE	After disconnect or command complete, before
 *				seeing disconnect interrupt or reselection
 *	SCS_DMACOMPLETE		After starting DMA, waiting for completion
 *	SCS_SENDINGMSG		After sending an MSGO byte
 *	SCS_GETTINGMSG		While getting MSGI bytes
 *	SCS_SENDINGCMD		While sending CMDO bytes
 *	SCS_DEATH_MARCH		The target got lost. Follow phases until
 *				it disconnects.
 */
typedef enum {
	SCS_UNINITIALIZED,	/* initial state			*/
	SCS_DISCONNECTED,	/* disconnected				*/
	SCS_SELECTING,		/* SELECT command issued 		*/
	SCS_RESELECTING,	/* Handle reselection after interrrupt	*/
	SCS_INITIATOR,		/* following target SCSI phase		*/
	SCS_COMPLETING,		/* initiator command complete in progress */
	SCS_WAIT_FOR_BUS_FREE,	/* transition after disconnect or complete */
	SCS_DMACOMPLETE,	/* dma (in or out) is in progress	*/
	SCS_SENDINGMSG,		/* MSG_OUT phase in progress		*/
	SCS_GETTINGMSG,		/* transfer msg in progress		*/
	SCS_SENDINGCMD,		/* command out in progress		*/
	SCS_DEATH_MARCH		/* recovery from target confusion	*/
} BusState;


/* 
 * The message out state machine works as follows:
 * 1. When the driver wishes to send a message out, it:
 *	-- places the message in currMsgOut[]
 *	-- places the number of message bytes in currMsgOutCnt
 *	-- asserts ATN 
 *	-- sets msgOutState to kMsgOutWaiting
 *	All of the above are done by -messageOut for single-byte messages.
 * 2. When bus phase = PHASE_MSGOUT, the message in currMsgOut[] is 
 *	sent to the target in -fsmPhaseChange. msgOutState is then
 *	set to kMsgOutSawMsgOut.
 * 3. On the next phase change to other than PHASE_MSGOUT or PHASE_MSGIN,
 *	msgOutState is set to kMsgOutNone and currMsgOutCnt is set to 0.
 */
typedef enum MsgOutState {
	kMsgOutNone	= 0,	/* no message to send			*/
	kMsgOutWaiting,		/* have msg, awaiting MSG OUT phase	*/
	kMsgOutSawMsgOut	/* sent msg, check for retry		*/
} MsgOutState;