cidentifier
驱动牛犊
驱动牛犊
  • 注册日期2003-11-13
  • 最后登录2009-09-20
  • 粉丝1
  • 关注0
  • 积分1分
  • 威望11点
  • 贡献值0点
  • 好评度9点
  • 原创分0分
  • 专家分0分
阅读:3296回复:21

kangzh,terrychen大虾看过来,关于scsiminiport,给100分

楼主#
更多 发布于:2004-08-21 16:48
我的scsiminiport经常会出现bus reset,系统就会挂起,没有任何响应。我认为只要正确处理HwScsiResetBus,系统会从bus reset状态恢复过来,我的HwScsiResetBus的内容如下:
BOOLEAN
MyDiskResetBus(
    IN PVOID HwDeviceExtension,
    IN ULONG PathId
)
{
  KdPrint(("bus reset.\n"));

  ScsiPortCompleteRequest(
    HwDeviceExtension,
    (UCHAR)PathId,
    SP_UNTAGGED,
    SP_UNTAGGED,
    SRB_STATUS_BUS_RESET
  );

  ScsiPortNotification(
    NextRequest,
    HwDeviceExtension,
    NULL
  );

  return TRUE;
}

上面例程被调用后,还是不行,系统仍然挂起,请问:
1、bus reset的真正含义是什么?
2、怎样从bus reset状态恢复过来,HwScsiResetBus到底应该怎样写

给100分,help me !!!!!

最新喜欢:

TOMG2004TOMG20...
control it, or forget it
kangzh
驱动小牛
驱动小牛
  • 注册日期2004-03-09
  • 最后登录2012-08-06
  • 粉丝0
  • 关注0
  • 积分4分
  • 威望22点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2004-08-23 10:20
经常出现总线reset应该是在规定的时间内scsi没有反馈srb给os造成的,一般为10ms,如果及时反馈,应该不会出现这个问题.你在reset之后才反馈,应该已经timeout了
cidentifier
驱动牛犊
驱动牛犊
  • 注册日期2003-11-13
  • 最后登录2009-09-20
  • 粉丝1
  • 关注0
  • 积分1分
  • 威望11点
  • 贡献值0点
  • 好评度9点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2004-08-23 14:23
问题是一旦出现bus reset,我还能恢复过来吗?
由于我做的是网络虚拟磁盘,保持响应时间在10ms之内对于网络来说不是那么容易保证的,比如服务器负载重,局域网网络负载重等情况,所以bus reset迟早会发生,这是一个不能回避的问题。

所以在一方面是提高响应时间,另一方面是在出现bus reset时怎样恢复过来,我注意到kangzh和terrychen做网络虚拟磁盘很长时间了,你们是怎样保持响应时间在10ms之内的,又是怎样从bus reset中恢复过来的呢?

??????

另外,bus reset时要求在HwScsiResetBus中完成所有的srb,而我在bus reset后利用!irpfind发现仍有未完成的irp(srb),显然我的HwScsiResetBus中的ScsiPortCompleteRequest调用并没有完成srb。于是我怀疑我是将在startio中将srb插入队列,交给一个内核线程来处理。在出现bus reset时,有可能线程正在处理该srb,这时HwScsiResetBus中该怎样完成srb呢?

办法一是让HwScsiResetBus和内核线程间有某种同步措施,同时只能有一方在处理srb。但HwScsiResetBus工作在dispatch_level,好像没法使用内核同步对象,即不能waitforxxxobject。

办法二是好像从外部杀掉内核线程,然后完成srb,但好像没有办法从外部杀掉一个内核线程。

我的分析有问题吗?真是痛苦啊!
control it, or forget it
terrychen
驱动小牛
驱动小牛
  • 注册日期2002-04-15
  • 最后登录2014-03-13
  • 粉丝0
  • 关注0
  • 积分174分
  • 威望68点
  • 贡献值0点
  • 好评度15点
  • 原创分0分
  • 专家分0分
地板#
发布于:2004-08-23 15:09
应该还是你ScsiPortCompleteRequest返回状态的问题,bus reset是一般在10秒中如果还不能返回数据(pending或者没有返回数据)情况下发生,具体timeout 的时间是由scsi_request_block里面的TimeOutValue数值决定的,10ms不能保证,10秒总可以吧,bus reset我没用过,说实在我很怕它,你还是看看你的返回程序吧,ScsiPortCompleteRequest只能在startio函数,或者timercall函数利被调用才能真正的把数据返回给scsi port driver.你再确认一遍,或者把你程序ScsiPortCompleteRequest调用的位置给大家看看。
cidentifier
驱动牛犊
驱动牛犊
  • 注册日期2003-11-13
  • 最后登录2009-09-20
  • 粉丝1
  • 关注0
  • 积分1分
  • 威望11点
  • 贡献值0点
  • 好评度9点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2004-08-23 16:35
terrychen, 以下是我的代码(只贴出最主要的vdisk.c文件,其他代码跟这个问题不相关,太多了,就不贴了),其中有些地方是访问tdi的,不用管。我只在HwVDiskTimer中调用了ScsiPortNotification来完成srb。

帮我看看,多谢!

#include <ntddk.h>
#include <ntddscsi.h>
#include <scsi.h>
#include <srb.h>

#include "vdisk.h"
#include "srbhandler.h"

extern SrbHandler SrbHandlerArray[0x60];

BOOLEAN SingletonFound = FALSE;

ULONG
DriverEntry(
IN PVOID DriverObject,
IN PVOID Argument2
)
{
ULONG i, status;
HW_INITIALIZATION_DATA hwInitData;

DbgPrint("Enter DriverEntry, IRQL:%d\n", KeGetCurrentIrql());

// zero hwInitData ...
for (i=0; i<sizeof(hwInitData); i++) {
((UCHAR *)(&hwInitData)) = 0;
}

hwInitData.HwInitializationDataSize = \
sizeof(HW_INITIALIZATION_DATA);

// init hwInitData ...
hwInitData.HwInitialize = VDiskInitialize;
hwInitData.HwResetBus = VDiskResetBus;
hwInitData.HwStartIo = VDiskStartIo;
hwInitData.HwFindAdapter = VDiskFindAdapter;

// give me virtual address ...
hwInitData.MapBuffers = TRUE;
hwInitData.NeedPhysicalAddresses = FALSE;

// set device extensions ...
hwInitData.DeviceExtensionSize = sizeof(VDISK_EXTENSION);
//hwInitData.SrbExtensionSize = GetExtraRequestSize();

// Specifiy the bus type ...
hwInitData.AdapterInterfaceType = Isa;
hwInitData.NumberOfAccessRanges = 1;

hwInitData.TaggedQueuing = FALSE; // don't support command queue now
//
// setting the AutoRequestSence to TRUE indicates that the HBA can perform
// a request-sense operation without requiring an explicit request to do so.
// we here set it to TRUE mean will set sense data in Srb->SenseInfoBuffer when
// error occurs ...
//
hwInitData.AutoRequestSense = TRUE;
hwInitData.MultipleRequestPerLu = FALSE; // don't support command queue now

// use SRB extension to store LIST_ENTRY, as to make SRB list.
hwInitData.SrbExtensionSize = sizeof(SRB_EXTENSION);

status = \
ScsiPortInitialize(
DriverObject, // first parameter of DriverEntry
Argument2, // second parameter of DriverEntry
&hwInitData, // pointer to hwInitData
NULL // address of context to be passed to HwScsiFindAdapter
);

return status;
}

/*
 * called by ScsiPortInitailize, and is responsible for filling in
 * rest fields of the PORT_CONFIGURATION_INFORMATION structure ...
 * Params --
 * HwDeviceExtension -- points to the miniport driver's per-HBA storage area
 * HwContext --  points to the context value
 * BusInformation -- points to bus-type-specific info that the port driver has gathered
 * ConfigInfo -- config info, which has been partly filled by port driver
 * Again -- TRUE indicates that the miniport driver want the port driver to call it
 * again to find another HBA.
*/
ULONG
VDiskFindAdapter(
IN PVOID  HwDeviceExtension,
IN PVOID  HwContext,
IN PVOID  BusInformation,
IN PCHAR  ArgumentString,
IN OUT PPORT_CONFIGURATION_INFORMATION  ConfigInfo,
OUT PBOOLEAN  Again
)
{
DbgPrint("Enter VDiskFindAdapter, IRQL:%d\n", KeGetCurrentIrql());

if( SingletonFound )
{
//
// Only support one controller
//
*Again = FALSE;
return SP_RETURN_NOT_FOUND;
}

SingletonFound = TRUE;

ConfigInfo->BusInterruptVector = 0; // virtual device, no interrupt
ConfigInfo->BusInterruptLevel = 0;
ConfigInfo->ScatterGather = FALSE; // not support scatter/gather

//
// the MTU of ethernet is 1500, so here the HBA only support max
// transfer length of 1024
//
ConfigInfo->MaximumTransferLength = MAX_TRANSFER; // 8K   //0x10000; // 1024
//
// Specifies the maximum number of breaks between address ranges that a data
// buffer can have if the HBA supports scatter/gather. 0 means no scatter/gather
// support.
//
ConfigInfo->NumberOfPhysicalBreaks = 0;
ConfigInfo->Master = FALSE;

//
// indeed it's easy to support multiple request per lu with current
// request queue implementation. You just need to change TaggedQueuing
// and MultipleRequestPerLu to TRUE here and modify RequestReturn.
//
ConfigInfo->TaggedQueuing = FALSE;
ConfigInfo->MultipleRequestPerLu = FALSE;

//
// with AutoRequestSense, I don't need to implement REQUEST SENSE command.
//
ConfigInfo->AutoRequestSense = TRUE;

ConfigInfo->AlignmentMask = 0x00000003;
ConfigInfo->BufferAccessScsiPortControlled = FALSE;
ConfigInfo->CachesData = FALSE;
ConfigInfo->NumberOfBuses = 1;
ConfigInfo->MaximumNumberOfTargets = 4;
ConfigInfo->Dma32BitAddresses = TRUE;

// we only want to support one HBA ...
*Again = FALSE;

//
// let port driver know that a supported HBA was found and that the
// HBA-relevant configuration information was successfully determined
// and set in the PORT_CONFIGURATION_INFORMATION structure.
//
return SP_RETURN_FOUND;
}

/*
 * For each supported HBA found by the miniport driver, its HwScsiInitialize
 * routine is called to set up the HBA's registers and initial state, if any.
 * If the initialization succeeds, HwScsiInitialize should return TRUE.
 * Paramters --
 * HwDeviceExtension -- Points to the miniport driver's per-HBA storage area.
*/
BOOLEAN
VDiskInitialize(
IN PVOID  HwDeviceExtension
)
{
NTSTATUS status;
PVDISK_EXTENSION pExt = (PVDISK_EXTENSION)HwDeviceExtension;
OBJECT_ATTRIBUTES ObjAttr;
IO_STATUS_BLOCK IoStatus;

DbgPrint("Enter VDiskInitialize, IRQL:%d\n", KeGetCurrentIrql());

//
pExt->BlockCount = pExt->BlockSize = 0;

// 初始化两个同步事件
KeInitializeEvent(
&(pExt->ThrdSyncEvent), // event handle
SynchronizationEvent, // synchronization event
FALSE // not signaled
);

KeInitializeEvent(
&(pExt->SrbListSyncEvent), // event handle
SynchronizationEvent, // synchronization event
FALSE // not signaled
);

// 初始化两个SRB  队列
InitializeListHead(&pExt->SrbList);
KeInitializeSpinLock(&pExt->SrbListLock);

InitializeListHead(&pExt->CompletedSrbList);
KeInitializeSpinLock(&pExt->CompletedSrbListLock);

//
// 创建工作线程,因为文件操作必须在
// PASSIVE_LEVEL  执行,所以所有的文件操作
// 都让工作线程来执行
//
status = PsCreateSystemThread(
&(pExt->ThrdHandle), // thread handle
(ACCESS_MASK)0L, // desired access
NULL, // object attr, NULL for driver created thread
NULL, // process handle, NULL for driver created thread
NULL, // client id, NULL for driver created thread
VDiskWorkerThrd, // start routine
HwDeviceExtension // start context
);

if ( !NT_SUCCESS(status)) {
KdPrint(("Fail to create working thread!\n"));
return FALSE;
}

// 等待工作线程初始化完成
KdPrint(("Waiting for worker thread to complete initialization ...\n"));
KeWaitForSingleObject(
(PVOID)(&(pExt->ThrdSyncEvent)), // event handle
Executive,
KernelMode,
FALSE,
0 // must be 0 at DISPATCH_LEVEL
);

KdPrint(("Continue to run after worker thread has completed initialization ...\n"));

// 设置定时器,定期处理完成的SRB
ScsiPortNotification(RequestTimerCall,HwDeviceExtension,HwVDiskTimer, VDISK_TIMER_PERIOD); // 0.1s

// 返回TRUE  表示初始化成功,可以接受请求了
return TRUE;
}

/*
 * All miniport drivers must have a HwScsiStartIo routine. The port driver
 * calls HwScsiStartIo first with each incoming I/O request for a target on
 * a SCSI bus. HwScsiStartIo returns TRUE to acknowledge receipt of the SRB.
 *
 * NOTE that we use "FILEDISK" to simulate all the disk operation, and all
 * the file operation must be executed under PASSIVE_LEVEL, so we use a
 * system thread to conduct file operation. And, the driver communicate with
 * system thread through 2 list, one for SRBs, and one for completed SRBs.
 *
 * VDiskStartIo just insert the comming SRBs into SRB List.
 *
 * Parameters --
 * HwDeviceExtension -- Points to the miniport driver's per-HBA storage area.
 * Srb -- points to the SRB passed in by port driver.
*/
BOOLEAN
VDiskStartIo(
IN PVOID  HwDeviceExtension,
IN PSCSI_REQUEST_BLOCK  Srb
)
{
PVDISK_EXTENSION pExt = (PVDISK_EXTENSION)HwDeviceExtension;

// Srb->SrbStatus = SRB_STATUS_PENDING;

// 将SRB   插入队列尾部
((PSRB_EXTENSION)(Srb->SrbExtension))->pSrb = Srb;
ExInterlockedInsertTailList(
&pExt->SrbList,
&((PSRB_EXTENSION)(Srb->SrbExtension))->ListEntry,
&pExt->SrbListLock
);

// 通知工作线程SRB  已经到来
KeSetEvent(
&pExt->SrbListSyncEvent,
IO_NO_INCREMENT,
FALSE
);

// miniport driver should always return TRUE here ...
return TRUE;
}

//
//
//
VOID
HwVDiskTimer(
IN PVOID HwDeviceExtension
)
{
PLIST_ENTRY ListEntry;
PSCSI_REQUEST_BLOCK pSrb;
PVDISK_EXTENSION pExt = (PVDISK_EXTENSION)HwDeviceExtension;
unsigned int i;

// 从完成队列头部取出完成的SRB
ListEntry = ExInterlockedRemoveHeadList (
&pExt->CompletedSrbList,
&pExt->CompletedSrbListLock
);

while( ListEntry!=NULL )
{
pSrb = SRB_FROM_ENTRY(ListEntry);

KdPrint(("\nA SRB Completed\n"));

ReturnFromStartIo(
pExt,
pSrb
);

// 从完成队列头部取出完成的SRB
ListEntry = ExInterlockedRemoveHeadList (
&pExt->CompletedSrbList,
&pExt->CompletedSrbListLock
);
}

// 这个定时器不是周期性的,每次响应后必须重新设置
ScsiPortNotification(RequestTimerCall,HwDeviceExtension,HwVDiskTimer, VDISK_TIMER_PERIOD);
}

/*
 * HwScsiResetBus resets a given SCSI bus. If the bus is successfully reset,
 * HwScsiResetBus returns TRUE.
 * Parameters --
 * HwDeviceExtension -- Points to the miniport driver's per-HBA storage area
 * PathId -- Identifies the SCSI bus to be reset
 */
BOOLEAN
VDiskResetBus(
    IN PVOID HwDeviceExtension,
    IN ULONG PathId
)
{
KdPrint(("bus reset, IRQL:%d\n", KeGetCurrentIrql()));
//
// ScsiPortCompleteRequest completes all of the active requests for
// the given SCSI bus, controller, or LU, including a request being
// processed by the calling miniport routine.
//
/*
ScsiPortCompleteRequest(
HwDeviceExtension, // points to the per-HBA storage ...
(UCHAR)PathId, // identifies the SCSI bus ...
SP_UNTAGGED, // identifies the target controler, SP_UNTAGGED means all the target ...
SP_UNTAGGED, // identifies the LU, SP_UNTAGGED means all the LU ...
SRB_STATUS_BUS_RESET // Specifies the completion status to be set in the SrbStatus member of each SRB.
);

//
// After completing the bus-reset request and any outstanding requests,
// the miniport must call ScsiPortNotification with the NotificationType
// NextRequest.
//
ScsiPortNotification(
NextRequest,
HwDeviceExtension,
NULL
);
*/

// do reset bus ...
// ...

return TRUE;
//return FALSE;

}

/*
 * VDiskWorkerThrd open "FILEDISK" and wait for SRB to process.
 * Parameters --
 * thrdContext -- points to the device extension
 */
VOID
VDiskWorkerThrd( PVOID thrdContext)
{
NTSTATUS status;
OBJECT_ATTRIBUTES  ObjAttr;
IO_STATUS_BLOCK IoStatus;
VDISK_EXTENSION *pExt = (PVDISK_EXTENSION)thrdContext;
FILE_STANDARD_INFORMATION StandardInfo;
UNICODE_STRING FileName;
PLIST_ENTRY ListEntry;
PSCSI_REQUEST_BLOCK pSrb;

TA_IP_ADDRESS transAddr;

// 打开本地传输层地址
TuInitTransAddr(&transAddr,  0/*INADDR_ANY*/, htons(5889));
status = TuOpenTransAddr(L"\\Device\\Udp", &transAddr, &pExt->TuLocalAddr);
if ( !NT_SUCCESS(status)) {
KdPrint(("In VDiskWorkerThrd, Fail to Open Transport Address!\n"));
return;
}

// 查询注册表,读取服务器地址和端口
// ...
((UCHAR *)(&pExt->srvAddr))[0] = 10;
((UCHAR *)(&pExt->srvAddr))[1] = 0;
((UCHAR *)(&pExt->srvAddr))[2] = 0;
((UCHAR *)(&pExt->srvAddr))[3] = 8;

pExt->srvPort = htons(5888);

// 登录远程服务器
// ...

// 通知父进程,已经准备好,可以 接受SRB  了
KeSetEvent(
&pExt->ThrdSyncEvent,
IO_NO_INCREMENT,
FALSE );

// 无限循环,处理SRB
KdPrint(("Worker thread is ready for processing SRBs ...\n"));
while (TRUE) {

// 如果SRB  已经进入队列,父进程会通知我
KeWaitForSingleObject(
&pExt->SrbListSyncEvent,
Executive,
KernelMode,
FALSE,
0
);

// 从队列中取出SRB
ListEntry = ExInterlockedRemoveHeadList(
&pExt->SrbList,
&pExt->SrbListLock // spin lock
);

// i'll eat all the ready SRBs at one time
while (ListEntry != NULL) {
pSrb = SRB_FROM_ENTRY(ListEntry);
// 处理SRB
if ( !VDiskProcessSrb( pExt, pSrb)) {
break;
}
// 从队列中取出SRB
ListEntry = ExInterlockedRemoveHeadList(
&pExt->SrbList,
&pExt->SrbListLock
);
}
}

DbgPrint(("worker thread terminated\n"));
PsTerminateSystemThread(status);
}

/*
 * Called by VDISK Worker Thread, and deal with all kinds of SRBs
 * Parameters --
 * HwDeviceExtension -- Points to the miniport driver's per-HBA storage area.
 * Srb -- points to the SRB passed in by port driver.
*/
BOOLEAN
VDiskProcessSrb(
IN PVOID HwDeviceExtension,
PSCSI_REQUEST_BLOCK pSrb
)
{
PVDISK_EXTENSION pExt = (PVDISK_EXTENSION)HwDeviceExtension;

// DumpSrb( pSrb);

pSrb->SrbStatus = SRB_STATUS_SUCCESS;
pSrb->ScsiStatus = SCSISTAT_GOOD;

switch (pSrb->Function) {

case SRB_FUNCTION_EXECUTE_SCSI:
// a deivce I/O should be executed on target LU ...
HandleExecuteScsi(HwDeviceExtension, pSrb);
break;

case SRB_FUNCTION_ABORT_COMMAND:
// cancel the SRB pointed by 'Srb->NextSrb' ...
KdPrint(("about message recved.\n"));
HandleAbortCommand(HwDeviceExtension, pSrb);
break;

case SRB_FUNCTION_RESET_BUS:
//
// reset the bus, miniport will receive this request only when a
// request is time-out, and the subsequent request to terminate
// the request is time-out.
// The miniport driver should complete all pending requests and
// must reset the given bus, but HOWTO complete pending requests.
//
KdPrint(("reset bus message received.\n"));
HandleResetBus(HwDeviceExtension, pSrb);
break;

case SRB_FUNCTION_TERMINATE_IO:
// terminate the request pointed by 'Srb->NextSrb', No IDEA ...
break;

case SRB_FUNCTION_RECEIVE_EVENT:
//
// The HBA should be prepared to receive an asynchronous event
// notification from the addressed target. No IDEA ...
//
break;

case SRB_FUNCTION_IO_CONTROL:
HandleIoControl(HwDeviceExtension, pSrb);
break;

//
// in PORT_CONFIGURATION_INFORMATION structure, there is a field named
// 'ResetTargetSupported'. Setting this value to TRUE indicates that the
// miniport driver has the ability to reset a target device in response
// to an 'SRB_FUNCTION_RESET_DEVICE' request from the port driver.
// By default, the value of this member is FALSE.
// Since we set this to FALSE, so we needn't deal with it here ...
//
case SRB_FUNCTION_RESET_DEVICE:

//
// following 2 requests are sent to a miniport driver only if it set
// CachesData to TRUE in the PORT_CONFIGURATION_INFORMATION for the HBA.
// we set the CachesData to FALSE, so needn't deal with them here ...
//
case SRB_FUNCTION_SHUTDOWN:
case SRB_FUNCTION_FLUSH:

default:
pSrb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
break;
}

//
// 处理完SRB  之后,将它们插入完成队列,
// 定时器会处理这些SRB,并把它们返回给PORT
//
ExInterlockedInsertTailList(
&pExt->CompletedSrbList,
&((PSRB_EXTENSION)pSrb->SrbExtension)->ListEntry,
&pExt->CompletedSrbListLock
);

return TRUE;
}

/*
 * Dump SRB
 * Parameters --
 * Srb -- points to the SRB passed in by port driver.
 *
 * SCSI_REQUEST_BLOCK is defined as follows ...
 *
    typedef struct _SCSI_REQUEST_BLOCK {
 USHORT Length;
 UCHAR Function;
 UCHAR SrbStatus;
 UCHAR ScsiStatus;
 UCHAR PathId;
 UCHAR TargetId;
 UCHAR Lun;
 UCHAR QueueTag;
 UCHAR QueueAction;
 UCHAR CdbLength;
 UCHAR SenseInfoBufferLength;
 ULONG SrbFlags;
 ULONG DataTransferLength;
 ULONG TimeOutValue;
 PVOID DataBuffer;
 PVOID SenseInfoBuffer;
 struct _SCSI_REQUEST_BLOCK *NextSrb;
 PVOID OriginalRequest;
 PVOID SrbExtension;
 union {
     ULONG InternalStatus;
     ULONG QueueSortKey;
 };
 UCHAR Cdb[16];
    } SCSI_REQUEST_BLOCK, *PSCSI_REQUEST_BLOCK;
 *
 * and the "Function" is defined as follows
 *
#define SRB_FUNCTION_EXECUTE_SCSI           0x00
#define SRB_FUNCTION_CLAIM_DEVICE         0x01
#define SRB_FUNCTION_IO_CONTROL             0x02
#define SRB_FUNCTION_RECEIVE_EVENT         0x03
#define SRB_FUNCTION_RELEASE_QUEUE         0x04
#define SRB_FUNCTION_ATTACH_DEVICE     0x05
#define SRB_FUNCTION_RELEASE_DEVICE       0x06
#define SRB_FUNCTION_SHUTDOWN             0x07
#define SRB_FUNCTION_FLUSH                   0x08
#define SRB_FUNCTION_ABORT_COMMAND     0x10
#define SRB_FUNCTION_RELEASE_RECOVERY   0x11
#define SRB_FUNCTION_RESET_BUS               0x12
#define SRB_FUNCTION_RESET_DEVICE           0x13
#define SRB_FUNCTION_TERMINATE_IO           0x14
#define SRB_FUNCTION_FLUSH_QUEUE             0x15
#define SRB_FUNCTION_REMOVE_DEVICE       0x16
#define SRB_FUNCTION_WMI                     0x17
#define SRB_FUNCTION_LOCK_QUEUE             0x18
#define SRB_FUNCTION_UNLOCK_QUEUE          0x19
 *
*/
VOID
DumpSrb( IN PSCSI_REQUEST_BLOCK Srb)
{
unsigned int i;

DbgPrint( "\n\n");
DbgPrint( "SRB Function: %02x\nPathId: %02x\nTargetId: %02x\nLUN: %02x\n", \
Srb->Function, Srb->PathId, Srb->TargetId, Srb->Lun);
if ( Srb->Function == SRB_FUNCTION_EXECUTE_SCSI) {
DbgPrint( "CDB: ");
for ( i=0; i<sizeof( Srb->Cdb); i++)
DbgPrint( "%02x ", Srb->Cdb);
}
DbgPrint( "\n\n");
return;
}

/*
 * this is a dispatch according to the Srb->Cdb[0]
 * parameters --
 * HwDeviceExtension -- Points to the miniport driver's per-HBA storage area.
 * Srb -- points to the SRB passed in by port driver.
*/
VOID
HandleExecuteScsi(
IN PVOID  HwDeviceExtension,
IN PSCSI_REQUEST_BLOCK  Srb
)
{
if ( Srb->Cdb[0] >= SRB_HANDLERS_COUNT) {
HandleInvalidRequest(
HwDeviceExtension,
Srb
);
return;
}

SrbHandlerArray[Srb->Cdb[0]](
HwDeviceExtension,
Srb
);

return;
}

VOID
HandleIoControl(
IN PVOID  HwDeviceExtension,
IN PSCSI_REQUEST_BLOCK  Srb
)
{
//
// all the io control sent to the miniport must have a header
// structure of type SRB_IO_CONTROL.
//
PSRB_IO_CONTROL pIoCtrlHeader;
ULONG IoCtrlCode;

KdPrint(("Enter HandleIoControl ...\n"));

pIoCtrlHeader = (PSRB_IO_CONTROL)Srb->DataBuffer;
IoCtrlCode = pIoCtrlHeader->ControlCode;

DumpIoCtrl( pIoCtrlHeader);

// we are not intent to deal with the io control ...
Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;

return;
}

/*
 * Dump SRB
*/
VOID
DumpIoCtrl( IN PSRB_IO_CONTROL pIoCtrlHeader)
{
UCHAR Signature[9];

DbgPrint("Header Length: %08x\n", pIoCtrlHeader->HeaderLength);

ScsiPortMoveMemory( Signature, pIoCtrlHeader->Signature, 8);
Signature[8] = 0;
DbgPrint("Signature: %s\n", Signature);

DbgPrint("Timeout: %08x\n", pIoCtrlHeader->Timeout);
DbgPrint("Control Code: %08x\n", pIoCtrlHeader->ControlCode);
DbgPrint("Additional Length: %08x\n", pIoCtrlHeader->Length);

return;
}

/*
 *
*/
VOID
HandleAbortCommand(
IN PVOID  HwDeviceExtension,
IN PSCSI_REQUEST_BLOCK  Srb
)
{
PSCSI_REQUEST_BLOCK TempSrb;

// get the active request on the target LU ...
TempSrb = ScsiPortGetSrb(
HwDeviceExtension, // Device extension ...
Srb->PathId, // identifies the SCSI bus ..
Srb->TargetId, // identifies the HBA ...
Srb->Lun, // identifies the LU ...
SP_UNTAGGED //
);
    
if ( TempSrb != Srb->NextSrb) {
// the current request is not the same as the one to be canceled ...
Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
goto out;
}

// do abort ...
Srb->SrbStatus = SRB_STATUS_ABORTED;

out:
ReturnFromStartIo( HwDeviceExtension, Srb);

return;
}

/*
 * just call VDiskResetBus ...
*/
VOID
HandleResetBus(
IN PVOID  HwDeviceExtension,
IN PSCSI_REQUEST_BLOCK  Srb
)
{
VDiskResetBus( HwDeviceExtension, Srb->PathId);
return;
}

/*
 * there are 2 things to do when return from HwScsiStartIo,
 * 1st, call ScsiPortNotification with Notification type RequestComplete,
 * 2nd, call ScsiPortNotification with Notification type NextRequest.
*/
VOID
ReturnFromStartIo(
IN PVOID  HwDeviceExtension,
IN PSCSI_REQUEST_BLOCK  Srb
)
{
// 1st, RequestComplete ...
ScsiPortNotification(
RequestComplete,
HwDeviceExtension,
Srb
);

// 2nd, NextRequest ...
ScsiPortNotification(
NextRequest,
HwDeviceExtension,
NULL
);

return;
}

control it, or forget it
terrychen
驱动小牛
驱动小牛
  • 注册日期2002-04-15
  • 最后登录2014-03-13
  • 粉丝0
  • 关注0
  • 积分174分
  • 威望68点
  • 贡献值0点
  • 好评度15点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2004-08-23 17:06
建议你在HwVDiskTimer里面
while( ListEntry!=NULL )
{
pSrb = SRB_FROM_ENTRY(ListEntry);
后面
加一句 pSrb->SrbStatus = SRB_STATUS_SUCCESS;
试试看,看结构应该ScsiPortNotification没有大问题。
你reset bus是偶然出现还是每次有规律的,如果有规律什么时候出现?
cidentifier
驱动牛犊
驱动牛犊
  • 注册日期2003-11-13
  • 最后登录2009-09-20
  • 粉丝1
  • 关注0
  • 积分1分
  • 威望11点
  • 贡献值0点
  • 好评度9点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2004-08-23 18:02
〉建议你在HwVDiskTimer里面
〉while( ListEntry!=NULL )
〉{
〉pSrb = SRB_FROM_ENTRY(ListEntry);
〉后面
〉加一句 pSrb->SrbStatus = SRB_STATUS_SUCCESS;

并不是所有的srb都要返回SRB_STATUS_SUCCESS,有的还要返回SRB_STATUS_INVALID_REQUEST。我把所有的function为SRB_FUNCTION_EXECUTE_SCSI的srb都返回SRB_STATUS_SUCCESS了。

reset bus一般出现在开机的时候,或是读写较大的文件的时候。

现在,我的驱动读写较小的文件时(100K左右)没什么问题,但读几兆大小的文件时就会产生bus reset。

我刚刚又在VDiskStartIo返回前加入了一句
ScsiPortNotification(
  NextRequest,
  HwDeviceExtension,
  NULL
);
也就是miniport每次把srb放入队列后马上从port driver取下一个srb,这样是不是应该限制一下队列的长度,比如最长20?

terrychen,kangzh,你们的网络虚拟磁盘工作正常吗?有没有遇到过我所遇到的bus reset的情况,或在读写大文件时有bus reset发生。
control it, or forget it
cidentifier
驱动牛犊
驱动牛犊
  • 注册日期2003-11-13
  • 最后登录2009-09-20
  • 粉丝1
  • 关注0
  • 积分1分
  • 威望11点
  • 贡献值0点
  • 好评度9点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2004-08-24 14:12
两位老大不在家吗,顶一顶
control it, or forget it
kangzh
驱动小牛
驱动小牛
  • 注册日期2004-03-09
  • 最后登录2012-08-06
  • 粉丝0
  • 关注0
  • 积分4分
  • 威望22点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2004-08-24 14:58
我没有出现过你说的情况,一般出现这个现象大概有几个原因:1,你的数据偏移不对,不能被操作系统识别,2,没有及时反馈,3,其他错误,你的代码太长,呵呵,我检查不出来,你看看我说的数据偏移是否正确
cidentifier
驱动牛犊
驱动牛犊
  • 注册日期2003-11-13
  • 最后登录2009-09-20
  • 粉丝1
  • 关注0
  • 积分1分
  • 威望11点
  • 贡献值0点
  • 好评度9点
  • 原创分0分
  • 专家分0分
9楼#
发布于:2004-08-24 15:26
我的文件系统是ntfs,格式化的时候每块大小设为512字节。读写时,srb的cdb中给出逻辑块号和需要读写多少块,偏移=逻辑块号*512,这样不就可以了吗?
control it, or forget it
Sundsea
驱动老牛
驱动老牛
  • 注册日期2003-05-06
  • 最后登录2012-06-05
  • 粉丝0
  • 关注0
  • 积分2分
  • 威望35点
  • 贡献值0点
  • 好评度15点
  • 原创分0分
  • 专家分0分
10楼#
发布于:2004-08-24 21:00
顶 !!!!!!!!
terrychen
驱动小牛
驱动小牛
  • 注册日期2002-04-15
  • 最后登录2014-03-13
  • 粉丝0
  • 关注0
  • 积分174分
  • 威望68点
  • 贡献值0点
  • 好评度15点
  • 原创分0分
  • 专家分0分
11楼#
发布于:2004-08-25 09:16
我建议你在startio里面这么做,你需要用timercall返回的srb,在startio里面也ScsiPortNotification()回去,不过status改为pending,那些SRB_STATUS_INVALID_REQUEST和你直接返回success的也在startio那里直接ScsiPortNotification()回去,减少出错可能,我觉得还是你ScsiPortNotification()返回有问题。
cidentifier
驱动牛犊
驱动牛犊
  • 注册日期2003-11-13
  • 最后登录2009-09-20
  • 粉丝1
  • 关注0
  • 积分1分
  • 威望11点
  • 贡献值0点
  • 好评度9点
  • 原创分0分
  • 专家分0分
12楼#
发布于:2004-08-26 21:12
let me try, however, thanks!
control it, or forget it
hawkforest
驱动牛犊
驱动牛犊
  • 注册日期2003-11-11
  • 最后登录2005-07-11
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
13楼#
发布于:2004-09-03 10:22
ZwCreateFile   加上 FILE_NO_INTERMEDIATE_BUFFERING
thinking...
johnnyweng
驱动牛犊
驱动牛犊
  • 注册日期2003-06-30
  • 最后登录2004-09-03
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
14楼#
发布于:2004-09-03 11:23
你程式中所用的CompleteRequest是在complete bus reset 呃
cidentifier
驱动牛犊
驱动牛犊
  • 注册日期2003-11-13
  • 最后登录2009-09-20
  • 粉丝1
  • 关注0
  • 积分1分
  • 威望11点
  • 贡献值0点
  • 好评度9点
  • 原创分0分
  • 专家分0分
15楼#
发布于:2004-09-06 17:35
thank u all

在众人的帮助下,我的网络虚拟磁盘基本可以工作了,由于我用的是udp,所以会有丢包,加了超时重发和校验和之后,效果还可以。

我并没有处理bus reset,不过我打算以后处理,johnnyweng的意见很重要。

感谢terrychen和kangzh,我决定散分了,头一次给分,还不知道怎么给,试试看。
control it, or forget it
terrychen
驱动小牛
驱动小牛
  • 注册日期2002-04-15
  • 最后登录2014-03-13
  • 粉丝0
  • 关注0
  • 积分174分
  • 威望68点
  • 贡献值0点
  • 好评度15点
  • 原创分0分
  • 专家分0分
16楼#
发布于:2004-09-06 17:48
great,祝贺你了,不知道你打算resetbus怎么处理?我也一直想处理,可是不知道怎么下手
cidentifier
驱动牛犊
驱动牛犊
  • 注册日期2003-11-13
  • 最后登录2009-09-20
  • 粉丝1
  • 关注0
  • 积分1分
  • 威望11点
  • 贡献值0点
  • 好评度9点
  • 原创分0分
  • 专家分0分
17楼#
发布于:2004-09-10 10:35
bus reset发生时,scsiport一般调用HwScsiResetBus,可以再做一个OOB(带外)队列,当发生bus reset时,让HwScsiResetBus向OOB队列中插入一个消息。

工作线程每次处理一个SRB后,检查OOB队列,如果有BUS RESET发生,则取出SRB队列中的所有SRB,插入SRB完成队列,并利用scsiportnotification以SRB_STATUS_BUS_RESET状态完成每个srb.

你认为可行吗,我还没试,如果你试验有结果,烦请告知

good luck
control it, or forget it
kangzh
驱动小牛
驱动小牛
  • 注册日期2004-03-09
  • 最后登录2012-08-06
  • 粉丝0
  • 关注0
  • 积分4分
  • 威望22点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
18楼#
发布于:2004-09-10 10:53
应该不可以吧,当发生bus reset时,好像系统就已经无法控制了,并且如果那样反馈srb,此时的srb并没有携带正确的数据,反馈给操作系统,一样会有问题的
cidentifier
驱动牛犊
驱动牛犊
  • 注册日期2003-11-13
  • 最后登录2009-09-20
  • 粉丝1
  • 关注0
  • 积分1分
  • 威望11点
  • 贡献值0点
  • 好评度9点
  • 原创分0分
  • 专家分0分
19楼#
发布于:2004-09-10 13:03
在bus reset时,系统仍在运行,并且工作线程仍可以被调度,所以可以插入。

利用scsiportnotification以SRB_STATUS_BUS_RESET状态完成每个srb,应该不需要携带什么数据吧.
control it, or forget it
上一页
游客

返回顶部