Cancel IO request packet by reset device ?

Dear all:
I am writting a disk lower filter driver. This driver will pending all IRP(IO request packet) in a queue, copy new IRP, and then send new IRP to lower device, such as AHCI control driver.And the driver need cancel all submitted IRP when it get emergent notification.
But I am worried that the driver can not cancel the IRP that have been fill into NCQ command List quickly. So I want to cancel these IRP by sending reset device command. And I have sent reset device with two solutions. Unluckly, no IRP will be cancelled and no IRP return status is unsuccess after reset device command has been sent.
Currently, I do not known how to work out this issue. And I except you can give some ideas.
Thanks a lot!

The following is detail of these two solutions(The return vaule are also SUCCESS):

The first way:

context = &deviceExtension->resetContext;

if(context == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}

// Save the device object in the context for use by the completion
// routine.

context->DeviceObject = deviceExtension->Self;
srb = &context->Srb;

// Zero out srb.

RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);

// Write length to SRB.

srb->Length = SCSI_REQUEST_BLOCK_SIZE;

srb->Function = SRB_FUNCTION_RESET_DEVICE;

// Build the asynchronous request to be sent to the port driver.
// Since this routine is called from a DPC the IRP should always be
// available.

irp = IoAllocateIrp(deviceExtension->Self->StackSize, FALSE);

if(irp == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}

IoSetCompletionRoutine(irp,
(PIO_COMPLETION_ROUTINE)ResetDevcieCompletion,
context,
TRUE,
TRUE,
TRUE);

irpStack = IoGetNextIrpStackLocation(irp);

irpStack->MajorFunction = IRP_MJ_SCSI;

srb->OriginalRequest = irp;

// Store the SRB address in next stack for port driver.
irpStack->Parameters.Scsi.Srb = srb;

// Call the port driver with the IRP.
IoCallDriver(deviceExtension->NextLowerDriver, irp);

The second way:

ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);

// Added by ZYQ. Check sleep flag again before sending unload command.
if(deviceExtension->PowerSleepOperationInProgress)
return STATUS_SUCCESS;
// Build the asynchronous request to be sent to the port driver.
// Since this routine is called from a DPC the IRP should always be
// available.

irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);

if(irp == NULL) {

#if DBG
#if UNLOAD_TESTING
deviceExtension->uloadCount–;
#endif
#endif
return STATUS_INSUFFICIENT_RESOURCES;
}

context = &deviceExtension->resetContextATA;
RtlZeroMemory(context, sizeof(COMPLETION_CONTEXT_ATACMD));

// Save the device object in the context for use by the completion
// routine.
context->DeviceObject = DeviceObject;

pApte = &context->Apte;

pApte->Length = sizeof(ATA_PASS_THROUGH_EX);
pApte->AtaFlags = ATA_FLAGS_DRDY_REQUIRED; // ATA_FLAGS_DATA_OUT;

pApte->DataTransferLength = 0;

pApte->TimeOutValue = DEFAULT_ATA_PASS_THROUGH_TIMEOUT;
pApte->DataBufferOffset = sizeof(ATA_PASS_THROUGH_EX);

{
pApte->CurrentTaskFile[0] = 0x00; // na
pApte->CurrentTaskFile[1] = 0x00; // na
pApte->CurrentTaskFile[2] = 0x00; // na
pApte->CurrentTaskFile[3] = 0x00; // na
pApte->CurrentTaskFile[4] = 0x00; // na
pApte->CurrentTaskFile[5] = 0xA0; // Drive Select(A0:Master,B0:Slave)
pApte->CurrentTaskFile[6] = 0x08; // IDE_COMMAND_RESET_DEVICE
}

// Set complete routine.
IoSetCompletionRoutine(irp,
ResetDevcieCompletion,
context,
TRUE,
TRUE,
TRUE);

// Fill with next irp stack.
irpStack = IoGetNextIrpStackLocation(irp);
irpStack->DeviceObject = DeviceObject;
irpStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_ATA_PASS_THROUGH;

irpStack->Parameters.DeviceIoControl.InputBufferLength = sizeof(ATA_PASS_THROUGH_EX)+sizeof(context->DataBuffer);
irpStack->Parameters.DeviceIoControl.OutputBufferLength = sizeof(ATA_PASS_THROUGH_EX)+sizeof(context->DataBuffer);

// Setup system buffer.
irp->AssociatedIrp.SystemBuffer = pApte;

DebugPrintEx((2, “%d:ResetDeviceByAtaCmd: DeviceObject %08X, Irp %08X, Context %08x\n”,
deviceExtension->HddNo, deviceExtension->NextLowerDriver, irp, context));

// Call the port driver with the IRP.
return IoCallDriver(deviceExtension->NextLowerDriver, irp);

What is the need in all of this? just wait for the submitted IRPs to complete instead.
Cancellation is to avoid nondeterministic delays, and disk delay is deterministic - like 10ms or such.

Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

<zhou_5129327> wrote in message news:xxxxx@ntdev…
> Dear all:
> I am writting a disk lower filter driver. This driver will pending all IRP(IO request packet) in a queue, copy new IRP, and then send new IRP to lower device, such as AHCI control driver.And the driver need cancel all submitted IRP when it get emergent notification.
> But I am worried that the driver can not cancel the IRP that have been fill into NCQ command List quickly. So I want to cancel these IRP by sending reset device command. And I have sent reset device with two solutions. Unluckly, no IRP will be cancelled and no IRP return status is unsuccess after reset device command has been sent.
> Currently, I do not known how to work out this issue. And I except you can give some ideas.
> Thanks a lot!
>
> The following is detail of these two solutions(The return vaule are also SUCCESS):
>
>
> The first way:
>
> context = &deviceExtension->resetContext;
>
> if(context == NULL) {
> return STATUS_INSUFFICIENT_RESOURCES;
> }
>
>
> // Save the device object in the context for use by the completion
> // routine.
>
> context->DeviceObject = deviceExtension->Self;
> srb = &context->Srb;
>
> // Zero out srb.
>
> RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
>
>
> // Write length to SRB.
>
> srb->Length = SCSI_REQUEST_BLOCK_SIZE;
>
> srb->Function = SRB_FUNCTION_RESET_DEVICE;
>
> // Build the asynchronous request to be sent to the port driver.
> // Since this routine is called from a DPC the IRP should always be
> // available.
>
> irp = IoAllocateIrp(deviceExtension->Self->StackSize, FALSE);
>
> if(irp == NULL) {
> return STATUS_INSUFFICIENT_RESOURCES;
> }
>
>
> IoSetCompletionRoutine(irp,
> (PIO_COMPLETION_ROUTINE)ResetDevcieCompletion,
> context,
> TRUE,
> TRUE,
> TRUE);
>
> irpStack = IoGetNextIrpStackLocation(irp);
>
> irpStack->MajorFunction = IRP_MJ_SCSI;
>
> srb->OriginalRequest = irp;
>
> // Store the SRB address in next stack for port driver.
> irpStack->Parameters.Scsi.Srb = srb;
>
>
> // Call the port driver with the IRP.
> IoCallDriver(deviceExtension->NextLowerDriver, irp);
>
>
>
> The second way:
>
> ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
>
> // Added by ZYQ. Check sleep flag again before sending unload command.
> if(deviceExtension->PowerSleepOperationInProgress)
> return STATUS_SUCCESS;
> // Build the asynchronous request to be sent to the port driver.
> // Since this routine is called from a DPC the IRP should always be
> // available.
>
>
> irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
>
> if(irp == NULL) {
>
> #if DBG
> #if UNLOAD_TESTING
> deviceExtension->uloadCount–;
> #endif
> #endif
> return STATUS_INSUFFICIENT_RESOURCES;
> }
>
> context = &deviceExtension->resetContextATA;
> RtlZeroMemory(context, sizeof(COMPLETION_CONTEXT_ATACMD));
>
> // Save the device object in the context for use by the completion
> // routine.
> context->DeviceObject = DeviceObject;
>
>
> pApte = &context->Apte;
>
> pApte->Length = sizeof(ATA_PASS_THROUGH_EX);
> pApte->AtaFlags = ATA_FLAGS_DRDY_REQUIRED; // ATA_FLAGS_DATA_OUT;
>
>
> pApte->DataTransferLength = 0;
>
> pApte->TimeOutValue = DEFAULT_ATA_PASS_THROUGH_TIMEOUT;
> pApte->DataBufferOffset = sizeof(ATA_PASS_THROUGH_EX);
>
>
> {
> pApte->CurrentTaskFile[0] = 0x00; // na
> pApte->CurrentTaskFile[1] = 0x00; // na
> pApte->CurrentTaskFile[2] = 0x00; // na
> pApte->CurrentTaskFile[3] = 0x00; // na
> pApte->CurrentTaskFile[4] = 0x00; // na
> pApte->CurrentTaskFile[5] = 0xA0; // Drive Select(A0:Master,B0:Slave)
> pApte->CurrentTaskFile[6] = 0x08; // IDE_COMMAND_RESET_DEVICE
> }
>
> // Set complete routine.
> IoSetCompletionRoutine(irp,
> ResetDevcieCompletion,
> context,
> TRUE,
> TRUE,
> TRUE);
>
> // Fill with next irp stack.
> irpStack = IoGetNextIrpStackLocation(irp);
> irpStack->DeviceObject = DeviceObject;
> irpStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
> irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_ATA_PASS_THROUGH;
>
> irpStack->Parameters.DeviceIoControl.InputBufferLength = sizeof(ATA_PASS_THROUGH_EX)+sizeof(context->DataBuffer);
> irpStack->Parameters.DeviceIoControl.OutputBufferLength = sizeof(ATA_PASS_THROUGH_EX)+sizeof(context->DataBuffer);
>
> // Setup system buffer.
> irp->AssociatedIrp.SystemBuffer = pApte;
>
>
> DebugPrintEx((2, “%d:ResetDeviceByAtaCmd: DeviceObject %08X, Irp %08X, Context %08x\n”,
> deviceExtension->HddNo, deviceExtension->NextLowerDriver, irp, context));
>
>
> // Call the port driver with the IRP.
> return IoCallDriver(deviceExtension->NextLowerDriver, irp);
></zhou_5129327>

Dear Maxim S. Shatskih:
I want to send unload command to park hdd head when driver get shock message. But AMD AHCI driver and Intel AHCI driver will finish all other IRP and then execute unload command. So driver need cancel all IRP quickly before sending unload command.

Driver will cost much time if driver just waits for all IRP to be completed somtime(Every AHCI port has 32 slots, so they may cost about 320ms if all of the slots have be fill with DMA transfer).

“I want to send unload command to park hdd head when driver get shock
message.”

Don’t disks do that by themselves?

But if you insist, send a SRB_FUNCTION_FLUSH_QUEUE SRB, then send your head park request with SRB_FLAGS_BYPASS_FROZEN_QUEUE, just in case.

Dear Alex Grig:
Thanks for your infromation!

Don’t disks do that by themselves?
Yes, current AHCI driver can not park the head to original safe location when sheck sensor(our own device)gets shock message.

But if you insist, send a SRB_FUNCTION_FLUSH_QUEUE SRB, then send your head park
request with SRB_FLAGS_BYPASS_FROZEN_QUEUE, just in case.
An SRB with its Function member set to SRB_FUNCTION_FLUSH tells the miniport driver to transfer data cached in the HBA, usually to a disk. The miniport driver must hold on to the flush request until all cached data has been transferred and, then, complete the flush request. So I
think HBA will cost much time to complete all transfers when many trasnfer requests are cached
in the HBA. But I will try your advice. Thanks!

Currently, I need send special command to park the disk head to safe location. Here is the code:

irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);

if(irp == NULL) {

#if DBG
#if UNLOAD_TESTING
deviceExtension->uloadCount–;
#endif
#endif
return STATUS_INSUFFICIENT_RESOURCES;
}

context = &deviceExtension->UnloadImmediateContextIoctl;
RtlZeroMemory(context, sizeof(UNLOAD_IMMEDIATE_CONTEXT_IOCTL));

// Save the device object in the context for use by the completion
// routine.
context->DeviceObject = DeviceObject;
context->Irp = irp;

pApte = &context->Apte;

pApte->Length = sizeof(ATA_PASS_THROUGH_EX);
pApte->AtaFlags = ATA_FLAGS_DRDY_REQUIRED; // ATA_FLAGS_DATA_OUT;

// DataTransferLength should be 0 because we don’t need data trasfer for UIC.
// If specified the length, it seems that iMSM need additional time to handle this command,
// and it will cause to the interrupt of USB data transfer on iMSM system.

// pApte->DataTransferLength = sizeof(context->DataBuffer);
pApte->DataTransferLength = 0;

pApte->TimeOutValue = DEFAULT_ATA_PASS_THROUGH_TIMEOUT;
pApte->DataBufferOffset = sizeof(ATA_PASS_THROUGH_EX);

// Fill with current task file.
if( deviceExtension->UicSupported )
{
pApte->CurrentTaskFile[0] = 0x44; // ‘D’
pApte->CurrentTaskFile[1] = 0x00; // na
pApte->CurrentTaskFile[2] = 0x4C; // ‘L’
pApte->CurrentTaskFile[3] = 0x4E; // ‘N’
pApte->CurrentTaskFile[4] = 0x55; // ‘U’
pApte->CurrentTaskFile[5] = 0xA0; // Drive Select(A0:Master,B0:Slave)
pApte->CurrentTaskFile[6] = 0xE1; // IDLE IMMEDIATE Command
}
else
{
pApte->CurrentTaskFile[0] = 0x00; // na
pApte->CurrentTaskFile[1] = 0x00; // na
pApte->CurrentTaskFile[2] = 0x00; // na
pApte->CurrentTaskFile[3] = 0x00; // na
pApte->CurrentTaskFile[4] = 0x00; // na
pApte->CurrentTaskFile[5] = 0xA0; // Drive Select(A0:Master,B0:Slave)
pApte->CurrentTaskFile[6] = 0xE0; // IDE_COMMAND_STANDBY_IMMEDIATE
}

// Set complete routine.
IoSetCompletionRoutine(irp,
ThpdrvUnloadImmediatCompletion,
context,
TRUE,
TRUE,
TRUE);

// Fill with next irp stack.
irpStack = IoGetNextIrpStackLocation(irp);
irpStack->DeviceObject = DeviceObject;
irpStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_ATA_PASS_THROUGH;

irpStack->Parameters.DeviceIoControl.InputBufferLength = sizeof(ATA_PASS_THROUGH_EX)+sizeof(context->DataBuffer);
irpStack->Parameters.DeviceIoControl.OutputBufferLength = sizeof(ATA_PASS_THROUGH_EX)+sizeof(context->DataBuffer);

// Setup system buffer.
irp->AssociatedIrp.SystemBuffer = pApte;

DebugPrintEx((MSG, “%d:ThpdrvPerformUnloadImmediateWithIoctl: DeviceObject %08X, Irp %08X, Context %08x\n”,
deviceExtension->HddNo, deviceExtension->NextLowerDriver, irp, context));

// Call the port driver with the IRP.
return IoCallDriver(deviceExtension->NextLowerDriver, irp);

Dear Alex Grig:
Sorry! SRB_FUNCTION_FLUSH_QUEUE does not flush transfer data cached in the HBA. It flushes the host adapter cache and then completes all requests in its internal queue with their SrbStatus members set to SRB_STATUS_REQUEST_FLUSHED. But I am still worried if it can cancel data transfers that have been filled in Comnad slots!
And I will try your advice, thanks a lot!

> -----Original Message-----

From: xxxxx@lists.osr.com [mailto:bounce-467261-
xxxxx@lists.osr.com] On Behalf Of zhou_5129327@163.com
Sent: Wednesday, July 27, 2011 4:10 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Cancel IO request packet by reset device ?

Dear Alex Grig:
Sorry! SRB_FUNCTION_FLUSH_QUEUE does not flush transfer data cached
in the HBA. It flushes the host adapter cache and then completes all
requests in its internal queue with their SrbStatus members set to
SRB_STATUS_REQUEST_FLUSHED. But I am still worried if it can cancel data
transfers that have been filled in Comnad slots!
And I will try your advice, thanks a lot!

If you flush your cache before you park the heads in response to detecting
that your device is falling, you are very likely still going to be flushing
when your device hits whatever it is falling on. Your device should PARK
without doing anything else at all.

Phil

Philip D. Barila

> I want to send unload command to park hdd head when driver get shock message.

Send the following:

  • freeze queue
  • UNLOAD with “bypass frozen queue”
  • when the shock is over - unfreeze the queue.

Note that this will have more priority then the port driver’s queued IRPs not yet delivered to hardware.

As about the NCQ hardware - can NCQ SATA protocol support cancellation? if not - then I think you’re in trouble.


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

Dear Phil Barila:
If you flush your cache before you park the heads in response to detecting
that your device is falling, you are very likely still going to be flushing
when your device hits whatever it is falling on. Your device should PARK
without doing anything else at all.

Yes, I want to do as your advice. But Intel and Amd tell us that their AHCI driver
will execute unload command after all of DMA transfer have been completed. So I need …

Dear Maxim S. Shatskih:

  • freeze queue
  • UNLOAD with “bypass frozen queue”
  • when the shock is over - unfreeze the queue.

Note that this will have more priority then the port driver’s queued IRPs not
yet delivered to hardware.

This may be good idea. But I am worried that if the disk head can move to safety location?

As about the NCQ hardware - can NCQ SATA protocol support cancellation? if not -
then I think you’re in trouble.

Yes, I think this is a big problem. I have tryed to find a command to cancel transfer requests
that have been filled to command slots.
MSACHI sample code(WDK 7600) has cancel function. But I do not known how to access this function currently. The following is the related code:

ChannelInterface->IdeHwReset = AhciHwReset;

BOOLEAN
AhciHwReset (
IN PVOID ChannelExtension
)
{
/*++
AtaHwReset can be called even if the miniport driver is not ready for another request.
The miniport driver should complete all pending requests and must reset the given channel.

It assumes:
nothing

Called by:
external

It performs:
COMRESET along with completing commands to be retried and restoring settings that may be be persistent across a COMRESET

(overview)
1 Initialize
2 Perform COMReset
3 Complete all outstanding commands
4 Restore device configuration

Affected Variables/Registers:
SCTL, CI, SACT
Channel Extension

Return Values:
AtaHwReset return TRUE if the reset operation succeeded.
If the reset failed the routine must return FALSE.
–*/
PAHCI_CHANNEL_EXTENSION channelExtension;
PSLOT_CONTENT slotContent;
UCHAR i;
UCHAR numberOfCommandsOutstanding;

//1.1 Initialize Variables
channelExtension = (PAHCI_CHANNEL_EXTENSION) ChannelExtension;
#ifdef ENABLE_HISTORY_LOG
RecordExecutionHistory(channelExtension, 0x00000006);//AhciHwReset
#endif

//2.1 Stop the channel
if (! P_NotRunning(channelExtension, channelExtension->Px, TRUE) ) {
return FALSE;
}
//2.2 Perform the COMRESET
AhciCOMRESET(channelExtension, channelExtension->Px);

//3.1 Complete all outstanding commands for retry
channelExtension->SlotManager.CommandsToComplete |=
(channelExtension->SlotManager.NCQueueSlice |
channelExtension->SlotManager.NormalQueueSlice |
channelExtension->SlotManager.SingleIoSlice |
channelExtension->SlotManager.CommandsIssued);
channelExtension->SlotManager.CommandsIssued = 0;
channelExtension->SlotManager.NCQueueSlice = 0;
channelExtension->SlotManager.NormalQueueSlice = 0;
channelExtension->SlotManager.SingleIoSlice = 0;
channelExtension->SlotManager.HighPriorityAttribute = 0;

numberOfCommandsOutstanding = 0;
for (i=0; i <= (channelExtension->CAP.NCS); i++)
{
if( ( channelExtension->SlotManager.CommandsToComplete & (1 << i) ) > 0)
{
numberOfCommandsOutstanding++;
}
}

if (numberOfCommandsOutstanding > 1)
{
for (i=0; i <= (channelExtension->CAP.NCS); i++)
{
if( ( channelExtension->SlotManager.CommandsToComplete & (1 << i) ) > 0)
{
slotContent = &channelExtension->Slot[i];
if (slotContent->Irb->Function == IRB_FUNCTION_ATA_IDENTIFY)
{
slotContent->Irb->IrbStatus = IRB_STATUS_BUSY;
}
}
}
}

AhciCompleteIssuedIRBs(channelExtension, IRB_STATUS_BUS_RESET);

//4.1 Restore device configuration
RestorePreservedSettings(ChannelExtension);
//2.3 Start the channel
P_Running_StartAttempt(ChannelExtension);

// record that the channel is reset.
RecordExecutionHistory(channelExtension, 0x10000006);//Exit AhciHwReset

return TRUE;
}

Dear Maxim S. Shatskih:

----- freeze queue
----- UNLOAD with “bypass frozen queue”
----- when the shock is over - unfreeze the queue.

—Note that this will have more priority then the port driver’s queued IRPs not
—yet delivered to hardware.

This may be good idea. But I am worried that if the disk head can move to
safety location?

—As about the NCQ hardware - can NCQ SATA protocol support cancellation? if not -

—then I think you’re in trouble.

Yes, I think this is a big problem. I have tryed to find a command to cancel
transfer requests that have been filled to command slots.
MSACHI sample code(WDK 7600) has cancel function. But I do not known how to
access this function currently. The following is the related code:

ChannelInterface->IdeHwReset = AhciHwReset;

BOOLEAN
AhciHwReset (
IN PVOID ChannelExtension
)
{
/*++
AtaHwReset can be called even if the miniport driver is not ready for another
request.
The miniport driver should complete all pending requests and must reset the
given channel.

It assumes:
nothing

Called by:
external

It performs:
COMRESET along with completing commands to be retried and restoring settings
that may be be persistent across a COMRESET

(overview)
1 Initialize
2 Perform COMReset
3 Complete all outstanding commands
4 Restore device configuration

Affected Variables/Registers:
SCTL, CI, SACT
Channel Extension

Return Values:
AtaHwReset return TRUE if the reset operation succeeded.
If the reset failed the routine must return FALSE.
–*/
PAHCI_CHANNEL_EXTENSION channelExtension;
PSLOT_CONTENT slotContent;
UCHAR i;
UCHAR numberOfCommandsOutstanding;

//1.1 Initialize Variables
channelExtension = (PAHCI_CHANNEL_EXTENSION) ChannelExtension;
#ifdef ENABLE_HISTORY_LOG
RecordExecutionHistory(channelExtension, 0x00000006);//AhciHwReset
#endif

//2.1 Stop the channel
if (! P_NotRunning(channelExtension, channelExtension->Px, TRUE) ) {
return FALSE;
}
//2.2 Perform the COMRESET
AhciCOMRESET(channelExtension, channelExtension->Px);

//3.1 Complete all outstanding commands for retry
channelExtension->SlotManager.CommandsToComplete |=
(channelExtension->SlotManager.NCQueueSlice |
channelExtension->SlotManager.NormalQueueSlice |
channelExtension->SlotManager.SingleIoSlice |
channelExtension->SlotManager.CommandsIssued);
channelExtension->SlotManager.CommandsIssued = 0;
channelExtension->SlotManager.NCQueueSlice = 0;
channelExtension->SlotManager.NormalQueueSlice = 0;
channelExtension->SlotManager.SingleIoSlice = 0;
channelExtension->SlotManager.HighPriorityAttribute = 0;

numberOfCommandsOutstanding = 0;
for (i=0; i <= (channelExtension->CAP.NCS); i++)
{
if( ( channelExtension->SlotManager.CommandsToComplete & (1 << i) ) > 0)

{
numberOfCommandsOutstanding++;
}
}

if (numberOfCommandsOutstanding > 1)
{
for (i=0; i <= (channelExtension->CAP.NCS); i++)
{
if( ( channelExtension->SlotManager.CommandsToComplete & (1 << i) )

{
slotContent = &channelExtension->Slot[i];
if (slotContent->Irb->Function == IRB_FUNCTION_ATA_IDENTIFY)
{
slotContent->Irb->IrbStatus = IRB_STATUS_BUSY;
}
}
}
}

AhciCompleteIssuedIRBs(channelExtension, IRB_STATUS_BUS_RESET);

//4.1 Restore device configuration
RestorePreservedSettings(ChannelExtension);
//2.3 Start the channel
P_Running_StartAttempt(ChannelExtension);

// record that the channel is reset.
RecordExecutionHistory(channelExtension, 0x10000006);//Exit AhciHwReset

return TRUE;
}

> MSACHI sample code(WDK 7600) has cancel function. But I do not known how to

access this function currently. The following is the related code:

Try IOCTL_STORAGE_RESET_BUS


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

Dear Maxim S. Shatskih

Try IOCTL_STORAGE_RESET_BUS

IOCTL_STORAGE_RESET_BUS is a device IO control code, it is used for Application send I/O request to driver device. And I think the driver need send a srb with a function, SRB_FUNCTION_RESET_BUS, to AHCI driver. The IOCTL_STORAGE_RESET_BUS request will be completed when this srb is fininshed by the AHCI driver. Is there any question about my understanding?

Currently, we have tested srb with SRB_FUNCTION_RESET_DEVICE. But not IRP can ben cancalled or failed. And we will test srb with SRB_FUNCTION_RESET_BUS.