1 /*++
2 
3 Copyright (C) Microsoft Corporation, 1991 - 1999
4 
5 Module Name:
6 
7     obsolete.c
8 
9 Abstract:
10 
11     THESE ARE EXPORTED CLASSPNP FUNCTIONS (and their subroutines)
12     WHICH ARE NOW OBSOLETE.
13     BUT WE NEED TO KEEP THEM AROUND FOR LEGACY REASONS.
14 
15 Environment:
16 
17     kernel mode only
18 
19 Notes:
20 
21 
22 Revision History:
23 
24 --*/
25 
26 #include "classp.h"
27 
28 PIRP NTAPI ClassRemoveCScanList(IN PCSCAN_LIST List);
29 VOID NTAPI ClasspInitializeCScanList(IN PCSCAN_LIST List);
30 
31 #ifdef ALLOC_PRAGMA
32     #pragma alloc_text(PAGE, ClassDeleteSrbLookasideList)
33     #pragma alloc_text(PAGE, ClassInitializeSrbLookasideList)
34 #endif
35 
36 typedef struct _CSCAN_LIST_ENTRY {
37     LIST_ENTRY Entry;
38     ULONGLONG BlockNumber;
39 } CSCAN_LIST_ENTRY, *PCSCAN_LIST_ENTRY;
40 
41 /*
42  *  ClassSplitRequest
43  *
44  *      This is a legacy exported function.
45  *      It is called by storage miniport driver that have their own
46  *      StartIo routine when the transfer size is too large for the hardware.
47  *      We map it to our new read/write handler.
48  */
49 VOID NTAPI ClassSplitRequest(IN PDEVICE_OBJECT Fdo, IN PIRP Irp, IN ULONG MaximumBytes)
50 {
51     PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
52     PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
53 
54     if (MaximumBytes > fdoData->HwMaxXferLen) {
55         DBGERR(("ClassSplitRequest - driver requesting split to size that "
56                 "hardware is unable to handle!\n"));
57     }
58 
59     if (MaximumBytes < fdoData->HwMaxXferLen){
60         DBGWARN(("ClassSplitRequest - driver requesting smaller HwMaxXferLen "
61                  "than required"));
62         fdoData->HwMaxXferLen = MAX(MaximumBytes, PAGE_SIZE);
63     }
64 
65     ServiceTransferRequest(Fdo, Irp);
66 }
67 
68 /*++////////////////////////////////////////////////////////////////////////////
69 
70 ClassIoCompleteAssociated()
71 
72 Routine Description:
73 
74     This routine executes when the port driver has completed a request.
75     It looks at the SRB status in the completing SRB and if not success
76     it checks for valid request sense buffer information. If valid, the
77     info is used to update status with more precise message of type of
78     error. This routine deallocates the SRB.  This routine is used for
79     requests which were build by split request.  After it has processed
80     the request it decrements the Irp count in the master Irp.  If the
81     count goes to zero then the master Irp is completed.
82 
83 Arguments:
84 
85     Fdo - Supplies the functional device object which represents the target.
86 
87     Irp - Supplies the Irp which has completed.
88 
89     Context - Supplies a pointer to the SRB.
90 
91 Return Value:
92 
93     NT status
94 
95 --*/
96 NTSTATUS
97 NTAPI
98 ClassIoCompleteAssociated(
99     IN PDEVICE_OBJECT Fdo,
100     IN PIRP Irp,
101     IN PVOID Context
102     )
103 {
104     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
105 
106     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
107     PSCSI_REQUEST_BLOCK srb = Context;
108 
109     PIRP originalIrp = Irp->AssociatedIrp.MasterIrp;
110     LONG irpCount;
111 
112     NTSTATUS status;
113     BOOLEAN retry;
114 
115     DBGWARN(("ClassIoCompleteAssociated is OBSOLETE !"));
116 
117     //
118     // Check SRB status for success of completing request.
119     //
120 
121     if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
122 
123         ULONG retryInterval;
124 
125         DebugPrint((2,"ClassIoCompleteAssociated: IRP %p, SRB %p", Irp, srb));
126 
127         //
128         // Release the queue if it is frozen.
129         //
130 
131         if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
132             ClassReleaseQueue(Fdo);
133         }
134 
135         retry = ClassInterpretSenseInfo(
136                     Fdo,
137                     srb,
138                     irpStack->MajorFunction,
139                     irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ?
140                         irpStack->Parameters.DeviceIoControl.IoControlCode :
141                         0,
142                     MAXIMUM_RETRIES -
143                         ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4),
144                     &status,
145                     &retryInterval);
146 
147         //
148         // If the status is verified required and the this request
149         // should bypass verify required then retry the request.
150         //
151 
152         if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
153             status == STATUS_VERIFY_REQUIRED) {
154 
155             status = STATUS_IO_DEVICE_ERROR;
156             retry = TRUE;
157         }
158 
159         if (retry && ((*(PCHAR*)&irpStack->Parameters.Others.Argument4)--)) {
160 
161             //
162             // Retry request. If the class driver has supplied a StartIo,
163             // call it directly for retries.
164             //
165 
166             DebugPrint((1, "Retry request %p\n", Irp));
167 
168             if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) {
169                 FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb);
170             }
171 
172             RetryRequest(Fdo, Irp, srb, TRUE, retryInterval);
173 
174             return STATUS_MORE_PROCESSING_REQUIRED;
175         }
176 
177     } else {
178 
179         //
180         // Set status for successful request.
181         //
182 
183         status = STATUS_SUCCESS;
184 
185     } // end if (SRB_STATUS(srb->SrbStatus) ...
186 
187     //
188     // Return SRB to list.
189     //
190 
191     if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) {
192         FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb);
193     }
194 
195     ClassFreeOrReuseSrb(fdoExtension, srb);
196 
197     //
198     // Set status in completing IRP.
199     //
200 
201     Irp->IoStatus.Status = status;
202 
203     DebugPrint((2, "ClassIoCompleteAssociated: Partial xfer IRP %p\n", Irp));
204 
205     //
206     // Get next stack location. This original request is unused
207     // except to keep track of the completing partial IRPs so the
208     // stack location is valid.
209     //
210 
211     irpStack = IoGetNextIrpStackLocation(originalIrp);
212 
213     //
214     // Update status only if error so that if any partial transfer
215     // completes with error, then the original IRP will return with
216     // error. If any of the asynchronous partial transfer IRPs fail,
217     // with an error then the original IRP will return 0 bytes transfered.
218     // This is an optimization for successful transfers.
219     //
220 
221     if (!NT_SUCCESS(status)) {
222 
223         originalIrp->IoStatus.Status = status;
224         originalIrp->IoStatus.Information = 0;
225 
226         //
227         // Set the hard error if necessary.
228         //
229 
230         if (IoIsErrorUserInduced(status)) {
231 
232             //
233             // Store DeviceObject for filesystem.
234             //
235 
236             IoSetHardErrorOrVerifyDevice(originalIrp, Fdo);
237         }
238     }
239 
240     //
241     // Decrement and get the count of remaining IRPs.
242     //
243 
244     irpCount = InterlockedDecrement(
245                     (PLONG)&irpStack->Parameters.Others.Argument1);
246 
247     DebugPrint((2, "ClassIoCompleteAssociated: Partial IRPs left %d\n",
248                 irpCount));
249 
250     //
251     // Ensure that the irpCount doesn't go negative.  This was happening once
252     // because classpnp would get confused if it ran out of resources when
253     // splitting the request.
254     //
255 
256     ASSERT(irpCount >= 0);
257 
258     if (irpCount == 0) {
259 
260         //
261         // All partial IRPs have completed.
262         //
263 
264         DebugPrint((2,
265                  "ClassIoCompleteAssociated: All partial IRPs complete %p\n",
266                  originalIrp));
267 
268         if (fdoExtension->CommonExtension.DriverExtension->InitData.ClassStartIo) {
269 
270             //
271             // Acquire a separate copy of the remove lock so the debugging code
272             // works okay and we don't have to hold up the completion of this
273             // irp until after we start the next packet(s).
274             //
275 
276             KIRQL oldIrql;
277             UCHAR uniqueAddress;
278             ClassAcquireRemoveLock(Fdo, (PIRP)&uniqueAddress);
279             ClassReleaseRemoveLock(Fdo, originalIrp);
280             ClassCompleteRequest(Fdo, originalIrp, IO_DISK_INCREMENT);
281 
282             KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
283             IoStartNextPacket(Fdo, FALSE);
284             KeLowerIrql(oldIrql);
285 
286             ClassReleaseRemoveLock(Fdo, (PIRP)&uniqueAddress);
287 
288         } else {
289 
290             //
291             // just complete this request
292             //
293 
294             ClassReleaseRemoveLock(Fdo, originalIrp);
295             ClassCompleteRequest(Fdo, originalIrp, IO_DISK_INCREMENT);
296 
297         }
298 
299     }
300 
301     //
302     // Deallocate IRP and indicate the I/O system should not attempt any more
303     // processing.
304     //
305 
306     IoFreeIrp(Irp);
307     return STATUS_MORE_PROCESSING_REQUIRED;
308 
309 } // end ClassIoCompleteAssociated()
310 
311 /*++////////////////////////////////////////////////////////////////////////////
312 
313 RetryRequest()
314 
315 Routine Description:
316 
317     This is a wrapper around the delayed retry DPC routine, RetryRequestDPC.
318     This reinitializes the necessary fields, queues the request, and sets
319     a timer to call the DPC if someone hasn't already done so.
320 
321 Arguments:
322 
323     DeviceObject - Supplies the device object associated with this request.
324 
325     Irp - Supplies the request to be retried.
326 
327     Srb - Supplies a Pointer to the SCSI request block to be retied.
328 
329     Associated - Indicates this is an associated Irp created by split request.
330 
331     RetryInterval - How long, in seconds, before retrying the request.
332 
333 Return Value:
334 
335     None
336 
337 --*/
338 VOID
339 NTAPI
340 RetryRequest(
341     PDEVICE_OBJECT DeviceObject,
342     PIRP Irp,
343     PSCSI_REQUEST_BLOCK Srb,
344     BOOLEAN Associated,
345     ULONG RetryInterval
346     )
347 {
348     PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
349     PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
350     ULONG transferByteCount;
351 
352     // This function is obsolete but is still used by some of our class drivers.
353     // DBGWARN(("RetryRequest is OBSOLETE !"));
354 
355     //
356     // Determine the transfer count of the request.  If this is a read or a
357     // write then the transfer count is in the Irp stack.  Otherwise assume
358     // the MDL contains the correct length.  If there is no MDL then the
359     // transfer length must be zero.
360     //
361 
362     if (currentIrpStack->MajorFunction == IRP_MJ_READ ||
363         currentIrpStack->MajorFunction == IRP_MJ_WRITE) {
364 
365         transferByteCount = currentIrpStack->Parameters.Read.Length;
366 
367     } else if (Irp->MdlAddress != NULL) {
368 
369         //
370         // Note this assumes that only read and write requests are spilt and
371         // other request do not need to be.  If the data buffer address in
372         // the MDL and the SRB don't match then transfer length is most
373         // likely incorrect.
374         //
375 
376         ASSERT(Srb->DataBuffer == MmGetMdlVirtualAddress(Irp->MdlAddress));
377         transferByteCount = Irp->MdlAddress->ByteCount;
378 
379     } else {
380 
381         transferByteCount = 0;
382     }
383 
384     //
385     // this is a safety net.  this should not normally be hit, since we are
386     // not guaranteed to be an fdoExtension
387     //
388 
389     ASSERT(!TEST_FLAG(Srb->SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
390 
391     //
392     // Reset byte count of transfer in SRB Extension.
393     //
394 
395     Srb->DataTransferLength = transferByteCount;
396 
397     //
398     // Zero SRB statuses.
399     //
400 
401     Srb->SrbStatus = Srb->ScsiStatus = 0;
402 
403     //
404     // Set the no disconnect flag, disable synchronous data transfers and
405     // disable tagged queuing. This fixes some errors.
406     // NOTE: Cannot clear these flags, just add to them
407     //
408 
409     SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DISABLE_DISCONNECT);
410     SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
411     CLEAR_FLAG(Srb->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE);
412 
413     Srb->QueueTag = SP_UNTAGGED;
414 
415     //
416     // Set up major SCSI function.
417     //
418 
419     nextIrpStack->MajorFunction = IRP_MJ_SCSI;
420 
421     //
422     // Save SRB address in next stack for port driver.
423     //
424 
425     nextIrpStack->Parameters.Scsi.Srb = Srb;
426 
427 
428     IoSetCompletionRoutine(Irp, ClassIoComplete, Srb, TRUE, TRUE, TRUE);
429 
430     {
431         LARGE_INTEGER retry100ns;
432         retry100ns.QuadPart = RetryInterval;  // seconds
433         retry100ns.QuadPart *= (LONGLONG)1000 * 1000 * 10;
434 
435         ClassRetryRequest(DeviceObject, Irp, retry100ns);
436     }
437     return;
438 } // end RetryRequest()
439 
440 /*++
441 
442 ClassBuildRequest()
443 
444 Routine Description:
445 
446     This routine allocates an SRB for the specified request then calls
447     ClasspBuildRequestEx to create a SCSI operation to read or write the device.
448 
449     If no SRB is available then the request will be queued to be issued later
450     when requests are available.  Drivers which do not want the queueing
451     behavior should allocate the SRB themselves and call ClasspBuildRequestEx
452     to issue it.
453 
454 Arguments:
455 
456     Fdo - Supplies the functional device object associated with this request.
457 
458     Irp - Supplies the request to be retried.
459 
460 Note:
461 
462     If the IRP is for a disk transfer, the byteoffset field
463     will already have been adjusted to make it relative to
464     the beginning of the disk.
465 
466 
467 Return Value:
468 
469     NT Status
470 
471 --*/
472 NTSTATUS
473 NTAPI
474 ClassBuildRequest(
475     PDEVICE_OBJECT Fdo,
476     PIRP Irp
477     )
478 {
479     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
480 
481     PSCSI_REQUEST_BLOCK srb;
482 
483     // This function is obsolete, but still called by CDROM.SYS .
484     // DBGWARN(("ClassBuildRequest is OBSOLETE !"));
485 
486     //
487     // Allocate an Srb.
488     //
489 
490     srb = ClasspAllocateSrb(fdoExtension);
491 
492     if(srb == NULL) {
493         return STATUS_INSUFFICIENT_RESOURCES;
494     }
495 
496     ClasspBuildRequestEx(fdoExtension, Irp, srb);
497     return STATUS_SUCCESS;
498 
499 } // end ClassBuildRequest()
500 
501 VOID
502 NTAPI
503 ClasspBuildRequestEx(
504     IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
505     IN PIRP Irp,
506     IN PSCSI_REQUEST_BLOCK Srb
507     )
508 
509 /*++
510 
511 ClasspBuildRequestEx()
512 
513 Routine Description:
514 
515     This routine allocates and builds an Srb for a read or write request.
516     The block address and length are supplied by the Irp. The retry count
517     is stored in the current stack for use by ClassIoComplete which
518     processes these requests when they complete.  The Irp is ready to be
519     passed to the port driver when this routine returns.
520 
521 Arguments:
522 
523     FdoExtension - Supplies the device extension associated with this request.
524 
525     Irp - Supplies the request to be issued.
526 
527     Srb - Supplies an SRB to be used for the request.
528 
529 Note:
530 
531     If the IRP is for a disk transfer, the byteoffset field
532     will already have been adjusted to make it relative to
533     the beginning of the disk.
534 
535 
536 Return Value:
537 
538     NT Status
539 
540 --*/
541 {
542     PIO_STACK_LOCATION  currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
543     PIO_STACK_LOCATION  nextIrpStack = IoGetNextIrpStackLocation(Irp);
544 
545     LARGE_INTEGER       startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
546 
547     PCDB                cdb;
548     ULONG               logicalBlockAddress;
549     USHORT              transferBlocks;
550 
551     // This function is obsolete, but still called by CDROM.SYS .
552     // DBGWARN(("ClasspBuildRequestEx is OBSOLETE !"));
553 
554     //
555     // Prepare the SRB.
556     //
557 
558     RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
559 
560     //
561     // Calculate relative sector address.
562     //
563 
564     logicalBlockAddress =
565         (ULONG)(Int64ShrlMod32(startingOffset.QuadPart,
566                                FdoExtension->SectorShift));
567 
568     //
569     // Write length to SRB.
570     //
571 
572     Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
573 
574     //
575     // Set up IRP Address.
576     //
577 
578     Srb->OriginalRequest = Irp;
579 
580     //
581     // Set up target ID and logical unit number.
582     //
583 
584     Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
585     Srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
586 
587     //
588     // Save byte count of transfer in SRB Extension.
589     //
590 
591     Srb->DataTransferLength = currentIrpStack->Parameters.Read.Length;
592 
593     //
594     // Initialize the queue actions field.
595     //
596 
597     Srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
598 
599     //
600     // Queue sort key is Relative Block Address.
601     //
602 
603     Srb->QueueSortKey = logicalBlockAddress;
604 
605     //
606     // Indicate auto request sense by specifying buffer and size.
607     //
608 
609     Srb->SenseInfoBuffer = FdoExtension->SenseData;
610     Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
611 
612     //
613     // Set timeout value of one unit per 64k bytes of data.
614     //
615 
616     Srb->TimeOutValue = ((Srb->DataTransferLength + 0xFFFF) >> 16) *
617                         FdoExtension->TimeOutValue;
618 
619     //
620     // Zero statuses.
621     //
622 
623     Srb->SrbStatus = Srb->ScsiStatus = 0;
624     Srb->NextSrb = 0;
625 
626     //
627     // Indicate that 10-byte CDB's will be used.
628     //
629 
630     Srb->CdbLength = 10;
631 
632     //
633     // Fill in CDB fields.
634     //
635 
636     cdb = (PCDB)Srb->Cdb;
637 
638     transferBlocks = (USHORT)(currentIrpStack->Parameters.Read.Length >>
639                               FdoExtension->SectorShift);
640 
641     //
642     // Move little endian values into CDB in big endian format.
643     //
644 
645     cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte3;
646     cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte2;
647     cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte1;
648     cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte0;
649 
650     cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&transferBlocks)->Byte1;
651     cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&transferBlocks)->Byte0;
652 
653     //
654     // Set transfer direction flag and Cdb command.
655     //
656 
657     if (currentIrpStack->MajorFunction == IRP_MJ_READ) {
658 
659         DebugPrint((3, "ClassBuildRequest: Read Command\n"));
660 
661         SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_IN);
662         cdb->CDB10.OperationCode = SCSIOP_READ;
663 
664     } else {
665 
666         DebugPrint((3, "ClassBuildRequest: Write Command\n"));
667 
668         SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_OUT);
669         cdb->CDB10.OperationCode = SCSIOP_WRITE;
670     }
671 
672     //
673     // If this is not a write-through request, then allow caching.
674     //
675 
676     if (!(currentIrpStack->Flags & SL_WRITE_THROUGH)) {
677 
678         SET_FLAG(Srb->SrbFlags, SRB_FLAGS_ADAPTER_CACHE_ENABLE);
679 
680     } else {
681 
682         //
683         // If write caching is enable then force media access in the
684         // cdb.
685         //
686 
687         if (FdoExtension->DeviceFlags & DEV_WRITE_CACHE) {
688             cdb->CDB10.ForceUnitAccess = TRUE;
689         }
690     }
691 
692     if(TEST_FLAG(Irp->Flags, (IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO))) {
693         SET_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING);
694     }
695 
696     //
697     // OR in the default flags from the device object.
698     //
699 
700     SET_FLAG(Srb->SrbFlags, FdoExtension->SrbFlags);
701 
702     //
703     // Set up major SCSI function.
704     //
705 
706     nextIrpStack->MajorFunction = IRP_MJ_SCSI;
707 
708     //
709     // Save SRB address in next stack for port driver.
710     //
711 
712     nextIrpStack->Parameters.Scsi.Srb = Srb;
713 
714     //
715     // Save retry count in current IRP stack.
716     //
717 
718     currentIrpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
719 
720     //
721     // Set up IoCompletion routine address.
722     //
723 
724     IoSetCompletionRoutine(Irp, ClassIoComplete, Srb, TRUE, TRUE, TRUE);
725 
726 }
727 
728 VOID NTAPI ClasspInsertCScanList(IN PLIST_ENTRY ListHead, IN PCSCAN_LIST_ENTRY Entry)
729 {
730     PCSCAN_LIST_ENTRY t;
731 
732     DBGWARN(("ClasspInsertCScanList is OBSOLETE !"));
733 
734     //
735     // Iterate through the list.  Insert this entry in the sorted list in
736     // order (after other requests for the same block).  At each stop if
737     // blockNumber(Entry) >= blockNumber(t) then move on.
738     //
739 
740     for(t = (PCSCAN_LIST_ENTRY) ListHead->Flink;
741         t != (PCSCAN_LIST_ENTRY) ListHead;
742         t = (PCSCAN_LIST_ENTRY) t->Entry.Flink) {
743 
744         if(Entry->BlockNumber < t->BlockNumber) {
745 
746             //
747             // Set the pointers in entry to the right location.
748             //
749 
750             Entry->Entry.Flink = &(t->Entry);
751             Entry->Entry.Blink = t->Entry.Blink;
752 
753             //
754             // Set the pointers in the surrounding elements to refer to us.
755             //
756 
757             t->Entry.Blink->Flink = &(Entry->Entry);
758             t->Entry.Blink = &(Entry->Entry);
759             return;
760         }
761     }
762 
763     //
764     // Insert this entry at the tail of the list.  If the list was empty this
765     // will also be the head of the list.
766     //
767 
768     InsertTailList(ListHead, &(Entry->Entry));
769 
770 }
771 
772 VOID NTAPI ClassInsertCScanList(IN PCSCAN_LIST List, IN PIRP Irp, IN ULONGLONG BlockNumber, IN BOOLEAN LowPriority)
773 /*++
774 
775 Routine Description:
776 
777     This routine inserts an entry into the CScan list based on it's block number
778     and priority.  It is assumed that the caller is providing synchronization
779     to the access of the list.
780 
781     Low priority requests are always scheduled to run on the next sweep across
782     the disk.  Normal priority requests will be inserted into the current or
783     next sweep based on the standard C-SCAN algorithm.
784 
785 Arguments:
786 
787     List - the list to insert into
788 
789     Irp - the irp to be inserted.
790 
791     BlockNumber - the block number for this request.
792 
793     LowPriority - indicates that the request is lower priority and should be
794                   done on the next sweep across the disk.
795 
796 Return Value:
797 
798     none
799 
800 --*/
801 {
802     PCSCAN_LIST_ENTRY entry = (PCSCAN_LIST_ENTRY)Irp->Tail.Overlay.DriverContext;
803 
804     DBGWARN(("ClassInsertCScanList is OBSOLETE !"));
805 
806     //
807     // Set the block number in the entry.  We need this to keep the list sorted.
808     //
809     entry->BlockNumber = BlockNumber;
810 
811     //
812     // If it's a normal priority request and further down the disk than our
813     // current position then insert this entry into the current sweep.
814     //
815 
816     if ((LowPriority == FALSE) && (BlockNumber > List->BlockNumber)) {
817         ClasspInsertCScanList(&(List->CurrentSweep), entry);
818     } else {
819         ClasspInsertCScanList(&(List->NextSweep), entry);
820     }
821     return;
822 }
823 
824 VOID NTAPI ClassFreeOrReuseSrb(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
825                                IN PSCSI_REQUEST_BLOCK Srb)
826 /*++
827 
828 Routine Description:
829 
830     This routine will attempt to reuse the provided SRB to start a blocked
831     read/write request.
832     If there is no need to reuse the request it will be returned
833     to the SRB lookaside list.
834 
835 Arguments:
836 
837     Fdo - the device extension
838 
839     Srb - the SRB which is to be reused or freed.
840 
841 Return Value:
842 
843     none.
844 
845 --*/
846 
847 {
848     PCOMMON_DEVICE_EXTENSION commonExt = &FdoExtension->CommonExtension;
849     //KIRQL oldIrql;
850     //PIRP blockedIrp;
851 
852     // This function is obsolete, but still called by DISK.SYS .
853     // DBGWARN(("ClassFreeOrReuseSrb is OBSOLETE !"));
854 
855     //
856     // safety net.  this should never occur.  if it does, it's a potential
857     // memory leak.
858     //
859     ASSERT(!TEST_FLAG(Srb->SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
860 
861     if (commonExt->IsSrbLookasideListInitialized){
862         /*
863          *  Put the SRB back in our lookaside list.
864          *
865          *  BUGBUG - Some class drivers use ClassIoComplete
866          *            to complete SRBs that they themselves allocated.
867          *            So we may be putting a "foreign" SRB
868          *            (e.g. with a different pool tag) into our lookaside list.
869          */
870         ClasspFreeSrb(FdoExtension, Srb);
871     }
872     else {
873         DBGERR(("ClassFreeOrReuseSrb: someone is trying to use an uninitialized SrbLookasideList !!!"));
874         ExFreePool(Srb);
875     }
876 }
877 
878 /*++////////////////////////////////////////////////////////////////////////////
879 
880 ClassDeleteSrbLookasideList()
881 
882 Routine Description:
883 
884     This routine deletes a lookaside listhead for srbs, and should be called
885     only during the final removal.
886 
887     If called at other times, the caller is responsible for
888     synchronization and removal issues.
889 
890 Arguments:
891 
892     CommonExtension - Pointer to the CommonExtension containing the listhead.
893 
894 Return Value:
895 
896     None
897 
898 --*/
899 VOID NTAPI ClassDeleteSrbLookasideList(IN PCOMMON_DEVICE_EXTENSION CommonExtension)
900 {
901     PAGED_CODE();
902 
903     // This function is obsolete, but is still called by some of our code.
904     // DBGWARN(("ClassDeleteSrbLookasideList is OBSOLETE !"));
905 
906     if (CommonExtension->IsSrbLookasideListInitialized){
907         CommonExtension->IsSrbLookasideListInitialized = FALSE;
908         ExDeleteNPagedLookasideList(&CommonExtension->SrbLookasideList);
909     }
910     else {
911         DBGWARN(("ClassDeleteSrbLookasideList: attempt to delete uninitialized or freed srblookasidelist"));
912     }
913 }
914 
915 /*++////////////////////////////////////////////////////////////////////////////
916 
917 ClassInitializeSrbLookasideList()
918 
919 Routine Description:
920 
921     This routine sets up a lookaside listhead for srbs, and should be called
922     only from the ClassInitDevice() routine to prevent race conditions.
923 
924     If called from other locations, the caller is responsible for
925     synchronization and removal issues.
926 
927 Arguments:
928 
929     CommonExtension - Pointer to the CommonExtension containing the listhead.
930 
931     NumberElements  - Supplies the maximum depth of the lookaside list.
932 
933 
934 Note:
935 
936     The Windows 2000 version of classpnp did not return any status value from
937     this call.
938 
939 --*/
940 
941 VOID NTAPI ClassInitializeSrbLookasideList(IN PCOMMON_DEVICE_EXTENSION CommonExtension,
942                                            IN ULONG NumberElements)
943 {
944     PAGED_CODE();
945 
946     // This function is obsolete, but still called by DISK.SYS .
947     // DBGWARN(("ClassInitializeSrbLookasideList is OBSOLETE !"));
948 
949     ASSERT(!CommonExtension->IsSrbLookasideListInitialized);
950     if (!CommonExtension->IsSrbLookasideListInitialized){
951 
952         ExInitializeNPagedLookasideList(&CommonExtension->SrbLookasideList,
953                                         NULL,
954                                         NULL,
955                                         NonPagedPool,
956                                         sizeof(SCSI_REQUEST_BLOCK),
957                                         '$scS',
958                                         (USHORT)NumberElements);
959 
960         CommonExtension->IsSrbLookasideListInitialized = TRUE;
961     }
962 
963 }
964 
965 VOID NTAPI ClasspInitializeCScanList(IN PCSCAN_LIST List)
966 {
967     PAGED_CODE();
968     RtlZeroMemory(List, sizeof(CSCAN_LIST));
969     InitializeListHead(&(List->CurrentSweep));
970     InitializeListHead(&(List->NextSweep));
971 }
972 
973 VOID NTAPI ClasspStartNextSweep(PCSCAN_LIST List)
974 {
975     ASSERT(IsListEmpty(&(List->CurrentSweep)) == TRUE);
976 
977     //
978     // If the next sweep is empty then there's nothing to do.
979     //
980 
981     if(IsListEmpty(&(List->NextSweep))) {
982         return;
983     }
984 
985     //
986     // Copy the next sweep list head into the current sweep list head.
987     //
988 
989     List->CurrentSweep = List->NextSweep;
990 
991     //
992     // Unlink the next sweep list from the list head now that we have a copy
993     // of it.
994     //
995 
996     InitializeListHead(&(List->NextSweep));
997 
998     //
999     // Update the next sweep list to point back to the current sweep list head.
1000     //
1001 
1002     List->CurrentSweep.Flink->Blink = &(List->CurrentSweep);
1003     List->CurrentSweep.Blink->Flink = &(List->CurrentSweep);
1004 
1005     return;
1006 }
1007 
1008 PIRP NTAPI ClassRemoveCScanList(IN PCSCAN_LIST List)
1009 {
1010     PCSCAN_LIST_ENTRY entry;
1011 
1012     //
1013     // If the current sweep is empty then promote the next sweep.
1014     //
1015 
1016     if(IsListEmpty(&(List->CurrentSweep))) {
1017         ClasspStartNextSweep(List);
1018     }
1019 
1020     //
1021     // If the current sweep is still empty then we're done.
1022     //
1023 
1024     if(IsListEmpty(&(List->CurrentSweep))) {
1025         return NULL;
1026     }
1027 
1028     //
1029     // Remove the head entry from the current sweep.  Record it's block number
1030     // so that nothing before it on the disk gets into the current sweep.
1031     //
1032 
1033     entry = (PCSCAN_LIST_ENTRY) RemoveHeadList(&(List->CurrentSweep));
1034 
1035     List->BlockNumber = entry->BlockNumber;
1036 
1037     return CONTAINING_RECORD(entry, IRP, Tail.Overlay.DriverContext);
1038 }
1039