Annotation of q_a/samples/ddk/spti/readme.txt, revision 1.1.1.1

1.1       root        1: Win32 applications can communicate directly with SCSI devices via
                      2: IOCtls.  The Win32 API that is used to implement an IOCtl request is
                      3: DeviceIoControl.  In order to make the DeviceIoControl call, a valid
                      4: handle must be obtained to the device.  The handle is obtained using
                      5: the Win32 API, CreateFile.
                      6: 
                      7: There are five IOCtls's that the SCSI port driver supports.  These
                      8: are IOCTL_SCSI_GET_INQUIRY_DATA, IOCTL_SCSI_GET_CAPABILITIES,
                      9: IOCTL_SCSI_PASS_THROUGH, IOCTL_SCSI_PASS_THROUGH_DIRECT and
                     10: IOCTL_SCSI_MINIPORT.  The first four are demonstrated in this sample.
                     11: 
                     12: IOCTL_SCSI_GET_INQUIRY_DATA
                     13: 
                     14: The first IOCtl, IOCTL_SCSI_GET_INQUIRY_DATA, fills out a
                     15: SCSI_ADAPTER_BUS_INFO structure for all devices that are on the SCSI
                     16: bus.  The structure member, BusData, is a structure of type
                     17: SCSI_BUS_DATA.  It contains an offset to the inquiry data which is
                     18: also stored as a structure, SCSI_INQUIRY_DATA.  See NTDDSCSI.H for
                     19: more details about these structures.  One interesting
                     20: SCSI_INQUIRY_DATA structure member is DeviceClaimed.  This tells the
                     21: caller whether or not this device has been claimed by a class driver.
                     22: 
                     23: IOCTL_SCSI_GET_CAPABILITIES
                     24: 
                     25: IOCTL_SCSI_GET_CAPABILITES fills out an IO_SCSI_CAPABILITES structure
                     26: (also found in NTDDSCSI.H).  This structure contains valuable
                     27: information.  Two items of note are the MaximumTransferLength, which
                     28: is the largest data block that can be handled in a single SRB as
                     29: defined by the miniport driver, and the AlignmentMask which defines
                     30: the alignment requirements of the current CPU platform.  For an x86
                     31: system, the AlignmentMask is 0 as there is no alignment requirement.
                     32: 
                     33: IOCTL_SCSI_PASS_THROUGH, IOCTL_SCSI_PASS_THROUGH_DIRECT
                     34: 
                     35: The two remaining IOCtls, IOCTL_SCSI_PASS_THROUGH and
                     36: IOCTL_SCSI_PASS_THROUGH_DIRECT, allow SCSI CDBs (Command Descriptor
                     37: Blocks) to be sent from a Win32 application to a SCSI device. 
                     38: Depending on which IOCtl is used, a corresponding pass through
                     39: structure is filled out by the Win32 application.  For
                     40: IOCTL_SCSI_PASS_THROUGH, the structure is SCSI_PASS_THROUGH.  For 
                     41: IOCTL_SCSI_PASS_THROUGH_DIRECT, the structure is
                     42: SCSI_PASS_THROUGH_DIRECT.  See NTDDSCSI.H for more details about
                     43: these structures.
                     44: 
                     45: The two structures SCSI_PASS_THROUGH and SCSI_PASS_THROUGH_DIRECT are
                     46: virtually identical.  The only difference is that the data buffer for
                     47: the SCSI_PASS_THROUGH structure must be contiguous with the
                     48: structure.  This structure member is called DataBufferOffset and is
                     49: of type ULONG.  The data buffer for the SCSI_PASS_THROUGH_DIRECT
                     50: structure does not have to be contiguous with the structure.  This
                     51: structure member is called DataBuffer and is of type PVOID.  This is
                     52: the only difference between the two structures.
                     53: 
                     54: IOCTL_SCSI_PASS_THROUGH and IOCTL_SCSI_PASS_THROUGH_DIRECT are not
                     55: substitues for a SCSI class driver and should only be used as a last
                     56: resort.  In situations in which CDBs need to be sent to a SCSI
                     57: device, the best solution is to write a SCSI class driver that will
                     58: send these CDBs to the respective devices.
                     59: 
                     60: Obtaining a handle to a device
                     61: 
                     62: Before any IOCtls can be sent to a SCSI device, a handle for the
                     63: device must be obtained.  The Win32 API, CreateFile, is used to
                     64: obtain this handle and to define the sharing mode and the access
                     65: mode.  The key is to supply the proper filename for the device that
                     66: is to be opened.  It is possible to obtain a handle to the device via
                     67: either the SCSI port driver or the appropriate SCSI class driver.  If
                     68: the handle is obtained via the class driver, then the filename to be
                     69: opened is defined by the class driver.  In the case of fixed disks
                     70: and optical storage devices, the filename is the corresponding drive
                     71: letter.  "\\.\I:" can be used to obtain a handle to a CD-ROM drive
                     72: that has been mapped to I:.  In the case of SCSI printers, the
                     73: filename is "LPTn", where n = 1, 2, etc.  For all remaining SCSI
                     74: devices, the appropriate name is defined by the SCSI class driver. 
                     75: Typically the name is related to the device (e.g. - "\\.\Scanner0",
                     76: "\\.\Tape1").  Except for COMn and LPTn, all device filenames must be
                     77: prepended with a \\.\ to inform the I/O Manager that this is a
                     78: device.
                     79: 
                     80: If the device is unclaimed by a SCSI class driver, then a handle to
                     81: the SCSI port driver is required.  The filename in this case is
                     82: "\\.\ScsiN:", where N = 0, 1, 2, etc.  The number N corresponds to
                     83: the SCSI host adapter card number that controls the desired SCSI
                     84: device.  If the device is claimed by a class driver and one of the
                     85: pass through IOCtls is to be used, then the filename opened must be
                     86: the one that is defined by the class driver.  While a handle to the
                     87: SCSI port driver can be obtained, subsequent calls to DeviceIoControl
                     88: with a control code of IOCTL_SCSI_PASS_THROUGH (or
                     89: IOCTL_SCSI_PASS_THROUGH_DIRECT) that reference a claimed device will
                     90: always fail with ERROR_INVALID_PARAMETER.
                     91: 
                     92: Initializing the structures
                     93: 
                     94: Once a valid handle is obtained to a SCSI device, then appropriate
                     95: input/output buffers for the requested IOCtl must be allocated and
                     96: defined in the DeviceIoControl parameters.  In the case of
                     97: IOCTL_SCSI_GET_INQUIRY_DATA and IOCTL_SCSI_GET_CAPABILITIES, no data
                     98: is sent to the device.  Data is only read from the device. Therefore,
                     99: the pointer to the input buffer is NULL and it's length is 0.  As for
                    100: the IOCTL_SCSI_GET_CAPABILITES output buffer, the buffer size must be
                    101: at least as large as the IO_SCSI_CAPABILITES structure.  The output
                    102: buffer for IOCTL_SCSI_GET_INQUIRY_DATA should be quite large as each
                    103: SCSI device on the bus will provide data that will fill three
                    104: structures for each device, SCSI_ADAPTER_BUS_INFO, SCSI_BUS_DATA and
                    105: SCSI_INQUIRY_DATA.  For the two pass through IOCtls,
                    106: IOCTL_SCSI_PASS_THROUGH and IOCTL_SCSI_PASS_THROUGH_DIRECT, both the
                    107: input and output buffers can vary in size depending on the sense info
                    108: buffer size and the data buffer size.  In all cases, the input and
                    109: output buffer sizes must be at least the size of the
                    110: SCSI_PASS_THROUGH (or SCSI_PASS_THROUGH_DIRECT) structure.  If the
                    111: SCSI port driver detects that one of the two buffers is too small,
                    112: then the DeviceIoControl API will fail with ERROR_INVALID_PARAMETER.
                    113: 
                    114: Once the appropriate input/output buffers have been allocated, then,
                    115: in the case of IOCTL_SCSI_PASS_THROUGH and
                    116: IOCTL_SCSI_PASS_THROUGH_DIRECT, the appropriate structure must be
                    117: initialized.  The SCSI_PASS_THROUGH structure is defined in
                    118: NTDDSCSI.H as follows :
                    119: 
                    120: typedef struct _SCSI_PASS_THROUGH {
                    121:     USHORT Length;
                    122:     UCHAR ScsiStatus;
                    123:     UCHAR PathId;
                    124:     UCHAR TargetId;
                    125:     UCHAR Lun;
                    126:     UCHAR CdbLength;
                    127:     UCHAR SenseInfoLength;
                    128:     UCHAR DataIn;
                    129:     ULONG DataTransferLength;
                    130:     ULONG TimeOutValue;
                    131:     ULONG DataBufferOffset;
                    132:     ULONG SenseInfoOffset;
                    133:     UCHAR Cdb[16];
                    134: }SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH;
                    135: 
                    136: The Length is the size of the the SCSI_PASS_THROUGH structure.  The
                    137: ScsiStatus should be initialized to 0.  The status of the requested
                    138: SCSI operation is returned in this structure member.  The possible
                    139: SCSI statuses are defined in SCSI.H and are of the form SCSISTAT_xxx.
                    140: The PathId is the bus number for the SCSI host adapter that controls
                    141: the SCSI device in question.  Typically, this value will be 0, but
                    142: there are SCSI host adapters available that contain more than one
                    143: SCSI bus.  The TargetId and Lun are the SCSI ID number and logical
                    144: unit number for the device.  If the handle was obtained for a claimed
                    145: device, then the PathId, TargetId and Lun as defined in this
                    146: structure will be ignored and the appropriate class driver will
                    147: provide these three items.  If the handle was obtained via the SCSI
                    148: port driver, then the PathId, TargetId and Lun must be correct for
                    149: the device intended.  The CdbLength is the length of the CDB. Typical
                    150: values are 6, 10, 12 up to the maximum of 16.  The SenseInfoLength is
                    151: the length of the SenseInfo buffer.  DataIn has three possible values
                    152: which are defined in NTDDSCSI.H; SCSI_IOCTL_DATA_OUT,
                    153: SCSI_IOCTL_DATA_IN and SCSI_IOCTL_DATA_UNSPECIFIED. 
                    154: SCSI_IOCTL_DATA_UNSPECIFIED should be used only if the appropriate
                    155: SCSI miniport driver supports its usage.  The DataTransferLength is
                    156: the size of the data buffer.  The TimeOutValue is the length of time,
                    157: in milliseconds, until a time out error should occur.  This can range
                    158: from 0 to a maximum of 30 minutes (108000 seconds).  The
                    159: DataBufferOffset is the offset of the data buffer from the beginning
                    160: of the pass through structure.  For the SCSI_PASS_THROUGH_DIRECT
                    161: structure, this value is no longer an offset, but rather is a pointer
                    162: to a data buffer.  The SenseInfoOffset is similarly an offset to the
                    163: SenseInfo buffer from the beginning of the pass through structure. 
                    164: Finally, the sixteen remaining bytes are for the CDB data.  The
                    165: format of this data must conform to the SCSI-2 standard as defined by
                    166: ANSI.
                    167: 
                    168: Buffer Alignment
                    169: 
                    170: The issue of buffer alignment is handled using two possible methods
                    171: for assuring that data buffers are aligned on the appropriate
                    172: boundaries.  The first method uses the compiler to align the buffer
                    173: on the correct boundary.  The structure
                    174: SCSI_PASS_THROUGH_WITH_BUFFERS contains a member, Filler, that is of
                    175: type ULONG.  The compiler aligns Filler on a ULONG (double word)
                    176: boundary.  The structure member that follows Filler, ucSenseBuf, is
                    177: now also on a double word boundary.  The ucSenseBuf array is of a
                    178: size that is a multiple of a double word, and so this makes the last
                    179: structure member, ucDataBuf, also begin on a double word boundary.
                    180: 
                    181: The other method to ensure buffer alignment is demonstrated in the
                    182: AllocateAlignedBuffer procedure.  This works on the fact that a
                    183: buffer that is aligned on a certain boundary will have 0's in it's
                    184: least significant bits depending on the aligment requirements.  A
                    185: buffer allocation request is made using the C runtime call, malloc,
                    186: that is the size of the requested buffer plus the alignment mask
                    187: value as returned by IOCTL_SCSI_GET_CAPABILITIES.  A pointer is
                    188: manipulated so that it is pointing to the first possible address in
                    189: the buffer that meets the alignment requirements.
                    190: 
                    191: METHOD_BUFFERED
                    192: 
                    193: The various IOCtls that are demonstrated in this sample are defined
                    194: by the SCSI port driver (see NTDDSCSI.H for details).  The memory
                    195: buffering is METHOD_BUFFERED.  What this means if the I/O manager
                    196: examines the length of the input buffer and the length of the output
                    197: buffer as defined by the DeviceIoControl parameters and allocates a
                    198: contiguous buffer that is the size of the larger of the two buffers. 
                    199: On entry, the contents of the Win32 application's input buffer are
                    200: copied to the buffer that was allocated by the I/O manager.  The
                    201: amount of data copied is controlled by the input buffer lenght.  The
                    202: I/O manager then makes calls the appropriate SCSI class driver's (or
                    203: port driver's) DeviceIoControl routine passing it the new buffer.  On
                    204: exit, the reverse process occurs and the data in the new buffer is
                    205: copied back into the Win32 application's output buffer as defined by
                    206: the output buffer length.  This is not user configurable.
                    207: 
                    208: Running the SPTI.EXE sample
                    209: 
                    210: Two command line parameters can be used with SPTI.EXE.  The first
                    211: parameter is mandatory.  It is the name of the device to be opened. 
                    212: Typical values for this are drive letters such as C:, or device
                    213: names as defined by a class driver such as Scanner0, or the SCSI port
                    214: driver name, ScsiN:, where N = 0, 1, 2, etc.
                    215: 
                    216: The second parameter is optional and is used to set the access flags
                    217: and the sector size.  The default is READ/WRITE mode and a sector
                    218: size of 512.  A value of 'r' makes the mode read-only.  A value of
                    219: 'w' makes the mode write-only.  A value of 'c' makes the mode
                    220: read-only and makes the sector size 2048.  Only optical storage
                    221: devices would use the 'c' parameter.

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.