The DEVICE_QUEUE_NOT_BUSY bug check has a value of 0x00000002.
This bug check appears very infrequently.
This topic is for programmers. If you are a customer who has received a blue screen error code while using your computer, see Troubleshoot blue screen errors.
The !analyze debug extension displays information about the bug check and can be helpful in determining the root cause.
Managing Device Queues
The I/O manager usually (except for FSDs) creates an associated device queue object when a driver calls IoCreateDevice. It also provides IoStartPacket and IoStartNextPacket, which drivers can call to have the I/O manager insert IRPs into the associated device queue or call their StartIo routines.
Consequently, it is rarely necessary (or particularly useful) for a driver to set up its own device queue objects for IRPs. Likely candidates are drivers, such as the SCSI port driver, that must coordinate incoming IRPs from some number of closely coupled class drivers for heterogeneous devices that are serviced through a single controller or bus adapter.
In other words, a driver for a disk array controller is more likely to use a driver-created controller object than to set up supplemental device queue object(s), while a driver for an add-on bus adapter and of a set of class drivers is slightly more likely to use supplemental device queues.
Using Supplemental Device Queues with a StartIo Routine
By calling IoStartPacket and IoStartNextPacket, a driver's Dispatch and DpcForIsr (or CustomDpc) routines synchronize calls to its StartIo routine using the device queue that the I/O manager created when the driver created the device object. For a port driver with a StartIo routine, IoStartPacket and IoStartNextPacket insert and remove IRPs in the device queue for the port driver's shared device controller/adapter. If the port driver also sets up supplemental device queues to hold requests coming in from closely coupled higher-level class drivers, it must "sort" incoming IRPs into its supplemental device queues, usually in its StartIo routine.
The port driver must determine which supplemental device queue each IRP belongs in before trying to insert that IRP into the appropriate queue. A pointer to the target device object is passed with the IRP to the driver's Dispatch routine. The driver should save the pointer for use in "sorting" the incoming IRPs. Note that the device object pointer passed to the StartIo routine is the driver's own device object, which represents the device controller/adapter, so it cannot be used for this purpose.
After queuing any IRPs, the driver programs its shared controller/adapter to carry out the request. Thus, the port driver can process incoming requests for all devices on a first-come, first-served basis until a call to KeInsertDeviceQueue puts an IRP into a particular class driver's device queue.
By using its own device queue for all IRPs to be processed through its StartIo routine, the underlying port driver serializes operations through the shared device (or bus) controller/adapter to all attached devices. By sometimes holding IRPs for each supported device in a separate device queue, this port driver inhibits the processing of IRPs for an already busy device while increasing I/O throughput for every other device that does I/O through its shared hardware.
In response to the call to IoStartPacket from the port driver's Dispatch routine, the I/O manager either calls that driver's StartIo routine immediately or puts the IRP into the device queue associated with the device object for the port driver's shared controller/adapter.
The port driver must maintain its own state information about each of the heterogeneous devices that it services through the shared device controller/adapter.