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