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