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