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