Annotation of q_a/samples/ddk/spti/readme.txt, revision 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.