Sync with trunk head.
[reactos.git] / drivers / storage / class / class2 / class2.c
1 /*
2 * PROJECT: ReactOS Storage Stack
3 * LICENSE: DDK - see license.txt in the root dir
4 * FILE: drivers/storage/class2/class2.c
5 * PURPOSE: SCSI Class driver routines
6 * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK
7 */
8
9 #include <ntddk.h>
10 #include <ntdddisk.h>
11 #include <scsi.h>
12 #include <include/class2.h>
13 #include <stdio.h>
14
15 //#define NDEBUG
16 #include <debug.h>
17
18 #ifdef ALLOC_PRAGMA
19 #pragma alloc_text(PAGE, ScsiClassGetInquiryData)
20 #pragma alloc_text(PAGE, ScsiClassInitialize)
21 #pragma alloc_text(PAGE, ScsiClassGetCapabilities)
22 #pragma alloc_text(PAGE, ScsiClassSendSrbSynchronous)
23 #pragma alloc_text(PAGE, ScsiClassClaimDevice)
24 #pragma alloc_text(PAGE, ScsiClassSendSrbAsynchronous)
25 #endif
26
27
28 #define INQUIRY_DATA_SIZE 2048
29 #define START_UNIT_TIMEOUT 30
30
31 NTSTATUS
32 NTAPI
33 ScsiClassCreateClose(
34 IN PDEVICE_OBJECT DeviceObject,
35 IN PIRP Irp
36 );
37
38 NTSTATUS
39 NTAPI
40 ScsiClassReadWrite(
41 IN PDEVICE_OBJECT DeviceObject,
42 IN PIRP Irp
43 );
44
45 NTSTATUS
46 NTAPI
47 ScsiClassDeviceControlDispatch(
48 PDEVICE_OBJECT DeviceObject,
49 PIRP Irp
50 );
51
52 NTSTATUS
53 NTAPI
54 ScsiClassDeviceControl(
55 PDEVICE_OBJECT DeviceObject,
56 PIRP Irp
57 );
58
59 NTSTATUS
60 NTAPI
61 ScsiClassInternalIoControl (
62 IN PDEVICE_OBJECT DeviceObject,
63 IN PIRP Irp
64 );
65
66 NTSTATUS
67 NTAPI
68 ScsiClassShutdownFlush(
69 IN PDEVICE_OBJECT DeviceObject,
70 IN PIRP Irp
71 );
72
73 NTSTATUS
74 NTAPI
75 DriverEntry(
76 IN PDRIVER_OBJECT DriverObject,
77 IN PUNICODE_STRING RegistryPath
78 );
79
80 //
81 // Class internal routines
82 //
83
84
85 VOID
86 NTAPI
87 RetryRequest(
88 PDEVICE_OBJECT DeviceObject,
89 PIRP Irp,
90 PSCSI_REQUEST_BLOCK Srb,
91 BOOLEAN Associated
92 );
93
94 VOID
95 NTAPI
96 StartUnit(
97 IN PDEVICE_OBJECT DeviceObject
98 );
99
100 NTSTATUS
101 NTAPI
102 ClassIoCompletion(
103 IN PDEVICE_OBJECT DeviceObject,
104 IN PIRP Irp,
105 IN PVOID Context
106 );
107
108 NTSTATUS
109 NTAPI
110 ClassCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,
111 IN PIRP Irp,
112 IN PVOID Context);
113
114
115 NTSTATUS
116 NTAPI
117 DriverEntry(
118 IN PDRIVER_OBJECT DriverObject,
119 IN PUNICODE_STRING RegistryPath
120 )
121 {
122 return STATUS_SUCCESS;
123 }
124
125 \f
126 ULONG
127 NTAPI
128 ScsiClassInitialize(
129 IN PVOID Argument1,
130 IN PVOID Argument2,
131 IN PCLASS_INIT_DATA InitializationData
132 )
133
134 /*++
135
136 Routine Description:
137
138 This routine is called by a class driver during its
139 DriverEntry routine to initialize the driver.
140
141 Arguments:
142
143 Argument1 - Driver Object.
144 Argument2 - Registry Path.
145 InitializationData - Device-specific driver's initialization data.
146
147 Return Value:
148
149 A valid return code for a DriverEntry routine.
150
151 --*/
152
153 {
154
155
156 PDRIVER_OBJECT DriverObject = Argument1;
157 ULONG portNumber = 0;
158 PDEVICE_OBJECT portDeviceObject;
159 NTSTATUS status;
160 STRING deviceNameString;
161 UNICODE_STRING unicodeDeviceName;
162 PFILE_OBJECT fileObject;
163 CCHAR deviceNameBuffer[256];
164 BOOLEAN deviceFound = FALSE;
165
166 DebugPrint((3,"\n\nSCSI Class Driver\n"));
167
168 //
169 // Validate the length of this structure. This is effectively a
170 // version check.
171 //
172
173 if (InitializationData->InitializationDataSize > sizeof(CLASS_INIT_DATA)) {
174
175 DebugPrint((0,"ScsiClassInitialize: Class driver wrong version\n"));
176 return (ULONG) STATUS_REVISION_MISMATCH;
177 }
178
179 //
180 // Check that each required entry is not NULL. Note that Shutdown, Flush and Error
181 // are not required entry points.
182 //
183
184 if ((!InitializationData->ClassFindDevices) ||
185 (!InitializationData->ClassDeviceControl) ||
186 (!((InitializationData->ClassReadWriteVerification) ||
187 (InitializationData->ClassStartIo)))) {
188
189 DebugPrint((0,
190 "ScsiClassInitialize: Class device-specific driver missing required entry\n"));
191
192 return (ULONG) STATUS_REVISION_MISMATCH;
193 }
194
195 //
196 // Update driver object with entry points.
197 //
198
199 DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiClassCreateClose;
200 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiClassCreateClose;
201 DriverObject->MajorFunction[IRP_MJ_READ] = ScsiClassReadWrite;
202 DriverObject->MajorFunction[IRP_MJ_WRITE] = ScsiClassReadWrite;
203 DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiClassInternalIoControl;
204 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiClassDeviceControlDispatch;
205 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = ScsiClassShutdownFlush;
206 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = ScsiClassShutdownFlush;
207
208 if (InitializationData->ClassStartIo) {
209 DriverObject->DriverStartIo = InitializationData->ClassStartIo;
210 }
211
212 //
213 // Open port driver controller device objects by name.
214 //
215
216 do {
217
218 sprintf(deviceNameBuffer, "\\Device\\ScsiPort%lu", portNumber);
219
220 DebugPrint((2, "ScsiClassInitialize: Open Port %s\n", deviceNameBuffer));
221
222 RtlInitString(&deviceNameString, deviceNameBuffer);
223
224 status = RtlAnsiStringToUnicodeString(&unicodeDeviceName,
225 &deviceNameString,
226 TRUE);
227
228 if (!NT_SUCCESS(status)){
229 break;
230 }
231
232 status = IoGetDeviceObjectPointer(&unicodeDeviceName,
233 FILE_READ_ATTRIBUTES,
234 &fileObject,
235 &portDeviceObject);
236
237 if (NT_SUCCESS(status)) {
238
239 //
240 // Call the device-specific driver's FindDevice routine.
241 //
242
243 if (InitializationData->ClassFindDevices(DriverObject, Argument2, InitializationData,
244 portDeviceObject, portNumber)) {
245
246 deviceFound = TRUE;
247 }
248 }
249
250 //
251 // Check next SCSI adapter.
252 //
253
254 portNumber++;
255
256 } while(NT_SUCCESS(status));
257
258 return deviceFound ? STATUS_SUCCESS : STATUS_NO_SUCH_DEVICE;
259 }
260
261 \f
262 NTSTATUS
263 NTAPI
264 ScsiClassCreateClose(
265 IN PDEVICE_OBJECT DeviceObject,
266 IN PIRP Irp
267 )
268
269 /*++
270
271 Routine Description:
272
273 SCSI class driver create and close routine. This is called by the I/O system
274 when the device is opened or closed.
275
276 Arguments:
277
278 DriverObject - Pointer to driver object created by system.
279
280 Irp - IRP involved.
281
282 Return Value:
283
284 Device-specific drivers return value or STATUS_SUCCESS.
285
286 --*/
287
288 {
289 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
290
291 //
292 // Invoke the device-specific routine, if one exists. Otherwise complete
293 // with SUCCESS
294 //
295
296 if (deviceExtension->ClassCreateClose) {
297
298 return deviceExtension->ClassCreateClose(DeviceObject, Irp);
299
300 } else {
301 Irp->IoStatus.Status = STATUS_SUCCESS;
302
303 IoCompleteRequest(Irp, IO_NO_INCREMENT);
304 return(STATUS_SUCCESS);
305 }
306 }
307
308
309 \f
310 NTSTATUS
311 NTAPI
312 ScsiClassReadWrite(
313 IN PDEVICE_OBJECT DeviceObject,
314 IN PIRP Irp
315 )
316
317 /*++
318
319 Routine Description:
320
321 This is the system entry point for read and write requests. The device-specific handler is invoked
322 to perform any validation necessary. The number of bytes in the request are
323 checked against the maximum byte counts that the adapter supports and requests are broken up into
324 smaller sizes if necessary.
325
326 Arguments:
327
328 DeviceObject
329 Irp - IO request
330
331 Return Value:
332
333 NT Status
334
335 --*/
336
337 {
338 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
339 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
340 ULONG transferPages;
341 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
342 ULONG maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength;
343 NTSTATUS status;
344
345 if (DeviceObject->Flags & DO_VERIFY_VOLUME &&
346 !(currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) {
347
348 //
349 // if DO_VERIFY_VOLUME bit is set
350 // in device object flags, fail request.
351 //
352
353 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
354
355 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
356 Irp->IoStatus.Information = 0;
357
358 IoCompleteRequest(Irp, 0);
359 return STATUS_VERIFY_REQUIRED;
360 }
361
362 //
363 // Invoke the device specific routine to do whatever it needs to verify
364 // this request.
365 //
366
367 ASSERT(deviceExtension->ClassReadWriteVerification);
368
369 status = deviceExtension->ClassReadWriteVerification(DeviceObject,Irp);
370
371 if (!NT_SUCCESS(status)) {
372
373 //
374 // It is up to the device specific driver to set the Irp status.
375 //
376
377 IoCompleteRequest (Irp, IO_NO_INCREMENT);
378 return status;
379 } else if (status == STATUS_PENDING) {
380
381 IoMarkIrpPending(Irp);
382 return STATUS_PENDING;
383 }
384
385 //
386 // Check for a zero length IO, as several macros will turn this into
387 // seemingly a 0xffffffff length request.
388 //
389
390 if (transferByteCount == 0) {
391 Irp->IoStatus.Status = STATUS_SUCCESS;
392 Irp->IoStatus.Information = 0;
393 IoCompleteRequest(Irp, IO_NO_INCREMENT);
394 return STATUS_SUCCESS;
395
396 }
397
398 if (deviceExtension->ClassStartIo) {
399
400 IoMarkIrpPending(Irp);
401
402 IoStartPacket(DeviceObject,
403 Irp,
404 NULL,
405 NULL);
406
407 return STATUS_PENDING;
408 }
409
410 //
411 // Mark IRP with status pending.
412 //
413
414 IoMarkIrpPending(Irp);
415
416 //
417 // Add partition byte offset to make starting byte relative to
418 // beginning of disk. In addition, add in skew for DM Driver, if any.
419 //
420
421 currentIrpStack->Parameters.Read.ByteOffset.QuadPart += (deviceExtension->StartingOffset.QuadPart +
422 deviceExtension->DMByteSkew);
423
424 //
425 // Calculate number of pages in this transfer.
426 //
427
428 transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
429 currentIrpStack->Parameters.Read.Length);
430
431 //
432 // Check if request length is greater than the maximum number of
433 // bytes that the hardware can transfer.
434 //
435
436 if (currentIrpStack->Parameters.Read.Length > maximumTransferLength ||
437 transferPages > deviceExtension->PortCapabilities->MaximumPhysicalPages) {
438
439 DebugPrint((2,"ScsiClassReadWrite: Request greater than maximum\n"));
440 DebugPrint((2,"ScsiClassReadWrite: Maximum is %lx\n",
441 maximumTransferLength));
442 DebugPrint((2,"ScsiClassReadWrite: Byte count is %lx\n",
443 currentIrpStack->Parameters.Read.Length));
444
445 transferPages =
446 deviceExtension->PortCapabilities->MaximumPhysicalPages - 1;
447
448 if (maximumTransferLength > transferPages << PAGE_SHIFT ) {
449 maximumTransferLength = transferPages << PAGE_SHIFT;
450 }
451
452 //
453 // Check that maximum transfer size is not zero.
454 //
455
456 if (maximumTransferLength == 0) {
457 maximumTransferLength = PAGE_SIZE;
458 }
459
460 //
461 // Mark IRP with status pending.
462 //
463
464 IoMarkIrpPending(Irp);
465
466 //
467 // Request greater than port driver maximum.
468 // Break up into smaller routines.
469 //
470
471 ScsiClassSplitRequest(DeviceObject, Irp, maximumTransferLength);
472
473
474 return STATUS_PENDING;
475 }
476
477 //
478 // Build SRB and CDB for this IRP.
479 //
480
481 ScsiClassBuildRequest(DeviceObject, Irp);
482
483 //
484 // Return the results of the call to the port driver.
485 //
486
487 return IoCallDriver(deviceExtension->PortDeviceObject, Irp);
488
489 } // end ScsiClassReadWrite()
490
491 \f
492 NTSTATUS
493 NTAPI
494 ScsiClassGetCapabilities(
495 IN PDEVICE_OBJECT PortDeviceObject,
496 OUT PIO_SCSI_CAPABILITIES *PortCapabilities
497 )
498
499 /*++
500
501 Routine Description:
502
503 This routine builds and sends a request to the port driver to
504 get a pointer to a structure that describes the adapter's
505 capabilities/limitations. This routine is sychronous.
506
507 Arguments:
508
509 PortDeviceObject - Port driver device object representing the HBA.
510
511 PortCapabilities - Location to store pointer to capabilities structure.
512
513 Return Value:
514
515 Nt status indicating the results of the operation.
516
517 Notes:
518
519 This routine should only be called at initialization time.
520
521 --*/
522
523 {
524 PIRP irp;
525 IO_STATUS_BLOCK ioStatus;
526 KEVENT event;
527 NTSTATUS status;
528
529 PAGED_CODE();
530
531 //
532 // Create notification event object to be used to signal the
533 // request completion.
534 //
535
536 KeInitializeEvent(&event, NotificationEvent, FALSE);
537
538 //
539 // Build the synchronous request to be sent to the port driver
540 // to perform the request.
541 //
542
543 irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_CAPABILITIES,
544 PortDeviceObject,
545 NULL,
546 0,
547 PortCapabilities,
548 sizeof(PVOID),
549 FALSE,
550 &event,
551 &ioStatus);
552
553 if (irp == NULL) {
554 return STATUS_INSUFFICIENT_RESOURCES;
555 }
556
557 //
558 // Pass request to port driver and wait for request to complete.
559 //
560
561 status = IoCallDriver(PortDeviceObject, irp);
562
563 if (status == STATUS_PENDING) {
564 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
565 return(ioStatus.Status);
566 }
567
568 return status;
569
570 } // end ScsiClassGetCapabilities()
571
572 \f
573 NTSTATUS
574 NTAPI
575 ScsiClassGetInquiryData(
576 IN PDEVICE_OBJECT PortDeviceObject,
577 OUT PSCSI_ADAPTER_BUS_INFO *ConfigInfo
578 )
579
580 /*++
581
582 Routine Description:
583
584 This routine sends a request to a port driver to return
585 configuration information. Space for the information is
586 allocated by this routine. The caller is responsible for
587 freeing the configuration information. This routine is
588 synchronous.
589
590 Arguments:
591
592 PortDeviceObject - Port driver device object representing the HBA.
593
594 ConfigInfo - Returns a pointer to the configuration information.
595
596 Return Value:
597
598 Nt status indicating the results of the operation.
599
600 Notes:
601
602 This routine should be called only at initialization time.
603
604 --*/
605
606 {
607 PIRP irp;
608 IO_STATUS_BLOCK ioStatus;
609 KEVENT event;
610 NTSTATUS status;
611 PSCSI_ADAPTER_BUS_INFO buffer;
612
613 PAGED_CODE();
614
615 buffer = ExAllocatePool(PagedPool, INQUIRY_DATA_SIZE);
616 *ConfigInfo = buffer;
617
618 if (buffer == NULL) {
619 return(STATUS_INSUFFICIENT_RESOURCES);
620 }
621
622 //
623 // Create notification event object to be used to signal the inquiry
624 // request completion.
625 //
626
627 KeInitializeEvent(&event, NotificationEvent, FALSE);
628
629 //
630 // Build the synchronous request to be sent to the port driver
631 // to perform the inquiries.
632 //
633
634 irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA,
635 PortDeviceObject,
636 NULL,
637 0,
638 buffer,
639 INQUIRY_DATA_SIZE,
640 FALSE,
641 &event,
642 &ioStatus);
643
644 if (irp == NULL) {
645 return(STATUS_INSUFFICIENT_RESOURCES);
646 }
647
648 //
649 // Pass request to port driver and wait for request to complete.
650 //
651
652 status = IoCallDriver(PortDeviceObject, irp);
653
654 if (status == STATUS_PENDING) {
655 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
656 status = ioStatus.Status;
657 }
658
659 if (!NT_SUCCESS(status)) {
660
661 //
662 // Free the buffer on an error.
663 //
664
665 ExFreePool(buffer);
666 *ConfigInfo = NULL;
667
668 }
669
670 return status;
671
672 } // end ScsiClassGetInquiryData()
673
674 \f
675 NTSTATUS
676 NTAPI
677 ScsiClassReadDriveCapacity(
678 IN PDEVICE_OBJECT DeviceObject
679 )
680
681 /*++
682
683 Routine Description:
684
685 This routine sends a READ CAPACITY to the requested device, updates
686 the geometry information in the device object and returns
687 when it is complete. This routine is synchronous.
688
689 Arguments:
690
691 DeviceObject - Supplies a pointer to the device object that represents
692 the device whose capacity is to be read.
693
694 Return Value:
695
696 Status is returned.
697
698 --*/
699 {
700 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
701 ULONG retries = 1;
702 ULONG lastSector;
703 PCDB cdb;
704 PREAD_CAPACITY_DATA readCapacityBuffer;
705 SCSI_REQUEST_BLOCK srb;
706 NTSTATUS status;
707
708 //
709 // Allocate read capacity buffer from nonpaged pool.
710 //
711
712 readCapacityBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
713 sizeof(READ_CAPACITY_DATA));
714
715 if (!readCapacityBuffer) {
716 return(STATUS_INSUFFICIENT_RESOURCES);
717 }
718
719 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
720
721 //
722 // Build the read capacity CDB.
723 //
724
725 srb.CdbLength = 10;
726 cdb = (PCDB)srb.Cdb;
727
728 //
729 // Set timeout value from device extension.
730 //
731
732 srb.TimeOutValue = deviceExtension->TimeOutValue;
733
734 cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
735
736 Retry:
737
738 status = ScsiClassSendSrbSynchronous(DeviceObject,
739 &srb,
740 readCapacityBuffer,
741 sizeof(READ_CAPACITY_DATA),
742 FALSE);
743
744 if (NT_SUCCESS(status)) {
745
746 //
747 // Copy sector size from read capacity buffer to device extension
748 // in reverse byte order.
749 //
750
751 ((PFOUR_BYTE)&deviceExtension->DiskGeometry->BytesPerSector)->Byte0 =
752 ((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte3;
753
754 ((PFOUR_BYTE)&deviceExtension->DiskGeometry->BytesPerSector)->Byte1 =
755 ((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte2;
756
757 ((PFOUR_BYTE)&deviceExtension->DiskGeometry->BytesPerSector)->Byte2 =
758 ((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte1;
759
760 ((PFOUR_BYTE)&deviceExtension->DiskGeometry->BytesPerSector)->Byte3 =
761 ((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte0;
762
763 //
764 // Copy last sector in reverse byte order.
765 //
766
767 ((PFOUR_BYTE)&lastSector)->Byte0 =
768 ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte3;
769
770 ((PFOUR_BYTE)&lastSector)->Byte1 =
771 ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte2;
772
773 ((PFOUR_BYTE)&lastSector)->Byte2 =
774 ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte1;
775
776 ((PFOUR_BYTE)&lastSector)->Byte3 =
777 ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte0;
778
779 //
780 // Calculate sector to byte shift.
781 //
782
783 WHICH_BIT(deviceExtension->DiskGeometry->BytesPerSector, deviceExtension->SectorShift);
784
785 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
786 deviceExtension->DiskGeometry->BytesPerSector));
787
788 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
789 lastSector + 1));
790
791 //
792 // Calculate media capacity in bytes.
793 //
794
795 deviceExtension->PartitionLength.QuadPart = (LONGLONG)(lastSector + 1);
796
797 //
798 // Calculate number of cylinders.
799 //
800
801 deviceExtension->DiskGeometry->Cylinders.QuadPart = (LONGLONG)((lastSector + 1)/(32 * 64));
802
803 deviceExtension->PartitionLength.QuadPart =
804 (deviceExtension->PartitionLength.QuadPart << deviceExtension->SectorShift);
805
806 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
807
808 //
809 // This device supports removable media.
810 //
811
812 deviceExtension->DiskGeometry->MediaType = RemovableMedia;
813
814 } else {
815
816 //
817 // Assume media type is fixed disk.
818 //
819
820 deviceExtension->DiskGeometry->MediaType = FixedMedia;
821 }
822
823 //
824 // Assume sectors per track are 32;
825 //
826
827 deviceExtension->DiskGeometry->SectorsPerTrack = 32;
828
829 //
830 // Assume tracks per cylinder (number of heads) is 64.
831 //
832
833 deviceExtension->DiskGeometry->TracksPerCylinder = 64;
834 }
835
836 if (status == STATUS_VERIFY_REQUIRED) {
837
838 //
839 // Routine ScsiClassSendSrbSynchronous does not retry
840 // requests returned with this status.
841 // Read Capacities should be retried
842 // anyway.
843 //
844
845 if (retries--) {
846
847 //
848 // Retry request.
849 //
850
851 goto Retry;
852 }
853 }
854
855 if (!NT_SUCCESS(status)) {
856
857 //
858 // If the read capacity fails, set the geometry to reasonable parameter
859 // so things don't fail at unexpected places. Zero the geometry
860 // except for the bytes per sector and sector shift.
861 //
862
863 RtlZeroMemory(deviceExtension->DiskGeometry, sizeof(DISK_GEOMETRY));
864 deviceExtension->DiskGeometry->BytesPerSector = 512;
865 deviceExtension->SectorShift = 9;
866 deviceExtension->PartitionLength.QuadPart = (LONGLONG) 0;
867
868 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
869
870 //
871 // This device supports removable media.
872 //
873
874 deviceExtension->DiskGeometry->MediaType = RemovableMedia;
875
876 } else {
877
878 //
879 // Assume media type is fixed disk.
880 //
881
882 deviceExtension->DiskGeometry->MediaType = FixedMedia;
883 }
884 }
885
886 //
887 // Deallocate read capacity buffer.
888 //
889
890 ExFreePool(readCapacityBuffer);
891
892 return status;
893
894 } // end ScsiClassReadDriveCapacity()
895
896 \f
897 VOID
898 NTAPI
899 ScsiClassReleaseQueue(
900 IN PDEVICE_OBJECT DeviceObject
901 )
902
903 /*++
904
905 Routine Description:
906
907 This routine issues an internal device control command
908 to the port driver to release a frozen queue. The call
909 is issued asynchronously as ScsiClassReleaseQueue will be invoked
910 from the IO completion DPC (and will have no context to
911 wait for a synchronous call to complete).
912
913 Arguments:
914
915 DeviceObject - The device object for the logical unit with
916 the frozen queue.
917
918 Return Value:
919
920 None.
921
922 --*/
923 {
924 PIO_STACK_LOCATION irpStack;
925 PIRP irp;
926 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
927 PCOMPLETION_CONTEXT context;
928 PSCSI_REQUEST_BLOCK srb;
929 KIRQL currentIrql;
930
931 //
932 // Allocate context from nonpaged pool.
933 //
934
935 context = ExAllocatePool(NonPagedPoolMustSucceed,
936 sizeof(COMPLETION_CONTEXT));
937
938 //
939 // Save the device object in the context for use by the completion
940 // routine.
941 //
942
943 context->DeviceObject = DeviceObject;
944 srb = &context->Srb;
945
946 //
947 // Zero out srb.
948 //
949
950 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
951
952 //
953 // Write length to SRB.
954 //
955
956 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
957
958 //
959 // Set up SCSI bus address.
960 //
961
962 srb->PathId = deviceExtension->PathId;
963 srb->TargetId = deviceExtension->TargetId;
964 srb->Lun = deviceExtension->Lun;
965
966 //
967 // If this device is removable then flush the queue. This will also
968 // release it.
969 //
970
971 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
972
973 srb->Function = SRB_FUNCTION_FLUSH_QUEUE;
974
975 } else {
976
977 srb->Function = SRB_FUNCTION_RELEASE_QUEUE;
978
979 }
980
981 //
982 // Build the asynchronous request to be sent to the port driver.
983 //
984
985 irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
986
987 if(irp == NULL) {
988
989 //
990 // We have no better way of dealing with this at the moment
991 //
992
993 KeBugCheck((ULONG)0x0000002DL);
994
995 }
996
997 IoSetCompletionRoutine(irp,
998 (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion,
999 context,
1000 TRUE,
1001 TRUE,
1002 TRUE);
1003
1004 irpStack = IoGetNextIrpStackLocation(irp);
1005
1006 irpStack->MajorFunction = IRP_MJ_SCSI;
1007
1008 srb->OriginalRequest = irp;
1009
1010 //
1011 // Store the SRB address in next stack for port driver.
1012 //
1013
1014 irpStack->Parameters.Scsi.Srb = srb;
1015
1016 //
1017 // Since this routine can cause outstanding requests to be completed, and
1018 // calling a completion routine at < DISPATCH_LEVEL is dangerous (if they
1019 // call IoStartNextPacket we will bugcheck) raise up to dispatch level before
1020 // issuing the request
1021 //
1022
1023 currentIrql = KeGetCurrentIrql();
1024
1025 if(currentIrql < DISPATCH_LEVEL) {
1026 KeRaiseIrql(DISPATCH_LEVEL, &currentIrql);
1027 IoCallDriver(deviceExtension->PortDeviceObject, irp);
1028 KeLowerIrql(currentIrql);
1029 } else {
1030 IoCallDriver(deviceExtension->PortDeviceObject, irp);
1031 }
1032
1033 return;
1034
1035 } // end ScsiClassReleaseQueue()
1036
1037 \f
1038 VOID
1039 NTAPI
1040 StartUnit(
1041 IN PDEVICE_OBJECT DeviceObject
1042 )
1043
1044 /*++
1045
1046 Routine Description:
1047
1048 Send command to SCSI unit to start or power up.
1049 Because this command is issued asynchronounsly, that is, without
1050 waiting on it to complete, the IMMEDIATE flag is not set. This
1051 means that the CDB will not return until the drive has powered up.
1052 This should keep subsequent requests from being submitted to the
1053 device before it has completely spun up.
1054 This routine is called from the InterpretSense routine, when a
1055 request sense returns data indicating that a drive must be
1056 powered up.
1057
1058 Arguments:
1059
1060 DeviceObject - The device object for the logical unit with
1061 the frozen queue.
1062
1063 Return Value:
1064
1065 None.
1066
1067 --*/
1068 {
1069 PIO_STACK_LOCATION irpStack;
1070 PIRP irp;
1071 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1072 PSCSI_REQUEST_BLOCK srb;
1073 PCOMPLETION_CONTEXT context;
1074 PCDB cdb;
1075
1076 //
1077 // Allocate Srb from nonpaged pool.
1078 //
1079
1080 context = ExAllocatePool(NonPagedPoolMustSucceed,
1081 sizeof(COMPLETION_CONTEXT));
1082
1083 //
1084 // Save the device object in the context for use by the completion
1085 // routine.
1086 //
1087
1088 context->DeviceObject = DeviceObject;
1089 srb = &context->Srb;
1090
1091 //
1092 // Zero out srb.
1093 //
1094
1095 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
1096
1097 //
1098 // Write length to SRB.
1099 //
1100
1101 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1102
1103 //
1104 // Set up SCSI bus address.
1105 //
1106
1107 srb->PathId = deviceExtension->PathId;
1108 srb->TargetId = deviceExtension->TargetId;
1109 srb->Lun = deviceExtension->Lun;
1110
1111 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1112
1113 //
1114 // Set timeout value large enough for drive to spin up.
1115 //
1116
1117 srb->TimeOutValue = START_UNIT_TIMEOUT;
1118
1119 //
1120 // Set the transfer length.
1121 //
1122
1123 srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER | SRB_FLAGS_DISABLE_AUTOSENSE | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
1124
1125 //
1126 // Build the start unit CDB.
1127 //
1128
1129 srb->CdbLength = 6;
1130 cdb = (PCDB)srb->Cdb;
1131
1132 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
1133 cdb->START_STOP.Start = 1;
1134 cdb->START_STOP.LogicalUnitNumber = srb->Lun;
1135
1136 //
1137 // Build the asynchronous request to be sent to the port driver.
1138 // Since this routine is called from a DPC the IRP should always be
1139 // available.
1140 //
1141
1142 irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1143 IoSetCompletionRoutine(irp,
1144 (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion,
1145 context,
1146 TRUE,
1147 TRUE,
1148 TRUE);
1149
1150 irpStack = IoGetNextIrpStackLocation(irp);
1151 irpStack->MajorFunction = IRP_MJ_SCSI;
1152 srb->OriginalRequest = irp;
1153
1154 //
1155 // Store the SRB address in next stack for port driver.
1156 //
1157
1158 irpStack->Parameters.Scsi.Srb = srb;
1159
1160 //
1161 // Call the port driver with the IRP.
1162 //
1163
1164 IoCallDriver(deviceExtension->PortDeviceObject, irp);
1165
1166 return;
1167
1168 } // end StartUnit()
1169
1170 \f
1171 NTSTATUS
1172 NTAPI
1173 ScsiClassAsynchronousCompletion(
1174 PDEVICE_OBJECT DeviceObject,
1175 PIRP Irp,
1176 PVOID Context
1177 )
1178 /*++
1179
1180 Routine Description:
1181
1182 This routine is called when an asynchronous I/O request
1183 which was issused by the class driver completes. Examples of such requests
1184 are release queue or START UNIT. This routine releases the queue if
1185 necessary. It then frees the context and the IRP.
1186
1187 Arguments:
1188
1189 DeviceObject - The device object for the logical unit; however since this
1190 is the top stack location the value is NULL.
1191
1192 Irp - Supplies a pointer to the Irp to be processed.
1193
1194 Context - Supplies the context to be used to process this request.
1195
1196 Return Value:
1197
1198 None.
1199
1200 --*/
1201
1202 {
1203 PCOMPLETION_CONTEXT context = Context;
1204 PSCSI_REQUEST_BLOCK srb;
1205
1206 srb = &context->Srb;
1207
1208 //
1209 // If this is an execute srb, then check the return status and make sure.
1210 // the queue is not frozen.
1211 //
1212
1213 if (srb->Function == SRB_FUNCTION_EXECUTE_SCSI) {
1214
1215 //
1216 // Check for a frozen queue.
1217 //
1218
1219 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
1220
1221 //
1222 // Unfreeze the queue getting the device object from the context.
1223 //
1224
1225 ScsiClassReleaseQueue(context->DeviceObject);
1226 }
1227 }
1228
1229 //
1230 // Free the context and the Irp.
1231 //
1232
1233 if (Irp->MdlAddress != NULL) {
1234 MmUnlockPages(Irp->MdlAddress);
1235 IoFreeMdl(Irp->MdlAddress);
1236
1237 Irp->MdlAddress = NULL;
1238 }
1239
1240 ExFreePool(context);
1241 IoFreeIrp(Irp);
1242
1243 //
1244 // Indicate the I/O system should stop processing the Irp completion.
1245 //
1246
1247 return STATUS_MORE_PROCESSING_REQUIRED;
1248
1249 } // ScsiClassAsynchronousCompletion()
1250
1251 \f
1252 VOID
1253 NTAPI
1254 ScsiClassSplitRequest(
1255 IN PDEVICE_OBJECT DeviceObject,
1256 IN PIRP Irp,
1257 IN ULONG MaximumBytes
1258 )
1259
1260 /*++
1261
1262 Routine Description:
1263
1264 Break request into smaller requests. Each new request will be the
1265 maximum transfer size that the port driver can handle or if it
1266 is the final request, it may be the residual size.
1267
1268 The number of IRPs required to process this request is written in the
1269 current stack of the original IRP. Then as each new IRP completes
1270 the count in the original IRP is decremented. When the count goes to
1271 zero, the original IRP is completed.
1272
1273 Arguments:
1274
1275 DeviceObject - Pointer to the class device object to be addressed.
1276
1277 Irp - Pointer to Irp the orginal request.
1278
1279 Return Value:
1280
1281 None.
1282
1283 --*/
1284
1285 {
1286 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1287 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
1288 PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
1289 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
1290 LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
1291 PVOID dataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
1292 ULONG dataLength = MaximumBytes;
1293 ULONG irpCount = (transferByteCount + MaximumBytes - 1) / MaximumBytes;
1294 ULONG i;
1295 PSCSI_REQUEST_BLOCK srb;
1296
1297 DebugPrint((2, "ScsiClassSplitRequest: Requires %d IRPs\n", irpCount));
1298 DebugPrint((2, "ScsiClassSplitRequest: Original IRP %lx\n", Irp));
1299
1300 //
1301 // If all partial transfers complete successfully then the status and
1302 // bytes transferred are already set up. Failing a partial-transfer IRP
1303 // will set status to error and bytes transferred to 0 during
1304 // IoCompletion. Setting bytes transferred to 0 if an IRP fails allows
1305 // asynchronous partial transfers. This is an optimization for the
1306 // successful case.
1307 //
1308
1309 Irp->IoStatus.Status = STATUS_SUCCESS;
1310 Irp->IoStatus.Information = transferByteCount;
1311
1312 //
1313 // Save number of IRPs to complete count on current stack
1314 // of original IRP.
1315 //
1316
1317 nextIrpStack->Parameters.Others.Argument1 = (PVOID)(ULONG_PTR) irpCount;
1318
1319 for (i = 0; i < irpCount; i++) {
1320
1321 PIRP newIrp;
1322 PIO_STACK_LOCATION newIrpStack;
1323
1324 //
1325 // Allocate new IRP.
1326 //
1327
1328 newIrp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1329
1330 if (newIrp == NULL) {
1331
1332 DebugPrint((1,"ScsiClassSplitRequest: Can't allocate Irp\n"));
1333
1334 //
1335 // If an Irp can't be allocated then the orginal request cannot
1336 // be executed. If this is the first request then just fail the
1337 // orginal request; otherwise just return. When the pending
1338 // requests complete, they will complete the original request.
1339 // In either case set the IRP status to failure.
1340 //
1341
1342 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1343 Irp->IoStatus.Information = 0;
1344
1345 if (i == 0) {
1346 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1347 }
1348
1349 return;
1350 }
1351
1352 DebugPrint((2, "ScsiClassSplitRequest: New IRP %lx\n", newIrp));
1353
1354 //
1355 // Write MDL address to new IRP. In the port driver the SRB data
1356 // buffer field is used as an offset into the MDL, so the same MDL
1357 // can be used for each partial transfer. This saves having to build
1358 // a new MDL for each partial transfer.
1359 //
1360
1361 newIrp->MdlAddress = Irp->MdlAddress;
1362
1363 //
1364 // At this point there is no current stack. IoSetNextIrpStackLocation
1365 // will make the first stack location the current stack so that the
1366 // SRB address can be written there.
1367 //
1368
1369 IoSetNextIrpStackLocation(newIrp);
1370 newIrpStack = IoGetCurrentIrpStackLocation(newIrp);
1371
1372 newIrpStack->MajorFunction = currentIrpStack->MajorFunction;
1373 newIrpStack->Parameters.Read.Length = dataLength;
1374 newIrpStack->Parameters.Read.ByteOffset = startingOffset;
1375 newIrpStack->DeviceObject = DeviceObject;
1376
1377 //
1378 // Build SRB and CDB.
1379 //
1380
1381 ScsiClassBuildRequest(DeviceObject, newIrp);
1382
1383 //
1384 // Adjust SRB for this partial transfer.
1385 //
1386
1387 newIrpStack = IoGetNextIrpStackLocation(newIrp);
1388
1389 srb = newIrpStack->Parameters.Others.Argument1;
1390 srb->DataBuffer = dataBuffer;
1391
1392 //
1393 // Write original IRP address to new IRP.
1394 //
1395
1396 newIrp->AssociatedIrp.MasterIrp = Irp;
1397
1398 //
1399 // Set the completion routine to ScsiClassIoCompleteAssociated.
1400 //
1401
1402 IoSetCompletionRoutine(newIrp,
1403 ScsiClassIoCompleteAssociated,
1404 srb,
1405 TRUE,
1406 TRUE,
1407 TRUE);
1408
1409 //
1410 // Call port driver with new request.
1411 //
1412
1413 IoCallDriver(deviceExtension->PortDeviceObject, newIrp);
1414
1415 //
1416 // Set up for next request.
1417 //
1418
1419 dataBuffer = (PCHAR)dataBuffer + MaximumBytes;
1420
1421 transferByteCount -= MaximumBytes;
1422
1423 if (transferByteCount > MaximumBytes) {
1424
1425 dataLength = MaximumBytes;
1426
1427 } else {
1428
1429 dataLength = transferByteCount;
1430 }
1431
1432 //
1433 // Adjust disk byte offset.
1434 //
1435
1436 startingOffset.QuadPart = startingOffset.QuadPart + MaximumBytes;
1437 }
1438
1439 return;
1440
1441 } // end ScsiClassSplitRequest()
1442
1443 \f
1444 NTSTATUS
1445 NTAPI
1446 ScsiClassIoComplete(
1447 IN PDEVICE_OBJECT DeviceObject,
1448 IN PIRP Irp,
1449 IN PVOID Context
1450 )
1451
1452 /*++
1453
1454 Routine Description:
1455
1456 This routine executes when the port driver has completed a request.
1457 It looks at the SRB status in the completing SRB and if not success
1458 it checks for valid request sense buffer information. If valid, the
1459 info is used to update status with more precise message of type of
1460 error. This routine deallocates the SRB.
1461
1462 Arguments:
1463
1464 DeviceObject - Supplies the device object which represents the logical
1465 unit.
1466
1467 Irp - Supplies the Irp which has completed.
1468
1469 Context - Supplies a pointer to the SRB.
1470
1471 Return Value:
1472
1473 NT status
1474
1475 --*/
1476
1477 {
1478 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
1479 PSCSI_REQUEST_BLOCK srb = Context;
1480 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1481 NTSTATUS status;
1482 BOOLEAN retry;
1483
1484 //
1485 // Check SRB status for success of completing request.
1486 //
1487
1488 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
1489
1490 DebugPrint((2,"ScsiClassIoComplete: IRP %lx, SRB %lx\n", Irp, srb));
1491
1492 //
1493 // Release the queue if it is frozen.
1494 //
1495
1496 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
1497 ScsiClassReleaseQueue(DeviceObject);
1498 }
1499
1500 retry = ScsiClassInterpretSenseInfo(
1501 DeviceObject,
1502 srb,
1503 irpStack->MajorFunction,
1504 irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? irpStack->Parameters.DeviceIoControl.IoControlCode : 0,
1505 MAXIMUM_RETRIES - ((ULONG_PTR)irpStack->Parameters.Others.Argument4),
1506 &status);
1507
1508 //
1509 // If the status is verified required and the this request
1510 // should bypass verify required then retry the request.
1511 //
1512
1513 if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
1514 status == STATUS_VERIFY_REQUIRED) {
1515
1516 status = STATUS_IO_DEVICE_ERROR;
1517 retry = TRUE;
1518 }
1519
1520 if (retry && (irpStack->Parameters.Others.Argument4 = (PVOID)((ULONG_PTR)irpStack->Parameters.Others.Argument4-1))) {
1521
1522 //
1523 // Retry request.
1524 //
1525
1526 DebugPrint((1, "Retry request %lx\n", Irp));
1527 RetryRequest(DeviceObject, Irp, srb, FALSE);
1528 return STATUS_MORE_PROCESSING_REQUIRED;
1529 }
1530 } else {
1531
1532 //
1533 // Set status for successful request.
1534 //
1535
1536 status = STATUS_SUCCESS;
1537
1538 } // end if (SRB_STATUS(srb->SrbStatus) ...
1539
1540 //
1541 // Return SRB to list.
1542 //
1543
1544 ExFreeToNPagedLookasideList(&deviceExtension->SrbLookasideListHead,
1545 srb);
1546
1547 //
1548 // Set status in completing IRP.
1549 //
1550
1551 Irp->IoStatus.Status = status;
1552 if ((NT_SUCCESS(status)) && (Irp->Flags & IRP_PAGING_IO)) {
1553 ASSERT(Irp->IoStatus.Information);
1554 }
1555
1556 //
1557 // Set the hard error if necessary.
1558 //
1559
1560 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
1561
1562 //
1563 // Store DeviceObject for filesystem, and clear
1564 // in IoStatus.Information field.
1565 //
1566
1567 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
1568 Irp->IoStatus.Information = 0;
1569 }
1570
1571 //
1572 // If pending has be returned for this irp then mark the current stack as
1573 // pending.
1574 //
1575
1576 if (Irp->PendingReturned) {
1577 IoMarkIrpPending(Irp);
1578 }
1579
1580 if (deviceExtension->ClassStartIo) {
1581 if (irpStack->MajorFunction != IRP_MJ_DEVICE_CONTROL) {
1582 IoStartNextPacket(DeviceObject, FALSE);
1583 }
1584 }
1585
1586 return status;
1587
1588 } // end ScsiClassIoComplete()
1589
1590 \f
1591 NTSTATUS
1592 NTAPI
1593 ScsiClassIoCompleteAssociated(
1594 IN PDEVICE_OBJECT DeviceObject,
1595 IN PIRP Irp,
1596 IN PVOID Context
1597 )
1598
1599 /*++
1600
1601 Routine Description:
1602
1603 This routine executes when the port driver has completed a request.
1604 It looks at the SRB status in the completing SRB and if not success
1605 it checks for valid request sense buffer information. If valid, the
1606 info is used to update status with more precise message of type of
1607 error. This routine deallocates the SRB. This routine is used for
1608 requests which were build by split request. After it has processed
1609 the request it decrements the Irp count in the master Irp. If the
1610 count goes to zero then the master Irp is completed.
1611
1612 Arguments:
1613
1614 DeviceObject - Supplies the device object which represents the logical
1615 unit.
1616
1617 Irp - Supplies the Irp which has completed.
1618
1619 Context - Supplies a pointer to the SRB.
1620
1621 Return Value:
1622
1623 NT status
1624
1625 --*/
1626
1627 {
1628 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
1629 PSCSI_REQUEST_BLOCK srb = Context;
1630 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1631 PIRP originalIrp = Irp->AssociatedIrp.MasterIrp;
1632 LONG irpCount;
1633 NTSTATUS status;
1634 BOOLEAN retry;
1635
1636 //
1637 // Check SRB status for success of completing request.
1638 //
1639
1640 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
1641
1642 DebugPrint((2,"ScsiClassIoCompleteAssociated: IRP %lx, SRB %lx", Irp, srb));
1643
1644 //
1645 // Release the queue if it is frozen.
1646 //
1647
1648 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
1649 ScsiClassReleaseQueue(DeviceObject);
1650 }
1651
1652 retry = ScsiClassInterpretSenseInfo(
1653 DeviceObject,
1654 srb,
1655 irpStack->MajorFunction,
1656 irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? irpStack->Parameters.DeviceIoControl.IoControlCode : 0,
1657 MAXIMUM_RETRIES - ((ULONG_PTR)irpStack->Parameters.Others.Argument4),
1658 &status);
1659
1660 //
1661 // If the status is verified required and the this request
1662 // should bypass verify required then retry the request.
1663 //
1664
1665 if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
1666 status == STATUS_VERIFY_REQUIRED) {
1667
1668 status = STATUS_IO_DEVICE_ERROR;
1669 retry = TRUE;
1670 }
1671
1672 if (retry && (irpStack->Parameters.Others.Argument4 = (PVOID)((ULONG_PTR)irpStack->Parameters.Others.Argument4-1))) {
1673
1674 //
1675 // Retry request. If the class driver has supplied a StartIo,
1676 // call it directly for retries.
1677 //
1678
1679 DebugPrint((1, "Retry request %lx\n", Irp));
1680
1681 /*
1682 if (!deviceExtension->ClassStartIo) {
1683 RetryRequest(DeviceObject, Irp, srb, TRUE);
1684 } else {
1685 deviceExtension->ClassStartIo(DeviceObject, Irp);
1686 }
1687 */
1688
1689 RetryRequest(DeviceObject, Irp, srb, TRUE);
1690
1691 return STATUS_MORE_PROCESSING_REQUIRED;
1692 }
1693
1694
1695
1696 } else {
1697
1698 //
1699 // Set status for successful request.
1700 //
1701
1702 status = STATUS_SUCCESS;
1703
1704 } // end if (SRB_STATUS(srb->SrbStatus) ...
1705
1706 //
1707 // Return SRB to list.
1708 //
1709
1710 ExFreeToNPagedLookasideList(&deviceExtension->SrbLookasideListHead,
1711 srb);
1712
1713 //
1714 // Set status in completing IRP.
1715 //
1716
1717 Irp->IoStatus.Status = status;
1718
1719 DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial xfer IRP %lx\n", Irp));
1720
1721 //
1722 // Get next stack location. This original request is unused
1723 // except to keep track of the completing partial IRPs so the
1724 // stack location is valid.
1725 //
1726
1727 irpStack = IoGetNextIrpStackLocation(originalIrp);
1728
1729 //
1730 // Update status only if error so that if any partial transfer
1731 // completes with error, then the original IRP will return with
1732 // error. If any of the asynchronous partial transfer IRPs fail,
1733 // with an error then the original IRP will return 0 bytes transfered.
1734 // This is an optimization for successful transfers.
1735 //
1736
1737 if (!NT_SUCCESS(status)) {
1738
1739 originalIrp->IoStatus.Status = status;
1740 originalIrp->IoStatus.Information = 0;
1741
1742 //
1743 // Set the hard error if necessary.
1744 //
1745
1746 if (IoIsErrorUserInduced(status)) {
1747
1748 //
1749 // Store DeviceObject for filesystem.
1750 //
1751
1752 IoSetHardErrorOrVerifyDevice(originalIrp, DeviceObject);
1753 }
1754 }
1755
1756 //
1757 // Decrement and get the count of remaining IRPs.
1758 //
1759
1760 irpCount = InterlockedDecrement((PLONG)&irpStack->Parameters.Others.Argument1);
1761
1762 DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial IRPs left %d\n",
1763 irpCount));
1764
1765 //
1766 // Old bug could cause irp count to negative
1767 //
1768
1769 ASSERT(irpCount >= 0);
1770
1771 if (irpCount == 0) {
1772
1773 //
1774 // All partial IRPs have completed.
1775 //
1776
1777 DebugPrint((2,
1778 "ScsiClassIoCompleteAssociated: All partial IRPs complete %lx\n",
1779 originalIrp));
1780
1781 IoCompleteRequest(originalIrp, IO_DISK_INCREMENT);
1782
1783 //
1784 // If the class driver has supplied a startio, start the
1785 // next request.
1786 //
1787
1788 if (deviceExtension->ClassStartIo) {
1789 IoStartNextPacket(DeviceObject, FALSE);
1790 }
1791 }
1792
1793 //
1794 // Deallocate IRP and indicate the I/O system should not attempt any more
1795 // processing.
1796 //
1797
1798 IoFreeIrp(Irp);
1799 return STATUS_MORE_PROCESSING_REQUIRED;
1800
1801 } // end ScsiClassIoCompleteAssociated()
1802
1803 \f
1804 NTSTATUS
1805 NTAPI
1806 ScsiClassSendSrbSynchronous(
1807 PDEVICE_OBJECT DeviceObject,
1808 PSCSI_REQUEST_BLOCK Srb,
1809 PVOID BufferAddress,
1810 ULONG BufferLength,
1811 BOOLEAN WriteToDevice
1812 )
1813
1814 /*++
1815
1816 Routine Description:
1817
1818 This routine is called by SCSI device controls to complete an
1819 SRB and send it to the port driver synchronously (ie wait for
1820 completion). The CDB is already completed along with the SRB CDB
1821 size and request timeout value.
1822
1823 Arguments:
1824
1825 DeviceObject - Supplies the device object which represents the logical
1826 unit.
1827
1828 Srb - Supplies a partially initialized SRB. The SRB cannot come from zone.
1829
1830 BufferAddress - Supplies the address of the buffer.
1831
1832 BufferLength - Supplies the length in bytes of the buffer.
1833
1834 WriteToDevice - Indicates the data should be transfer to the device.
1835
1836 Return Value:
1837
1838 Nt status indicating the final results of the operation.
1839
1840 --*/
1841
1842 {
1843 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1844 IO_STATUS_BLOCK ioStatus;
1845 ULONG controlType, mjFunction;
1846 PIRP irp;
1847 PIO_STACK_LOCATION irpStack;
1848 KEVENT event;
1849 PUCHAR senseInfoBuffer;
1850 ULONG retryCount = MAXIMUM_RETRIES;
1851 NTSTATUS status;
1852 BOOLEAN retry;
1853 LARGE_INTEGER dummy;
1854
1855 PAGED_CODE();
1856
1857 dummy.QuadPart = 0;
1858
1859 //
1860 // Write length to SRB.
1861 //
1862
1863 Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1864
1865 //
1866 // Set SCSI bus address.
1867 //
1868
1869 Srb->PathId = deviceExtension->PathId;
1870 Srb->TargetId = deviceExtension->TargetId;
1871 Srb->Lun = deviceExtension->Lun;
1872 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1873
1874 //
1875 // NOTICE: The SCSI-II specification indicates that this field should be
1876 // zero; however, some target controllers ignore the logical unit number
1877 // in the INDENTIFY message and only look at the logical unit number field
1878 // in the CDB.
1879 //
1880
1881 Srb->Cdb[1] |= deviceExtension->Lun << 5;
1882
1883 //
1884 // Enable auto request sense.
1885 //
1886
1887 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1888
1889 //
1890 // Sense buffer is in aligned nonpaged pool.
1891 //
1892
1893 senseInfoBuffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
1894
1895 if (senseInfoBuffer == NULL) {
1896
1897 DebugPrint((1,
1898 "ScsiClassSendSrbSynchronous: Can't allocate request sense buffer\n"));
1899 return(STATUS_INSUFFICIENT_RESOURCES);
1900 }
1901
1902 Srb->SenseInfoBuffer = senseInfoBuffer;
1903 Srb->DataBuffer = BufferAddress;
1904
1905 //
1906 // Start retries here.
1907 //
1908
1909 retry:
1910
1911 //
1912 // Set the event object to the unsignaled state.
1913 // It will be used to signal request completion.
1914 //
1915
1916 KeInitializeEvent(&event, NotificationEvent, FALSE);
1917
1918 //
1919 // Set controlType and Srb direction flags.
1920 //
1921
1922 if (BufferAddress != NULL) {
1923
1924 if (WriteToDevice) {
1925
1926 controlType = IOCTL_SCSI_EXECUTE_OUT;
1927 Srb->SrbFlags = SRB_FLAGS_DATA_OUT;
1928 mjFunction = IRP_MJ_WRITE;
1929
1930 } else {
1931
1932 controlType = IOCTL_SCSI_EXECUTE_IN;
1933 Srb->SrbFlags = SRB_FLAGS_DATA_IN;
1934 mjFunction = IRP_MJ_READ;
1935 }
1936
1937 } else {
1938
1939 BufferLength = 0;
1940 controlType = IOCTL_SCSI_EXECUTE_NONE;
1941 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
1942 mjFunction = IRP_MJ_FLUSH_BUFFERS;
1943 }
1944
1945 //
1946 // Build device I/O control request with data transfer.
1947 //
1948 irp = IoBuildAsynchronousFsdRequest(
1949 mjFunction,
1950 deviceExtension->DeviceObject,
1951 BufferAddress,
1952 (BufferAddress) ? BufferLength : 0,
1953 &dummy,
1954 &ioStatus);
1955
1956 if (irp == NULL) {
1957 ExFreePool(senseInfoBuffer);
1958 DebugPrint((1, "ScsiClassSendSrbSynchronous: Can't allocate Irp\n"));
1959 return(STATUS_INSUFFICIENT_RESOURCES);
1960 }
1961
1962 // Set event field
1963 irp->UserEvent = &event;
1964
1965 //
1966 // Disable synchronous transfer for these requests.
1967 //
1968
1969 Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
1970
1971 //
1972 // Set the transfer length.
1973 //
1974
1975 Srb->DataTransferLength = BufferLength;
1976
1977 //
1978 // Zero out status.
1979 //
1980
1981 Srb->ScsiStatus = Srb->SrbStatus = 0;
1982 Srb->NextSrb = 0;
1983
1984 // Set completion routine
1985 IoSetCompletionRoutine(
1986 irp,
1987 ClassCompletionRoutine,
1988 NULL,
1989 TRUE,
1990 TRUE,
1991 TRUE);
1992
1993 //
1994 // Get next stack location.
1995 //
1996
1997 irpStack = IoGetNextIrpStackLocation(irp);
1998
1999 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
2000 irpStack->Parameters.DeviceIoControl.IoControlCode = controlType;
2001
2002 //
2003 // Set up SRB for execute scsi request. Save SRB address in next stack
2004 // for the port driver.
2005 //
2006
2007 irpStack->Parameters.Scsi.Srb = Srb;
2008
2009 //
2010 // Set up IRP Address.
2011 //
2012
2013 Srb->OriginalRequest = irp;
2014
2015 //
2016 // Call the port driver with the request and wait for it to complete.
2017 //
2018
2019 status = IoCallDriver(deviceExtension->PortDeviceObject, irp);
2020
2021 if (status == STATUS_PENDING) {
2022 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
2023 }
2024
2025 //
2026 // Check that request completed without error.
2027 //
2028
2029 if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) {
2030
2031 //
2032 // Release the queue if it is frozen.
2033 //
2034
2035 if (Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
2036 ScsiClassReleaseQueue(DeviceObject);
2037 }
2038
2039 //
2040 // Update status and determine if request should be retried.
2041 //
2042
2043 retry = ScsiClassInterpretSenseInfo(DeviceObject,
2044 Srb,
2045 IRP_MJ_SCSI,
2046 0,
2047 MAXIMUM_RETRIES - retryCount,
2048 &status);
2049
2050 if (retry) {
2051
2052 if ((status == STATUS_DEVICE_NOT_READY && ((PSENSE_DATA) senseInfoBuffer)
2053 ->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) ||
2054 SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT) {
2055
2056 LARGE_INTEGER delay;
2057
2058 //
2059 // Delay for 2 seconds.
2060 //
2061
2062 delay.QuadPart = (LONGLONG)( - 10 * 1000 * 1000 * 2 );
2063
2064 //
2065 // Stall for a while to let the controller spinup.
2066 //
2067
2068 KeDelayExecutionThread(KernelMode,
2069 FALSE,
2070 &delay);
2071
2072 }
2073
2074 //
2075 // If retries are not exhausted then retry this operation.
2076 //
2077
2078 if (retryCount--) {
2079 goto retry;
2080 }
2081 }
2082
2083 } else {
2084
2085 status = STATUS_SUCCESS;
2086 }
2087
2088 ExFreePool(senseInfoBuffer);
2089 return status;
2090
2091 } // end ScsiClassSendSrbSynchronous()
2092
2093 \f
2094 BOOLEAN
2095 NTAPI
2096 ScsiClassInterpretSenseInfo(
2097 IN PDEVICE_OBJECT DeviceObject,
2098 IN PSCSI_REQUEST_BLOCK Srb,
2099 IN UCHAR MajorFunctionCode,
2100 IN ULONG IoDeviceCode,
2101 IN ULONG RetryCount,
2102 OUT NTSTATUS *Status
2103 )
2104
2105 /*++
2106
2107 Routine Description:
2108
2109 This routine interprets the data returned from the SCSI
2110 request sense. It determines the status to return in the
2111 IRP and whether this request can be retried.
2112
2113 Arguments:
2114
2115 DeviceObject - Supplies the device object associated with this request.
2116
2117 Srb - Supplies the scsi request block which failed.
2118
2119 MajorFunctionCode - Supplies the function code to be used for logging.
2120
2121 IoDeviceCode - Supplies the device code to be used for logging.
2122
2123 Status - Returns the status for the request.
2124
2125 Return Value:
2126
2127 BOOLEAN TRUE: Drivers should retry this request.
2128 FALSE: Drivers should not retry this request.
2129
2130 --*/
2131
2132 {
2133 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2134 PDEVICE_EXTENSION physicalExtension = deviceExtension->PhysicalDevice->DeviceExtension;
2135 PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
2136 BOOLEAN retry = TRUE;
2137 BOOLEAN logError = FALSE;
2138 ULONG badSector = 0;
2139 ULONG uniqueId = 0;
2140 NTSTATUS logStatus;
2141 ULONG readSector;
2142 ULONG index;
2143 PIO_ERROR_LOG_PACKET errorLogEntry;
2144 #if DBG
2145 ULONG i;
2146 #endif
2147
2148
2149 //
2150 // Check that request sense buffer is valid.
2151 //
2152
2153 #if DBG
2154 DebugPrint((3, "Opcode %x\nParameters: ",Srb->Cdb[0]));
2155 for (i = 1; i < 12; i++) {
2156 DebugPrint((3,"%x ",Srb->Cdb[i]));
2157 }
2158 DebugPrint((3,"\n"));
2159 #endif
2160
2161 if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID &&
2162 Srb->SenseInfoBufferLength >= FIELD_OFFSET(SENSE_DATA, CommandSpecificInformation)) {
2163
2164 DebugPrint((1,"ScsiClassInterpretSenseInfo: Error code is %x\n",
2165 senseBuffer->ErrorCode));
2166 DebugPrint((1,"ScsiClassInterpretSenseInfo: Sense key is %x\n",
2167 senseBuffer->SenseKey));
2168 DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code is %x\n",
2169 senseBuffer->AdditionalSenseCode));
2170 DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code qualifier is %x\n",
2171 senseBuffer->AdditionalSenseCodeQualifier));
2172
2173 //
2174 // Zero the additional sense code and additional sense code qualifier
2175 // if they were not returned by the device.
2176 //
2177
2178 readSector = senseBuffer->AdditionalSenseLength +
2179 FIELD_OFFSET(SENSE_DATA, AdditionalSenseLength);
2180
2181 if (readSector > Srb->SenseInfoBufferLength) {
2182 readSector = Srb->SenseInfoBufferLength;
2183 }
2184
2185 if (readSector <= FIELD_OFFSET(SENSE_DATA, AdditionalSenseCode)) {
2186 senseBuffer->AdditionalSenseCode = 0;
2187 }
2188
2189 if (readSector <= FIELD_OFFSET(SENSE_DATA, AdditionalSenseCodeQualifier)) {
2190 senseBuffer->AdditionalSenseCodeQualifier = 0;
2191 }
2192
2193 switch (senseBuffer->SenseKey & 0xf) {
2194
2195 case SCSI_SENSE_NOT_READY:
2196
2197 DebugPrint((1,"ScsiClassInterpretSenseInfo: Device not ready\n"));
2198 *Status = STATUS_DEVICE_NOT_READY;
2199
2200 switch (senseBuffer->AdditionalSenseCode) {
2201
2202 case SCSI_ADSENSE_LUN_NOT_READY:
2203
2204 DebugPrint((1,"ScsiClassInterpretSenseInfo: Lun not ready\n"));
2205
2206 switch (senseBuffer->AdditionalSenseCodeQualifier) {
2207
2208 case SCSI_SENSEQ_BECOMING_READY:
2209
2210 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2211 " In process of becoming ready\n"));
2212 break;
2213
2214 case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED:
2215
2216 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2217 " Manual intervention required\n"));
2218 *Status = STATUS_NO_MEDIA_IN_DEVICE;
2219 retry = FALSE;
2220 break;
2221
2222 case SCSI_SENSEQ_FORMAT_IN_PROGRESS:
2223
2224 DebugPrint((1, "ScsiClassInterpretSenseInfo: Format in progress\n"));
2225 retry = FALSE;
2226 break;
2227
2228 case SCSI_SENSEQ_INIT_COMMAND_REQUIRED:
2229
2230 default:
2231
2232 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2233 " Initializing command required\n"));
2234
2235 //
2236 // This sense code/additional sense code
2237 // combination may indicate that the device
2238 // needs to be started. Send an start unit if this
2239 // is a disk device.
2240 //
2241
2242 if (deviceExtension->DeviceFlags & DEV_SAFE_START_UNIT) {
2243 StartUnit(DeviceObject);
2244 }
2245
2246 break;
2247
2248 } // end switch (senseBuffer->AdditionalSenseCodeQualifier)
2249
2250 break;
2251
2252 case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE:
2253
2254 DebugPrint((1,
2255 "ScsiClassInterpretSenseInfo:"
2256 " No Media in device.\n"));
2257 *Status = STATUS_NO_MEDIA_IN_DEVICE;
2258 retry = FALSE;
2259
2260 //
2261 // signal autorun that there isn't any media in the device
2262 //
2263
2264 if((deviceExtension->MediaChangeEvent != NULL)&&
2265 (!deviceExtension->MediaChangeNoMedia)) {
2266 KeSetEvent(deviceExtension->MediaChangeEvent,
2267 (KPRIORITY) 0,
2268 FALSE);
2269 DebugPrint((0, "ScsiClassInterpretSenseInfo:"
2270 "Detected No Media In Device "
2271 "[irp = 0x%lx]\n", Srb->OriginalRequest));
2272 deviceExtension->MediaChangeNoMedia = TRUE;
2273 }
2274
2275 break;
2276 } // end switch (senseBuffer->AdditionalSenseCode)
2277
2278 break;
2279
2280 case SCSI_SENSE_DATA_PROTECT:
2281
2282 DebugPrint((1, "ScsiClassInterpretSenseInfo: Media write protected\n"));
2283 *Status = STATUS_MEDIA_WRITE_PROTECTED;
2284 retry = FALSE;
2285 break;
2286
2287 case SCSI_SENSE_MEDIUM_ERROR:
2288
2289 DebugPrint((1,"ScsiClassInterpretSenseInfo: Bad media\n"));
2290 *Status = STATUS_DEVICE_DATA_ERROR;
2291
2292 retry = FALSE;
2293 logError = TRUE;
2294 uniqueId = 256;
2295 logStatus = 0;//IO_ERR_BAD_BLOCK;
2296 break;
2297
2298 case SCSI_SENSE_HARDWARE_ERROR:
2299
2300 DebugPrint((1,"ScsiClassInterpretSenseInfo: Hardware error\n"));
2301 *Status = STATUS_IO_DEVICE_ERROR;
2302
2303 logError = TRUE;
2304 uniqueId = 257;
2305 logStatus = 0;//IO_ERR_CONTROLLER_ERROR;
2306
2307 break;
2308
2309 case SCSI_SENSE_ILLEGAL_REQUEST:
2310
2311 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal SCSI request\n"));
2312 *Status = STATUS_INVALID_DEVICE_REQUEST;
2313
2314 switch (senseBuffer->AdditionalSenseCode) {
2315
2316 case SCSI_ADSENSE_ILLEGAL_COMMAND:
2317 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal command\n"));
2318 retry = FALSE;
2319 break;
2320
2321 case SCSI_ADSENSE_ILLEGAL_BLOCK:
2322 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal block address\n"));
2323 *Status = STATUS_NONEXISTENT_SECTOR;
2324 retry = FALSE;
2325 break;
2326
2327 case SCSI_ADSENSE_INVALID_LUN:
2328 DebugPrint((1,"ScsiClassInterpretSenseInfo: Invalid LUN\n"));
2329 *Status = STATUS_NO_SUCH_DEVICE;
2330 retry = FALSE;
2331 break;
2332
2333 case SCSI_ADSENSE_MUSIC_AREA:
2334 DebugPrint((1,"ScsiClassInterpretSenseInfo: Music area\n"));
2335 retry = FALSE;
2336 break;
2337
2338 case SCSI_ADSENSE_DATA_AREA:
2339 DebugPrint((1,"ScsiClassInterpretSenseInfo: Data area\n"));
2340 retry = FALSE;
2341 break;
2342
2343 case SCSI_ADSENSE_VOLUME_OVERFLOW:
2344 DebugPrint((1, "ScsiClassInterpretSenseInfo: Volume overflow\n"));
2345 retry = FALSE;
2346 break;
2347
2348 case SCSI_ADSENSE_INVALID_CDB:
2349 DebugPrint((1, "ScsiClassInterpretSenseInfo: Invalid CDB\n"));
2350
2351 //
2352 // Check if write cache enabled.
2353 //
2354
2355 if (deviceExtension->DeviceFlags & DEV_WRITE_CACHE) {
2356
2357 //
2358 // Assume FUA is not supported.
2359 //
2360
2361 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
2362 retry = TRUE;
2363
2364 } else {
2365 retry = FALSE;
2366 }
2367
2368 break;
2369
2370 } // end switch (senseBuffer->AdditionalSenseCode)
2371
2372 break;
2373
2374 case SCSI_SENSE_UNIT_ATTENTION:
2375
2376 switch (senseBuffer->AdditionalSenseCode) {
2377 case SCSI_ADSENSE_MEDIUM_CHANGED:
2378 DebugPrint((1, "ScsiClassInterpretSenseInfo: Media changed\n"));
2379
2380 if(deviceExtension->MediaChangeEvent != NULL) {
2381
2382 KeSetEvent(deviceExtension->MediaChangeEvent,
2383 (KPRIORITY) 0,
2384 FALSE);
2385 DebugPrint((0, "ScsiClassInterpretSenseInfo:"
2386 "New Media Found - Setting MediaChanged event"
2387 " [irp = 0x%lx]\n", Srb->OriginalRequest));
2388 deviceExtension->MediaChangeNoMedia = FALSE;
2389
2390 }
2391 break;
2392
2393 case SCSI_ADSENSE_BUS_RESET:
2394 DebugPrint((1,"ScsiClassInterpretSenseInfo: Bus reset\n"));
2395 break;
2396
2397 default:
2398 DebugPrint((1,"ScsiClassInterpretSenseInfo: Unit attention\n"));
2399 break;
2400
2401 } // end switch (senseBuffer->AdditionalSenseCode)
2402
2403 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA &&
2404 DeviceObject->Vpb->Flags & VPB_MOUNTED) {
2405
2406 //
2407 // Set bit to indicate that media may have changed
2408 // and volume needs verification.
2409 //
2410
2411 DeviceObject->Flags |= DO_VERIFY_VOLUME;
2412
2413 *Status = STATUS_VERIFY_REQUIRED;
2414 retry = FALSE;
2415
2416 } else {
2417
2418 *Status = STATUS_IO_DEVICE_ERROR;
2419
2420 }
2421
2422 //
2423 // A media change may have occured so increment the change
2424 // count for the physical device
2425 //
2426
2427 physicalExtension->MediaChangeCount++;
2428
2429 DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change "
2430 "count for device %d is %d\n",
2431 physicalExtension->DeviceNumber,
2432 physicalExtension->MediaChangeCount));
2433
2434 break;
2435
2436 case SCSI_SENSE_ABORTED_COMMAND:
2437
2438 DebugPrint((1,"ScsiClassInterpretSenseInfo: Command aborted\n"));
2439 *Status = STATUS_IO_DEVICE_ERROR;
2440 break;
2441
2442 case SCSI_SENSE_RECOVERED_ERROR:
2443
2444 DebugPrint((1,"ScsiClassInterpretSenseInfo: Recovered error\n"));
2445 *Status = STATUS_SUCCESS;
2446 retry = FALSE;
2447 logError = TRUE;
2448 uniqueId = 258;
2449
2450 switch(senseBuffer->AdditionalSenseCode) {
2451 case SCSI_ADSENSE_SEEK_ERROR:
2452 case SCSI_ADSENSE_TRACK_ERROR:
2453 logStatus = 0;//IO_ERR_SEEK_ERROR;
2454 break;
2455
2456 case SCSI_ADSENSE_REC_DATA_NOECC:
2457 case SCSI_ADSENSE_REC_DATA_ECC:
2458 logStatus = 0;//IO_RECOVERED_VIA_ECC;
2459 break;
2460
2461 default:
2462 logStatus = 0;//IO_ERR_CONTROLLER_ERROR;
2463 break;
2464
2465 } // end switch(senseBuffer->AdditionalSenseCode)
2466
2467 if (senseBuffer->IncorrectLength) {
2468
2469 DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
2470 *Status = STATUS_INVALID_BLOCK_LENGTH ;
2471 }
2472
2473 break;
2474
2475 case SCSI_SENSE_NO_SENSE:
2476
2477 //
2478 // Check other indicators.
2479 //
2480
2481 if (senseBuffer->IncorrectLength) {
2482
2483 DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
2484 *Status = STATUS_INVALID_BLOCK_LENGTH ;
2485 retry = FALSE;
2486
2487 } else {
2488
2489 DebugPrint((1, "ScsiClassInterpretSenseInfo: No specific sense key\n"));
2490 *Status = STATUS_IO_DEVICE_ERROR;
2491 retry = TRUE;
2492 }
2493
2494 break;
2495
2496 default:
2497
2498 DebugPrint((1, "ScsiClassInterpretSenseInfo: Unrecognized sense code\n"));
2499 *Status = STATUS_IO_DEVICE_ERROR;
2500 break;
2501
2502 } // end switch (senseBuffer->SenseKey & 0xf)
2503
2504 //
2505 // Try to determine the bad sector from the inquiry data.
2506 //
2507
2508 if ((((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_READ ||
2509 ((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_VERIFY ||
2510 ((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_WRITE)) {
2511
2512 for (index = 0; index < 4; index++) {
2513 badSector = (badSector << 8) | senseBuffer->Information[index];
2514 }
2515
2516 readSector = 0;
2517 for (index = 0; index < 4; index++) {
2518 readSector = (readSector << 8) | Srb->Cdb[index+2];
2519 }
2520
2521 index = (((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb << 8) |
2522 ((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb;
2523
2524 //
2525 // Make sure the bad sector is within the read sectors.
2526 //
2527
2528 if (!(badSector >= readSector && badSector < readSector + index)) {
2529 badSector = readSector;
2530 }
2531 }
2532
2533 } else {
2534
2535 //
2536 // Request sense buffer not valid. No sense information
2537 // to pinpoint the error. Return general request fail.
2538 //
2539
2540 DebugPrint((1,"ScsiClassInterpretSenseInfo: Request sense info not valid. SrbStatus %2x\n",
2541 SRB_STATUS(Srb->SrbStatus)));
2542 retry = TRUE;
2543
2544 switch (SRB_STATUS(Srb->SrbStatus)) {
2545 case SRB_STATUS_INVALID_LUN:
2546 case SRB_STATUS_INVALID_TARGET_ID:
2547 case SRB_STATUS_NO_DEVICE:
2548 case SRB_STATUS_NO_HBA:
2549 case SRB_STATUS_INVALID_PATH_ID:
2550 *Status = STATUS_NO_SUCH_DEVICE;
2551 retry = FALSE;
2552 break;
2553
2554 case SRB_STATUS_COMMAND_TIMEOUT:
2555 case SRB_STATUS_ABORTED:
2556 case SRB_STATUS_TIMEOUT:
2557
2558 //
2559 // Update the error count for the device.
2560 //
2561
2562 deviceExtension->ErrorCount++;
2563 *Status = STATUS_IO_TIMEOUT;
2564 break;
2565
2566 case SRB_STATUS_SELECTION_TIMEOUT:
2567 logError = TRUE;
2568 logStatus = 0;//IO_ERR_NOT_READY;
2569 uniqueId = 260;
2570 *Status = STATUS_DEVICE_NOT_CONNECTED;
2571 retry = FALSE;
2572 break;
2573
2574 case SRB_STATUS_DATA_OVERRUN:
2575 *Status = STATUS_DATA_OVERRUN;
2576 retry = FALSE;
2577 break;
2578
2579 case SRB_STATUS_PHASE_SEQUENCE_FAILURE:
2580
2581 //
2582 // Update the error count for the device.
2583 //
2584
2585 deviceExtension->ErrorCount++;
2586 *Status = STATUS_IO_DEVICE_ERROR;
2587
2588 //
2589 // If there was phase sequence error then limit the number of
2590 // retries.
2591 //
2592
2593 if (RetryCount > 1 ) {
2594 retry = FALSE;
2595 }
2596
2597 break;
2598
2599 case SRB_STATUS_REQUEST_FLUSHED:
2600
2601 //
2602 // If the status needs verification bit is set. Then set
2603 // the status to need verification and no retry; otherwise,
2604 // just retry the request.
2605 //
2606
2607 if (DeviceObject->Flags & DO_VERIFY_VOLUME ) {
2608
2609 *Status = STATUS_VERIFY_REQUIRED;
2610 retry = FALSE;
2611 } else {
2612 *Status = STATUS_IO_DEVICE_ERROR;
2613 }
2614
2615 break;
2616
2617 case SRB_STATUS_INVALID_REQUEST:
2618
2619 //
2620 // An invalid request was attempted.
2621 //
2622
2623 *Status = STATUS_INVALID_DEVICE_REQUEST;
2624 retry = FALSE;
2625 break;
2626
2627 case SRB_STATUS_UNEXPECTED_BUS_FREE:
2628 case SRB_STATUS_PARITY_ERROR:
2629
2630 //
2631 // Update the error count for the device.
2632 //
2633
2634 deviceExtension->ErrorCount++;
2635
2636 //
2637 // Fall through to below.
2638 //
2639
2640 case SRB_STATUS_BUS_RESET:
2641 *Status = STATUS_IO_DEVICE_ERROR;
2642 break;
2643
2644 case SRB_STATUS_ERROR:
2645
2646 *Status = STATUS_IO_DEVICE_ERROR;
2647 if (Srb->ScsiStatus == 0) {
2648
2649 //
2650 // This is some strange return code. Update the error
2651 // count for the device.
2652 //
2653
2654 deviceExtension->ErrorCount++;
2655
2656 } if (Srb->ScsiStatus == SCSISTAT_BUSY) {
2657
2658 *Status = STATUS_DEVICE_NOT_READY;
2659
2660 } if (Srb->ScsiStatus == SCSISTAT_RESERVATION_CONFLICT) {
2661
2662 *Status = STATUS_DEVICE_BUSY;
2663 retry = FALSE;
2664
2665 }
2666
2667 break;
2668
2669 default:
2670 logError = TRUE;
2671 logStatus = 0;//IO_ERR_CONTROLLER_ERROR;
2672 uniqueId = 259;
2673 *Status = STATUS_IO_DEVICE_ERROR;
2674 break;
2675
2676 }
2677
2678 //
2679 // If the error count has exceeded the error limit, then disable
2680 // any tagged queuing, multiple requests per lu queueing
2681 // and sychronous data transfers.
2682 //
2683
2684 if (deviceExtension->ErrorCount == 4) {
2685
2686 //
2687 // Clearing the no queue freeze flag prevents the port driver
2688 // from sending multiple requests per logical unit.
2689 //
2690
2691 deviceExtension->SrbFlags &= ~(SRB_FLAGS_QUEUE_ACTION_ENABLE |
2692 SRB_FLAGS_NO_QUEUE_FREEZE);
2693
2694 deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
2695 DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling tagged queuing and synchronous data tranfers.\n"));
2696
2697 } else if (deviceExtension->ErrorCount == 8) {
2698
2699 //
2700 // If a second threshold is reached, disable disconnects.
2701 //
2702
2703 deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT;
2704 DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling disconnects.\n"));
2705 }
2706 }
2707
2708 //
2709 // If there is a class specific error handler call it.
2710 //
2711
2712 if (deviceExtension->ClassError != NULL) {
2713
2714 deviceExtension->ClassError(DeviceObject,
2715 Srb,
2716 Status,
2717 &retry);
2718 }
2719
2720 //
2721 // Log an error if necessary.
2722 //
2723
2724 if (logError) {
2725
2726 errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
2727 DeviceObject,
2728 sizeof(IO_ERROR_LOG_PACKET) + 5 * sizeof(ULONG));
2729
2730 if (errorLogEntry == NULL) {
2731
2732 //
2733 // Return if no packet could be allocated.
2734 //
2735
2736 return retry;
2737
2738 }
2739
2740 if (retry && RetryCount < MAXIMUM_RETRIES) {
2741 errorLogEntry->FinalStatus = STATUS_SUCCESS;
2742 } else {
2743 errorLogEntry->FinalStatus = *Status;
2744 }
2745
2746 //
2747 // Calculate the device offset if there is a geometry.
2748 //
2749
2750 if (deviceExtension->DiskGeometry != NULL) {
2751
2752 errorLogEntry->DeviceOffset.QuadPart = (LONGLONG) badSector;
2753 errorLogEntry->DeviceOffset = RtlExtendedIntegerMultiply(
2754 errorLogEntry->DeviceOffset,
2755 deviceExtension->DiskGeometry->BytesPerSector);
2756 }
2757
2758 errorLogEntry->ErrorCode = logStatus;
2759 errorLogEntry->SequenceNumber = 0;
2760 errorLogEntry->MajorFunctionCode = MajorFunctionCode;
2761 errorLogEntry->IoControlCode = IoDeviceCode;
2762 errorLogEntry->RetryCount = (UCHAR) RetryCount;
2763 errorLogEntry->UniqueErrorValue = uniqueId;
2764 errorLogEntry->DumpDataSize = 6 * sizeof(ULONG);
2765 errorLogEntry->DumpData[0] = Srb->PathId;
2766 errorLogEntry->DumpData[1] = Srb->TargetId;
2767 errorLogEntry->DumpData[2] = Srb->Lun;
2768 errorLogEntry->DumpData[3] = 0;
2769 errorLogEntry->DumpData[4] = Srb->SrbStatus << 8 | Srb->ScsiStatus;
2770
2771 if (senseBuffer != NULL) {
2772 errorLogEntry->DumpData[5] = senseBuffer->SenseKey << 16 |
2773 senseBuffer->AdditionalSenseCode << 8 |
2774 senseBuffer->AdditionalSenseCodeQualifier;
2775
2776 }
2777
2778 //
2779 // Write the error log packet.
2780 //
2781
2782 IoWriteErrorLogEntry(errorLogEntry);
2783 }
2784
2785 return retry;
2786
2787 } // end ScsiClassInterpretSenseInfo()
2788
2789 \f
2790 VOID
2791 NTAPI
2792 RetryRequest(
2793 PDEVICE_OBJECT DeviceObject,
2794 PIRP Irp,
2795 PSCSI_REQUEST_BLOCK Srb,
2796 BOOLEAN Associated
2797 )
2798
2799 /*++
2800
2801 Routine Description:
2802
2803 This routine reinitalizes the necessary fields, and sends the request
2804 to the port driver.
2805
2806 Arguments:
2807
2808 DeviceObject - Supplies the device object associated with this request.
2809
2810 Irp - Supplies the request to be retried.
2811
2812 Srb - Supplies a Pointer to the SCSI request block to be retied.
2813
2814 Assocaiated - Indicates this is an assocatied Irp created by split request.
2815
2816 Return Value:
2817
2818 None
2819
2820 --*/
2821
2822 {
2823 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2824 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
2825 PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
2826 ULONG transferByteCount;
2827
2828 //
2829 // Determine the transfer count of the request. If this is a read or a
2830 // write then the transfer count is in the Irp stack. Otherwise assume
2831 // the MDL contains the correct length. If there is no MDL then the
2832 // transfer length must be zero.
2833 //
2834
2835 if (currentIrpStack->MajorFunction == IRP_MJ_READ ||
2836 currentIrpStack->MajorFunction == IRP_MJ_WRITE) {
2837
2838 transferByteCount = currentIrpStack->Parameters.Read.Length;
2839
2840 } else if (Irp->MdlAddress != NULL) {
2841
2842 //
2843 // Note this assumes that only read and write requests are spilt and
2844 // other request do not need to be. If the data buffer address in
2845 // the MDL and the SRB don't match then transfer length is most
2846 // likely incorrect.
2847 //
2848
2849 ASSERT(Srb->DataBuffer == MmGetMdlVirtualAddress(Irp->MdlAddress));
2850 transferByteCount = Irp->MdlAddress->ByteCount;
2851
2852 } else {
2853
2854 transferByteCount = 0;
2855 }
2856
2857 //
2858 // Reset byte count of transfer in SRB Extension.
2859 //
2860
2861 Srb->DataTransferLength = transferByteCount;
2862
2863 //
2864 // Zero SRB statuses.
2865 //
2866
2867 Srb->SrbStatus = Srb->ScsiStatus = 0;
2868
2869 //
2870 // Set the no disconnect flag, disable synchronous data transfers and
2871 // disable tagged queuing. This fixes some errors.
2872 //
2873
2874 Srb->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT |
2875 SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
2876
2877 Srb->SrbFlags &= ~SRB_FLAGS_QUEUE_ACTION_ENABLE;
2878 Srb->QueueTag = SP_UNTAGGED;
2879
2880 //
2881 // Set up major SCSI function.
2882 //
2883
2884 nextIrpStack->MajorFunction = IRP_MJ_SCSI;
2885
2886 //
2887 // Save SRB address in next stack for port driver.
2888 //
2889
2890 nextIrpStack->Parameters.Scsi.Srb = Srb;
2891
2892 //
2893 // Set up IoCompletion routine address.
2894 //
2895
2896 if (Associated) {
2897
2898 IoSetCompletionRoutine(Irp, ScsiClassIoCompleteAssociated, Srb, TRUE, TRUE, TRUE);
2899
2900 } else {
2901
2902 IoSetCompletionRoutine(Irp, ScsiClassIoComplete, Srb, TRUE, TRUE, TRUE);
2903 }
2904
2905 //
2906 // Pass the request to the port driver.
2907 //
2908
2909 (VOID)IoCallDriver(deviceExtension->PortDeviceObject, Irp);
2910
2911 } // end RetryRequest()
2912 \f
2913 VOID
2914 NTAPI
2915 ScsiClassBuildRequest(
2916 PDEVICE_OBJECT DeviceObject,
2917 PIRP Irp
2918 )
2919
2920 /*++
2921
2922 Routine Description:
2923
2924 This routine allocates and builds an Srb for a read or write request.
2925 The block address and length are supplied by the Irp. The retry count
2926 is stored in the current stack for use by ScsiClassIoComplete which
2927 processes these requests when they complete. The Irp is ready to be
2928 passed to the port driver when this routine returns.
2929
2930 Arguments:
2931
2932 DeviceObject - Supplies the device object associated with this request.
2933
2934 Irp - Supplies the request to be retried.
2935
2936 Note:
2937
2938 If the IRP is for a disk transfer, the byteoffset field
2939 will already have been adjusted to make it relative to
2940 the beginning of the disk.
2941
2942
2943 Return Value:
2944
2945 None.
2946
2947 --*/
2948
2949 {
2950 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2951 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
2952 PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
2953 LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
2954 PSCSI_REQUEST_BLOCK srb;
2955 PCDB cdb;
2956 ULONG logicalBlockAddress;
2957 USHORT transferBlocks;
2958
2959 //
2960 // Calculate relative sector address.
2961 //
2962
2963 logicalBlockAddress = (ULONG)(Int64ShrlMod32(startingOffset.QuadPart, deviceExtension->SectorShift));
2964
2965 //
2966 // Allocate an Srb.
2967 //
2968
2969 srb = ExAllocateFromNPagedLookasideList(&deviceExtension->SrbLookasideListHead);
2970
2971 srb->SrbFlags = 0;
2972
2973 //
2974 // Write length to SRB.
2975 //
2976
2977 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
2978
2979 //
2980 // Set up IRP Address.
2981 //
2982
2983 srb->OriginalRequest = Irp;
2984
2985 //
2986 // Set up target ID and logical unit number.
2987 //
2988
2989 srb->PathId = deviceExtension->PathId;
2990 srb->TargetId = deviceExtension->TargetId;
2991 srb->Lun = deviceExtension->Lun;
2992 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
2993 srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
2994
2995 //
2996 // Save byte count of transfer in SRB Extension.
2997 //
2998
2999 srb->DataTransferLength = currentIrpStack->Parameters.Read.Length;
3000
3001 //
3002 // Initialize the queue actions field.
3003 //
3004
3005 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
3006
3007 //
3008 // Queue sort key is Relative Block Address.
3009 //
3010
3011 srb->QueueSortKey = logicalBlockAddress;
3012
3013 //
3014 // Indicate auto request sense by specifying buffer and size.
3015 //
3016
3017 srb->SenseInfoBuffer = deviceExtension->SenseData;
3018 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
3019
3020 //
3021 // Set timeout value of one unit per 64k bytes of data.
3022 //
3023
3024 srb->TimeOutValue = ((srb->DataTransferLength + 0xFFFF) >> 16) *
3025 deviceExtension->TimeOutValue;
3026
3027 //
3028 // Zero statuses.
3029 //
3030
3031 srb->SrbStatus = srb->ScsiStatus = 0;
3032 srb->NextSrb = 0;
3033
3034 //
3035 // Indicate that 10-byte CDB's will be used.
3036 //
3037
3038 srb->CdbLength = 10;
3039
3040 //
3041 // Fill in CDB fields.
3042 //
3043
3044 cdb = (PCDB)srb->Cdb;
3045
3046 //
3047 // Zero 12 bytes for Atapi Packets
3048 //
3049
3050 RtlZeroMemory(cdb, MAXIMUM_CDB_SIZE);
3051
3052 cdb->CDB10.LogicalUnitNumber = deviceExtension->Lun;
3053 transferBlocks = (USHORT)(currentIrpStack->Parameters.Read.Length >> deviceExtension->SectorShift);
3054
3055 //
3056 // Move little endian values into CDB in big endian format.
3057 //
3058
3059 cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte3;
3060 cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte2;
3061 cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte1;
3062 cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte0;
3063
3064 cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&transferBlocks)->Byte1;
3065 cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&transferBlocks)->Byte0;
3066
3067 //
3068 // Set transfer direction flag and Cdb command.
3069 //
3070
3071 if (currentIrpStack->MajorFunction == IRP_MJ_READ) {
3072
3073 DebugPrint((3, "ScsiClassBuildRequest: Read Command\n"));
3074
3075 srb->SrbFlags |= SRB_FLAGS_DATA_IN;
3076 cdb->CDB10.OperationCode = SCSIOP_READ;
3077
3078 } else {
3079
3080 DebugPrint((3, "ScsiClassBuildRequest: Write Command\n"));
3081
3082 srb->SrbFlags |= SRB_FLAGS_DATA_OUT;
3083 cdb->CDB10.OperationCode = SCSIOP_WRITE;
3084 }
3085
3086 //
3087 // If this is not a write-through request, then allow caching.
3088 //
3089
3090 if (!(currentIrpStack->Flags & SL_WRITE_THROUGH)) {
3091
3092 srb->SrbFlags |= SRB_FLAGS_ADAPTER_CACHE_ENABLE;
3093
3094 } else {
3095
3096 //
3097 // If write caching is enable then force media access in the
3098 // cdb.
3099 //
3100
3101 if (deviceExtension->DeviceFlags & DEV_WRITE_CACHE) {
3102 cdb->CDB10.ForceUnitAccess = TRUE;
3103 }
3104 }
3105
3106 //
3107 // Or in the default flags from the device object.
3108 //
3109
3110 srb->SrbFlags |= deviceExtension->SrbFlags;
3111
3112 //
3113 // Set up major SCSI function.
3114 //
3115
3116 nextIrpStack->MajorFunction = IRP_MJ_SCSI;
3117
3118 //
3119 // Save SRB address in next stack for port driver.
3120 //
3121
3122 nextIrpStack->Parameters.Scsi.Srb = srb;
3123
3124 //
3125 // Save retry count in current IRP stack.
3126 //
3127
3128 currentIrpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
3129
3130 //
3131 // Set up IoCompletion routine address.
3132 //
3133
3134 IoSetCompletionRoutine(Irp, ScsiClassIoComplete, srb, TRUE, TRUE, TRUE);
3135
3136 return;
3137
3138 } // end ScsiClassBuildRequest()
3139 \f
3140 ULONG
3141 NTAPI
3142 ScsiClassModeSense(
3143 IN PDEVICE_OBJECT DeviceObject,
3144 IN PCHAR ModeSenseBuffer,
3145 IN ULONG Length,
3146 IN UCHAR PageMode
3147 )
3148
3149 /*++
3150
3151 Routine Description:
3152
3153 This routine sends a mode sense command to a target ID and returns
3154 when it is complete.
3155
3156 Arguments:
3157
3158 DeviceObject - Supplies the device object associated with this request.
3159
3160 ModeSenseBuffer - Supplies a buffer to store the sense data.
3161
3162 Length - Supplies the length in bytes of the mode sense buffer.
3163
3164 PageMode - Supplies the page or pages of mode sense data to be retrived.
3165
3166 Return Value:
3167
3168 Length of the transferred data is returned.
3169
3170 --*/
3171 {
3172 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3173 PCDB cdb;
3174 SCSI_REQUEST_BLOCK srb;
3175 ULONG retries = 1;
3176 NTSTATUS status;
3177
3178 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
3179
3180 //
3181 // Build the MODE SENSE CDB.
3182 //
3183
3184 srb.CdbLength = 6;
3185 cdb = (PCDB)srb.Cdb;
3186
3187 //
3188 // Set timeout value from device extension.
3189 //
3190
3191 srb.TimeOutValue = deviceExtension->TimeOutValue;
3192
3193 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
3194 cdb->MODE_SENSE.PageCode = PageMode;
3195 cdb->MODE_SENSE.AllocationLength = (UCHAR)Length;
3196
3197 Retry:
3198
3199 status = ScsiClassSendSrbSynchronous(DeviceObject,
3200 &srb,
3201 ModeSenseBuffer,
3202 Length,
3203 FALSE);
3204
3205
3206 if (status == STATUS_VERIFY_REQUIRED) {
3207
3208 //
3209 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
3210 // this status. MODE SENSE commands should be retried anyway.
3211 //
3212
3213 if (retries--) {
3214
3215 //
3216 // Retry request.
3217 //
3218
3219 goto Retry;
3220 }
3221
3222 } else if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
3223 status = STATUS_SUCCESS;
3224 }
3225
3226 if (NT_SUCCESS(status)) {
3227 return(srb.DataTransferLength);
3228 } else {
3229 return(0);
3230 }
3231
3232 } // end ScsiClassModeSense()
3233
3234 \f
3235 PVOID
3236 NTAPI
3237 ScsiClassFindModePage(
3238 IN PCHAR ModeSenseBuffer,
3239 IN ULONG Length,
3240 IN UCHAR PageMode,
3241 IN BOOLEAN Use6Byte
3242 )
3243
3244 /*++
3245
3246 Routine Description:
3247
3248 This routine scans through the mode sense data and finds the requested
3249 mode sense page code.
3250
3251 Arguments:
3252 ModeSenseBuffer - Supplies a pointer to the mode sense data.
3253
3254 Length - Indicates the length of valid data.
3255
3256 PageMode - Supplies the page mode to be searched for.
3257
3258 Use6Byte - Indicates whether 6 or 10 byte mode sense was used.
3259
3260 Return Value:
3261
3262 A pointer to the the requested mode page. If the mode page was not found
3263 then NULL is return.
3264
3265 --*/
3266 {
3267 PUCHAR limit;
3268 ULONG parameterHeaderLength;
3269
3270 limit = (PUCHAR)ModeSenseBuffer + Length;
3271 parameterHeaderLength = (Use6Byte) ? sizeof(MODE_PARAMETER_HEADER) : sizeof(MODE_PARAMETER_HEADER10);
3272
3273
3274 //
3275 // Skip the mode select header and block descriptors.
3276 //
3277
3278 if (Length < parameterHeaderLength) {
3279 return(NULL);
3280 }
3281
3282
3283
3284 ModeSenseBuffer += parameterHeaderLength + ((Use6Byte) ? ((PMODE_PARAMETER_HEADER) ModeSenseBuffer)->BlockDescriptorLength :
3285 ((PMODE_PARAMETER_HEADER10) ModeSenseBuffer)->BlockDescriptorLength[1]);
3286
3287 //
3288 // ModeSenseBuffer now points at pages. Walk the pages looking for the
3289 // requested page until the limit is reached.
3290 //
3291
3292
3293 while ((PUCHAR)ModeSenseBuffer < limit) {
3294
3295 if (((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageCode == PageMode) {
3296 return(ModeSenseBuffer);
3297 }
3298
3299 //
3300 // Advance to the next page.
3301 //
3302
3303 ModeSenseBuffer += ((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageLength + 2;
3304 }
3305
3306 return(NULL);
3307 }
3308 \f
3309 NTSTATUS
3310 NTAPI
3311 ScsiClassSendSrbAsynchronous(
3312 PDEVICE_OBJECT DeviceObject,
3313 PSCSI_REQUEST_BLOCK Srb,
3314 PIRP Irp,
3315 PVOID BufferAddress,
3316 ULONG BufferLength,
3317 BOOLEAN WriteToDevice
3318 )
3319 /*++
3320
3321 Routine Description:
3322
3323 This routine takes a partially built Srb and an Irp and sends it down to
3324 the port driver.
3325
3326 Arguments:
3327 DeviceObject - Supplies the device object for the orginal request.
3328
3329 Srb - Supplies a paritally build ScsiRequestBlock. In particular, the
3330 CDB and the SRB timeout value must be filled in. The SRB must not be
3331 allocated from zone.
3332
3333 Irp - Supplies the requesting Irp.
3334
3335 BufferAddress - Supplies a pointer to the buffer to be transfered.
3336
3337 BufferLength - Supplies the length of data transfer.
3338
3339 WriteToDevice - Indicates the data transfer will be from system memory to
3340 device.
3341
3342 Return Value:
3343
3344 Returns STATUS_INSUFFICIENT_RESOURCES or the status of IoCallDriver.
3345
3346 --*/
3347 {
3348
3349 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3350 PIO_STACK_LOCATION irpStack;
3351
3352 PAGED_CODE();
3353
3354 //
3355 // Write length to SRB.
3356 //
3357
3358 Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
3359
3360 //
3361 // Set SCSI bus address.
3362 //
3363
3364 Srb->PathId = deviceExtension->PathId;
3365 Srb->TargetId = deviceExtension->TargetId;
3366 Srb->Lun = deviceExtension->Lun;
3367
3368 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
3369
3370 //
3371 // This is a violation of the SCSI spec but it is required for
3372 // some targets.
3373 //
3374
3375 Srb->Cdb[1] |= deviceExtension->Lun << 5;
3376
3377 //
3378 // Indicate auto request sense by specifying buffer and size.
3379 //
3380
3381 Srb->SenseInfoBuffer = deviceExtension->SenseData;
3382 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
3383 Srb->DataBuffer = BufferAddress;
3384
3385 if (BufferAddress != NULL) {
3386
3387 //
3388 // Build Mdl if necessary.
3389 //
3390
3391 if (Irp->MdlAddress == NULL) {
3392
3393 if (IoAllocateMdl(BufferAddress,
3394 BufferLength,
3395 FALSE,
3396 FALSE,
3397 Irp) == NULL) {
3398
3399 return(STATUS_INSUFFICIENT_RESOURCES);
3400 }
3401
3402 MmBuildMdlForNonPagedPool(Irp->MdlAddress);
3403
3404 } else {
3405
3406 //
3407 // Make sure the buffer requested matches the MDL.
3408 //
3409
3410 ASSERT(BufferAddress == MmGetMdlVirtualAddress(Irp->MdlAddress));
3411 }
3412
3413 //
3414 // Set read flag.
3415 //
3416
3417 Srb->SrbFlags = WriteToDevice ? SRB_FLAGS_DATA_OUT : SRB_FLAGS_DATA_IN;
3418
3419 } else {
3420
3421 //
3422 // Clear flags.
3423 //
3424
3425 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
3426 }
3427
3428 //
3429 // Disable synchronous transfer for these requests.
3430 //
3431
3432 Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
3433
3434 //
3435 // Set the transfer length.
3436 //
3437
3438 Srb->DataTransferLength = BufferLength;
3439
3440 //
3441 // Zero out status.
3442 //
3443
3444 Srb->ScsiStatus = Srb->SrbStatus = 0;
3445
3446 Srb->NextSrb = 0;
3447
3448 //
3449 // Save a few parameters in the current stack location.
3450 //
3451
3452 irpStack = IoGetCurrentIrpStackLocation(Irp);
3453
3454 //
3455 // Save retry count in current Irp stack.
3456 //
3457
3458 irpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
3459
3460 //
3461 // Set up IoCompletion routine address.
3462 //
3463
3464 IoSetCompletionRoutine(Irp, ScsiClassIoComplete, Srb, TRUE, TRUE, TRUE);
3465
3466 //
3467 // Get next stack location and
3468 // set major function code.
3469 //
3470
3471 irpStack = IoGetNextIrpStackLocation(Irp);
3472
3473 irpStack->MajorFunction = IRP_MJ_SCSI;
3474
3475 //
3476 // Save SRB address in next stack for port driver.
3477 //
3478
3479 irpStack->Parameters.Scsi.Srb = Srb;
3480
3481 //
3482 // Set up Irp Address.
3483 //
3484
3485 Srb->OriginalRequest = Irp;
3486
3487 //
3488 // Call the port driver to process the request.
3489 //
3490
3491 return(IoCallDriver(deviceExtension->PortDeviceObject, Irp));
3492
3493 }
3494
3495 \f
3496 NTSTATUS
3497 NTAPI
3498 ScsiClassDeviceControlDispatch(
3499 PDEVICE_OBJECT DeviceObject,
3500 PIRP Irp
3501 )
3502
3503 /*++
3504
3505 Routine Description:
3506
3507 The routine is the common class driver device control dispatch entry point.
3508 This routine is invokes the device-specific drivers DeviceControl routine,
3509 (which may call the Class driver's common DeviceControl routine).
3510
3511 Arguments:
3512
3513 DeviceObject - Supplies a pointer to the device object for this request.
3514
3515 Irp - Supplies the Irp making the request.
3516
3517 Return Value:
3518
3519 Returns the status returned from the device-specific driver.
3520
3521 --*/
3522
3523 {
3524
3525 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3526
3527
3528 //
3529 // Call the class specific driver DeviceControl routine.
3530 // If it doesn't handle it, it will call back into ScsiClassDeviceControl.
3531 //
3532
3533 ASSERT(deviceExtension->ClassDeviceControl);
3534
3535 return deviceExtension->ClassDeviceControl(DeviceObject,Irp);
3536 }
3537
3538 \f
3539 NTSTATUS
3540 NTAPI
3541 ScsiClassDeviceControl(
3542 PDEVICE_OBJECT DeviceObject,
3543 PIRP Irp
3544 )
3545 /*++
3546
3547 Routine Description:
3548
3549 The routine is the common class driver device control dispatch function.
3550 This routine is called by a class driver when it get an unrecognized
3551 device control request. This routine will perform the correct action for
3552 common requests such as lock media. If the device request is unknown it
3553 passed down to the next level.
3554
3555 Arguments:
3556
3557 DeviceObject - Supplies a pointer to the device object for this request.
3558
3559 Irp - Supplies the Irp making the request.
3560
3561 Return Value:
3562
3563 Returns back a STATUS_PENDING or a completion status.
3564
3565 --*/
3566
3567 {
3568 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
3569 PIO_STACK_LOCATION nextStack;
3570 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3571 PSCSI_REQUEST_BLOCK srb;
3572 PCDB cdb;
3573 NTSTATUS status;
3574 ULONG modifiedIoControlCode;
3575
3576 if (irpStack->Parameters.DeviceIoControl.IoControlCode ==
3577 IOCTL_STORAGE_RESET_DEVICE) {
3578
3579 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
3580 IoCompleteRequest(Irp, IO_NO_INCREMENT);
3581 status = STATUS_UNSUCCESSFUL;
3582 goto SetStatusAndReturn;
3583 }
3584
3585 //
3586 // If this is a pass through I/O control, set the minor function code
3587 // and device address and pass it to the port driver.
3588 //
3589
3590 if (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH
3591 || irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT) {
3592
3593 PSCSI_PASS_THROUGH scsiPass;
3594
3595 nextStack = IoGetNextIrpStackLocation(Irp);
3596
3597 //
3598 // Validiate the user buffer.
3599 //
3600
3601 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH)){
3602
3603 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
3604 IoCompleteRequest(Irp, IO_NO_INCREMENT);
3605 status = STATUS_INVALID_PARAMETER;
3606 goto SetStatusAndReturn;
3607 }
3608
3609 //
3610 // Force the SCSI address to the correct value.
3611 //
3612
3613 scsiPass = Irp->AssociatedIrp.SystemBuffer;
3614 scsiPass->PathId = deviceExtension->PathId;
3615 scsiPass->TargetId = deviceExtension->TargetId;
3616 scsiPass->Lun = deviceExtension->Lun;
3617
3618 //
3619 // NOTICE: The SCSI-II specificaiton indicates that this field
3620 // should be zero; however, some target controllers ignore the logical
3621 // unit number in the INDENTIFY message and only look at the logical
3622 // unit number field in the CDB.
3623 //
3624
3625 scsiPass->Cdb[1] |= deviceExtension->Lun << 5;
3626
3627 nextStack->Parameters = irpStack->Parameters;
3628 nextStack->MajorFunction = irpStack->MajorFunction;
3629 nextStack->MinorFunction = IRP_MN_SCSI_CLASS;
3630
3631 status = IoCallDriver(deviceExtension->PortDeviceObject, Irp);
3632 goto SetStatusAndReturn;
3633 }
3634
3635 if (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_GET_ADDRESS) {
3636
3637 PSCSI_ADDRESS scsiAddress = Irp->AssociatedIrp.SystemBuffer;
3638
3639 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
3640 sizeof(SCSI_ADDRESS)) {
3641
3642 //
3643 // Indicate unsuccessful status and no data transferred.
3644 //
3645
3646 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
3647 Irp->IoStatus.Information = 0;
3648 IoCompleteRequest(Irp, IO_NO_INCREMENT);
3649 status = STATUS_BUFFER_TOO_SMALL;
3650 goto SetStatusAndReturn;
3651
3652 }
3653
3654 scsiAddress->Length = sizeof(SCSI_ADDRESS);
3655 scsiAddress->PortNumber = deviceExtension->PortNumber;
3656 scsiAddress->PathId = deviceExtension->PathId;
3657 scsiAddress->TargetId = deviceExtension->TargetId;
3658 scsiAddress->Lun = deviceExtension->Lun;
3659 Irp->IoStatus.Information = sizeof(SCSI_ADDRESS);
3660 Irp->IoStatus.Status = STATUS_SUCCESS;
3661 IoCompleteRequest(Irp, IO_NO_INCREMENT);
3662 status = STATUS_SUCCESS;
3663 goto SetStatusAndReturn;
3664 }
3665
3666 srb = ExAllocatePool(NonPagedPool, SCSI_REQUEST_BLOCK_SIZE);
3667
3668 if (srb == NULL) {
3669
3670 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
3671 IoCompleteRequest(Irp, IO_NO_INCREMENT);
3672 status = STATUS_INSUFFICIENT_RESOURCES;
3673 goto SetStatusAndReturn;
3674 }
3675
3676 //
3677 // Write zeros to Srb.
3678 //
3679
3680 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
3681
3682 cdb = (PCDB)srb->Cdb;
3683
3684 //
3685 // Change the device type to disk for the switch statement.
3686 //
3687
3688 modifiedIoControlCode = (irpStack->Parameters.DeviceIoControl.IoControlCode
3689 & ~0xffff0000) | (IOCTL_DISK_BASE << 16);
3690
3691 switch (modifiedIoControlCode) {
3692
3693 case IOCTL_DISK_CHECK_VERIFY: {
3694
3695 PIRP irp2 = NULL;
3696 PIO_STACK_LOCATION newStack;
3697
3698 DebugPrint((1,"ScsiDeviceIoControl: Check verify\n"));
3699
3700 //
3701 // If a buffer for a media change count was provided, make sure it's
3702 // big enough to hold the result
3703 //
3704
3705 if(irpStack->Parameters.DeviceIoControl.OutputBufferLength) {
3706
3707 //
3708 // If the buffer is too small to hold the media change count
3709 // then return an error to the caller
3710 //
3711
3712 if(irpStack->Parameters.DeviceIoControl.OutputBufferLength <
3713 sizeof(ULONG)) {
3714
3715 DebugPrint((3,"ScsiDeviceIoControl: media count "
3716 "buffer too small\n"));
3717
3718 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
3719 Irp->IoStatus.Information = 0;
3720 ExFreePool(srb);
3721 IoCompleteRequest(Irp, IO_NO_INCREMENT);
3722 status = STATUS_BUFFER_TOO_SMALL;
3723 goto SetStatusAndReturn;
3724
3725 }
3726
3727 //
3728 // The caller has provided a valid buffer. Allocate an additional
3729 // irp and stick the CheckVerify completion routine on it. We will
3730 // then send this down to the port driver instead of the irp the
3731 // caller sent in
3732 //
3733
3734 DebugPrint((2,"ScsiDeviceIoControl: Check verify wants "
3735 "media count\n"));
3736
3737 //
3738 // Allocate a new irp to send the TestUnitReady to the port driver
3739 //
3740
3741 irp2 = IoAllocateIrp((CCHAR) (DeviceObject->StackSize + 3), FALSE);
3742
3743 if(irp2 == NULL) {
3744 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
3745 Irp->IoStatus.Information = 0;
3746 ExFreePool(srb);
3747 IoCompleteRequest(Irp, IO_NO_INCREMENT);
3748 status = STATUS_INSUFFICIENT_RESOURCES;
3749 goto SetStatusAndReturn;
3750
3751 break;
3752 }
3753
3754 irp2->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread;
3755 IoSetNextIrpStackLocation(irp2);
3756
3757 //
3758 // Set the top stack location and shove the master Irp into the
3759 // top location
3760 //
3761
3762 newStack = IoGetCurrentIrpStackLocation(irp2);
3763 newStack->Parameters.Others.Argument1 = Irp;
3764 newStack->DeviceObject = DeviceObject;
3765
3766 //
3767 // Stick the check verify completion routine onto the stack
3768 // and prepare the irp for the port driver
3769 //
3770
3771 IoSetCompletionRoutine(irp2,
3772 ScsiClassCheckVerifyComplete,
3773 NULL,
3774 TRUE,
3775 TRUE,
3776 TRUE);
3777
3778 IoSetNextIrpStackLocation(irp2);
3779 newStack = IoGetCurrentIrpStackLocation(irp2);
3780 newStack->DeviceObject = DeviceObject;
3781
3782 //
3783 // Mark the master irp as pending - whether the lower level
3784 // driver completes it immediately or not this should allow it
3785 // to go all the way back up.
3786 //
3787
3788 IoMarkIrpPending(Irp);
3789
3790 Irp = irp2;
3791
3792 }
3793
3794 //
3795 // Test Unit Ready
3796 //
3797
3798 srb->CdbLength = 6;
3799 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
3800
3801 //
3802 // Set timeout value.
3803 //
3804
3805 srb->TimeOutValue = deviceExtension->TimeOutValue;
3806
3807 //
3808 // Since this routine will always hand the request to the
3809 // port driver if there isn't a data transfer to be done
3810 // we don't have to worry about completing the request here
3811 // on an error
3812 //
3813
3814 status = ScsiClassSendSrbAsynchronous(DeviceObject,
3815 srb,
3816 Irp,
3817 NULL,
3818 0,
3819 FALSE);
3820
3821 break;
3822 }
3823
3824 case IOCTL_DISK_MEDIA_REMOVAL: {
3825
3826 PPREVENT_MEDIA_REMOVAL MediaRemoval = Irp->AssociatedIrp.SystemBuffer;
3827
3828 //
3829 // Prevent/Allow media removal.
3830 //
3831
3832 DebugPrint((3,"DiskIoControl: Prevent/Allow media removal\n"));
3833
3834 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
3835 sizeof(PREVENT_MEDIA_REMOVAL)) {
3836
3837 //
3838 // Indicate unsuccessful status and no data transferred.
3839 //
3840
3841 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
3842 Irp->IoStatus.Information = 0;
3843 ExFreePool(srb);
3844 IoCompleteRequest(Irp, IO_NO_INCREMENT);
3845 status = STATUS_BUFFER_TOO_SMALL;
3846 goto SetStatusAndReturn;
3847 }
3848
3849 //
3850 // Get physical device extension. This is where the
3851 // lock count is stored.
3852 //
3853
3854 deviceExtension = deviceExtension->PhysicalDevice->DeviceExtension;
3855
3856 //
3857 // If command succeeded then increment or decrement lock counter.
3858 //
3859
3860 if (MediaRemoval->PreventMediaRemoval) {
3861
3862 //
3863 // This is a lock command. Reissue the command in case bus or device
3864 // was reset and lock cleared.
3865 //
3866
3867 InterlockedIncrement(&deviceExtension->LockCount);
3868
3869 DebugPrint((1,
3870 "ScsiClassDeviceControl: Lock media, lock count %x on disk %x\n",
3871 deviceExtension->LockCount,
3872 deviceExtension->DeviceNumber));
3873
3874 } else {
3875
3876 //
3877 // This is an unlock command.
3878 //
3879
3880 if (!deviceExtension->LockCount ||
3881 (InterlockedDecrement(&deviceExtension->LockCount) != 0)) {
3882
3883 DebugPrint((1,
3884 "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n",
3885 deviceExtension->LockCount,
3886 deviceExtension->DeviceNumber));
3887
3888 //
3889 // Don't unlock because someone still wants it locked.
3890 //
3891
3892 Irp->IoStatus.Status = STATUS_SUCCESS;
3893 ExFreePool(srb);
3894 IoCompleteRequest(Irp, IO_NO_INCREMENT);
3895 status = STATUS_SUCCESS;
3896 goto SetStatusAndReturn;
3897 }
3898
3899 DebugPrint((1,
3900 "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n",
3901 deviceExtension->LockCount,
3902 deviceExtension->DeviceNumber));
3903 }
3904
3905 srb->CdbLength = 6;
3906
3907 cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
3908
3909 //
3910 // TRUE - prevent media removal.
3911 // FALSE - allow media removal.
3912 //
3913
3914 cdb->MEDIA_REMOVAL.Prevent = MediaRemoval->PreventMediaRemoval;
3915
3916 //
3917 // Set timeout value.
3918 //
3919
3920 srb->TimeOutValue = deviceExtension->TimeOutValue;
3921 status = ScsiClassSendSrbAsynchronous(DeviceObject,
3922 srb,
3923 Irp,
3924 NULL,
3925 0,
3926 FALSE);
3927
3928 //
3929 // Some devices will not support lock/unlock.
3930 // Pretend that it worked.
3931 //
3932
3933 break;
3934 }
3935
3936 case IOCTL_DISK_RESERVE: {
3937
3938 //
3939 // Reserve logical unit.
3940 //
3941
3942 srb->CdbLength = 6;
3943
3944 cdb->CDB6GENERIC.OperationCode = SCSIOP_RESERVE_UNIT;
3945
3946 //
3947 // Set timeout value.
3948 //
3949
3950 srb->TimeOutValue = deviceExtension->TimeOutValue;
3951
3952 status = ScsiClassSendSrbAsynchronous(DeviceObject,
3953 srb,
3954 Irp,
3955 NULL,
3956 0,
3957 FALSE);
3958
3959 break;
3960 }
3961
3962 case IOCTL_DISK_RELEASE: {
3963
3964 //
3965 // Release logical unit.
3966 //
3967
3968 srb->CdbLength = 6;
3969
3970 cdb->CDB6GENERIC.OperationCode = SCSIOP_RELEASE_UNIT;
3971
3972 //
3973 // Set timeout value.
3974 //
3975
3976 srb->TimeOutValue = deviceExtension->TimeOutValue;
3977
3978 status = ScsiClassSendSrbAsynchronous(DeviceObject,
3979 srb,
3980 Irp,
3981 NULL,
3982 0,
3983 FALSE);
3984
3985 break;
3986 }
3987
3988 case IOCTL_DISK_EJECT_MEDIA: {
3989
3990 //
3991 // Eject media.
3992 //
3993
3994 srb->CdbLength = 6;
3995
3996 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
3997 cdb->START_STOP.LoadEject = 1;
3998 cdb->START_STOP.Start = 0;
3999
4000 //
4001 // Set timeout value.
4002 //
4003
4004 srb->TimeOutValue = deviceExtension->TimeOutValue;
4005 status = ScsiClassSendSrbAsynchronous(DeviceObject,
4006 srb,
4007 Irp,
4008 NULL,
4009 0,
4010 FALSE);
4011 break;
4012 }
4013
4014 case IOCTL_DISK_LOAD_MEDIA: {
4015
4016 //
4017 // Load media.
4018 //
4019
4020 DebugPrint((3,"CdRomDeviceControl: Load media\n"));
4021
4022 srb->CdbLength = 6;
4023
4024 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
4025 cdb->START_STOP.LoadEject = 1;
4026 cdb->START_STOP.Start = 1;
4027
4028 //
4029 // Set timeout value.
4030 //
4031
4032 srb->TimeOutValue = deviceExtension->TimeOutValue;
4033 status = ScsiClassSendSrbAsynchronous(DeviceObject,
4034 srb,
4035 Irp,
4036 NULL,
4037 0,
4038 FALSE);
4039
4040 break;
4041 }
4042
4043 case IOCTL_DISK_FIND_NEW_DEVICES: {
4044
4045 //
4046 // Search for devices that have been powered on since the last
4047 // device search or system initialization.
4048 //
4049
4050 DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
4051 status = DriverEntry(DeviceObject->DriverObject,
4052 NULL);
4053
4054 Irp->IoStatus.Status = status;
4055 ExFreePool(srb);
4056 IoCompleteRequest(Irp, IO_NO_INCREMENT);
4057
4058 break;
4059 }
4060
4061 default: {
4062
4063 DebugPrint((3,"ScsiIoDeviceControl: Unsupported device IOCTL\n"));
4064
4065 //
4066 // Pass the device control to the next driver.
4067 //
4068
4069 ExFreePool(srb);
4070
4071 //
4072 // Copy the Irp stack parameters to the next stack location.
4073 //
4074
4075 nextStack = IoGetNextIrpStackLocation(Irp);
4076 nextStack->Parameters = irpStack->Parameters;
4077 nextStack->MajorFunction = irpStack->MajorFunction;
4078 nextStack->MinorFunction = irpStack->MinorFunction;
4079
4080 status = IoCallDriver(deviceExtension->PortDeviceObject, Irp);
4081 break;
4082 }
4083
4084 } // end switch( ...
4085
4086 SetStatusAndReturn:
4087
4088 return status;
4089 }
4090
4091 \f
4092 NTSTATUS
4093 NTAPI
4094 ScsiClassShutdownFlush(
4095 IN PDEVICE_OBJECT DeviceObject,
4096 IN PIRP Irp
4097 )
4098
4099 /*++
4100
4101 Routine Description:
4102
4103 This routine is called for a shutdown and flush IRPs. These are sent by the
4104 system before it actually shuts down or when the file system does a flush.
4105 If it exists, the device-specific driver's routine will be invoked. If there
4106 wasn't one specified, the Irp will be completed with an Invalid device request.
4107
4108 Arguments:
4109
4110 DriverObject - Pointer to device object to being shutdown by system.
4111
4112 Irp - IRP involved.
4113
4114 Return Value:
4115
4116 NT Status
4117
4118 --*/
4119
4120 {
4121 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4122
4123 if (deviceExtension->ClassShutdownFlush) {
4124
4125 //
4126 // Call the device-specific driver's routine.
4127 //
4128
4129 return deviceExtension->ClassShutdownFlush(DeviceObject, Irp);
4130 }
4131
4132 //
4133 // Device-specific driver doesn't support this.
4134 //
4135
4136 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
4137 IoCompleteRequest(Irp, IO_NO_INCREMENT);
4138
4139 return STATUS_INVALID_DEVICE_REQUEST;
4140 }
4141
4142 \f
4143 ULONG
4144 NTAPI
4145 ScsiClassFindUnclaimedDevices(
4146 IN PCLASS_INIT_DATA InitializationData,
4147 IN PSCSI_ADAPTER_BUS_INFO AdapterInformation
4148 )
4149
4150 {
4151 ULONG scsiBus,deviceCount = 0;
4152 PCHAR buffer = (PCHAR)AdapterInformation;
4153 PSCSI_INQUIRY_DATA lunInfo;
4154 PINQUIRYDATA inquiryData;
4155
4156 for (scsiBus=0; scsiBus < (ULONG)AdapterInformation->NumberOfBuses; scsiBus++) {
4157
4158 //
4159 // Get the SCSI bus scan data for this bus.
4160 //
4161
4162 lunInfo = (PVOID) (buffer + AdapterInformation->BusData[scsiBus].InquiryDataOffset);
4163
4164 //
4165 // Search list for unclaimed disk devices.
4166 //
4167
4168 while (AdapterInformation->BusData[scsiBus].InquiryDataOffset) {
4169
4170 inquiryData = (PVOID)lunInfo->InquiryData;
4171
4172 ASSERT(InitializationData->ClassFindDeviceCallBack);
4173
4174 if ((InitializationData->ClassFindDeviceCallBack(inquiryData)) && (!lunInfo->DeviceClaimed)) {
4175
4176 deviceCount++;
4177 }
4178
4179 if (lunInfo->NextInquiryDataOffset == 0) {
4180 break;
4181 }
4182
4183 lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset);
4184 }
4185 }
4186 return deviceCount;
4187 }
4188
4189
4190 \f
4191 NTSTATUS
4192 NTAPI
4193 ScsiClassCreateDeviceObject(
4194 IN PDRIVER_OBJECT DriverObject,
4195 IN PCCHAR ObjectNameBuffer,
4196 IN OPTIONAL PDEVICE_OBJECT PhysicalDeviceObject,
4197 IN OUT PDEVICE_OBJECT *DeviceObject,
4198 IN PCLASS_INIT_DATA InitializationData
4199 )
4200
4201 /*++
4202
4203 Routine Description:
4204
4205 This routine creates an object for the physical device specified and
4206 sets up the deviceExtension's function pointers for each entry point
4207 in the device-specific driver.
4208
4209 Arguments:
4210
4211 DriverObject - Pointer to driver object created by system.
4212
4213 ObjectNameBuffer - Dir. name of the object to create.
4214
4215 PhysicalDeviceObject - Pointer to the physical (class) device object for
4216 this logical unit or NULL if this is it.
4217
4218 DeviceObject - Pointer to the device object pointer we will return.
4219
4220 InitializationData - Pointer to the init data created by the device-specific driver.
4221
4222 Return Value:
4223
4224 NTSTATUS
4225
4226 --*/
4227
4228 {
4229 STRING ntNameString;
4230 UNICODE_STRING ntUnicodeString;
4231 NTSTATUS status;
4232 PDEVICE_OBJECT deviceObject = NULL;
4233
4234 *DeviceObject = NULL;
4235
4236 DebugPrint((2,
4237 "ScsiClassCreateDeviceObject: Create device object %s\n",
4238 ObjectNameBuffer));
4239
4240 RtlInitString(&ntNameString,
4241 ObjectNameBuffer);
4242
4243 status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
4244 &ntNameString,
4245 TRUE);
4246
4247 if (!NT_SUCCESS(status)) {
4248
4249 DebugPrint((1,
4250 "CreateDiskDeviceObjects: Cannot convert string %s\n",
4251 ObjectNameBuffer));
4252
4253 ntUnicodeString.Buffer = NULL;
4254 return status;
4255 }
4256
4257 status = IoCreateDevice(DriverObject,
4258 InitializationData->DeviceExtensionSize,
4259 &ntUnicodeString,
4260 InitializationData->DeviceType,
4261 InitializationData->DeviceCharacteristics,
4262 FALSE,
4263 &deviceObject);
4264
4265
4266 if (!NT_SUCCESS(status)) {
4267
4268 DebugPrint((1,
4269 "CreateDiskDeviceObjects: Can not create device object %s\n",
4270 ObjectNameBuffer));
4271
4272 } else {
4273
4274 PDEVICE_EXTENSION deviceExtension = deviceObject->DeviceExtension;
4275
4276 //
4277 // Fill in entry points
4278 //
4279
4280 deviceExtension->ClassError = InitializationData->ClassError;
4281 deviceExtension->ClassReadWriteVerification = InitializationData->ClassReadWriteVerification;
4282 deviceExtension->ClassFindDevices = InitializationData->ClassFindDevices;
4283 deviceExtension->ClassDeviceControl = InitializationData->ClassDeviceControl;
4284 deviceExtension->ClassShutdownFlush = InitializationData->ClassShutdownFlush;
4285 deviceExtension->ClassCreateClose = InitializationData->ClassCreateClose;
4286 deviceExtension->ClassStartIo = InitializationData->ClassStartIo;
4287
4288 deviceExtension->MediaChangeCount = 0;
4289
4290 //
4291 // If a pointer to the physical device object was passed in then use
4292 // that. If the value was NULL, then this is the physical device so
4293 // use the pointer to the device we just created.
4294 //
4295
4296 if(ARGUMENT_PRESENT(PhysicalDeviceObject)) {
4297 deviceExtension->PhysicalDevice = PhysicalDeviceObject;
4298 } else {
4299 deviceExtension->PhysicalDevice = deviceObject;
4300 }
4301 }
4302
4303 *DeviceObject = deviceObject;
4304
4305 RtlFreeUnicodeString(&ntUnicodeString);
4306
4307 //
4308 // Indicate the ntUnicodeString is free.
4309 //
4310
4311 ntUnicodeString.Buffer = NULL;
4312
4313 return status;
4314 }
4315
4316 \f
4317 NTSTATUS
4318 NTAPI
4319 ScsiClassClaimDevice(
4320 IN PDEVICE_OBJECT PortDeviceObject,
4321 IN PSCSI_INQUIRY_DATA LunInfo,
4322 IN BOOLEAN Release,
4323 OUT PDEVICE_OBJECT *NewPortDeviceObject OPTIONAL
4324 )
4325 /*++
4326
4327 Routine Description:
4328
4329 This function claims a device in the port driver. The port driver object
4330 is updated with the correct driver object if the device is successfully
4331 claimed.
4332
4333 Arguments:
4334
4335 PortDeviceObject - Supplies the base port device object.
4336
4337 LunInfo - Supplies the logical unit inforamtion of the device to be claimed.
4338
4339 Release - Indicates the logical unit should be released rather than claimed.
4340
4341 NewPortDeviceObject - Returns the updated port device object to be used
4342 for all future accesses.
4343
4344 Return Value:
4345
4346 Returns a status indicating success or failure of the operation.
4347
4348 --*/
4349
4350 {
4351 IO_STATUS_BLOCK ioStatus;
4352 PIRP irp;
4353 PIO_STACK_LOCATION irpStack;
4354 KEVENT event;
4355 NTSTATUS status;
4356 SCSI_REQUEST_BLOCK srb;
4357
4358 PAGED_CODE();
4359
4360 if (NewPortDeviceObject != NULL) {
4361 *NewPortDeviceObject = NULL;
4362 }
4363
4364 //
4365 // Clear the SRB fields.
4366 //
4367
4368 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
4369
4370 //
4371 // Write length to SRB.
4372 //
4373
4374 srb.Length = SCSI_REQUEST_BLOCK_SIZE;
4375
4376 //
4377 // Set SCSI bus address.
4378 //
4379
4380 srb.PathId = LunInfo->PathId;
4381 srb.TargetId = LunInfo->TargetId;
4382 srb.Lun = LunInfo->Lun;
4383
4384 srb.Function = Release ? SRB_FUNCTION_RELEASE_DEVICE :
4385 SRB_FUNCTION_CLAIM_DEVICE;
4386
4387 //
4388 // Set the event object to the unsignaled state.
4389 // It will be used to signal request completion.
4390 //
4391
4392 KeInitializeEvent(&event, NotificationEvent, FALSE);
4393
4394 //
4395 // Build synchronous request with no transfer.
4396 //
4397
4398 irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE,
4399 PortDeviceObject,
4400 NULL,
4401 0,
4402 NULL,
4403 0,
4404 TRUE,
4405 &event,
4406 &ioStatus);
4407
4408 if (irp == NULL) {
4409
4410 DebugPrint((1, "ScsiClassClaimDevice: Can't allocate Irp\n"));
4411 return STATUS_INSUFFICIENT_RESOURCES;
4412 }
4413
4414 irpStack = IoGetNextIrpStackLocation(irp);
4415
4416 //
4417 // Save SRB address in next stack for port driver.
4418 //
4419
4420 irpStack->Parameters.Scsi.Srb = &srb;
4421
4422 //
4423 // Set up IRP Address.
4424 //
4425
4426 srb.OriginalRequest = irp;
4427
4428 //
4429 // Call the port driver with the request and wait for it to complete.
4430 //
4431
4432 status = IoCallDriver(PortDeviceObject, irp);
4433 if (status == STATUS_PENDING) {
4434
4435 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
4436 status = ioStatus.Status;
4437 }
4438
4439 //
4440 // If this is a release request, then just decrement the reference count
4441 // and return. The status does not matter.
4442 //
4443
4444 if (Release) {
4445
4446 ObDereferenceObject(PortDeviceObject);
4447 return STATUS_SUCCESS;
4448 }
4449
4450 if (!NT_SUCCESS(status)) {
4451 return status;
4452 }
4453
4454 ASSERT(srb.DataBuffer != NULL);
4455
4456 //
4457 // Reference the new port driver object so that it will not go away while
4458 // it is being used.
4459 //
4460
4461 status = ObReferenceObjectByPointer(srb.DataBuffer,
4462 0,
4463 NULL,
4464 KernelMode );
4465
4466 if (!NT_SUCCESS(status)) {
4467
4468 return status;
4469 }
4470
4471 //
4472 // Return the new port device object pointer.
4473 //
4474
4475 if (NewPortDeviceObject != NULL) {
4476 *NewPortDeviceObject = srb.DataBuffer;
4477 }
4478
4479 return status;
4480 }
4481
4482 \f
4483 NTSTATUS
4484 NTAPI
4485 ScsiClassInternalIoControl (
4486 IN PDEVICE_OBJECT DeviceObject,
4487 IN PIRP Irp
4488 )
4489
4490 /*++
4491
4492 Routine Description:
4493
4494 This routine passes internal device controls to the port driver.
4495 Internal device controls are used by higher level class drivers to
4496 send scsi requests to a device that are not normally sent by a generic
4497 class driver.
4498
4499 The path ID, target ID and logical unit ID are set in the srb so the
4500 higher level driver does not have to figure out what values are actually
4501 used.
4502
4503 Arguments:
4504
4505 DeviceObject - Supplies a pointer to the device object for this request.
4506
4507 Irp - Supplies the Irp making the request.
4508
4509 Return Value:
4510
4511 Returns back a STATUS_PENDING or a completion status.
4512
4513 --*/
4514 {
4515 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
4516 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4517 PSCSI_REQUEST_BLOCK srb;
4518
4519 //
4520 // Get a pointer to the SRB.
4521 //
4522
4523 srb = irpStack->Parameters.Scsi.Srb;
4524
4525 //
4526 // Set SCSI bus address.
4527 //
4528
4529 srb->PathId = deviceExtension->PathId;
4530 srb->TargetId = deviceExtension->TargetId;
4531 srb->Lun = deviceExtension->Lun;
4532
4533 //
4534 // NOTICE: The SCSI-II specificaiton indicates that this field should be
4535 // zero; however, some target controllers ignore the logical unit number
4536 // in the INDENTIFY message and only look at the logical unit number field
4537 // in the CDB.
4538 //
4539
4540 srb->Cdb[1] |= deviceExtension->Lun << 5;
4541
4542 //
4543 // Set the parameters in the next stack location.
4544 //
4545
4546 irpStack = IoGetNextIrpStackLocation(Irp);
4547
4548 irpStack->Parameters.Scsi.Srb = srb;
4549 irpStack->MajorFunction = IRP_MJ_SCSI;
4550 irpStack->MinorFunction = IRP_MN_SCSI_CLASS;
4551
4552 IoSetCompletionRoutine(Irp, ClassIoCompletion, NULL, TRUE, TRUE, TRUE);
4553 return IoCallDriver(deviceExtension->PortDeviceObject, Irp);
4554 }
4555 \f
4556 NTSTATUS
4557 NTAPI
4558 ClassIoCompletion(
4559 IN PDEVICE_OBJECT DeviceObject,
4560 IN PIRP Irp,
4561 IN PVOID Context
4562 )
4563
4564 /*++
4565
4566 Routine Description:
4567
4568 This routine is called when an internal device control I/O request
4569 has completed. It marks the IRP pending if necessary and returns the
4570 status of the request.
4571
4572 Arguments:
4573
4574 DeviceObject - Target device object.
4575
4576 Irp - Completed request.
4577
4578 Context - not used.
4579
4580 Return Value:
4581
4582 Returns the status of the completed request.
4583
4584 --*/
4585
4586 {
4587 UNREFERENCED_PARAMETER(Context);
4588 UNREFERENCED_PARAMETER(DeviceObject);
4589
4590 //
4591 // If pending is returned for this Irp then mark current stack
4592 // as pending
4593 //
4594
4595 if (Irp->PendingReturned) {
4596
4597 IoMarkIrpPending( Irp );
4598 }
4599
4600 return Irp->IoStatus.Status;
4601 }
4602
4603 \f
4604 VOID
4605 NTAPI
4606 ScsiClassInitializeSrbLookasideList(
4607 IN PDEVICE_EXTENSION DeviceExtension,
4608 IN ULONG NumberElements
4609 )
4610
4611 /*++
4612
4613 Routine Description:
4614
4615 This routine sets up a lookaside listhead for srbs.
4616
4617 Arguments:
4618
4619 DeviceExtension - Pointer to the deviceExtension containing the listhead.
4620
4621 NumberElements - Supplies the maximum depth of the lookaside list.
4622
4623
4624 Return Value:
4625
4626 None
4627
4628 --*/
4629
4630 {
4631 ExInitializeNPagedLookasideList(&DeviceExtension->SrbLookasideListHead,
4632 NULL,
4633 NULL,
4634 NonPagedPoolMustSucceed,
4635 SCSI_REQUEST_BLOCK_SIZE,
4636 'ScsH',
4637 (USHORT)NumberElements);
4638
4639 }
4640
4641 \f
4642 ULONG
4643 NTAPI
4644 ScsiClassQueryTimeOutRegistryValue(
4645 IN PUNICODE_STRING RegistryPath
4646 )
4647
4648 /*++
4649
4650 Routine Description:
4651
4652 This routine determines whether a reg key for a user-specified timeout value exists.
4653
4654 Arguments:
4655
4656 RegistryPath - Pointer to the hardware reg. entry describing the key.
4657
4658 Return Value:
4659
4660 New default timeout for a class of devices.
4661
4662 --*/
4663
4664 {
4665 //
4666 // Find the appropriate reg. key
4667 //
4668
4669 PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
4670 PWSTR path;
4671 NTSTATUS status;
4672 LONG timeOut = 0;
4673 ULONG zero = 0;
4674 ULONG size;
4675
4676 if (!RegistryPath) {
4677 return 0;
4678 }
4679
4680 parameters = ExAllocatePool(NonPagedPool,
4681 sizeof(RTL_QUERY_REGISTRY_TABLE)*2);
4682
4683 if (!parameters) {
4684 return 0;
4685 }
4686
4687 size = RegistryPath->MaximumLength + sizeof(WCHAR);
4688 path = ExAllocatePool(NonPagedPool, size);
4689
4690 if (!path) {
4691 ExFreePool(parameters);
4692 return 0;
4693 }
4694
4695 RtlZeroMemory(path,size);
4696 RtlCopyMemory(path, RegistryPath->Buffer, size - sizeof(WCHAR));
4697
4698
4699 //
4700 // Check for the Timeout value.
4701 //
4702
4703 RtlZeroMemory(parameters,
4704 (sizeof(RTL_QUERY_REGISTRY_TABLE)*2));
4705
4706 parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
4707 parameters[0].Name = L"TimeOutValue";
4708 parameters[0].EntryContext = &timeOut;
4709 parameters[0].DefaultType = REG_DWORD;
4710 parameters[0].DefaultData = &zero;
4711 parameters[0].DefaultLength = sizeof(ULONG);
4712
4713 status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
4714 path,
4715 parameters,
4716 NULL,
4717 NULL);
4718
4719 if (!(NT_SUCCESS(status))) {
4720 timeOut = 0;
4721 }
4722
4723 ExFreePool(parameters);
4724 ExFreePool(path);
4725
4726 DebugPrint((2,
4727 "ScsiClassQueryTimeOutRegistryValue: Timeout value %d\n",
4728 timeOut));
4729
4730
4731 return timeOut;
4732
4733 }
4734 \f
4735 NTSTATUS
4736 NTAPI
4737 ScsiClassCheckVerifyComplete(
4738 IN PDEVICE_OBJECT DeviceObject,
4739 IN PIRP Irp,
4740 IN PVOID Context
4741 )
4742
4743 /*++
4744
4745 Routine Description:
4746
4747 This routine executes when the port driver has completed a check verify
4748 ioctl. It will set the status of the master Irp, copy the media change
4749 count and complete the request.
4750
4751 Arguments:
4752
4753 DeviceObject - Supplies the device object which represents the logical
4754 unit.
4755
4756 Irp - Supplies the Irp which has completed.
4757
4758 Context - NULL
4759
4760 Return Value:
4761
4762 NT status
4763
4764 --*/
4765
4766 {
4767 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
4768 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4769 PDEVICE_EXTENSION physicalExtension =
4770 deviceExtension->PhysicalDevice->DeviceExtension;
4771 PIRP originalIrp;
4772
4773 originalIrp = irpStack->Parameters.Others.Argument1;
4774
4775 //
4776 // Copy the media change count and status
4777 //
4778
4779 *((PULONG) (originalIrp->AssociatedIrp.SystemBuffer)) =
4780 physicalExtension->MediaChangeCount;
4781
4782 DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change count for"
4783 "device %d is %d\n",
4784 physicalExtension->DeviceNumber,
4785 physicalExtension->MediaChangeCount));
4786
4787 originalIrp->IoStatus.Status = Irp->IoStatus.Status;
4788 originalIrp->IoStatus.Information = sizeof(ULONG);
4789
4790 IoCompleteRequest(originalIrp, IO_DISK_INCREMENT);
4791
4792 IoFreeIrp(Irp);
4793
4794 return STATUS_MORE_PROCESSING_REQUIRED;
4795 }
4796
4797 NTSTATUS
4798 NTAPI
4799 ClassCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,
4800 IN PIRP Irp,
4801 IN PVOID Context)
4802 {
4803 PIO_STATUS_BLOCK IoStatusBlock = Irp->UserIosb;
4804 PKEVENT Event = Irp->UserEvent;
4805 PMDL Mdl;
4806
4807 *IoStatusBlock = Irp->IoStatus;
4808 Irp->UserIosb = NULL;
4809 Irp->UserEvent = NULL;
4810
4811 if(Irp->MdlAddress)
4812 {
4813 Mdl = Irp->MdlAddress;
4814
4815 // if necessary - unlock pages
4816 if ((Mdl->MdlFlags & MDL_PAGES_LOCKED) &&
4817 !(Mdl->MdlFlags & MDL_PARTIAL_HAS_BEEN_MAPPED))
4818 {
4819 MmUnlockPages(Mdl);
4820 }
4821
4822 // free this mdl
4823 IoFreeMdl(Mdl);
4824 }
4825
4826 // free irp and set event to unsignaled state
4827 IoFreeIrp(Irp);
4828 KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
4829
4830 return STATUS_MORE_PROCESSING_REQUIRED;
4831 }