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