  Programming Notes for IDEDASD Package

  April 26, 2005

  OS/2 Device Driver Development
  IBM Solution Technologies
  Austin, TX

  Contents
  ________

  1    Introduction
  2    CD-ROM Device Manager (OS2CDROM.DMD)
  3    S.M.A.R.T. Commands (IBM1S506.ADD)
   3.1 SMART IOCTLs descriptions
   3.2 Sample SMART IOCTL call
  4    Copyright and Trademark Information

  1  Introduction
  _______________

  This file contains programming information related to the drivers included  in
  the IDEDASD  package. This  information can be  used in addition  to reference 
  found in the Device Driver Kit (DDK) for OS/2 and the  OS/2 Developers Toolkit
  (SDK).

  2  CD-ROM Device Manager (OS2CDROM.DMD)
  _______________________________________

  The  CD-ROM  Device  Manager  (OS2CDROM.DMD) has  the  following features:

  o   supports read/write blocks for CD-RW media,

  o   supports USB CD-ROM, CD-RW, DVD-ROM, DVD-RAM devices,

  o   low level formatting for CD-RW and DVD-RAM media,

  o   new IOCtl functions added:
         Format and Verify Disk		(Cat: 08h, Funct: 45h),
         Execute SCSI-command		(Cat: 80h, Funct: 7Ah),
         Execute SCSI-command-2		(Cat: 82h, Funct: 7Ah),
         Write sectors			(Cat: 80h, Funct: 52h),
         Write and verify sectors	(Cat: 80h, Funct: 53h),
         OS2CDROM Features		(Cat: 82h, Funct: 63h),
         Get CD-ROM Drives		(Cat: 82h, Funct: 60h),
         Blank Disk			(Cat: 08h, Funct: 46h),
         Flush Buffers			(Cat: 80h, Funct: 54h),
         Verify sectors			(Cat: 80h, Funct: 55h),
         Get Media Attributes		(Cat: 80h: Funct: 64h),
         Read data  sectors		(Cat: 80h, Funct: 76h),
         Write data sectors		(Cat: 80h, Funct: 56h),
         Write and Verify data sectors	(Cat: 80h, Funct: 57h),
         Return error history		(Cat: 80h, Funct: EEh),
         Return error history-2		(Cat: 82h, Funct: EEh),
         Get Extended Device Status	(Cat: 82h, Funct: 61h).

  o   some IOCtl functions modified:
         Get Device Parameters		(Cat: 08h, Funct: 63h),
         Read sectors			(Cat: 80h, Funct: 72h)
         Get Device Status		(Cat: 80h, Funct: 60h).

  Format and Verify Disk
  ----------------------

    Category: IOCTL_DISK	 (08h)
    Function: DSK_FORMATVERIFY	 (45h)
    Description: Format and Verify Disk

    Parameter Packet format:

     struct FmtVerify_param {
        UCHAR        Command;  // Bit 7: 0 - start/cancel formatting, 1 - get format status
                               // Bit 0: 0 - start formatting, 1 - cancel formatting
                               // Bit 1: 1 - Mount Rainier
                               // Bit 2: 1 - wait for background formatting complete
                               // Bit 3: 1 - resume background formatting
     };

    Data Packet format:

     struct FmtVerify_data {
        UCHAR        Status;   // Percent of formatted volume, if supported such feature
                               // 0, if not supported
     };

    Returns:

	02h - device not ready
	03h - bad command (this IOCtl function is not supported)
	13h - unsupported parameter
	14h - device already in use
	a3h - uncertain media

    Compatibility issue:

    If IOCtl  function DSK_FORMATVERIFY (45h) is  used with an earlier version of
    OS2CDROM.DMD you will get a return code of 03h. This means that this version of
    OS2CDROM.DMD does not support this function.

  Blank Disk
  ----------

    Category: IOCTL_DISK	(08h)
    Function: DSK_BLANK		(46h)
    Description: Blank the Disk

    Parameter Packet format:

     struct Blank_param {
        UCHAR        Command;  // Bit 7: 0 - start blanking, 1 - get blanking status
                               // Bit 0: 0
                               // Bit 1: 0 - full blanking, 1 - minimal blanking
     };

    Data Packet format:

     struct Blank_data {
        UCHAR    Status;  // Percent of blanked volume if supported such feature
                          // 0, if not supported
     };

    Returns:

	02h - device not ready
	03h - bad command (this IOCtl is not supported)
	13h - unsupported parameter
	14h - device already in use
	a3h - uncertain media

    Compatibility issue:

    If IOCtl function DSK_BLANK (46h) is used with an earlier version of OS2CDROM.DMD you will get
    a return code of 03h. This means that this version of OS2CDROM.DMD does not support this function.

    Note: To cancel blanking use IOCtl function DSK_FORMATVERIFY (45h) of category
    IOCTL_DISK (08h) with parameter Command = 1.

  Flush Buffers
  -------------

    Category: IOCTL_CDROMDISK		(80h)
    Function: CDROMDISK_FLUSHBUFFERS	(54h)
    Description: Flush cache buffers.

     Parameter Packet format:

     struct FlushBuf_param {
       ULONG   ID_code;       // 'CD01'
    };

    Data Packet format:

     None.

    Returns:

	02h - device not ready
	03h - bad command (this IOCtl is not supported)
	13h - unsupported parameter
	14h - device already in use

    Compatibility issue:

    If IOCtl function CDROMDISK_FLUSHBUFFERS (54h) is used with an earlier version of
    OS2CDROM.DMD you will get a return code of 03h. This means that this version
    of OS2CDROM.DMD does not support this function.

  Get Media Attributes
  --------------------

    Category: IOCTL_CDROMDISK		  (80h)
    Function: CDROMDISK_MEDIAATTRIBUTES   (64h)
    Description: Get media attributes.

     Parameter Packet format:

     struct MedAttrib_param {
       ULONG   ID_code;       // 'CD01'
    };

    Data Packet format:

     struct MedAttrib_data {
        ULONG    Status;
     };

  Status returns information about media attribites:
	Bits 0-6: media type (the same value that function DSK_GETDEVICEPARAMS (63h)
                  returns)
	Bit 7:    1 - media is write protected
	Bit 8:    1 - MRW formatted media
	Bit 9:    1 - media is blank (non-formatted), 0 - media is low level formatted
	Bit 10:   1 - background formatting has not completed and now is suspended
	Bit 11:   1 - background formatting is in progress now

  Other bits are reserved and are set to 0.

    Returns:

	02h - device not ready
	03h - bad command (this IOCtl is not supported)
	13h - unsupported parameter
	14h - device already in use

    Compatibility issue:

    If IOCtl function CDROMDISK_MEDIAATTRIBUTES (64h) is used with an earlier version of
    OS2CDROM.DMD you will get a return code of 03h. This means that this version of OS2CDROM.DMD
    does not support this function.


  Execute SCSI command
  --------------------
  
    Category: IOCTL_CDROMDISK	(80h)
    Function: CDROMDISK_EXECMD	(7Ah)
    Description: Executes SCSI command

    Parameter Packet format:

     struct ExecCMD {
        ULONG        ID_code;          // 'CD01'
        USHORT       data_length;      // length of the Data Packet
        USHORT       cmd_length;       // length of the Command Buffer
        USHORT       flags;            // flags
        UCHAR        cmd_buffer[16];   // Command Buffer for SCSI command
        ULONG        cmd_timeout;      // Timeout for executing command (0 - default)
     };

    flags:
	#define EX_DIRECTION_IN	 0x0001
	#define EX_PLAYING_CHK	 0x0002
	#define EX_RETURN_STATUS 0x0004
        #define EX_SET_TIMEOUT   0x0008

	EX_DIRECTION_IN   0 - transfer data to device, 1 - transfer data from device
	EX_PLAYING_CHK    0 - don't check playing audio, 1 - if device plays audio
                          return error
	EX_RETURN_STATUS  0 - return only Data Packet, 1 - if return Data Packet
                          and Error Status
        EX_SET_TIMEOUT    0 - timeout is not set, 1 - timeout is set

    Data Packet format:

    The content of the  Data Packet depends on the SCSI command. Length is
    defined by data_length field in the Parameter Packet.

    Error Status format:

    If EX_RETURN_STATUS is set additional structure RetStatus (length of 3 bytes) containing
    information about error is returned after Data Packet:

    struct RetStatus {
        UCHAR       sense_key;    // Sense Key
        UCHAR       asc_code;     // Additional Sense Code (ASC)
        UCHAR       ascq_code;    // Additional Sense Code Qualifier (ASCQ)
    };

    data_length field in the Parameter Packet defines area size for returned Data Packet and
    additional 3 bytes should be reserved after this area if EX_RETURN_STATUS flag is set.

    Returns:

	02h - device not ready
	03h - bad command (this IOCtl function is not supported)
	13h - unsupported parameter
	14h - device already in use

    Compatibility issue:

    If IOCtl  function CDROMDISK_EXECMD (7Ah) is used with an earlier version of
    OS2CDROM.DMD  you  will get a  return  code of 03h.   This  means  that this version  of
    OS2CDROM.DMD does not support this function.

  Execute SCSI command-2
  ----------------------
  
    Category: IOCTL_CDROMDISK2	(82h)
    Function: CDROMDISK_EXECMD	(7Ah)
    Description: Executes SCSI command

    Parameter Packet format:

     struct ExecCMD2 {
        UCHAR         unit;           // unit number: 0 for A:, 1 for B:, etc.
        USHORT       data_length;     // length of the Data Packet
        USHORT       cmd_length;      // length of the Command Buffer
        USHORT       flags;           // flags
        UCHAR        cmd_buffer[16];  // Command Buffer for SCSI command
        ULONG        cmd_timeout;     // Timeout for executing command (0 - default)
     };

    flags:
	#define EX_DIRECTION_IN	 0x0001
	#define EX_PLAYING_CHK 	 0x0002
	#define EX_RETURN_STATUS 0x0004
        #define EX_SET_TIMEOUT   0x0008

	EX_DIRECTION_IN   0 - transfer data to device,  1 - transfer data from device
	EX_PLAYING_CHK    0 - don't check playing audio, 1 - device plays audio return
                          error
	EX_RETURN_STATUS  0 - return only Data Packet, 1 - return Data Packet 
                          and error status
        EX_SET_TIMEOUT    0 - timeout is not set, 1 - timeout is set

    Data Packet format:

    The content of the  Data Packet depends on the SCSI  command.  Length is
    defined by data_length field in the Parameter Packet.

    Error Status format:

    If EX_RETURN_STATUS is set additional structure RetStatus (length of 3 bytes)
    containing information about error is returned after Data Packet:

    struct RetStatus {
        UCHAR       sense_key;    // Sense Key
        UCHAR       asc_code;     // Additional Sense Code (ASC)
        UCHAR       ascq_code;    // Additional Sense Code Qualifier (ASCQ)
    };

    data_length field in the Parameter Packet defines area size for returned Data Packet and
    additional 3 bytes should be reserved after this area in this case.

    Returns:

	02h - device not ready
	03h - bad command (this IOCtl function is not supported)
	13h - unsupported parameter
	14h - device already in use

    Compatibility issue:

    If IOCtl  function CDROMDISK_EXECMD (7Ah) is used with an earlier version of
    OS2CDROM.DMD you will get a return code of 03h. This means that this version
    of OS2CDROM.DMD does not support this function.

  Return features of the current DM  version
  ------------------------------------------

    Category: IOCTL_CDROMDISK2		(82h)
    Function: CDROMDISK2_FEATURES	(63h)
    Description:  Returns features of the current DM version if applied to
                  "CD-ROM2$" device name.

    Parameter Packet format:

       None.

    Data Packet format:

      ULONG driver_status;

	#define FEATURE_USB_SUPPORT	   0x00000001L
	#define FEATURE_CDRW_SUPPORT	   0x00000002L
	#define FEATURE_EXECMD_SUPPORT	   0x00000004L
	#define FEATURE_DDCDRW_SUPPORT     0x00000008L
	#define FEATURE_DVDRW_SUPPORT      0x00000010L
	#define FEATURE_DVDRWPLUS_SUPPORT  0x00000020L
	#define FEATURE_CACHING		   0x00000040L
	#define FEATURE_RW_DATA		   0x00000080L
        #define FEATURE_EXECMD_RETERR_DUP  0x00000100L

    Returns:

	03h - bad command (this IOCtl function is not supported)

    Compatibility issue:

    If IOCtl function CDROMDISK2_FEATURES (63h) is used with an earlier version of
    OS2CDROM.DMD you will get a return code of 03h. This means that this version of
    OS2CDROM.DMD doesn't support this function.


  Return drive letters for CD-ROM devices
  ---------------------------------------
    
    Category: IOCTL_CDROMDISK2		(82h)
    Function: CDROMDISK2_DRIVELETTERS	(60h)
    Description:  Returns drive letters for CD-ROM devices that are controlled by
                 "CD-ROM2$" device name.

    Parameter Packet format:

       None.

    Data Packet format:

     struct DriveLetters {
        USHORT        DriveCount;         // number of supported CD-ROM drives
        USHORT        DriveFirst;         // letter of the first CD-ROM drive
     };

    Returns:

	03h - bad command (this IOCtl function is not supported)

    Compatibility issue:

    This function didn't work correctly with previous versions of OS2CDROM.DMD.

  Query device parameters
  -----------------------

    Category: IOCTL_DISK		(08h)
    Function: DSK_GETDEVICEPARAMS	(63h)
    Description: Query device parameters

    Parameter and data packet formats are standard but the values of 2 fields of
    BIOSPARAMETERBLOCK depends on device and media type.

    Media Descriptor contains information about media type:

       MEDIA TYPE           VALUE

       CD-R			4
       CD-ROM			5
       DVD-ROM			6
       DVD-RAM			7
       CD-RW			8
       DVD-R			9
       DVD-RW			10
       DVD+RW			11
       DDCD-ROM			12
       DDCD-R			13
       DDCD-RW			14
       DVD+R			15

    If media allows  writing but cannot be written at  the moment (device cannot
    write such media type or disk is write-protected) 128 is added to the value.

    Device Type field  contains information about device type.  If the device cannot
    write on the inserted disk  a value  of 7h is returned. If the device allows writing on
    the inserted disk  (DVD-RAM disk in the DVD-RAM device or  CD-RW disk in the
    CD-Writer) a value of 8h will be  returned.

  Get device status
  -----------------

    Category: IOCTL_CDROMDISK	(80h)
    Function: DSK_DEVICESTATUS	(60h)
    Description: Get device status

    Parameter and data packet formats are standard but the device status uses 2 additional
    bits (18 and 19) to return information about Mount Rainier technology support:
        Bit 18:  1 - device is capable of reading disk with the MRW format
        Bit 19:  1 - device is capable of formatting disks in the MRW format and
                 writing disks that have been MRW formatted

  Get Extended Device Status
  --------------------------

    Category: IOCTL_CDROMDISK2		   (82h)
    Function: CDROMDISK_EXTDEVICESTATUS    (61h)
    Description: Get extended device status.

     Parameter Packet format:

     struct ExtDevSts_param {
        UCHAR         unit;            // unit number: 0 for A:, 1 for B:, etc.
    };

    Data Packet format:

     struct ExtDevSts_data {
        ULONG    Status;
     };

  Status returns current status of device:
	Bit 0:        1 - door opened, 0 - door closed
	Bit 1:        1 - media is present, 0 - media is not present
	Bits 2-3:     0 - device is not ready, 1 - device is becoming ready,
                      2 - device is busy  (some command is executing now),
                      3 - device is ready
	Bits 4-6:     interface with computer: 0 - not known, 1 - SCSI, 2 - ATAPI,
                      3 - Proprietary, 4 - USB

 Other bits are reserved and are set to 0.

    Returns:

	02h - device not ready
	03h - bad command (this IOCtl is not supported)
	13h - unsupported parameter
	14h - device already in use

    Compatibility issue:

    If IOCtl function CDROMDISK_EXTDEVICESTATUS (61h) is used with an earlier version of
    OS2CDROM.DMD you will get a return code of 03h. This means that this version of OS2CDROM.DMD
    does not support this function.

  Read long
  ---------
   
    Category: IOCTL_CDROMDISK		(80h)
    Function: CDROMDISK_READLONG	(72h)
    Description: Reads the specified sectors in the data buffer.

    Parameter Packet format:

     struct ReadLong_param {
       ULONG       ID_code;                // 'CD01'
       UCHAR       address_mode;           // Addressing format of start_sector:
                                           //  00 - Logical Block format
                                           //  01 - Minutes/Seconds/Frame format
       USHORT      transfer_count;         // Numbers of sectors to read.
                                           //  Must  be non zero
       ULONG       start_sector;           // Starting sector number of the read operation
       UCHAR       reserved;               // Reserved. Must be 0
       UCHAR       interleave_size;        // Not used. Must be 0
       UCHAR       interleave_skip_factor; // Not used. Must be 0
     };

    Data Packet format:

     struct ReadLong_data {
        UCHAR       sector_data[SECTOR_SIZE];    // Sector read from the disk
                                                 // SECTOR_SIZE is 2352 for CD
                                                 // disks and 2048 for DVD disks
     };

     The media type is detected by means of IOCtl function DSK_GETDEVICEPARAMS
     (63h) of category IOCTL_DISK (08h) (see above).

     For  DVD   disk  (DVD-ROM,  DVD-R,  DVD+R,  DVD-RAM,   DVD-RW  and  DVD+RW)
     sector_data contains user data (2048 bytes).

     For CD  disk (CD-ROM, CD-R,  CD-RW, DDCD-ROM, DDCD-R,  DDCD-RW) sector_data
     consists of 2352  bytes. Contents of the sector depends on  the mode of the
     sector (byte 15 from the beginning of the sector_data or field data_mode of
     the structure describing sector's contents (see below)).

     Mode 0 is rarely  used format as it is zero filled  in the entire user data
     area.   Structure   of   the   sector   for  Mode   0   is   described   by
     Mode_0_sector_data:

     struct Mode_0_sector_data {
        UCHAR     sync_pattern[12]; // Data block sync pattern
        UCHAR     msf[3];           // Block MSF address
        UCHAR     data_mode;        // Data mode = 0
        UCHAR     user_data[2336];  // User data (each byte is 0)
     };

     Mode  1 data is  most prevalent  in CD-ROM  applications. Structure  of the
     sector for Mode 1 is described by Mode_1_sector_data:

     struct Mode_1_sector_data {
        UCHAR     sync_pattern[12]; // Data block sync pattern
        UCHAR     msf[3];           // Block MSF address
        UCHAR     data_mode;        // Data mode = 1
        UCHAR     user_data[2048];  // User data
        UCHAR     crc[4];           // CRC
        UCHAR     zero_fill[8];     // Zero bytes
        UCHAR     p_parity[172];    // P parity symbols
        UCHAR     q_parity[104];    // Q parity symbols
     };

     The Mode  2 form 1  format is regularly  used in recorder  applications and
     Video  CD.  Structure  of the  sector for  Mode 2  form 1  is  described by
     Mode_21_sector_data:

     struct Mode_21_sector_data {
        UCHAR     sync_pattern[12]; // Data block sync pattern
        UCHAR     msf[3];           // Block MSF address
        UCHAR     data_mode;        // Data mode = 2
        UCHAR     sub_header1[4];   // Sub-header, first copy
        UCHAR     sub_header2[4];   // Sub-header, second copy
        UCHAR     user_data[2048];  // User data
        UCHAR     crc[4];           // CRC
        UCHAR     p_parity[172];    // P parity symbols
        UCHAR     q_parity[104];    // Q parity symbols
     };

     The Mode  2 form 2  format is regularly  used in recorder  applications and
     Video  CD.  Structure  of the  sector for  Mode 2  form 2  is  described by
     Mode_22_sector_data:

     struct Mode_22_sector_data {
        UCHAR     sync_pattern[12]; // Data block sync pattern
        UCHAR     msf[3];           // Block MSF address
        UCHAR     data_mode;        // Data mode = 2
        UCHAR     sub_header1[4];   // Sub-header, first copy
        UCHAR     sub_header2[4];   // Sub-header, second copy
        UCHAR     user_data[2324];  // User data
        UCHAR     crc[4];           // Optional CRC
     };

     The difference between the (2) forms of Mode 2 is defined by the sub-header
     (Bit 5 of the field sub_mode):

     struct Mode_2_sub_header {
        UCHAR     file_number;      // Identifies the file to which the block belongs
        UCHAR     channel_number;   // Playback channel selection
        UCHAR     sub_mode;         // Bit 7: End of file
                                    // Bit 6: Real time block
                                    // Bit 5: 0 - form 1, 1 - form 2
                                    // Bit 4: Trigger block
                                    // Bit 3: Data block
                                    // Bit 2: Audio block
                                    // Bit 1: Video block
                                    // Bit 0: End of record
        UCHAR     code_info;        // Coding information
     };

    Returns:

	02h - device not ready
	03h - bad command (this IOCtl function is not supported)
	08h - sector not found
	10h - uncertain media
	13h - unsupported parameter
	14h - device already in use

  Write long
  ----------
  
    Category: IOCTL_CDROMDISK		(80h)
    Function: CDROMDISK_WRITELONG	(52h)
    Description: Writes the data buffer to the specified sectors.

    Parameter Packet format:

     struct WriteLong_param {
       ULONG       ID_code;                // 'CD01'
       UCHAR       address_mode;           // Addressing format of start_sector:
                                           //  00 - Logical Block format
                                           //  01 - Minutes/Seconds/Frame format
       USHORT      transfer_count;         // Numbers of sectors to read.
                                           //  Must  be non zero
       ULONG       start_sector;           // Starting sector number of the read operation
       UCHAR       reserved;               // Reserved. Must be 0
       UCHAR       interleave_size;        // Not used. Must be 0
       UCHAR       interleave_skip_factor; // Not used. Must be 0
     };

    Data Packet format:

     struct WriteLong_data {
        UCHAR       sector_data[2048]; // Sector to be written to the disk
     };

    Returns:

	02h - device not ready
	03h - bad command (this IOCtl function is not supported)
	08h - sector not found
	10h - uncertain media
	13h - unsupported parameter
	14h - device already in use

  Write and Verify long
  ---------------------
  
    Category: IOCTL_CDROMDISK		(80h)
    Function: CDROMDISK_WRITEVLONG	(53h)
    Description: Writes the data buffer to the specified sectors and verifies.

    Parameter Packet format:

     struct WriteVLong_param {
       ULONG       ID_code;                // 'CD01'
       UCHAR       address_mode;           // Addressing format of start_sector:
                                           //  00 - Logical Block format
                                           //  01 - Minutes/Seconds/Frame format
       USHORT      transfer_count;         // Numbers of sectors to read.
                                           //  Must  be non zero
       ULONG       start_sector;           // Starting sector number of the read operation
       UCHAR       reserved;               // Reserved. Must be 0
       UCHAR       interleave_size;        // Not used. Must be 0
       UCHAR       interleave_skip_factor; // Not used. Must be 0
     };

    Data Packet format:

     struct WriteVLong_data {
        UCHAR       sector_data[2048]; // Sector to be written to the disk
     };

    Returns:

	02h - device not ready
	03h - bad command (this IOCtl function is not supported)
	08h - sector not found
	10h - uncertain media
	13h - unsupported parameter
	14h - device already in use

  Read data
  ---------
   
    Category: IOCTL_CDROMDISK		(80h)
    Function: CDROMDISK_READDATA	(76h)
    Description: Reads the data of specified sectors in the data buffer.

    Parameter Packet format:

     struct ReadData_param {
       ULONG       ID_code;                // 'CD01'
       UCHAR       address_mode;           // Addressing format of start_sector:
                                           //  00 - Logical Block format
                                           //  01 - Minutes/Seconds/Frame format
       USHORT      transfer_count;         // Numbers of sectors to read.
                                           //  Must  be non zero
       ULONG       start_sector;           // Starting sector number of the read operation
       UCHAR       reserved;               // Reserved. Must be 0
       UCHAR       interleave_size;        // Not used. Must be 0
       UCHAR       interleave_skip_factor; // Not used. Must be 0
     };

    Data Packet format:

     struct ReadData_data {
        UCHAR       sector_data[2048]; // Sector read from the disk
     };

    Returns:

	02h - device not ready
	03h - bad command (this IOCtl function is not supported)
	08h - sector not found
	10h - uncertain media
	13h - unsupported parameter
	14h - device already in use

    Compatibility issue:

    If IOCtl function CDROMDISK_READDATA (76h) is used with an earlier version of
    OS2CDROM.DMD you will get a return code of 03h. This means that this version of OS2CDROM.DMD
    does not support this function.

     Note:
     For DVD media CDROMDISK_READDATA (76h) and CDROMDISK_READLONG (72h)
     functions are equivalent. For CD media CDROMDISK_READDATA (76h) returns only data of
     the sector (2048 bytes) but CDROMDISK_READLONG (72h) also returns control structures of
     the sector.

  Write data
  ----------
  
    Category: IOCTL_CDROMDISK		(80h)
    Function: CDROMDISK_WRITEDATA	(56h)
    Description: Writes the data buffer to the specified sectors.

    Parameter Packet format:

     struct WriteData_param {
       ULONG       ID_code;                // 'CD01'
       UCHAR       address_mode;           // Addressing format of start_sector:
                                           //  00 - Logical Block format
                                           //  01 - Minutes/Seconds/Frame format
       USHORT      transfer_count;         // Numbers of sectors to read.
                                           //  Must  be non zero
       ULONG       start_sector;           // Starting sector number of the read operation
       UCHAR       reserved;               // Reserved. Must be 0
       UCHAR       interleave_size;        // Not used. Must be 0
       UCHAR       interleave_skip_factor; // Not used. Must be 0
     };

    Data Packet format:

     struct WriteData_data {
        UCHAR       sector_data[2048]; // Sector to be written to the disk
     };

    Returns:

	02h - device not ready
	03h - bad command (this IOCtl function is not supported)
	08h - sector not found
	10h - uncertain media
	13h - unsupported parameter
	14h - device already in use

    Compatibility issue:

    If IOCtl function CDROMDISK_WRITEDATA (56h) is used with an earlier version of
    OS2CDROM.DMD you will get a return code of 03h. This means that this version of OS2CDROM.DMD
    does not support this function.

    Note:
    Functions CDROMDISK_WRITELONG (52h) and CDROMDISK_WRITEDATA (56h) are
    equivalent for CD and DVD media.

  Write and Verify data
  ---------------------
  
    Category: IOCTL_CDROMDISK	   (80h)
    Function: CDROMDISK_WRITEVDATA (57h)
    Description: Writes the data buffer to the specified sectors and verifies.

    Parameter Packet format:

     struct WriteVData_param {
       ULONG       ID_code;                // 'CD01'
       UCHAR       address_mode;           // Addressing format of start_sector:
                                           //  00 - Logical Block format
                                           //  01 - Minutes/Seconds/Frame format
       USHORT      transfer_count;         // Numbers of sectors to read.
                                           //  Must  be non zero
       ULONG       start_sector;           // Starting sector number of the read operation
       UCHAR       reserved;               // Reserved. Must be 0
       UCHAR       interleave_size;        // Not used. Must be 0
       UCHAR       interleave_skip_factor; // Not used. Must be 0
     };

    Data Packet format:

     struct WriteVData_data {
        UCHAR       sector_data[2048]; // Sector to be written to the disk
     };

    Returns:

	02h - device not ready
	03h - bad command (this IOCtl function is not supported)
	08h - sector not found
	10h - uncertain media
	13h - unsupported parameter
	14h - device already in use

    Compatibility issue:

    If IOCtl function CDROMDISK_WRITEVDATA (57h) is used with an earlier version of
    OS2CDROM.DMD you will get a return code of 03h. This means that this version of OS2CDROM.DMD
    does not support this function.

    Note:
    Functions CDROMDISK_WRITEVLONG (53h) and CDROMDISK_WRITEVDATA (57h) are
    equivalent for CD and DVD media.

  Verify sectors
  --------------
   
    Category: IOCTL_CDROMDISK	(80h)
    Function: CDROMDISK_VERIFY  (55h)
    Description: Verify the specified sectors.

    Parameter Packet format:

     struct Verify_param {
       ULONG       ID_code;                // 'CD01'
       UCHAR       address_mode;           // Addressing format of start_sector:
                                           //  00 - Logical Block format
                                           //  01 - Minutes/Seconds/Frame format
       USHORT      transfer_count;         // Numbers of sectors to read.
                                           //  Must  be non zero
       ULONG       start_sector;           // Starting sector number of the read operation
       UCHAR       reserved;               // Reserved. Must be 0
       UCHAR       interleave_size;        // Not used. Must be 0
       UCHAR       interleave_skip_factor; // Not used. Must be 0
     };

    Data Packet format:

     None.

    Returns:

	02h - device not ready
	03h - bad command (this IOCtl function is not supported)
	08h - sector not found
	10h - uncertain media
	13h - unsupported parameter
	14h - device already in use

    Compatibility issue:

    If IOCtl function CDROMDISK_VERIFY (55h) is used with an earlier version of
    OS2CDROM.DMD you will get a return code of 03h. This means that this version of OS2CDROM.DMD
    does not support this function.

  Note:
  CDROMDISK_VERIFY (55h) reads the specified sectors like CDROMDISK_READDATA (76h)
  but doesn't returns its data. If read without error, verifying is considered to be successful.

  Return error history
  --------------------

    Category: IOCTL_CDROMDISK		  (80h)
    Function: CDROMDISK_RETURNERRORS      (EEh)
    Description: Returns information about last 24 errors that have been
                 returned to the driver from the device.

     Parameter Packet format:

     struct RetErr_param {
       ULONG   ID_code;       // 'CD01'
    };

    Data Packet format:

     struct RetErr_Data {
        UCHAR       num_errors;		// Number of elements used in the error_info array
        struct Error_Info error_info[24];
     };
     struct Error_Info
     {
       UCHAR	strategy_command;	// Strategy command (see "OS/2 Physical Device
                                        // Driver Reference" document)
       UCHAR    category;		// Category of IOCTL command (for Strategy Command 10h
                                        // only)
       UCHAR    function;		// Function of IOCTL command (for Strategy Command 10h
                                        // only)
       UCHAR    SCSI_command;    	// SCSI command operation code
       UCHAR    sense_key;		// Sense Key of the error
       UCHAR    asc_code;		// ASC code of the error
       UCHAR    ascq_code;		// ASCQ code of the error
       UCHAR    exe_time;               // Execution time of the SCSI command (in sec)
       UCHAR    reserved[2];		// Reserved field
       USHORT   error_code;		// Status of Strategy command (see "OS/2 Physical Device
                                        // Driver Reference" document)
       ULONG    start_time;             // Start time of the command (global time in seconds passed
                                        // since 01-01-1970
     };
  
   Returns:

	02h - device not ready
	03h - bad command (this IOCtl is not supported)
	13h - unsupported parameter
	14h - device already in use

    Compatibility issue:

    If IOCtl function CDROMDISK_RETURNERRORS (EEh) is used with an earlier version of
    OS2CDROM.DMD you will get a return code of 03h. This means that this version of 
    OS2CDROM.DMD does not support this function.

  Return error history-2
  ----------------------

    Category: IOCTL_CDROMDISK2		      (82h)
    Function: CDROMDISK_RETURNERRORS          (EEh)
    Description: Returns information about last 24 errors that have been
                 returned to the driver from the device.

     Parameter Packet format:

     struct RetErr2_param {
        UCHAR         unit;           // unit number: 0 for A:, 1 for B:, etc.
    };

    Data Packet format:

     struct RetErr_Data {
        UCHAR       num_errors;		// Number of elements used in the error_info array
        struct Error_Info error_info[24];
     };
     struct Error_Info
     {
       UCHAR	strategy_command;	// Strategy command (see "OS/2 Physical Device
                                        // Driver Reference" document)
       UCHAR    category;		// Category of IOCTL command (for Strategy Command 10h
                                        // only)
       UCHAR    function;		// Function of IOCTL command (for Strategy Command 10h
                                        // only)
       UCHAR    SCSI_command;   	// SCSI command operation code
       UCHAR    sense_key;		// Sense Key of the error
       UCHAR    asc_code;		// ASC code of the error
       UCHAR    ascq_code;		// ASCQ code of the error
       UCHAR    exe_time;               // Execution time of the SCSI command (in sec)
       UCHAR    reserved[2];		// Reserved field
       USHORT   error_code;		// Status of Strategy command (see "OS/2 Physical Device
                                        // Driver Reference" document)
       ULONG    start_time;             // Start time of the command (global time in seconds passed
                                        // since 01-01-1970
     };
  
   Returns:

	02h - device not ready
	03h - bad command (this IOCtl is not supported)
	13h - unsupported parameter
	14h - device already in use

    Compatibility issue:

    If IOCtl function CDROMDISK_RETURNERRORS (EEh) is used with an earlier version of
    OS2CDROM.DMD you will get a return code of 03h. This means that this version of 
    OS2CDROM.DMD does not support this function.

  Example of using IOCtl function of category IOCTL_CDROMDISK2
  ------------------------------------------------------------
  #define INCL_DOS
  #define INCL_ERRORS
  #define INCL_DOSDEVIOCTL
  #include <os2.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <ctype.h>

  void getmsg(int Number,PSZ Drive);

  #define CDROMDISK_RETERR    0xEE
  #define IOCTL_CDROMDISK2     0x82

  #pragma pack(1)
  typedef struct 
  {
    UCHAR  drive;
  }PARM;

  typedef struct
  { 
    UCHAR strategy_command;
    UCHAR category;
    UCHAR function;
    UCHAR SCSI_command;
    UCHAR sense_key;
    UCHAR asc_code;
    UCHAR ascq_code;
    UCHAR exe_time;
    UCHAR reserved[2];
    USHORT error_code;
    ULONG start_time;
  } Error_Info;

  typedef struct
  {
    UCHAR num_errors;
    Error_Info error_info[24];
  } DATAINQ;

  int main(int argc, char *argv[], char *envp[])
  {
    ULONG rc=0;
    USHORT i;
    ULONG parmsize=sizeof(PARM);
    PARM parm;
    char devname[3] = "C:";
    ULONG datasize;
    DATAINQ data_buff;
    HFILE handle=-1;
    ULONG ulAction, time_delta;

    DosError(2);
    /* valdate parms */
    if ((argc>=2) && (strlen(argv[1])==2) &&
          (isalpha(argv[1][0]) && argv[1][1] == ':'))
    {
      /* uppercase the drive letter */

      parm.drive=(argv[1][0]&0xdf) - 0x41;

      rc = DosOpen("CD-ROM2$", &handle, &ulAction, 0,
           FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS,
           OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY, NULL);
 
      if (rc)
      {
        printf("RC On Open, rc=%4x \n",rc);
        return (rc);
      }

      rc = DosDevIOCtl(handle, IOCTL_CDROMDISK2, CDROMDISK_RETERR,
                           (PVOID)&parm, sizeof(parm), (PULONG)&parmsize,
                           (PVOID)&data_buff, sizeof(data_buff), (PULONG)&datasize);
      if (rc == 0)
      {
         for (i=0; i<data_buff.num_errors; i++)
         {
            if (i == 0)
               time_delta = 0;
            else
               time_delta = data_buff.error_info[i].start_time - data_buff.error_info[0].start_time;
            printf("\n%6ld: Cmd:%2x", time_delta, data_buff.error_info[i].strategy_command);
            if (data_buff.error_info[i].strategy_command == 0x10)
            {
               printf("(%02x:%02x)", data_buff.error_info[i].category, data_buff.error_info[i].function);
            }
            else
               printf("       ");
            printf("  SCSI:%02x  Error:%04x   (%1x/%02x/%02x)",data_buff.error_info[i].SCSI_command, data_buff.error_info[i].error_code,   data_buff.error_info[i].sense_key, data_buff.error_info[i].asc_code,   data_buff.error_info[i].ascq_code);
            if (data_buff.error_info[i].exe_time > 1)
               printf("  Time: %ds", data_buff.error_info[i].exe_time);
         }
      }
      else
      {
         printf("\nError: %4x", rc);
      }       

      rc = DosClose(handle);
    } /* endif */
    else
    {
       printf("No drive");
    }

    return rc; 
  }

 3  S.M.A.R.T. Commands (IBM1S506.ADD)
  _____________________________________


  The IDE Adapter Device Driver (IBM1S506.ADD) has the following features:

  o   IOCtl to get ATA/ATAPI device identify data (Cat: 90h, Funct: 42h)

  o   SMART related IOCtl functions:
         Turn SMART on or off          (Cat: 80h, Funct: 20h),
         Turn SMART autosave on or off (Cat: 80h, Funct: 21h),
         Force save of SMART data      (Cat: 80h, Funct: 22h),
         Get SMART status (pass/fail)  (Cat: 80h, Funct: 23h),
         Get SMART atributes table     (Cat: 80h, Funct: 24h),
         Get SMART tresholds table     (Cat: 80h, Funct: 25h),
         Read SMART log                (Cat: 80h, Funct: 26h),
         Write SMART log               (Cat: 80h, Funct: 27h),
         Read log ext.                 (Cat: 80h, Funct: 28h),
         Write log ext.                (Cat: 80h, Funct: 29h),
         Execute off-line immediate    (Cat: 80h, Funct: 30h)
  
  For detailed information about SMART commands see ATA/ATAPI standard 
  (available from "Technical Committee T13" http://www.t13.org)


  3.1  SMART IOCTLs descriptions
  ______________________________
  

  Get identify data
  -----------------
  
    Category: DSKSP_CAT_GENERIC      (90h)
    Function: DSKSP_GET_INQUIRY_DATA (42h)
    Description: Get identify data for ATA and APAPI devices.

    Parameter Packet format:
     struct GetInquiryData_Param {
        UCHAR        byPhysicalUnit;  // 0=Pri/Mas, 1=Pri/Sla, 2=Sec/Mas, etc.
                                      //   Pri - means Primary Device
                                      //   Sec - means Secondary Device
                                      //   Sla - means Slave device
                                      //   Mas - means master device
     };

    Returns:
     00h - IOCtl compleated sucesefuly
     any non-zero value - error executing IOCtl

    Return Data Packet format:
     struct GetInquiryData_Data {
        UCHAR    data[512]; // 512 bytes of IDE ATA/ATAPI device identify data.
                            // see ATA/ATPI standard for detailed information
     };

  Turn SMART on or off
  --------------------
  
    Category: DSKSP_CAT_SMART   (80h)
    Function: DSKSP_SMART_ONOFF (20h)
    Description: Turn SMART on or off

    Parameter Packet format:
     struct SMART_Param {
        UCHAR        byPhysicalUnit;  // 0=Pri/Mas, 1=Pri/Sla, 2=Sec/Mas, etc.
     };

    Data Packet format:
     struct SMART_OnOff_Data {
        UCHAR        ucOnOff;  // 0=off, 1=on
     };

    Returns:
     00h - IOCtl compleated sucesefuly
     any non-zero value - error executing IOCtl

  Turn SMART autosave on or off
  -----------------------------
  
    Category: DSKSP_CAT_SMART            (80h)
    Function: DSKSP_SMART_AUTOSAVE_ONOFF (21h)
    Description: Turn SMART autosave on or off

    Parameter Packet format:
     struct SMART_Param {
        UCHAR        byPhysicalUnit;  // 0=Pri/Mas, 1=Pri/Sla, 2=Sec/Mas, etc.
     };

    Data Packet format:
     struct SMART_OnOff_Data {
        UCHAR        ucOnOff;  // 0=off, 1=on
     };

    Returns:
     00h - IOCtl compleated sucesefuly
     any non-zero value - error executing IOCtl

  Force save of SMART data
  ------------------------
  
    Category: DSKSP_CAT_SMART  (80h)
    Function: DSKSP_SMART_SAVE (22h)
    Description: Force save of SMART data

    Parameter Packet format:
     struct SMART_Param {
        UCHAR        byPhysicalUnit;  // 0=Pri/Mas, 1=Pri/Sla, 2=Sec/Mas, etc.
     };

    Returns:
     00h - IOCtl compleated sucesefuly
     any non-zero value - error executing IOCtl

  Get SMART status
  ----------------
  
    Category: DSKSP_CAT_SMART       (80h)
    Function: DSKSP_SMART_GETSTATUS (23h)
    Description: Get SMART status

    Parameter Packet format:
     struct SMART_Param {
        UCHAR        byPhysicalUnit;  // 0=Pri/Mas, 1=Pri/Sla, 2=Sec/Mas, etc.
     };

    Returns:
     00h - IOCtl compleated sucesefuly
     any non-zero value - error executing IOCtl

    Return Data Packet format:
     struct SMART_STATUS_Data {
        ULONG        ulStatus;  // 0=SMART ok, 1=SMART error, -1=device error
     };

  Get SMART attributes
  --------------------

    Category: DSKSP_CAT_SMART            (80h)
    Function: DSKSP_SMART_GET_ATTRIBUTES (24h)
    Description: Get SMART attributes table

    Parameter Packet format:
     struct SMART_Param {
        UCHAR        byPhysicalUnit;  // 0=Pri/Mas, 1=Pri/Sla, 2=Sec/Mas, etc.
     };

    Returns:
     00h - IOCtl compleated sucesefuly
     any non-zero value - error executing IOCtl

    Return Data Packet format:
     struct SMART_attributes_Data {
        UCHAR      data[512];  // 512 bytes of SMART atributes table 
                               // see ATA/ATPI standard for detailed information
     };

  Get SMART thresholds
  --------------------
  
    Category: DSKSP_CAT_SMART            (80h)
    Function: DSKSP_SMART_GET_THRESHOLDS (25h)
    Description: Get SMART thresholds table

    Parameter Packet format:
     struct SMART_Param {
        UCHAR        byPhysicalUnit;  // 0=Pri/Mas, 1=Pri/Sla, 2=Sec/Mas, etc.
     };

    Returns:
     00h - IOCtl compleated sucesefuly
     any non-zero value - error executing IOCtl

    Return Data Packet format:
     struct SMART_attributes_Data {
        UCHAR      data[512];  // 512 bytes of SMART thresholds table 
                               // see ATA/ATPI standard for detailed information
     };

  Read SMART log
  --------------
  
    Category: DSKSP_CAT_SMART      (80h)
    Function: DSKSP_SMART_READ_LOG (26h)
    Description: Read SMART log

    Parameter Packet format:
     struct SMART_ParamExt {
        UCHAR      byPhysicalUnit;  // 0=Pri/Mas, 1=Pri/Sla, 2=Sec/Mas, etc.
        ULONG      LogAddress;      // valid values 0-255. See ATA/ATPI standard
                                    // for details
        ULONG      SectorCount;     // valid values 0-255  See ATA/ATPI standard
                                    // for details
        ULONG      reserved;        // reserved. must be set to 0
     };

    Returns:
     00h - IOCtl compleated sucesefuly
     any non-zero value - error executing IOCtl

    Return Data Packet format:
     struct SMART_attributes_Data {
        UCHAR      data[512*SectorCount];  // SectorCount sectors (512 bytes
                                           // each) of SMART LOG data
                                           // see ATA/ATPI standard for detailed
                                           // information
     };

  Write SMART log
  ---------------
  
    Category: DSKSP_CAT_SMART       (80h)
    Function: DSKSP_SMART_WRITE_LOG (27h)
    Description: Write SMART log

    Parameter Packet format:
     struct SMART_ParamExt {
        UCHAR      byPhysicalUnit;  // 0=Pri/Mas, 1=Pri/Sla, 2=Sec/Mas, etc.
        ULONG      LogAddress;      // valid values 0-255. See ATA/ATPI standard
                                    // for details
        ULONG      SectorCount;     // valid values 0-255  See ATA/ATPI standard
                                    // for details
        ULONG      reserved;        // reserved. must be set to 0
     };
    
    Data Packet format:
     struct SMART_attributes_Data {
        UCHAR      data[512*SectorCount];  // SectorCount sectors (512 bytes
                                           // each) of SMART LOG data
                                           // see ATA/ATPI standard for details
     };

    Returns:
     00h - IOCtl compleated sucesefuly
     any non-zero value - error executing IOCtl

  Read log extended
  -----------------
  
    Category: DSKSP_CAT_SMART    (80h)
    Function: DSKSP_READ_LOG_EXT (28h)
    Description: Read log extended

    Parameter Packet format:
     struct SMART_ParamExt {
        UCHAR      byPhysicalUnit;  // 0=Pri/Mas, 1=Pri/Sla, 2=Sec/Mas, etc.
        ULONG      LogAddress;      // valid values 0-255. See ATA/ATPI standard
                                    // for details
        ULONG      SectorCount;     // valid values 0-255  See ATA/ATPI standard
                                    // for details
        ULONG      SectorOffset;    // valid values 0-255  See ATA/ATPI standard
                                    // for details
     };

    Returns:
     00h - IOCtl compleated sucesefuly
     any non-zero value - error executing IOCtl

    Return Data Packet format:
     struct SMART_attributes_Data {
        UCHAR      data[512*SectorCount];  // SectorCount sectors (512 bytes
                                           // each) of SMART LOG data
                                           // see ATA/ATPI standard for details
     };

  Write log extended
  ------------------

    Category: DSKSP_CAT_SMART     (80h)
    Function: DSKSP_WRITE_LOG_EXT (29h)
    Description: Write log extended

    Parameter Packet format:
     struct SMART_ParamExt {
        UCHAR      byPhysicalUnit;  // 0=Pri/Mas, 1=Pri/Sla, 2=Sec/Mas, etc.
        ULONG      LogAddress;      // valid values 0-255. See ATA/ATPI standard
                                    // for details
        ULONG      SectorCount;     // valid values 0-255  See ATA/ATPI standard
                                    // for details
        ULONG      SectorOffset;    // valid values 0-255  See ATA/ATPI standard
                                    // for details
     };
    
    Data Packet format:
     struct SMART_attributes_Data {
        UCHAR      data[512*SectorCount];  // SectorCount sectors (512 bytes
                                           // each) of SMART LOG data
                                           // see ATA/ATPI standard for details
     };

    Returns:
     00h - IOCtl compleated sucesefuly
     any non-zero value - error executing IOCtl

  SMART Execute Off-Line Immediate
  --------------------------------

    Category: DSKSP_CAT_SMART  (80h)
    Function: DSKSP_SMART_EOLI (30h)
    Description: SMART Execute Off-Line Immediate

    Parameter Packet format:
     struct SMART_Param {
        UCHAR        byPhysicalUnit;  // 0=Pri/Mas, 1=Pri/Sla, 2=Sec/Mas, etc.
     };
    
    Data Packet format:
     struct SMART_EOLI_Data {
        UCHAR      ucSubCmdParam;  // SMART Execute Off-Line Immediate sucomand
                                   // parametter. See ATA/ATPI standard for
                                   // details 
     };

    Returns:
     00h - IOCtl compleated sucesefuly
     any non-zero value - error executing IOCtl

  
  3.2  Sample SMART IOCTL call
  _______________________________

  #include <os2.h>
  #include <string.h>
  #include <stdlib.h>
  #include <time.h>
  #include <stdio.h>

  #define DSKSP_CAT_SMART             0x80  /* SMART IOCTL category */
  #define DSKSP_SMART_ONOFF           0x20  /* turn SMART on or off */
  #define DSKSP_SMART_AUTOSAVE_ONOFF  0x21  /* turn SMART autosave on or off */
  #define DSKSP_SMART_SAVE            0x22  /* force save of SMART data */
  #define DSKSP_SMART_GETSTATUS       0x23  /* get SMART status (pass/fail) */
  #define DSKSP_SMART_GET_ATTRIBUTES  0x24  /* get SMART attributes table */
  #define DSKSP_SMART_GET_THRESHOLDS  0x25  /* get SMART thresholds table */
  #define DSKSP_SMART_READ_LOG        0x26  
  #define DSKSP_SMART_WRITE_LOG       0x27  
  #define DSKSP_SMART_READ_LOG_EXT    0x28  
  #define DSKSP_SMART_WRITE_LOG_EXT   0x29  
  #define DSKSP_SMART_EOLI            0x30  /* EXECUTE OFF-LINE IMMEDIATE */

  #define SMART_CMD_ON      1   /* on  value for related SMART functions */
  #define SMART_CMD_OFF     0   /* off value for related SMART functions */

  #define DSKSP_CAT_GENERIC           0x90  /* generic IOCTL category */
  #define DSKSP_GET_INQUIRY_DATA      0x42  /* get ATA/ATAPI inquiry data */

  typedef struct _DSKSP_CommandParameters
  {
    BYTE        byPhysicalUnit;             /* physical unit number 0-n */
                             /* 0 = Pri/Mas, 1=Pri/Sla, 2=Sec/Mas, etc. */
  } DSKSP_CommandParameters, NEAR *NPDSKSP_CommandParameters;

  void main (void)
  {
     ULONG   ulDriveAction = 0L;
     ULONG   cbFile = 0L;
     HFILE   h506 = 0L;
     ULONG   rc;
     UCHAR   usDeviceIndex;
     UCHAR   adapter, device;
     UCHAR   ID_Buffer[512];
     UCHAR   Data[512];


     printf( "Searching for IBM1S506.ADD...");
     rc = DosOpen( "DEV\\IBMS506$",
                   &h506, 
                   &ulDriveAction, cbFile, 
                   FILE_NORMAL,
                   OPEN_ACTION_OPEN_IF_EXISTS,
                   OPEN_SHARE_DENYNONE | 
                   OPEN_ACCESS_READONLY | 
                   OPEN_FLAGS_NOINHERIT,
                   0                           );
     if (rc) 
     {
         printf("Failed. DosOpen error: %d 0x%X\n", rc, rc);
     }
     else 
     {
        DSKSP_CommandParameters SmartParams;
        ULONG   cbDataLenMax;
        ULONG   cbParmLen;

        printf("OK\n");
        
        printf("Read device identify data...");
        
        adapter = 0; //Primary channel
        device  = 1; //Master device
        usDeviceIndex=adapter*2+device;
        cbDataLenMax = 512;
        cbParmLen = sizeof(SmartParams);

        SmartParams.byPhysicalUnit = usDeviceIndex;

        rc = DosDevIOCtl(
                         h506,                       //HFILE hDevice, 
                         DSKSP_CAT_GENERIC,          //ULONG category,
                         DSKSP_GET_INQUIRY_DATA,     //ULONG function, 
                         (UCHAR FAR *) &SmartParams, //PVOID pParams, 
                         cbParmLen,                  //ULONG cbParmLenMax, 
                         &cbParmLen,                 //PULONG pcbParmLen, 
                         (UCHAR FAR *) ID_Buffer,    //PVOID pData, 
                         cbDataLenMax,               //ULONG cbDataLenMax, 
                         &cbDataLenMax               //PULONG pcbDataLen
                        );
        if (rc) 
        {
           printf("Failed. IOCTl error: %d 0x%X\n", rc, rc);
        }
        else
        {
           printf("OK\n");
           if ( !( ((USHORT*)ID_Buffer)[82] & 0x0001 ) ) 
           {
              printf("Failed. Device does not support SMART commands\n");
           } 
           else
           {
              if ( !( ((USHORT*)ID_Buffer)[85] & 0x0001 ) ) 
              {
                 printf("Failed. SMART support DISABLED\n");
              }
              else
              {
                 printf("SMART READ ATTRIBUTES...");

                 adapter = 0; //Primary channel
                 device  = 1; //Master device
                 usDeviceIndex = adapter * 2 + device;
                 cbDataLenMax = 512;
                 cbParmLen = sizeof(SmartParams);
                 SmartParams.byPhysicalUnit = usDeviceIndex;
                 
                 rc = DosDevIOCtl(
                              h506,                       //HFILE hDevice,
                              DSKSP_CAT_SMART,            //ULONG category,
                              DSKSP_SMART_GET_ATTRIBUTES, //ULONG function,
                              (UCHAR FAR *) &SmartParams, //PVOID pParams,
                              cbParmLen,                  //ULONG cbParmLenMax,
                              &cbParmLen,                 //PULONG pcbParmLen,
                              (UCHAR FAR *) Data,         //PVOID pData,
                              cbDataLenMax,               //ULONG cbDataLenMax,
                              &cbDataLenMax               //PULONG pcbDataLen
                                 );
                 if (rc) 
                 {
                    printf("Failed. IOCTl error: %d 0x%X\n", rc, rc);
                 }
                 else
                 {
                    printf("OK\n");
                    if (Data[368] & 0x02) printf("Autosave supported\n");
                    if (Data[370] & 0x01) printf("ErrLogging supported\n");
                 }
              }
           }
        }
        DosClose(h506);
     }
  }



  4  Copyright and Trademark Information
  ________________________________________

  The  following  terms  are  trademarks of  International  Business  Machines
  Corporation in the United States and/or other countries:
        IBM
        OS/2
        Warp
        Warp Server
        Warp Server for e-business
  Other company, product, and service names may be trademarks or service marks
  of others.

  THE INFORMATION PROVIDED IN THIS README IS PROVIDED "AS IS" WITHOUT WARRANTY
  OF ANY  KIND.  IBM DISCLAIMS  ALL WARRANTIES, WHETHER EXPRESSED  OR IMPLIED,
  INCLUDING  WITHOUT  LIMITATION, THE  IMPLIED  WARRANTIES  OF  FITNESS FOR  A
  PARTICULAR PURPOSE  AND MERCHANTABILITY WITH  RESPECT TO THE  INFORMATION IN
  THIS DOCUMENT.  BY FURNISHING THIS DOCUMENT,  IBM GRANTS NO  LICENSES TO ANY
  PATENTS OR COPYRIGHTS.

  (C) Copyright IBM Corporation, 2001, 2005. All rights reserved.
  U.S.  Government  Users Restricted Rights -- Use,  duplication or disclosure
  restricted by GSA ADP Schedule Contract with IBM Corp.

