/*
 *  scsi.h Copyright (C) 1992 Drew Eckhardt 
 *         Copyright (C) 1993, 1994, 1995, 1998, 1999 Eric Youngdale
 *  generic SCSI package header file by
 *      Initial versions: Drew Eckhardt
 *      Subsequent revisions: Eric Youngdale
 *
 *  <drew@colorado.edu>
 *
 *       Modified by Eric Youngdale eric@andante.org to
 *       add scatter-gather, multiple outstanding request, and other
 *       enhancements.
 */

#ifndef _SCSI_H_
#define _SCSI_H_


/*
 * Some of the public constants are being moved to this file.
 * We include it here so that what came from where is transparent.
 */

/*
 *      SCSI opcodes
 */
#define TEST_UNIT_READY       	0x00
#define REZERO_UNIT           	0x01
#define REQUEST_SENSE         	0x03
#define FORMAT_UNIT           	0x04
#define READ_BLOCK_LIMITS     	0x05
#define REASSIGN_BLOCKS       	0x07
#define READ_6                	0x08
#define WRITE_6               	0x0a
#define SEEK_6                	0x0b
#define READ_REVERSE          	0x0f
#define WRITE_FILEMARKS       	0x10
#define SPACE                 	0x11
#define INQUIRY               	0x12
#define RECOVER_BUFFERED_DATA 	0x14
#define MODE_SELECT           	0x15
#define RESERVE               	0x16
#define RELEASE               	0x17
#define COPY                  	0x18
#define ERASE                 	0x19
#define MODE_SENSE            	0x1a
#define START_STOP            	0x1b
#define RECEIVE_DIAGNOSTIC    	0x1c
#define SEND_DIAGNOSTIC       	0x1d
#define ALLOW_MEDIUM_REMOVAL  	0x1e

#define SET_WINDOW            	0x24
#define READ_CAPACITY         	0x25
#define READ_10               	0x28
#define WRITE_10              	0x2a
#define SEEK_10               	0x2b
#define WRITE_VERIFY          	0x2e
#define VERIFY                	0x2f
#define SEARCH_HIGH           	0x30
#define SEARCH_EQUAL          	0x31
#define SEARCH_LOW            	0x32
#define SET_LIMITS            	0x33
#define PRE_FETCH             	0x34
#define READ_POSITION         	0x34
#define SYNCHRONIZE_CACHE     	0x35
#define LOCK_UNLOCK_CACHE     	0x36
#define READ_DEFECT_DATA      	0x37
#define MEDIUM_SCAN           	0x38
#define COMPARE               	0x39
#define COPY_VERIFY           	0x3a
#define WRITE_BUFFER          	0x3b
#define READ_BUFFER           	0x3c
#define UPDATE_BLOCK          	0x3d
#define READ_LONG             	0x3e
#define WRITE_LONG            	0x3f
#define CHANGE_DEFINITION     	0x40
#define WRITE_SAME            	0x41
#define READ_TOC              	0x43
#define LOG_SELECT            	0x4c
#define LOG_SENSE             	0x4d
#define MODE_SELECT_10        	0x55
#define RESERVE_10            	0x56
#define RELEASE_10            	0x57
#define MODE_SENSE_10         	0x5a
#define PERSISTENT_RESERVE_IN 	0x5e
#define PERSISTENT_RESERVE_OUT 	0x5f
#define MOVE_MEDIUM           	0xa5
#define READ_12               	0xa8
#define WRITE_12              	0xaa
#define WRITE_VERIFY_12       	0xae
#define SEARCH_HIGH_12        	0xb0
#define SEARCH_EQUAL_12       	0xb1
#define SEARCH_LOW_12         	0xb2
#define READ_ELEMENT_STATUS   	0xb8
#define SEND_VOLUME_TAG       	0xb6
#define WRITE_LONG_2          	0xea

/*
 *  Status codes
 */
#define GOOD                 	0x00
#define CHECK_CONDITION      	0x01
#define CONDITION_GOOD       	0x02
#define BUSY                 	0x04
#define INTERMEDIATE_GOOD    	0x08
#define INTERMEDIATE_C_GOOD  	0x0a
#define RESERVATION_CONFLICT 	0x0c
#define COMMAND_TERMINATED   	0x11
#define QUEUE_FULL           	0x14
#define STATUS_MASK          	0x3e


/*
 *  SENSE KEYS
 */
#define NO_SENSE            	0x00
#define RECOVERED_ERROR     	0x01
#define NOT_READY           	0x02
#define MEDIUM_ERROR        	0x03
#define HARDWARE_ERROR      	0x04
#define ILLEGAL_REQUEST     	0x05
#define UNIT_ATTENTION      	0x06
#define DATA_PROTECT        	0x07
#define BLANK_CHECK         	0x08
#define COPY_ABORTED        	0x0a
#define ABORTED_COMMAND     	0x0b
#define VOLUME_OVERFLOW     	0x0d
#define MISCOMPARE          	0x0e


/*
 *  DEVICE TYPES
 */
#define TYPE_DISK           	0x00
#define TYPE_TAPE           	0x01
#define TYPE_PROCESSOR      	0x03    /* HP scanners use this */
#define TYPE_WORM           	0x04    /* Treated as ROM by our system */
#define TYPE_CDROM            	0x05
#define TYPE_SCANNER        	0x06
#define TYPE_MOD            	0x07    /* Magneto-optical disk - 
									     * - treated as TYPE_DISK */
#define TYPE_MEDIUM_CHANGER 	0x08
#define TYPE_COMM           	0x09    /* Communications device */
#define TYPE_ENCLOSURE      	0x0d    /* Enclosure Services Device */
#define TYPE_NO_LUN         	0x7f

/*
 *  MESSAGE CODES
 */
#define COMMAND_COMPLETE    	0x00
#define EXTENDED_MESSAGE    	0x01
#define 	EXTENDED_MODIFY_DATA_POINTER    0x00
#define     EXTENDED_SDTR                   0x01
#define     EXTENDED_EXTENDED_IDENTIFY      0x02    /* SCSI-I only */
#define     EXTENDED_WDTR                   0x03
#define SAVE_POINTERS       	0x02
#define RESTORE_POINTERS    	0x03
#define DISCONNECT          	0x04
#define INITIATOR_ERROR     	0x05
#define ABORT               	0x06
#define MESSAGE_REJECT      	0x07
#define NOP                 	0x08
#define MSG_PARITY_ERROR    	0x09
#define LINKED_CMD_COMPLETE 	0x0a
#define LINKED_FLG_CMD_COMPLETE 0x0b
#define BUS_DEVICE_RESET    	0x0c

#define INITIATE_RECOVERY   	0x0f    /* SCSI-II only */
#define RELEASE_RECOVERY    	0x10    /* SCSI-II only */

#define SIMPLE_QUEUE_TAG    	0x20
#define HEAD_OF_QUEUE_TAG   	0x21
#define ORDERED_QUEUE_TAG   	0x22

/*
 * Here are some scsi specific ioctl commands which are sometimes useful.
 */
/* These are a few other constants  only used by scsi  devices */
#define SCSI_IOCTL_GET_IDLUN    0x5382

/* Used to turn on and off tagged queuing for scsi devices */

#define SCSI_IOCTL_TAGGED_ENABLE	0x5383
#define SCSI_IOCTL_TAGGED_DISABLE	0x5384

/* Used to obtain the host number of a device. */
#define SCSI_IOCTL_PROBE_HOST 		0x5385

/* Used to get the bus number for a device */
#define SCSI_IOCTL_GET_BUS_NUMBER 	0x5386


/* copied from scatterlist.h, and remove scatterlist.h */
typedef struct scatterlist 
{
    CHAR    *address;                  /* Location data is to be transferred to */
    CHAR    *alt_address;              /* Location of actual if address is a 
                                        * dma indirect buffer.  NULL otherwise */
    UINT32  length;
} SCATTER_LIST_T;

#define ISA_DMA_THRESHOLD (0x00ffffff)


/*
 * These are the values that the SCpnt->sc_data_direction and 
 * SRpnt->sr_data_direction can take.  These need to be set
 * The SCSI_DATA_UNKNOWN value is essentially the default.
 * In the event that the command creator didn't bother to
 * set a value, you will see SCSI_DATA_UNKNOWN.
 */
#define SCSI_DATA_UNKNOWN       0
#define SCSI_DATA_WRITE         1
#define SCSI_DATA_READ          2
#define SCSI_DATA_NONE          3

/*
 * Some defs, in case these are not defined elsewhere.
 */
#ifndef TRUE
  #define TRUE 1
#endif
#ifndef FALSE
  #define FALSE 0
#endif


#ifdef DEBUG
  #define SCSI_TIMEOUT (5*HZ)
#else
  #define SCSI_TIMEOUT (2*HZ)
#endif



/*
 *  Use these to separate status msg and our bytes
 *
 *  These are set by:
 *
 *      status byte = set from target device
 *      msg_byte    = return status from host adapter itself.
 *      host_byte   = set by low-level driver to indicate status.
 *      driver_byte = set by mid-level.
 */
#define status_byte(result) (((result) >> 1) & 0x1f)
#define msg_byte(result)    (((result) >> 8) & 0xff)
#define host_byte(result)   (((result) >> 16) & 0xff)
#define driver_byte(result) (((result) >> 24) & 0xff)
#define suggestion(result)  (driver_byte(result) & SUGGEST_MASK)

#define sense_class(sense)  (((sense) >> 4) & 0x7)
#define sense_error(sense)  ((sense) & 0xf)
#define sense_valid(sense)  ((sense) & 0x80);

#define NEEDS_RETRY     	0x2001
#define SUCCESS         	0x2002
#define FAILED          	0x2003
#define QUEUED          	0x2004
#define SOFT_ERROR      	0x2005
#define ADD_TO_MLQUEUE  	0x2006

/*
 * These are the values that scsi_cmd->state can take.
 */
#define SCSI_STATE_TIMEOUT         0x1000
#define SCSI_STATE_FINISHED        0x1001
#define SCSI_STATE_FAILED          0x1002
#define SCSI_STATE_QUEUED          0x1003
#define SCSI_STATE_UNUSED          0x1006
#define SCSI_STATE_DISCONNECTING   0x1008
#define SCSI_STATE_INITIALIZING    0x1009
#define SCSI_STATE_BHQUEUE         0x100a
#define SCSI_STATE_MLQUEUE         0x100b

/*
 * These are the values that the owner field can take.
 * They are used as an indication of who the command belongs to.
 */
#define SCSI_OWNER_HIGHLEVEL       0x100
#define SCSI_OWNER_MIDLEVEL        0x101
#define SCSI_OWNER_LOWLEVEL        0x102
#define SCSI_OWNER_ERROR_HANDLER   0x103
#define SCSI_OWNER_BH_HANDLER      0x104
#define SCSI_OWNER_NOBODY          0x105

#define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7]

#define IDENTIFY_BASE       0x80
#define IDENTIFY(can_disconnect, lun)   (IDENTIFY_BASE |\
                     ((can_disconnect) ?  0x40 : 0) |\
                     ((lun) & 0x07))


/*
 *  the return of the status word will be in the following format :
 *  The low byte is the status returned by the SCSI command, 
 *  with vendor specific bits masked.
 *  
 *  The next byte is the message which followed the SCSI status.
 *  This allows a stos to be used, since the Intel is a little
 *  endian machine.
 *  
 *  The final byte is a host return code, which is one of the following.
 *  
 *  IE 
 *  lsb     msb
 *  status  msg host code   
 *  
 *  Our errors returned by OUR driver, NOT SCSI message.  Or'd with
 *  SCSI message passed back to driver <IF any>.
 */
#define DID_OK          	0x00    /* NO error                                */
#define DID_NO_CONNECT  	0x01    /* Couldn't connect before timeout period  */
#define DID_BUS_BUSY    	0x02    /* BUS stayed busy through time out period */
#define DID_TIME_OUT    	0x03    /* TIMED OUT for other reason              */
#define DID_BAD_TARGET  	0x04    /* BAD target.                             */
#define DID_ABORT       	0x05    /* Told to abort for some other reason     */
#define DID_PARITY      	0x06    /* Parity error                            */
#define DID_ERROR       	0x07    /* Internal error                          */
#define DID_RESET       	0x08    /* Reset by somebody.                      */
#define DID_BAD_INTR    	0x09    /* Got an interrupt we weren't expecting.  */
#define DID_PASSTHROUGH 	0x0a    /* Force command past mid-layer            */
#define DID_SOFT_ERROR  	0x0b    /* The low level driver just wish a retry  */
#define DRIVER_OK       	0x00    /* Driver status                           */

/*
 *  These indicate the error that occurred, and what is available.
 */
#define DRIVER_BUSY         0x01
#define DRIVER_SOFT         0x02
#define DRIVER_MEDIA        0x03
#define DRIVER_ERROR        0x04

#define DRIVER_INVALID      0x05
#define DRIVER_TIMEOUT      0x06
#define DRIVER_HARD         0x07
#define DRIVER_SENSE        0x08

#define SUGGEST_RETRY       0x10
#define SUGGEST_ABORT       0x20
#define SUGGEST_REMAP       0x30
#define SUGGEST_DIE         0x40
#define SUGGEST_SENSE       0x80
#define SUGGEST_IS_OK       0xff

#define DRIVER_MASK         0x0f
#define SUGGEST_MASK        0xf0

#define MAX_COMMAND_SIZE    	12
#define SCSI_SENSE_BUFFERSIZE   64

/*
 *  SCSI command sets
 */

#define SCSI_UNKNOWN    0
#define SCSI_1          1
#define SCSI_1_CCS      2
#define SCSI_2          3
#define SCSI_3          4

/*
 *  Every SCSI command starts with a one byte OP-code.
 *  The next byte's high three bits are the LUN of the
 *  device.  Any multi-byte quantities are stored high byte
 *  first, and may have a 5 bit MSB in the same byte
 *  as the LUN.
 */

/*
 *  As the scsi do command functions are intelligent, and may need to
 *  redo a command, we need to keep track of the last command
 *  executed on each one.
 */
#define WAS_RESET         0x01
#define WAS_TIMEDOUT      0x02
#define WAS_SENSE         0x04
#define IS_RESETTING      0x08
#define IS_ABORTING       0x10
#define ASKED_FOR_SENSE   0x20
#define SYNC_RESET        0x40

/*
 * Add some typedefs so that we can prototyope a bunch of the functions.
 */
struct scsi_cmnd;
struct scsi_request;
struct umas_data;

#define SCSI_CMND_MAGIC    0xE25C23A5
#define SCSI_REQ_MAGIC     0x75F6D354


#define RQ_INACTIVE             (-1)
#define RQ_ACTIVE               1
#define RQ_SCSI_BUSY            0xffff
#define RQ_SCSI_DONE            0xfffe
#define RQ_SCSI_DISCONNECTING   0xffe0

/*
 * Ok, this is an expanded form so that we can use the same
 * request for paging requests when that is implemented. In
 * paging, 'bh' is NULL, and the semaphore is used to wait
 * for read/write completion.
 */
struct request 
{
    INT     cmd;                /* READ or WRITE */
    INT     errors;
    UINT32  start_time;
    UINT32  sector;
    UINT32  nr_sectors;
    UINT32  hard_sector, hard_nr_sectors;
    UINT32  nr_segments;
    UINT32  nr_hw_segments;
    UINT32  current_nr_sectors;
    VOID    *special;
    CHAR    *buffer;
    struct buffer_head  *bh;
    struct buffer_head  *bhtail;
};



/*
 * The SCSI_CMD_T structure is used by scsi.c internally, and for communication
 * with low level drivers that support multiple outstanding commands.
 */
typedef struct scsi_pointer 
{
    CHAR *ptr;              /* data pointer */
    INT this_residual;      /* left in this buffer */
    struct scatterlist *buffer;     /* which buffer */
    INT buffers_residual;   /* how many buffers left */

    volatile INT Status;
    volatile INT Message;
    volatile INT have_data_in;
    volatile INT sent_command;
    volatile INT phase;
} Scsi_Pointer;



/*
 * FIXME(eric) - one of the great regrets that I have is that I failed to define
 * these structure elements as something like sc_foo instead of foo.  This would
 * make it so much easier to grep through sources and so forth.  I propose that
 * all new elements that get added to these structures follow this convention.
 * As time goes on and as people have the stomach for it, it should be possible to 
 * go back and retrofit at least some of the elements here with with the prefix.
 */
typedef struct scsi_cmnd 
{
    struct umas_data  *umas;	

    /*
     * A SCSI Command is assigned a nonzero serial_number when internal_cmnd
     * passes it to the driver's queue command function.  The serial_number
     * is cleared when scsi_done is entered indicating that the command has
     * been completed.  If a timeout occurs, the serial number at the moment
     * of timeout is copied into serial_number_at_timeout.  By subsequently
     * comparing the serial_number and serial_number_at_timeout fields
     * during abort or reset processing, we can detect whether the command
     * has already completed.  This also detects cases where the command has
     * completed and the SCSI Command structure has already being reused
     * for another command, so that we can avoid incorrectly aborting or
     * resetting the new command.
     */
    UINT32  serial_number;

    UINT32  target;
    UINT32  lun;
    UINT32  channel;
    UINT8   cmd_len;
    UINT8   old_cmd_len;
    UINT8   sc_data_direction;
    UINT8   sc_old_data_direction;

    /* These elements define the operation we are about to perform */
    UINT8   cmnd[MAX_COMMAND_SIZE];
    UINT32  request_bufflen;       /* Actual request size */

    UINT8   *request_buff;       /* Actual requested buffer */

    /* These elements define the operation we ultimately want to perform */
    UINT8   data_cmnd[MAX_COMMAND_SIZE];
    UINT16  old_use_sg;            /* We save  use_sg here when requesting sense info */
    UINT16  use_sg;                /* Number of pieces of scatter-gather */
    UINT16  sglist_len;            /* size of malloc'd scatter-gather list */
    UINT32  bufflen;               /* Size of data buffer */
    VOID    *buffer;               /* Data buffer */

    UINT32  transfersize;          /* How much we are guaranteed to transfer
                                    * with each SCSI transfer (ie, between 
                                    * disconnect reconnects. 
                                    * Probably == sector size */

    struct request request;        /* A copy of the command we are working on */

    UINT8   sense_buffer[SCSI_SENSE_BUFFERSIZE];              
                                   /* obtained by REQUEST SENSE when CHECK 
                                    * CONDITION is received on original 
                                    * command (auto-sense) */
    INT     result;                /* Status code from lower level driver */
} SCSI_CMD_T;

/*
 *  Flag bit for the internal_timeout array
 */
#define NORMAL_TIMEOUT 0

/*
 * Definitions and prototypes used for scsi mid-level queue.
 */
#define SCSI_MLQUEUE_HOST_BUSY       0x1055
#define SCSI_MLQUEUE_DEVICE_BUSY     0x1056

/* old style reset request from external source (private to sg.c and
 * scsi_error.c, supplied by scsi_obsolete.c)
 * */
#define SCSI_TRY_RESET_DEVICE   1
#define SCSI_TRY_RESET_BUS      2
#define SCSI_TRY_RESET_HOST     3

#endif  /* _SCSI_H_ */

