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