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