Anton,
After banging on this problem from several different directions and spending
hours and days of stepping through the disassembly of ScsiPort, I have found
a few things you might be interested in. First … there are no context bits
that designate “family” calls into ScsiPort from “non-family” calls. From
what I have seen, the primary problem is the ability to queue the ScsiPort
DPC in the ScsiPort FDO. This is normally queued from either the ISR or a
Timer Call. A typical virtual Scsi miniport will not have an IRQ so you
normally wind up polling the hell out of things using a timer call back to
kick off your next transfer.
Now, in my miniport, I have to call down in the DriverEntry function to a
bus driver to acquire a private interface, which means I have a standard DDK
edge to my miniport. To do this I have to create a device object to pass to
IoCallDriver so that the bus driver can give me that private interface.
Since, what I needed was a DPC, which is the CallEnableInterrupts call back
function, I tried creating my own DPC queue in my own device object. That
didn’t work … but … since I have to run the device objects in the driver
object, I decided to look for the FDO created by ScsiPortInitialize. See
where I am going? That FDO has a DPC.
Here is my Scsi transfer logic …
--------------------------SCSI source ------------------------
FcRB is a fibre channel request block
Convert an SRB to an FcRB
In the FcRB set an ISR callback function
Send the FcRB to the bus driver through the private interface
Complete HwStartIo
Wait for the ISR callback.
On ISR call back
Queue the SRB to a completion queue
Call a DDK function to queue completion DPC for ScsiPortFDO.
Exit the ISR
On DPC
while the completion queue is not empty
complete an SRB
endwhile
while the retry/start SRB queue is not empty
start an SRB
endwhile
complete DPC ---- [CallDisableInterrupts callback]
--------------------------DDK source ------------------------
The DDK function to queue a completion DPC simply does
“IoRequestDpc(ScsiPortFDO, NULL, NULL);”
This obviously is a cheat, which would fail if ScsiPort quits using a DPC.
But I don’t think that will happen, unless there is a major change in how IO
is accomplished in Windows.
Gary G. Little
Broadband Storage, Inc.
xxxxx@broadstor.com
xxxxx@inland.net
-----Original Message-----
From: Anton Kolomyeytsev [mailto:xxxxx@cooldev.com]
Sent: Monday, January 21, 2002 12:32 AM
To: NT Developers Interest List
Subject: [ntdev] Re: problem with scsi miniport driver
Hi,
Finally that’s part of my own SCSI miniport driver. Try to compare what
I’ve did with what you did.
Good luck!
Anton
//
// some constants used in driver
//
#define MINIGUN_INITIATOR_ID 7
#define MINIGUN_NUMBER_OF_TARGETS 7
#define MINIGUN_NUMBER_OF_BUSES 1
#define MINIGUN_NUMBER_OF_HOSTS 1
#define MINIGUN_MAX_XFER_LEN 61140
#define MINIGUN_TARGET_ID 0 //
target ID we will support
#define MINIGUN_LUN 0
// target LUN we will support on ID
#define MINIGUN_SECTOR_SIZE 512 //
sector size
#define MINIGUN_SENSE_DATA_SIZE 18 // we will
not use full sense data
#define MINIGUN_TIMER_INTERVAL 10 // call
timer (may very)
// attention! add 10 'case latency overhead
#define MINIGUN_VENDOR_ID "MiniGun "
#define MINIGUN_PRODUCT_ID "7.62 mm cannon "
#define MINIGUN_REVISION_LEVEL “0004”
#define LBA( cdb ) ( cdb[2] << 24 | cdb[3] << 16 | cdb[4] << 8 |
cdb[
5 ] )
#define AL( cdb ) ( cdb[7] << 8 | cdb[8])
ULONG
DriverEntry(
IN PVOID pvDriverObject,
IN PVOID pvRegistryPath
)
/*++
Routine Description:
Main driver entry, called by I/O Manager
Arguments:
Ptr to Driver Object
Ptr to Registry Path
Return Value:
Status from call to ScsiPortInitialize()
–*/
{
HW_INITIALIZATION_DATA hwInitializationData;
ULONG ulStatus = 0xFFFFFFFF;
ULONG i;
ADAPTER_COUNT adapterCount;
//
// show startup banner
//
DbgPrint( “MiniGun: DriverEntry(): entered…\n” );
//
// init ADAPTER_COUNT structure
//
// in real wourld i think it will be better to query registry
// and init top border value with value in registry, not constant
//
if (
MiniGunGetNumberOfPorts(
( PUNICODE_STRING )( pvRegistryPath ),
&adapterCount.ulongMaxNumberOfAdapters
) == FALSE
)
{
//
// say we cannot read the registry
//
DbgPrint( “MiniGun: DriverEntry(): cannot read registry!\n”
);
//
// init with the default value
//
adapterCount.ulongMaxNumberOfAdapters =
MINIGUN_NUMBER_OF_HOSTS;
}
//
// init already present adapters with zero…
//
adapterCount.ulongAlreadyPresentAdapters = 0;
//
// zero out initialization data
//
MiniGunZeroMemory(
( PUCHAR )( &hwInitializationData ),
sizeof( hwInitializationData )
);
//
// set size of the structure
//
hwInitializationData.HwInitializationDataSize = sizeof(
hwInitializationData );
//
// set entry points which we do support
//
hwInitializationData.HwFindAdapter = MiniGunFindAdapter;
hwInitializationData.HwInitialize = MiniGunInitialize;
hwInitializationData.HwStartIo = MiniGunStartIo;
hwInitializationData.HwResetBus = MiniGunResetBus;
//hwInitializationData.HwTimer = MiniGunTimer;
//
// set size of extensions
//
hwInitializationData.DeviceExtensionSize = sizeof(
MINIGUN_DEVICE_EXTENSION );
//
// set primary I/O bus interface (need to be correct, or I/O Manager
// will refuse to load us just 'cause we emulate inexisting I/O bus)
//
hwInitializationData.AdapterInterfaceType = PCIBus;
//
// set automatic request sense
//
hwInitializationData.AutoRequestSense = TRUE;
//
// call SCSI port to initialize the driver and keep return code
//
ulStatus =
ScsiPortInitialize(
pvDriverObject,
pvRegistryPath,
&hwInitializationData,
&adapterCount
);
//
// dump what we’ve got
//
DbgPrint( “MiniGun: DriverEntry(): ScsiPortInitialize(): status ==
0x%08X\n”, ulStatus );
//
// return the status of call to ScsiPortInitialize()
//
return ulStatus;
}
BOOLEAN
MiniGunGetNumberOfPorts(
IN PUNICODE_STRING pustrDriverPath,
IN OUT PULONG pulNumberOfPorts
)
/*++
Routine Description:
Called by DriverEntry() to determine number of SCSI ports installed
installed in the machine
Arguments:
Ptr to device registry string
Ptr to ULONG which will recieve installed port counter
Return Value:
TRUE if we read the data successfuly,
FALSE if we failed to read the data…
–*/
{
RTL_QUERY_REGISTRY_TABLE rtlQueryTabReg[2];
ULONG ulDefData;
NTSTATUS ntStatus;
//
// zero out the table. last zeroed entry means the end
// of the table
//
MiniGunZeroMemory(
( PUCHAR )( &rtlQueryTabReg[0] ),
sizeof( rtlQueryTabReg )
);
//
// init the query table
//
rtlQueryTabReg[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
rtlQueryTabReg[0].Name = L"NumberOfPorts";
rtlQueryTabReg[0].EntryContext = pulNumberOfPorts;
rtlQueryTabReg[0].DefaultType = REG_DWORD;
rtlQueryTabReg[0].DefaultData = &ulDefData;
rtlQueryTabReg[0].DefaultLength = sizeof( ULONG );
//
// read the values from the registry
//
ntStatus =
RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
pustrDriverPath->Buffer,
&rtlQueryTabReg[0],
NULL,
NULL
);
//
// check the return code
//
if ( NT_SUCCESS( ntStatus ) == FALSE )
{
//
// say we failed to read the data
//
DbgPrint(
“MiniGun: MiniGunGetNumberOfPorts(): cannot read
registry with error ==
0x%08X!\n”,
ntStatus
);
//
// return failure
//
return FALSE;
}
//
// return success
//
return TRUE;
}
ULONG
MiniGunFindAdapter(
IN OUT PVOID pvoidMiniGunDeviceExtension,
IN PVOID pvContext,
IN PVOID pvBusInformation,
IN PCHAR pchArgumentString,
IN OUT PPORT_CONFIGURATION_INFORMATION pPortConfigInfo,
OUT PBOOLEAN pboAgain
)
/*++
Routine Description:
Called by SCSI Port driver to gather information and to find
if adapter is present in the system.
Arguments:
Ptr to device extension
Ptr to context (aux parameter used to pass number of adapters)
Ptr to bus information
Ptr to argument string (???)
Ptr to port config info used to store miniport data in
Ptr to boolean indicates need we be called again or not
Return Value:
Constant code means did we found adapter present and workable
or we failed in such a dirty bussiness…
–*/
{
PMINIGUN_DEVICE_EXTENSION pMiniGunDeviceExtension =
( PMINIGUN_DEVICE_EXTENSION )( pvoidMiniGunDeviceExtension
);
PADAPTER_COUNT pAdapterCount = ( PADAPTER_COUNT )( pvContext );
//
// show we’re just came in…
//
DbgPrint( “MiniGun: MiniGunFindAdapter(): entered…\n” );
//
// check here, if the number of already found adapters exceeds
// number of adapters we can support. in real world it have
// to probe hardware, in true software world we have to poll
registry,
// in the our world we have to limit the adapter to predefined
// value…
//
if ( pAdapterCount->ulongAlreadyPresentAdapters >=
pAdapterCount->ulongMaxNumberOfAdapters )
{
//
// say about the sutuation we’re envolved to…
//
DbgPrint(
“MiniGun: MiniGunFindAdapter(): just before
SP_RETURN_NOT_FOUND exit,
adapters: 0x%08X\n”,
pAdapterCount->ulongAlreadyPresentAdapters
);
//
// set pointer to Again to FALSE, this will cause SCSI Port
to
// avoid calling us once more
//
*pboAgain = FALSE;
//
// return special status to signall SCSI Port we did not
found
// “our” adapter present in the system. attention! this WILL
NOT
// make him call use once or more times for another instance
of I/O bus
// if such a bus present in the system in more then one
instance…
//
return SP_RETURN_NOT_FOUND;
}
//
// fill some port configuration & our device extension here
// as lot as we can manage this (btw, does anybody know which
// fields are “must” and which can be staied in default state?)
//
//
// set unique index of adapter
//
pMiniGunDeviceExtension->ulongUniqueIndex =
pAdapterCount->ulongAlreadyPresentAdapters;
//
// update adapter index counter, so we can “break up” next time if
the
counter
// will reach top allowed border
//
pAdapterCount->ulongAlreadyPresentAdapters++;
//
// set the initiator SCSI ID
//
pPortConfigInfo->InitiatorBusId[0] = MINIGUN_INITIATOR_ID;
//
// keep it in current device extension
//
pMiniGunDeviceExtension->ucharInitiatorId = MINIGUN_INITIATOR_ID;
//
// set maximum transfer length we can support
//
pPortConfigInfo->MaximumTransferLength = MINIGUN_MAX_XFER_LEN;
//
// set number of buses we do support
//
pPortConfigInfo->NumberOfBuses = MINIGUN_NUMBER_OF_BUSES;
//
// set number of targets
//
pPortConfigInfo->MaximumNumberOfTargets = MINIGUN_NUMBER_OF_TARGETS;
//
// say we do touch the things other then ScsiPortXXX
//
pPortConfigInfo->BufferAccessScsiPortControlled = FALSE;
//
// set we will touch the SRBs buffer “by hands”
//
pPortConfigInfo->MapBuffers = TRUE;
//
// set pboAgain to TRUE to initiate calling us more then once.
// we will “break up” next time
//
*pboAgain = TRUE;
//
// say about the sutuation we’re envolved to…
//
DbgPrint(
“MiniGun: MiniGunFindAdapter(): just before SP_RETURN_FOUND
exit,
adapters: 0x%08X\n”,
pAdapterCount->ulongAlreadyPresentAdapters
);
//
// return the constant indicating we did found proprerly
// configured adapter
//
return SP_RETURN_FOUND;
}
On 01/18/02, “Murali S ” wrote:
> Hi,
>
> we are in the process of writing a scsi miniport
> driver, we have been able to install and were able to
> see in the SCSI and RAID Controllers in the Device
> manager list.
> The xxxxstartIo routine is not getting any
> requests at all. The Information we are filling in
> HW_INITIALIZE_DATA and PPORT_CONFIGURATION_INFORMATION
> are here
>
> hwInitializationData.HwInitializationDataSize =
> sizeof(HW_INITIALIZATION_DATA);
> hwInitializationData.HwInitialize = SCSI_HwInitialize;
> hwInitializationData.HwResetBus = SCSI_ResetBus;
> hwInitializationData.HwStartIo = SCSI_StartIo;
> hwInitializationData.HwFindAdapter = SCSI_FindAdapter;
>
> hwInitializationData.NeedPhysicalAddresses = FALSE;
> hwInitializationData.AutoRequestSense = FALSE;
> hwInitializationData.TaggedQueuing = TRUE;
> hwInitializationData.MultipleRequestPerLu = FALSE;
> hwInitializationData.DeviceExtensionSize = 0;
> hwInitializationData.SpecificLuExtensionSize = 0;
> hwInitializationData.AdapterInterfaceType = PCIBus;
> hwInitializationData.NumberOfAccessRanges = 0;
> hwInitializationData.SrbExtensionSize = 0;
>
>
> and the port config structure is
>
> ConfigInfo->NumberOfBuses = 0;
> ConfigInfo->MaximumTransferLength = xxx;
> ConfigInfo->MaximumTransferLength = xxx;
> ConfigInfo->ScatterGather = FALSE;
> ConfigInfo->Master = FALSE;
> ConfigInfo->NeedPhysicalAddresses =FALSE;
> ConfigInfo->Dma32BitAddresses = FALSE;
> ConfigInfo->InterruptMode = LevelSensitive;
> ConfigInfo->TaggedQueuing = TRUE;
> ConfigInfo->AlignmentMask = 0x0;
> ConfigInfo->MaximumNumberOfTargets = 8;
> ConfigInfo->InitiatorBusId[0] = 0x0;
>
>
>
> are we missing out any thing here??
>
> thanks,
> Murali
>
> __________________________________________________
> Do You Yahoo!?
> Send FREE video emails in Yahoo! Mail!
> http://promo.yahoo.com/videomail/
>
> —
> You are currently subscribed to ntdev as: xxxxx@broadstor.com
> To unsubscribe send a blank email to %%email.unsub%%
—
You are currently subscribed to ntdev as: xxxxx@broadstor.com
To unsubscribe send a blank email to %%email.unsub%%