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