A.1.5.1  SCSI Class Driver’s ReleaseQueue Routine

Unless a SCSI class driver ORs the SrbFlags for a given request with SRB_FLAGS_NO_QUEUE_FREEZE, the system port driver freezes a queue for a given logical unit after any of the following:

·A bus reset occurred while the logical unit was executing a request.

·The logical unit returned SCSISTAT_CHECK_CONDITION or SCSISTAT_COMMAND_TERMINATED, which the class driver can find in the SRB’s ScsiStatus member.

·A request was timed out.

·A request was terminated by a bus message command such as SCSIMESS_ABORT.

The port driver indicates that an LU-specific queue has been frozen by returning a request with SRB_STATUS_QUEUE_FROZEN in the SrbStatus member. New requests from the class driver can be inserted into the queue, but no requests are sent to the logical unit except autosense requests.

Freezing the queue under these conditions gives each SCSI class driver an opportunity to analyze an error before other queued jobs are executed. For example, a class driver might need to reinitialize the TID after the controller has been reset, or queued jobs might need to be cancelled if the media has changed. To reinitialize a TID, the driver can send a request with the SrbFlags ORed with SRB_FLAGS_BYPASS_FROZEN_QUEUE.

A ReleaseQueue routine allocates and sets up an IRP and an SRB to either release or flush a frozen queue. The Function member of the SRB must be set to SRB_FUNCTION_RELEASE_QUEUE or SRB_FUNCTION_FLUSH_QUEUE, which both releases a frozen queue and cancels all currently queued requests for the target logical unit. The port driver completes all requests in a flushed queue with their SrbStatus members set to SRB_STATUS_FLUSHED.

A ReleaseQueue routine should allocate memory for an SRB by calling ExAllocatePool with the memory type NonPagedPoolMustSucceed because failing to release a frozen queue makes the device inaccessible.

Note that a class driver’s ReleaseQueue routine is called asynchronously, generally from its IoCompletion routine. A class driver’s IoCompletion routine cannot call ReleaseQueue to flush a queue that is not frozen. However, it can call ReleaseQueue to release an unfrozen queue, and the port driver simply ignores such a request.