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 */
ClassSplitRequest(_In_ PDEVICE_OBJECT Fdo,_In_ PIRP Irp,_In_ ULONG MaximumBytes)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 */
ClassIoCompleteAssociated(IN PDEVICE_OBJECT Fdo,IN PIRP Irp,IN PVOID Context)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