The NT Insider

Getting Better: Virtual Storport Tweaks
(By: The NT Insider, Volume 17, Issue 2 , July-August 2010 | Published: 05-Aug-10| Modified: 05-Aug-10)

Storport is a welcome relief to storage driver writers wishing to develop a driver that exports a virtual device.  This article updates the Virtual Storport Miniport Driver that we developed in the earlier three issues of The NT Insider.  

Another Article?

Well to be honest, when we completed the last article we put the Virtual Storport Miniport Driver code away and expected not to have to revisit it for a long while.   However, we were contacted by Mike Berhan of busTRACE Technologies who used their busTRACE 9.0 product (www.bustrace.com) to see how accurate our implementation was in emulating a SCSI adapter/device.

So, How Did We Do?

Well, it seems that we missed some stuff.  And while windows didn’t complain, we’d be doing the development community a disservice if we didn’t clean the errors up and indicate where those errors were. So the purpose of this article is to tell you the errors that were found and how they were corrected. Of course, we’ll replace the current download code with the updated version.

So let’s get into what Mike found, using busTRACEand busPROBE(which are terrific tools, by the way).

Assumption of Pre-Zeroed Data Buffers

For SCSI operations other than read or write, Mike noted their busPROBEproduct found that the Storport Virtual Miniport driver did not pre-zero the data buffer which will contain the output from the driver. Thus when the driver filled in the return data, and fields that were not explicitly zeroed were filled with random data..  

While this may not seem like a big deal, remember that the Storport Virtual Miniport Driver is trying to create and emulate fully compliant SCSI devices, so in order to be compliant the driver was changed to do this.

No SRB DataTransferLength Update

The biggest violation that busTRACEfound was the failure of the Storport Virtual Miniport to update the DataTransferLengthfield in the SRB when completing a command that involved a data transfer.  While this isn’t critical, in order to be properly compliant with the Microsoft’s SRB definition requirement, it must be filled in.   Thus, for example, if you diff the old and new code you’ll see that OsrUserReadDataand OsrUserWriteDatanow set the SRB DataTransferLengthfield to the size of the data transfer.

busTRACEalso pointed out that when the driver failed a request, it was not setting the SRB’s DataTransferLengthfiled to zero to indicate that no data was transferred.

Validating the SRB DataTransferLength

Another interesting busTRACEfind was that the Storport Virtual Miniport Driver was not validating that the size of the buffer described by the SRBs’ DataTransferLengthfield was large enough to hold the data requested.   What this means is that when the Storport Virtual Miniport gets a request, for example a read or write, it needs to get the length of the transfer described in the CDB and ensure that the SRB DataTransferLengthfield is large enough.  Failure to make this check would lead to crashes or data corruption since the driver could attempt to access past the end of the allocated buffer.

SCSIOP_INQUIRY – Additional Length Field Not Set

busTRACEalso flagged the Storport Virtual Miniport Driver for an error processing the SCSIOP_INQUIRYcommand, because the Miniport wasn’t filling in the AdditionalLengthfield of  the SCSI_INQUIRY_DATAthat we were returning. The field was being left as zero which is invalid. In the code, it should be set to 0x1F (0x1F plus 5 = 0x24 bytes which is the valid length).   In the driver the code sets AdditionalLengthto “INQUIRYDATABUFFERSIZE-5” where INQUIRYDATABUFFERSIZEis 36 and the “-5” accounts for the 5 bytes of data  (this includes that AdditionalLengthbyte) preceed the additional data returned.

Figure 1 (previous page) shows the busTRACE output that highlights the error (see Additional Length in the figure). In the retail version of the product, the user can float the mouse over the red highlighted area and busTRACE tells you what firmware bug it has detected.

Figure 2 shows how the SCSIOP_INQUIRYprocessing code was corrected to correct the errors that busTRACEflagged.   Notice the setting of the pInquiryData->AdditionalLengthfield as well as the setting of the PSRB->DataTransferLengthfield.

 

case SCSIOP_INQUIRY             : {// 0x12
            PCDB       pCdb = (PCDB) &PSrb->Cdb;
            PUCHAR     pBuffer = (PUCHAR) OsrSpGetSrbDataAddress(pIInfo->OsrSPLocalHandle,PSrb);
            PINQUIRYDATA            pInquiryData;
 
            if(!pBuffer || PSrb->DataTransferLength < INQUIRYDATABUFFERSIZE) {
                status = STATUS_INSUFFICIENT_RESOURCES;
                //Irp->IoStatus.Information = 0;
                PSrb->SrbStatus = SRB_STATUS_ERROR;
                goto completeRequest;
            }
            pInquiryData = (PINQUIRYDATA) pBuffer;
 
            //
            // The media is a regular disk, return the correct information.
            //
   ASSERT(pIInfo->StorageType == OsrDisk);
 
            pInquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
            pInquiryData->DeviceTypeQualifier = DEVICE_CONNECTED;
            pInquiryData->DeviceTypeModifier = 0;
            pInquiryData->RemovableMedia = TRUE;
            pInquiryData->Versions = 2;             // SCSI-2 support
            pInquiryData->ResponseDataFormat = 2;   // Same as Version?? according to SCSI book
            pInquiryData->Wide32Bit = TRUE;         // 32 bit wide transfers
            pInquiryData->Synchronous = TRUE;       // Synchronous commands
            pInquiryData->CommandQueue = FALSE;     // Does not support tagged commands
            pInquiryData->AdditionalLength =
                          INQUIRYDATABUFFERSIZE-5;  // Amount of data we are returning
            pInquiryData->LinkedCommands = FALSE;   // No Linked Commands
            RtlCopyMemory((PUCHAR) &pInquiryData->VendorId[0],OSR_INQUIRY_VENDOR_ID,
strlen(OSR_INQUIRY_VENDOR_ID));
            RtlCopyMemory((PUCHAR) &pInquiryData->ProductId[0],OSR_INQUIRY_PRODUCT_ID,
strlen(OSR_INQUIRY_PRODUCT_ID));
            RtlCopyMemory((PUCHAR)
                   &pInquiryData->ProductRevisionLevel[0],OSR_INQUIRY_PRODUCT_REVISION,
                                strlen(OSR_INQUIRY_PRODUCT_REVISION));
 
            status = STATUS_SUCCESS;
            PSrb->SrbStatus = SRB_STATUS_SUCCESS;
            PSrb->DataTransferLength = INQUIRYDATABUFFERSIZE;
            goto completeRequest;
            }
 

 

Figure 2—SCSIOP_INQUIRY Processing

Another SCSIOP_INQUIRY issue that busTRACE found was that the driver was not checking the EnableVitalProductDatabit (VPD bit) and PAGE CODE field on input. This request, shown in Figure 3 (page 22), is sent by the Storport driver, after it has enumerated a device in order to enumerate a devices’ VPD pages.  The Storport Virtual Miniport Driver completely ignored this bit.   Since we saw no reason to support this feature the Storport Virtual Miniport driver was changed to fail the SCSIOP_INQUIRY request if the VPD bit and the PAGE CODE field is zero.   This was done to be compliant with the SCSI specifications.

Mode Sense Emulation

As with most of the errors in the Virtual Storport Miniport Driver, the error in handling the Mode Sense command was in setting the Mode Data Length field in the returned data.  As Figure 4 (page 22) illustrates the code was returning 0x4 in the Mode Data Length field of the returned data.

 

Figure 4—busTRACE Mode Sense Output

If there are only four bytes actually valid, then the "Mode Data Length" should be set to 3 (i.e. 3 bytes are valid following the Mode Data Length field) since the Mode Data Length field is not included in the count.

Prevent/Allow Medium Handling

When the Storport Virtual Miniport received a SCSI operation that it did not handle, the driver set the SRB status to SRB_STATUS_ERROR and completed the request.  While this isn’t necessarily wrong, the Storport Virtual Miniport Driver is trying to emulate a device capable of handling CDBs.  Therefore, the Miniport should really be responding as a real conformant device would.   What this means is that, if an SRB SenseInfoBufferhas been specified, the driver should be filling it correctly.  

Figure 5 (page 23), shows the routine ProcessScsiCommand Errorthat sets the sense data that is returned when a command error occurs.  This data will be returned if the input SRB contains a SenseInfoBuffer.  Of course, your implementation of this may vary depending on what your driver needs to accomplish.

 

 

NTSTATUS ProcessScsiCommandError(PSCSI_REQUEST_BLOCK PSrb)
{
    NTSTATUS status = STATUS_SUCCESS;
 
    if(PSrb->SenseInfoBuffer && PSrb->SenseInfoBufferLength) {
        PSENSE_DATA pSense = (PSENSE_DATA) PSrb->SenseInfoBuffer;
        RtlZeroMemory(pSense,PSrb->SenseInfoBufferLength);
        pSense->ErrorCode = 0x70;
        pSense->Valid = 0;
        pSense->SenseKey = SCSI_SENSE_ILLEGAL_REQUEST;
        pSense->AdditionalSenseLength = 0x15;
        pSense->AdditionalSenseCode = SCSI_ADSENSE_ILLEGAL_COMMAND;
        pSense->AdditionalSenseCodeQualifier = 0;
        PSrb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
        PSrb->SrbStatus = SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_ERROR;
    } else {
        status = STATUS_UNSUCCESSFUL;
        PSrb->SrbStatus = SRB_STATUS_ERROR;
    }
 
    return status;
}
 

 

Figure 5—ProcessScsiCommandError

Notice that the driver “OR’d” SRB_STATUS_AUTOSENSE _VALID to SRB_STATUS_ERROR to indicate to the caller that the SenseInfoBuffercontains valid data.

When you look at the new code, you will see that the driver has been modified to call the routine in Figure 5 whenever it receives a command that it does not handle.

Adapter Type

One interesting thing that Mike pointed out was that the AdapterInterfaceTypefor the Virtual Storport Driver was showing up as “Fibre”.   This AdapterInterfaceTypeis a field in the PORT_CONFIGURATION_ INFORMATIONblock that is set up in our HwFindAdapter routine.   Figuring that the field was not initialized the driver was modified to set the field to PNPBus.   To our surprise setting this field had no effect.   Since we were stumped  as to why, we contacted James Antognini of Microsoft WDK support who informed us that Storport gets the setting from the field “\Registry\Machine\System\Current ControlSet\Services\\Parmeters\BusType”.   This field is a 32-bit REG_DWORD.   Thus we modified the INF file to set the value of this key to 0xE (BusTypeVirtual) and it worked.   If you don’t set a value, it defaults to BusTypeFibre.

Crash

Alas, during his testing Mike managed to get the driver to crash.  This problem has been fixed in the new code drop.   It turns out that the code in CreateConnectionthat added a new connection to the list of current connections did not synchronize access to the ConnectionList.   Thus if you added and removed connections quickly enough you would cause the list to become corrupted.    The fix was simple; just hold the ConnectionListLockaround the adding of the new entry to the list in “CreateConnection”.

Summary

In our article series Writing a Virtual Storport Miniport Driver we described key aspects of the architecture, design, and implementation of this type of driver. We've built on that series, and made the driver more compliant, with the tweaks described in this article.  And while these tweaks might not be absolutely critical, they do make the driver more compliant with the SCSI specification and thus make it act more properly like a physical device. This compliance helps increase the driver's chance of interoperating with all sorts of software, and that's a certainly good thing.

Sample code to OSR’s Virtual Storport Miniport Driver can be downloaded from http://www.osronline.com/OsrDown.cfm/osrvmmemsample.zip?name=osrvmmemsample.zip&id=558

 

OSR would like to thank Mike Berhan of busTRACE Technologies for taking the time to test and analyze the OSR Virtual Storport Miniport Driver and for providing us with a copy of busTRACE so that we could find and fix the issues discussed in this article.  Without the help of Mike and his fine tool, we wouldn't have known about the driver's failure to conform to the specifications.

This article was printed from OSR Online http://www.osronline.com

Copyright 2017 OSR Open Systems Resources, Inc.