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