/*
    File:       MacSCSICommand.h

    Contains:   SCSI specific definitions.

    Written by: Martin Minow

*/

/*
 * Copyright 1995, 1997 by Apple Computer, Inc.
 *              All Rights Reserved 
 *  
 * Permission to use, copy, modify, and distribute this software and 
 * its documentation for any purpose and without fee is hereby granted, 
 * provided that the above copyright notice appears in all copies and 
 * that both the copyright notice and this permission notice appear in 
 * supporting documentation. 
 *  
 * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 * FOR A PARTICULAR PURPOSE. 
 *  
 * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
 */

/*
 * Scsi-specific definitions.
 */
#ifndef __MacSCSICommand__
#define __MacSCSICommand__

/*
 * The 6-byte commands are used for most simple
 * I/O requests.
 */
struct SCSI_6_Byte_Command {                /* Six-byte command         */
    unsigned char       opcode;             /*  0                       */
    unsigned char       lbn3;               /*  1 lbn in low 5          */
    unsigned char       lbn2;               /*  2                       */
    unsigned char       lbn1;               /*  3                       */
    unsigned char       len;                /*  4                       */
    unsigned char       ctrl;               /*  5                       */
};
typedef struct SCSI_6_Byte_Command SCSI_6_Byte_Command;

struct SCSI_10_Byte_Command {               /* Ten-byte command         */
    unsigned char       opcode;             /*  0                       */
    unsigned char       lun;                /*  1                       */
    unsigned char       lbn4;               /*  2                       */
    unsigned char       lbn3;               /*  3                       */
    unsigned char       lbn2;               /*  4                       */
    unsigned char       lbn1;               /*  5                       */
    unsigned char       pad;                /*  6                       */
    unsigned char       len2;               /*  7                       */
    unsigned char       len1;               /*  8                       */
    unsigned char       ctrl;               /*  9                       */
};
typedef struct SCSI_10_Byte_Command SCSI_10_Byte_Command;

struct SCSI_12_Byte_Command {               /* Twelve-byte command      */
    unsigned char       opcode;             /*  0                       */
    unsigned char       lun;                /*  1                       */
    unsigned char       lbn4;               /*  2                       */
    unsigned char       lbn3;               /*  3                       */
    unsigned char       lbn2;               /*  4                       */
    unsigned char       lbn1;               /*  5                       */
    unsigned char       len4;               /*  6                       */
    unsigned char       len3;               /*  7                       */
    unsigned char       len2;               /*  8                       */
    unsigned char       len1;               /*  9                       */
    unsigned char       pad;                /* 10                       */
    unsigned char       ctrl;               /* 11                       */
};
typedef struct SCSI_12_Byte_Command SCSI_12_Byte_Command;

/*
 * This union defines all scsi commands.
 */
union SCSI_Command {
    SCSI_6_Byte_Command     scsi6;
    SCSI_10_Byte_Command    scsi10;
    SCSI_12_Byte_Command    scsi12;
    unsigned char           scsi[12];
};
typedef union SCSI_Command SCSI_Command, *SCSI_CommandPtr;

/*
 * Returned by a read-capacity command.
 */
struct SCSI_Capacity_Data {
    unsigned char       lbn4;               /* Number                   */
    unsigned char       lbn3;               /*  of                      */
    unsigned char       lbn2;               /*   logical                */
    unsigned char       lbn1;               /*    blocks                */
    unsigned char       len4;               /* Length                   */
    unsigned char       len3;               /*  of each                 */
    unsigned char       len2;               /*   logical block          */
    unsigned char       len1;               /*    in bytes              */
};
typedef struct SCSI_Capacity_Data SCSI_Capacity_Data;

struct SCSI_Inquiry_Data {                  /* Inquiry returns this     */
    unsigned char       devType;            /*  0 Device type,          */
    unsigned char       devTypeMod;         /*  1 Device type modifier  */
    unsigned char       version;            /*  2 ISO/ECMA/ANSI version */
    unsigned char       format;             /*  3 Response data format  */
    unsigned char       length;             /*  4 Additional Length     */
    unsigned char       reserved5;          /*  5 Reserved              */
    unsigned char       reserved6;          /*  6 Reserved              */
    unsigned char       flags;              /*  7 Capability flags      */
    unsigned char       vendor[8];          /*  8-15 Vendor-specific    */
    unsigned char       product[16];        /* 16-31 Product id         */
    unsigned char       revision[4];        /* 32-35 Product revision   */
    unsigned char       vendorSpecific[20]; /* 36-55 Vendor stuff       */
    unsigned char       moreReserved[40];   /* 56-95 Reserved           */
};
typedef struct SCSI_Inquiry_Data SCSI_Inquiry_Data;

/*
 * This bit may be set in SCSI_Inquiry_Data.devTypeMod
 */
enum {
    kScsiInquiryRMB = 0x80                  /* Removable medium if set  */
};
/*
 * These bits may be set in SCSI_Inquiry_Data.flags
 */
enum {
    kScsiInquiryRelAdr  = 0x80,             /* Has relative addressing  */
    kScsiInquiryWBus32  = 0x40,             /* Wide (32-bit) transfers  */
    kScsiInquiryWBus16  = 0x20,             /* Wide (16-bit) transfers  */
    kScsiInquirySync    = 0x10,             /* Synchronous transfers    */
    kScsiInquiryLinked  = 0x08,             /* Linked commands ok       */
    kScsiInquiryReserved = 0x04,
    kScsiInquiryCmdQue  = 0x02,             /* Tagged cmd queuing ok    */
    kScsiInquirySftRe   = 0x01              /* Soft reset alternative   */
};

/*
 * These bits may be set in SCSI_Inquiry_Data.devType
 */
enum {
    kScsiDevTypeDirect                  = 0,
    kScsiDevTypeSequential,
    kScsiDevTypePrinter,
    kScsiDevTypeProcessor,
    kScsiDevTypeWorm,                       /* Write-once, read mult    */
    kScsiDevTypeCDROM,
    kScsiDevTypeScanner,
    kScsiDevTypeOptical,
    kScsiDevTypeChanger,
    kScsiDevTypeComm,
    kScsiDevTypeGraphicArts0A,
    kScsiDevTypeGraphicArts0B,
    kScsiDevTypeFirstReserved,              /* Reserved sequence start  */
    kScsiDevTypeUnknownOrMissing        = 0x1F,
    kScsiDevTypeMask                    = 0x1F
};
/*
 * These are device type qualifiers. We need them to distinguish between "unknown"
 * and "missing" devices.
 */
enum {
    kScsiDevTypeQualifierConnected      = 0x00, /* Exists and is connected      */
    kScsiDevTypeQualifierNotConnected   = 0x20, /* Logical unit exists          */
    kScsiDevTypeQualifierReserved       = 0x40,
    kScsiDevTypeQualifierMissing        = 0x60, /* No such logical unit         */
    kScsiDevTypeQualifierVendorSpecific = 0x80, /* Other bits are unspecified   */
    kScsiDevTypeQualifierMask           = 0xE0
};
#define kScsiDevTypeMissing \
    (kScsiDevTypeUnknownOrMissing | kScsiDevTypeQualifierMissing)

/*
 * This is the data that is returned after a GetExtendedStatus
 * request. The errorCode gives a general indication of the error,
 * which may be qualified by the additionalSenseCode and
 * additionalSenseQualifier fields. These may be device (vendor)
 * specific values, however. The info[] field contains additional
 * information. For a media error, it contains the failing
 * logical block number (most-significant byte first).
 */
struct SCSI_Sense_Data {                /* Request Sense result         */
    unsigned char       errorCode;      /*  0   Class code, valid lbn   */
    unsigned char       segmentNumber;  /*  1   Segment number          */
    unsigned char       senseKey;       /*  2   Sense key and flags     */
    unsigned char       info[4];
    unsigned char       additionalSenseLength;
    unsigned char       reservedForCopy[4];
    unsigned char       additionalSenseCode;
    unsigned char       additionalSenseQualifier;   
    unsigned char       fruCode;        /* Field replacable unit code   */
    unsigned char       senseKeySpecific[2];
    unsigned char       additional[101];
};
typedef struct SCSI_Sense_Data SCSI_Sense_Data;
/*
 * The high-bit of errorCode signals whether there is a logical
 * block. The low value signals whether there is a valid sense
 */
#define kScsiSenseHasLBN            0x80    /* Logical block number set */
#define kScsiSenseInfoValid         0x70    /* Is sense key valid?      */
#define kScsiSenseInfoMask          0x70    /* Mask for sense info      */
/*
 * These bits may be set in the sense key
 */
#define kScsiSenseKeyMask           0x0F
#define kScsiSenseILI               0x20    /* Illegal logical Length   */
#define kScsiSenseEOM               0x40    /* End of media             */
#define kScsiSenseFileMark          0x80    /* End of file mark         */

/*
 * SCSI sense codes. (Returned after request sense).
 */
#define  kScsiSenseNone             0x00    /* No error                 */
#define  kScsiSenseRecoveredErr     0x01    /* Warning                  */
#define  kScsiSenseNotReady         0x02    /* Device not ready         */
#define  kScsiSenseMediumErr        0x03    /* Device medium error      */
#define  kScsiSenseHardwareErr      0x04    /* Device hardware error    */
#define  kScsiSenseIllegalReq       0x05    /* Illegal request for dev. */
#define  kScsiSenseUnitAtn          0x06    /* Unit attention (not err) */
#define  kScsiSenseDataProtect      0x07    /* Data protection          */
#define  kScsiSenseBlankCheck       0x08    /* Tape-specific error      */
#define  kScsiSenseVendorSpecific   0x09    /* Vendor-specific error    */
#define  kScsiSenseCopyAborted      0x0a    /* Copy request cancelled   */
#define  kScsiSenseAbortedCmd       0x0b    /* Initiator aborted cmd.   */
#define  kScsiSenseEqual            0x0c    /* Comparison equal         */
#define  kScsiSenseVolumeOverflow   0x0d    /* Write past end mark      */
#define  kScsiSenseMiscompare       0x0e    /* Comparison failed        */
#define  kScsiSenseCurrentErr       0x70
#define  kScsiSenseDeferredErr      0x71

/*
 * Mode sense parameter header
 */
struct SCSI_ModeParamHeader {
    unsigned char       modeDataLength;
    unsigned char       mediumType;
    unsigned char       deviceSpecific;
    unsigned char       blockDescriptorLength;
};
typedef struct SCSI_ModeParamHeader SCSI_ModeParamHeader;

struct SCSI_ModeParamBlockDescriptor {
    unsigned char       densityCode;
    unsigned char       numberOfBlocks[3];
    unsigned char       reserved;
    unsigned char       blockLength[3];
};
typedef struct SCSI_ModeParamBlockDescriptor SCSI_ModeParamBlockDescriptor;

union SCSI_ModeParamPage {
    unsigned char       data[1];
    struct {
	unsigned char   code;
	unsigned char   length;
    } page;
};
typedef union SCSI_ModeParamPage SCSI_ModeParamPage;

/*
 * LogSense parameter header
 */
struct SCSI_LogSenseParamHeader {
    unsigned char       pageCode;
    unsigned char       reserved;
    unsigned char       pageLength[2];
};
typedef struct SCSI_LogSenseParamHeader SCSI_LogSenseParamHeader;

/*
 * Log parameter pages are variable-length with a fixed length header.
 */
union SCSI_LogSenseParamPage {
    unsigned char       data[1];
    struct {
	unsigned char   parameterCode[2];
	unsigned char   flags;
	unsigned char   parameterLength;
    } page;
};
typedef union SCSI_LogSenseParamPage SCSI_LogSenseParamPage;

/*
 * SCSI command status (from status phase)
 */
#define  kScsiStatusGood            0x00    /* Normal completion        */
#define  kScsiStatusCheckCondition  0x02    /* Need GetExtendedStatus   */
#define  kScsiStatusConditionMet    0x04
#define  kScsiStatusBusy            0x08    /* Device busy (self-test?) */
#define  kScsiStatusIntermediate    0x10    /* Intermediate status      */
#define  kScsiStatusResConflict     0x18    /* Reservation conflict     */
#define  kScsiStatusQueueFull       0x28    /* Target can't do command  */
#define  kScsiStatusReservedMask    0x3e    /* Vendor specific?         */

/*
 * SCSI command codes. Commands defined as ...6, ...10, ...12, are
 * six-byte, ten-byte, and twelve-byte variants of the indicated command.
 */
/*
 * These commands are supported for all devices.
 */
#define kScsiCmdChangeDefinition    0x40
#define kScsiCmdCompare             0x39
#define kScsiCmdCopy                0x18
#define kScsiCmdCopyAndVerify       0x3a
#define kScsiCmdInquiry             0x12
#define kScsiCmdLogSelect           0x4c
#define kScsiCmdLogSense            0x4d
#define kScsiCmdModeSelect10        0x55
#define kScsiCmdModeSelect6         0x15
#define kScsiCmdModeSense10         0x5a
#define kScsiCmdModeSense6          0x1a
#define kScsiCmdReadBuffer          0x3c
#define kScsiCmdRecvDiagResult      0x1c
#define kScsiCmdRequestSense        0x03
#define kScsiCmdSendDiagnostic      0x1d
#define kScsiCmdTestUnitReady       0x00
#define kScsiCmdWriteBuffer         0x3b

/*
 * These commands are supported by direct-access devices only.
 */
#define kScsiCmdFormatUnit          0x04
#define kSCSICmdCopy                0x18
#define kSCSICmdCopyAndVerify       0x3a
#define kScsiCmdLockUnlockCache     0x36
#define kScsiCmdPrefetch            0x34
#define kScsiCmdPreventAllowRemoval 0x1e
#define kScsiCmdRead6               0x08
#define kScsiCmdRead10              0x28
#define kScsiCmdReadCapacity        0x25
#define kScsiCmdReadDefectData      0x37
#define kScsiCmdReadLong            0x3e
#define kScsiCmdReassignBlocks      0x07
#define kScsiCmdRelease             0x17
#define kScsiCmdReserve             0x16
#define kScsiCmdRezeroUnit          0x01
#define kScsiCmdSearchDataEql       0x31
#define kScsiCmdSearchDataHigh      0x30
#define kScsiCmdSearchDataLow       0x32
#define kScsiCmdSeek6               0x0b
#define kScsiCmdSeek10              0x2b
#define kScsiCmdSetLimits           0x33
#define kScsiCmdStartStopUnit       0x1b
#define kScsiCmdSynchronizeCache    0x35
#define kScsiCmdVerify              0x2f
#define kScsiCmdWrite6              0x0a
#define kScsiCmdWrite10             0x2a
#define kScsiCmdWriteAndVerify      0x2e
#define kScsiCmdWriteLong           0x3f
#define kScsiCmdWriteSame           0x41

/*
 * These commands are supported by sequential devices.
 */
#define kScsiCmdRewind              0x01
#define kScsiCmdWriteFilemarks      0x10
#define kScsiCmdSpace               0x11
#define kScsiCmdLoadUnload          0x1B
/*
 * ANSI SCSI-II for CD-ROM devices.
 */
#define kScsiCmdReadCDTableOfContents   0x43

/*
 * Message codes (for Msg In and Msg Out phases).
 */
#define kScsiMsgAbort               0x06
#define kScsiMsgAbortTag            0x0d
#define kScsiMsgBusDeviceReset      0x0c
#define kScsiMsgClearQueue          0x0e
#define kScsiMsgCmdComplete         0x00
#define kScsiMsgDisconnect          0x04
#define kScsiMsgIdentify            0x80
#define kScsiMsgIgnoreWideResdue    0x23
#define kScsiMsgInitiateRecovery    0x0f
#define kScsiMsgInitiatorDetectedErr 0x05
#define kScsiMsgLinkedCmdComplete   0x0a
#define kScsiMsgLinkedCmdCompleteFlag 0x0b
#define kScsiMsgParityErr           0x09
#define kScsiMsgRejectMsg           0x07
#define kScsiMsgModifyDataPtr       0x00 /* Extended msg        */
#define kScsiMsgNop                 0x08
#define kScsiMsgHeadOfQueueTag      0x21 /* Two byte msg        */
#define kScsiMsgOrderedQueueTag     0x22 /* Two byte msg        */
#define kScsiMsgSimpleQueueTag      0x20 /* Two byte msg        */
#define kScsiMsgReleaseRecovery     0x10
#define kScsiMsgRestorePointers     0x03
#define kScsiMsgSaveDataPointers    0x02
#define kScsiMsgSyncXferReq         0x01 /* Extended msg        */
#define kScsiMsgWideDataXferReq     0x03 /* Extended msg        */
#define kScsiMsgTerminateIOP        0x11
#define kScsiMsgExtended            0x01
#define kScsiMsgEnableDisconnectMask 0x40

#define kScsiMsgTwoByte             0x20
#define kScsiMsgTwoByteMin          0x20
#define kScsiMsgTwoByteMax          0x2f

/*
 * Default timeout times for SCSI commands (times are in Msec).
 */
#define kScsiNormalCompletionTime   (500L)          /* 1/2 second               */
/*
 * Dratted DAT tape.
 */
#define kScsiDATCompletionTime      (60L * 1000L);  /* One minute               */
/*
 * Yes, we do allow 90 seconds for spin-up of those dratted tape drives.
 */
#define kScsiSpinUpCompletionTime   (90L * 1000L)


#endif /* __MacSCSICommand__ */