Removed unreachable line (#517)
[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_UNIQUE_ID ||
4045 irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME) {
4046
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 if (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_MOUNTDEV_QUERY_DEVICE_NAME) {
4056
4057 PMOUNTDEV_NAME name = Irp->AssociatedIrp.SystemBuffer;
4058
4059 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTDEV_NAME)) {
4060
4061 Irp->IoStatus.Information = 0;
4062 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
4063 IoCompleteRequest(Irp, IO_NO_INCREMENT);
4064 status = STATUS_INVALID_PARAMETER;
4065 goto SetStatusAndReturn;
4066 }
4067
4068 RtlZeroMemory(name, sizeof(MOUNTDEV_NAME));
4069 name->NameLength = deviceExtension->DeviceName.Length;
4070
4071 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < FIELD_OFFSET(MOUNTDEV_NAME, Name) + name->NameLength) {
4072
4073 Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME);
4074 Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
4075 IoCompleteRequest(Irp, IO_NO_INCREMENT);
4076 status = STATUS_BUFFER_OVERFLOW;
4077 goto SetStatusAndReturn;
4078 }
4079
4080 RtlCopyMemory(name->Name, deviceExtension->DeviceName.Buffer,
4081 name->NameLength);
4082 status = STATUS_SUCCESS;
4083 Irp->IoStatus.Status = STATUS_SUCCESS;
4084 Irp->IoStatus.Information = FIELD_OFFSET(MOUNTDEV_NAME, Name) + name->NameLength;
4085 IoCompleteRequest(Irp, IO_NO_INCREMENT);
4086 goto SetStatusAndReturn;
4087 }
4088
4089 srb = ExAllocatePool(NonPagedPool, SCSI_REQUEST_BLOCK_SIZE);
4090
4091 if (srb == NULL) {
4092
4093 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
4094 IoCompleteRequest(Irp, IO_NO_INCREMENT);
4095 status = STATUS_INSUFFICIENT_RESOURCES;
4096 goto SetStatusAndReturn;
4097 }
4098
4099 //
4100 // Write zeros to Srb.
4101 //
4102
4103 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
4104
4105 cdb = (PCDB)srb->Cdb;
4106
4107 //
4108 // Change the device type to disk for the switch statement.
4109 //
4110
4111 modifiedIoControlCode = (irpStack->Parameters.DeviceIoControl.IoControlCode
4112 & ~0xffff0000) | (IOCTL_DISK_BASE << 16);
4113
4114 switch (modifiedIoControlCode) {
4115
4116 case IOCTL_DISK_CHECK_VERIFY: {
4117
4118 PIRP irp2 = NULL;
4119 PIO_STACK_LOCATION newStack;
4120
4121 DebugPrint((1,"ScsiDeviceIoControl: Check verify\n"));
4122
4123 //
4124 // If a buffer for a media change count was provided, make sure it's
4125 // big enough to hold the result
4126 //
4127
4128 if(irpStack->Parameters.DeviceIoControl.OutputBufferLength) {
4129
4130 //
4131 // If the buffer is too small to hold the media change count
4132 // then return an error to the caller
4133 //
4134
4135 if(irpStack->Parameters.DeviceIoControl.OutputBufferLength <
4136 sizeof(ULONG)) {
4137
4138 DebugPrint((3,"ScsiDeviceIoControl: media count "
4139 "buffer too small\n"));
4140
4141 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
4142 Irp->IoStatus.Information = 0;
4143 ExFreePool(srb);
4144 IoCompleteRequest(Irp, IO_NO_INCREMENT);
4145 status = STATUS_BUFFER_TOO_SMALL;
4146 goto SetStatusAndReturn;
4147
4148 }
4149
4150 //
4151 // The caller has provided a valid buffer. Allocate an additional
4152 // irp and stick the CheckVerify completion routine on it. We will
4153 // then send this down to the port driver instead of the irp the
4154 // caller sent in
4155 //
4156
4157 DebugPrint((2,"ScsiDeviceIoControl: Check verify wants "
4158 "media count\n"));
4159
4160 //
4161 // Allocate a new irp to send the TestUnitReady to the port driver
4162 //
4163
4164 irp2 = IoAllocateIrp((CCHAR) (DeviceObject->StackSize + 3), FALSE);
4165
4166 if(irp2 == NULL) {
4167 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
4168 Irp->IoStatus.Information = 0;
4169 ExFreePool(srb);
4170 IoCompleteRequest(Irp, IO_NO_INCREMENT);
4171 status = STATUS_INSUFFICIENT_RESOURCES;
4172 goto SetStatusAndReturn;
4173 }
4174
4175 irp2->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread;
4176 IoSetNextIrpStackLocation(irp2);
4177
4178 //
4179 // Set the top stack location and shove the master Irp into the
4180 // top location
4181 //
4182
4183 newStack = IoGetCurrentIrpStackLocation(irp2);
4184 newStack->Parameters.Others.Argument1 = Irp;
4185 newStack->DeviceObject = DeviceObject;
4186
4187 //
4188 // Stick the check verify completion routine onto the stack
4189 // and prepare the irp for the port driver
4190 //
4191
4192 IoSetCompletionRoutine(irp2,
4193 ScsiClassCheckVerifyComplete,
4194 NULL,
4195 TRUE,
4196 TRUE,
4197 TRUE);
4198
4199 IoSetNextIrpStackLocation(irp2);
4200 newStack = IoGetCurrentIrpStackLocation(irp2);
4201 newStack->DeviceObject = DeviceObject;
4202
4203 //
4204 // Mark the master irp as pending - whether the lower level
4205 // driver completes it immediately or not this should allow it
4206 // to go all the way back up.
4207 //
4208
4209 IoMarkIrpPending(Irp);
4210
4211 Irp = irp2;
4212
4213 }
4214
4215 //
4216 // Test Unit Ready
4217 //
4218
4219 srb->CdbLength = 6;
4220 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
4221
4222 //
4223 // Set timeout value.
4224 //
4225
4226 srb->TimeOutValue = deviceExtension->TimeOutValue;
4227
4228 //
4229 // Since this routine will always hand the request to the
4230 // port driver if there isn't a data transfer to be done
4231 // we don't have to worry about completing the request here
4232 // on an error
4233 //
4234
4235 status = ScsiClassSendSrbAsynchronous(DeviceObject,
4236 srb,
4237 Irp,
4238 NULL,
4239 0,
4240 FALSE);
4241
4242 break;
4243 }
4244
4245 case IOCTL_DISK_MEDIA_REMOVAL: {
4246
4247 PPREVENT_MEDIA_REMOVAL MediaRemoval = Irp->AssociatedIrp.SystemBuffer;
4248
4249 //
4250 // Prevent/Allow media removal.
4251 //
4252
4253 DebugPrint((3,"DiskIoControl: Prevent/Allow media removal\n"));
4254
4255 if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
4256 sizeof(PREVENT_MEDIA_REMOVAL)) {
4257
4258 //
4259 // Indicate unsuccessful status and no data transferred.
4260 //
4261
4262 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
4263 Irp->IoStatus.Information = 0;
4264 ExFreePool(srb);
4265 IoCompleteRequest(Irp, IO_NO_INCREMENT);
4266 status = STATUS_BUFFER_TOO_SMALL;
4267 goto SetStatusAndReturn;
4268 }
4269
4270 //
4271 // Get physical device extension. This is where the
4272 // lock count is stored.
4273 //
4274
4275 deviceExtension = deviceExtension->PhysicalDevice->DeviceExtension;
4276
4277 //
4278 // If command succeeded then increment or decrement lock counter.
4279 //
4280
4281 if (MediaRemoval->PreventMediaRemoval) {
4282
4283 //
4284 // This is a lock command. Reissue the command in case bus or device
4285 // was reset and lock cleared.
4286 //
4287
4288 InterlockedIncrement(&deviceExtension->LockCount);
4289
4290 DebugPrint((1,
4291 "ScsiClassDeviceControl: Lock media, lock count %x on disk %x\n",
4292 deviceExtension->LockCount,
4293 deviceExtension->DeviceNumber));
4294
4295 } else {
4296
4297 //
4298 // This is an unlock command.
4299 //
4300
4301 if (!deviceExtension->LockCount ||
4302 (InterlockedDecrement(&deviceExtension->LockCount) != 0)) {
4303
4304 DebugPrint((1,
4305 "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n",
4306 deviceExtension->LockCount,
4307 deviceExtension->DeviceNumber));
4308
4309 //
4310 // Don't unlock because someone still wants it locked.
4311 //
4312
4313 Irp->IoStatus.Status = STATUS_SUCCESS;
4314 ExFreePool(srb);
4315 IoCompleteRequest(Irp, IO_NO_INCREMENT);
4316 status = STATUS_SUCCESS;
4317 goto SetStatusAndReturn;
4318 }
4319
4320 DebugPrint((1,
4321 "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n",
4322 deviceExtension->LockCount,
4323 deviceExtension->DeviceNumber));
4324 }
4325
4326 srb->CdbLength = 6;
4327
4328 cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
4329
4330 //
4331 // TRUE - prevent media removal.
4332 // FALSE - allow media removal.
4333 //
4334
4335 cdb->MEDIA_REMOVAL.Prevent = MediaRemoval->PreventMediaRemoval;
4336
4337 //
4338 // Set timeout value.
4339 //
4340
4341 srb->TimeOutValue = deviceExtension->TimeOutValue;
4342 status = ScsiClassSendSrbAsynchronous(DeviceObject,
4343 srb,
4344 Irp,
4345 NULL,
4346 0,
4347 FALSE);
4348
4349 //
4350 // Some devices will not support lock/unlock.
4351 // Pretend that it worked.
4352 //
4353
4354 break;
4355 }
4356
4357 case IOCTL_DISK_RESERVE: {
4358
4359 //
4360 // Reserve logical unit.
4361 //
4362
4363 srb->CdbLength = 6;
4364
4365 cdb->CDB6GENERIC.OperationCode = SCSIOP_RESERVE_UNIT;
4366
4367 //
4368 // Set timeout value.
4369 //
4370
4371 srb->TimeOutValue = deviceExtension->TimeOutValue;
4372
4373 status = ScsiClassSendSrbAsynchronous(DeviceObject,
4374 srb,
4375 Irp,
4376 NULL,
4377 0,
4378 FALSE);
4379
4380 break;
4381 }
4382
4383 case IOCTL_DISK_RELEASE: {
4384
4385 //
4386 // Release logical unit.
4387 //
4388
4389 srb->CdbLength = 6;
4390
4391 cdb->CDB6GENERIC.OperationCode = SCSIOP_RELEASE_UNIT;
4392
4393 //
4394 // Set timeout value.
4395 //
4396
4397 srb->TimeOutValue = deviceExtension->TimeOutValue;
4398
4399 status = ScsiClassSendSrbAsynchronous(DeviceObject,
4400 srb,
4401 Irp,
4402 NULL,
4403 0,
4404 FALSE);
4405
4406 break;
4407 }
4408
4409 case IOCTL_DISK_EJECT_MEDIA: {
4410
4411 //
4412 // Eject media.
4413 //
4414
4415 srb->CdbLength = 6;
4416
4417 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
4418 cdb->START_STOP.LoadEject = 1;
4419 cdb->START_STOP.Start = 0;
4420
4421 //
4422 // Set timeout value.
4423 //
4424
4425 srb->TimeOutValue = deviceExtension->TimeOutValue;
4426 status = ScsiClassSendSrbAsynchronous(DeviceObject,
4427 srb,
4428 Irp,
4429 NULL,
4430 0,
4431 FALSE);
4432 break;
4433 }
4434
4435 case IOCTL_DISK_LOAD_MEDIA: {
4436
4437 //
4438 // Load media.
4439 //
4440
4441 DebugPrint((3,"CdRomDeviceControl: Load media\n"));
4442
4443 srb->CdbLength = 6;
4444
4445 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
4446 cdb->START_STOP.LoadEject = 1;
4447 cdb->START_STOP.Start = 1;
4448
4449 //
4450 // Set timeout value.
4451 //
4452
4453 srb->TimeOutValue = deviceExtension->TimeOutValue;
4454 status = ScsiClassSendSrbAsynchronous(DeviceObject,
4455 srb,
4456 Irp,
4457 NULL,
4458 0,
4459 FALSE);
4460
4461 break;
4462 }
4463
4464 case IOCTL_DISK_FIND_NEW_DEVICES: {
4465
4466 //
4467 // Search for devices that have been powered on since the last
4468 // device search or system initialization.
4469 //
4470
4471 DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
4472 status = DriverEntry(DeviceObject->DriverObject,
4473 NULL);
4474
4475 Irp->IoStatus.Status = status;
4476 ExFreePool(srb);
4477 IoCompleteRequest(Irp, IO_NO_INCREMENT);
4478
4479 break;
4480 }
4481
4482 default: {
4483
4484 DebugPrint((3,"ScsiIoDeviceControl: Unsupported device IOCTL\n"));
4485
4486 //
4487 // Pass the device control to the next driver.
4488 //
4489
4490 ExFreePool(srb);
4491
4492 //
4493 // Copy the Irp stack parameters to the next stack location.
4494 //
4495
4496 nextStack = IoGetNextIrpStackLocation(Irp);
4497 nextStack->Parameters = irpStack->Parameters;
4498 nextStack->MajorFunction = irpStack->MajorFunction;
4499 nextStack->MinorFunction = irpStack->MinorFunction;
4500
4501 status = IoCallDriver(deviceExtension->PortDeviceObject, Irp);
4502 break;
4503 }
4504
4505 } // end switch( ...
4506
4507 SetStatusAndReturn:
4508
4509 return status;
4510 }
4511
4512 \f
4513 NTSTATUS
4514 NTAPI
4515 ScsiClassShutdownFlush(
4516 IN PDEVICE_OBJECT DeviceObject,
4517 IN PIRP Irp
4518 )
4519
4520 /*++
4521
4522 Routine Description:
4523
4524 This routine is called for a shutdown and flush IRPs. These are sent by the
4525 system before it actually shuts down or when the file system does a flush.
4526 If it exists, the device-specific driver's routine will be invoked. If there
4527 wasn't one specified, the Irp will be completed with an Invalid device request.
4528
4529 Arguments:
4530
4531 DriverObject - Pointer to device object to being shutdown by system.
4532
4533 Irp - IRP involved.
4534
4535 Return Value:
4536
4537 NT Status
4538
4539 --*/
4540
4541 {
4542 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4543
4544 ASSERT(*(PULONG)deviceExtension != '2slc');
4545
4546 if (deviceExtension->ClassShutdownFlush) {
4547
4548 //
4549 // Call the device-specific driver's routine.
4550 //
4551
4552 return deviceExtension->ClassShutdownFlush(DeviceObject, Irp);
4553 }
4554
4555 //
4556 // Device-specific driver doesn't support this.
4557 //
4558
4559 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
4560 IoCompleteRequest(Irp, IO_NO_INCREMENT);
4561
4562 return STATUS_INVALID_DEVICE_REQUEST;
4563 }
4564
4565 \f
4566 ULONG
4567 NTAPI
4568 ScsiClassFindUnclaimedDevices(
4569 IN PCLASS_INIT_DATA InitializationData,
4570 IN PSCSI_ADAPTER_BUS_INFO AdapterInformation
4571 )
4572
4573 {
4574 ULONG scsiBus,deviceCount = 0;
4575 PCHAR buffer = (PCHAR)AdapterInformation;
4576 PSCSI_INQUIRY_DATA lunInfo;
4577 PINQUIRYDATA inquiryData;
4578
4579 for (scsiBus=0; scsiBus < (ULONG)AdapterInformation->NumberOfBuses; scsiBus++) {
4580
4581 //
4582 // Get the SCSI bus scan data for this bus.
4583 //
4584
4585 lunInfo = (PVOID) (buffer + AdapterInformation->BusData[scsiBus].InquiryDataOffset);
4586
4587 //
4588 // Search list for unclaimed disk devices.
4589 //
4590
4591 while (AdapterInformation->BusData[scsiBus].InquiryDataOffset) {
4592
4593 inquiryData = (PVOID)lunInfo->InquiryData;
4594
4595 ASSERT(InitializationData->ClassFindDeviceCallBack);
4596
4597 if ((InitializationData->ClassFindDeviceCallBack(inquiryData)) && (!lunInfo->DeviceClaimed)) {
4598
4599 deviceCount++;
4600 }
4601
4602 if (lunInfo->NextInquiryDataOffset == 0) {
4603 break;
4604 }
4605
4606 lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset);
4607 }
4608 }
4609 return deviceCount;
4610 }
4611
4612
4613 \f
4614 NTSTATUS
4615 NTAPI
4616 ScsiClassCreateDeviceObject(
4617 IN PDRIVER_OBJECT DriverObject,
4618 IN PCCHAR ObjectNameBuffer,
4619 IN OPTIONAL PDEVICE_OBJECT PhysicalDeviceObject,
4620 IN OUT PDEVICE_OBJECT *DeviceObject,
4621 IN PCLASS_INIT_DATA InitializationData
4622 )
4623
4624 /*++
4625
4626 Routine Description:
4627
4628 This routine creates an object for the physical device specified and
4629 sets up the deviceExtension's function pointers for each entry point
4630 in the device-specific driver.
4631
4632 Arguments:
4633
4634 DriverObject - Pointer to driver object created by system.
4635
4636 ObjectNameBuffer - Dir. name of the object to create.
4637
4638 PhysicalDeviceObject - Pointer to the physical (class) device object for
4639 this logical unit or NULL if this is it.
4640
4641 DeviceObject - Pointer to the device object pointer we will return.
4642
4643 InitializationData - Pointer to the init data created by the device-specific driver.
4644
4645 Return Value:
4646
4647 NTSTATUS
4648
4649 --*/
4650
4651 {
4652 STRING ntNameString;
4653 UNICODE_STRING ntUnicodeString;
4654 NTSTATUS status;
4655 PDEVICE_OBJECT deviceObject = NULL;
4656
4657 *DeviceObject = NULL;
4658
4659 DebugPrint((2,
4660 "ScsiClassCreateDeviceObject: Create device object %s\n",
4661 ObjectNameBuffer));
4662
4663 RtlInitString(&ntNameString,
4664 ObjectNameBuffer);
4665
4666 status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
4667 &ntNameString,
4668 TRUE);
4669
4670 if (!NT_SUCCESS(status)) {
4671
4672 DebugPrint((1,
4673 "CreateDiskDeviceObjects: Cannot convert string %s\n",
4674 ObjectNameBuffer));
4675
4676 ntUnicodeString.Buffer = NULL;
4677 return status;
4678 }
4679
4680 status = IoCreateDevice(DriverObject,
4681 InitializationData->DeviceExtensionSize,
4682 &ntUnicodeString,
4683 InitializationData->DeviceType,
4684 InitializationData->DeviceCharacteristics,
4685 FALSE,
4686 &deviceObject);
4687
4688
4689 if (!NT_SUCCESS(status)) {
4690
4691 DebugPrint((1,
4692 "CreateDiskDeviceObjects: Can not create device object %s\n",
4693 ObjectNameBuffer));
4694
4695 } else {
4696
4697 PDEVICE_EXTENSION deviceExtension = deviceObject->DeviceExtension;
4698
4699 ASSERT(*(PULONG)deviceExtension != '2slc');
4700
4701 //
4702 // Fill in entry points
4703 //
4704
4705 deviceExtension->ClassError = InitializationData->ClassError;
4706 deviceExtension->ClassReadWriteVerification = InitializationData->ClassReadWriteVerification;
4707 deviceExtension->ClassFindDevices = InitializationData->ClassFindDevices;
4708 deviceExtension->ClassDeviceControl = InitializationData->ClassDeviceControl;
4709 deviceExtension->ClassShutdownFlush = InitializationData->ClassShutdownFlush;
4710 deviceExtension->ClassCreateClose = InitializationData->ClassCreateClose;
4711 deviceExtension->ClassStartIo = InitializationData->ClassStartIo;
4712
4713 deviceExtension->MediaChangeCount = 0;
4714
4715 //
4716 // If a pointer to the physical device object was passed in then use
4717 // that. If the value was NULL, then this is the physical device so
4718 // use the pointer to the device we just created.
4719 //
4720
4721 if(ARGUMENT_PRESENT(PhysicalDeviceObject)) {
4722 deviceExtension->PhysicalDevice = PhysicalDeviceObject;
4723 } else {
4724 deviceExtension->PhysicalDevice = deviceObject;
4725 }
4726
4727 deviceExtension->DeviceName = ntUnicodeString;
4728 }
4729
4730 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
4731
4732 *DeviceObject = deviceObject;
4733
4734 return status;
4735 }
4736
4737 \f
4738 NTSTATUS
4739 NTAPI
4740 ScsiClassClaimDevice(
4741 IN PDEVICE_OBJECT PortDeviceObject,
4742 IN PSCSI_INQUIRY_DATA LunInfo,
4743 IN BOOLEAN Release,
4744 OUT PDEVICE_OBJECT *NewPortDeviceObject OPTIONAL
4745 )
4746 /*++
4747
4748 Routine Description:
4749
4750 This function claims a device in the port driver. The port driver object
4751 is updated with the correct driver object if the device is successfully
4752 claimed.
4753
4754 Arguments:
4755
4756 PortDeviceObject - Supplies the base port device object.
4757
4758 LunInfo - Supplies the logical unit inforamtion of the device to be claimed.
4759
4760 Release - Indicates the logical unit should be released rather than claimed.
4761
4762 NewPortDeviceObject - Returns the updated port device object to be used
4763 for all future accesses.
4764
4765 Return Value:
4766
4767 Returns a status indicating success or failure of the operation.
4768
4769 --*/
4770
4771 {
4772 IO_STATUS_BLOCK ioStatus;
4773 PIRP irp;
4774 PIO_STACK_LOCATION irpStack;
4775 KEVENT event;
4776 NTSTATUS status;
4777 SCSI_REQUEST_BLOCK srb;
4778
4779 PAGED_CODE();
4780
4781 if (NewPortDeviceObject != NULL) {
4782 *NewPortDeviceObject = NULL;
4783 }
4784
4785 //
4786 // Clear the SRB fields.
4787 //
4788
4789 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
4790
4791 //
4792 // Write length to SRB.
4793 //
4794
4795 srb.Length = SCSI_REQUEST_BLOCK_SIZE;
4796
4797 //
4798 // Set SCSI bus address.
4799 //
4800
4801 srb.PathId = LunInfo->PathId;
4802 srb.TargetId = LunInfo->TargetId;
4803 srb.Lun = LunInfo->Lun;
4804
4805 srb.Function = Release ? SRB_FUNCTION_RELEASE_DEVICE :
4806 SRB_FUNCTION_CLAIM_DEVICE;
4807
4808 //
4809 // Set the event object to the unsignaled state.
4810 // It will be used to signal request completion.
4811 //
4812
4813 KeInitializeEvent(&event, NotificationEvent, FALSE);
4814
4815 //
4816 // Build synchronous request with no transfer.
4817 //
4818
4819 irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE,
4820 PortDeviceObject,
4821 NULL,
4822 0,
4823 NULL,
4824 0,
4825 TRUE,
4826 &event,
4827 &ioStatus);
4828
4829 if (irp == NULL) {
4830
4831 DebugPrint((1, "ScsiClassClaimDevice: Can't allocate Irp\n"));
4832 return STATUS_INSUFFICIENT_RESOURCES;
4833 }
4834
4835 irpStack = IoGetNextIrpStackLocation(irp);
4836
4837 //
4838 // Save SRB address in next stack for port driver.
4839 //
4840
4841 irpStack->Parameters.Scsi.Srb = &srb;
4842
4843 //
4844 // Set up IRP Address.
4845 //
4846
4847 srb.OriginalRequest = irp;
4848
4849 //
4850 // Call the port driver with the request and wait for it to complete.
4851 //
4852
4853 status = IoCallDriver(PortDeviceObject, irp);
4854 if (status == STATUS_PENDING) {
4855
4856 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
4857 status = ioStatus.Status;
4858 }
4859
4860 //
4861 // If this is a release request, then just decrement the reference count
4862 // and return. The status does not matter.
4863 //
4864
4865 if (Release) {
4866
4867 //ObDereferenceObject(PortDeviceObject);
4868 return STATUS_SUCCESS;
4869 }
4870
4871 if (!NT_SUCCESS(status)) {
4872 return status;
4873 }
4874
4875 ASSERT(srb.DataBuffer != NULL);
4876
4877 //
4878 // Reference the new port driver object so that it will not go away while
4879 // it is being used.
4880 //
4881
4882 status = ObReferenceObjectByPointer(srb.DataBuffer,
4883 0,
4884 NULL,
4885 KernelMode );
4886
4887 if (!NT_SUCCESS(status)) {
4888
4889 return status;
4890 }
4891 ObDereferenceObject(srb.DataBuffer);
4892
4893 //
4894 // Return the new port device object pointer.
4895 //
4896
4897 if (NewPortDeviceObject != NULL) {
4898 *NewPortDeviceObject = srb.DataBuffer;
4899 }
4900
4901 return status;
4902 }
4903
4904 \f
4905 NTSTATUS
4906 NTAPI
4907 ScsiClassInternalIoControl (
4908 IN PDEVICE_OBJECT DeviceObject,
4909 IN PIRP Irp
4910 )
4911
4912 /*++
4913
4914 Routine Description:
4915
4916 This routine passes internal device controls to the port driver.
4917 Internal device controls are used by higher level class drivers to
4918 send scsi requests to a device that are not normally sent by a generic
4919 class driver.
4920
4921 The path ID, target ID and logical unit ID are set in the srb so the
4922 higher level driver does not have to figure out what values are actually
4923 used.
4924
4925 Arguments:
4926
4927 DeviceObject - Supplies a pointer to the device object for this request.
4928
4929 Irp - Supplies the Irp making the request.
4930
4931 Return Value:
4932
4933 Returns back a STATUS_PENDING or a completion status.
4934
4935 --*/
4936 {
4937 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
4938 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
4939 PSCSI_REQUEST_BLOCK srb;
4940
4941 ASSERT(*(PULONG)deviceExtension != '2slc');
4942
4943 //
4944 // Get a pointer to the SRB.
4945 //
4946
4947 srb = irpStack->Parameters.Scsi.Srb;
4948
4949 //
4950 // Set SCSI bus address.
4951 //
4952
4953 srb->PathId = deviceExtension->PathId;
4954 srb->TargetId = deviceExtension->TargetId;
4955 srb->Lun = deviceExtension->Lun;
4956
4957 //
4958 // NOTICE: The SCSI-II specification indicates that this field should be
4959 // zero; however, some target controllers ignore the logical unit number
4960 // in the IDENTIFY message and only look at the logical unit number field
4961 // in the CDB.
4962 //
4963
4964 srb->Cdb[1] |= deviceExtension->Lun << 5;
4965
4966 //
4967 // Set the parameters in the next stack location.
4968 //
4969
4970 irpStack = IoGetNextIrpStackLocation(Irp);
4971
4972 irpStack->Parameters.Scsi.Srb = srb;
4973 irpStack->MajorFunction = IRP_MJ_SCSI;
4974 irpStack->MinorFunction = IRP_MN_SCSI_CLASS;
4975
4976 IoSetCompletionRoutine(Irp, ClassIoCompletion, NULL, TRUE, TRUE, TRUE);
4977 return IoCallDriver(deviceExtension->PortDeviceObject, Irp);
4978 }
4979 \f
4980 NTSTATUS
4981 NTAPI
4982 ClassIoCompletion(
4983 IN PDEVICE_OBJECT DeviceObject,
4984 IN PIRP Irp,
4985 IN PVOID Context
4986 )
4987
4988 /*++
4989
4990 Routine Description:
4991
4992 This routine is called when an internal device control I/O request
4993 has completed. It marks the IRP pending if necessary and returns the
4994 status of the request.
4995
4996 Arguments:
4997
4998 DeviceObject - Target device object.
4999
5000 Irp - Completed request.
5001
5002 Context - not used.
5003
5004 Return Value:
5005
5006 Returns the status of the completed request.
5007
5008 --*/
5009
5010 {
5011 UNREFERENCED_PARAMETER(Context);
5012 UNREFERENCED_PARAMETER(DeviceObject);
5013
5014 //
5015 // If pending is returned for this Irp then mark current stack
5016 // as pending
5017 //
5018
5019 if (Irp->PendingReturned) {
5020
5021 IoMarkIrpPending( Irp );
5022 }
5023
5024 return Irp->IoStatus.Status;
5025 }
5026
5027 \f
5028 VOID
5029 NTAPI
5030 ScsiClassInitializeSrbLookasideList(
5031 IN PDEVICE_EXTENSION DeviceExtension,
5032 IN ULONG NumberElements
5033 )
5034
5035 /*++
5036
5037 Routine Description:
5038
5039 This routine sets up a lookaside listhead for srbs.
5040
5041 Arguments:
5042
5043 DeviceExtension - Pointer to the deviceExtension containing the listhead.
5044
5045 NumberElements - Supplies the maximum depth of the lookaside list.
5046
5047
5048 Return Value:
5049
5050 None
5051
5052 --*/
5053
5054 {
5055 ExInitializeNPagedLookasideList(&DeviceExtension->SrbLookasideListHead,
5056 NULL,
5057 NULL,
5058 NonPagedPoolMustSucceed,
5059 SCSI_REQUEST_BLOCK_SIZE,
5060 'ScsH',
5061 (USHORT)NumberElements);
5062
5063 }
5064
5065 \f
5066 ULONG
5067 NTAPI
5068 ScsiClassQueryTimeOutRegistryValue(
5069 IN PUNICODE_STRING RegistryPath
5070 )
5071
5072 /*++
5073
5074 Routine Description:
5075
5076 This routine determines whether a reg key for a user-specified timeout value exists.
5077
5078 Arguments:
5079
5080 RegistryPath - Pointer to the hardware reg. entry describing the key.
5081
5082 Return Value:
5083
5084 New default timeout for a class of devices.
5085
5086 --*/
5087
5088 {
5089 //
5090 // Find the appropriate reg. key
5091 //
5092
5093 PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
5094 PWSTR path;
5095 NTSTATUS status;
5096 LONG timeOut = 0;
5097 ULONG zero = 0;
5098 ULONG size;
5099
5100 if (!RegistryPath) {
5101 return 0;
5102 }
5103
5104 parameters = ExAllocatePool(NonPagedPool,
5105 sizeof(RTL_QUERY_REGISTRY_TABLE)*2);
5106
5107 if (!parameters) {
5108 return 0;
5109 }
5110
5111 size = RegistryPath->MaximumLength + sizeof(WCHAR);
5112 path = ExAllocatePool(NonPagedPool, size);
5113
5114 if (!path) {
5115 ExFreePool(parameters);
5116 return 0;
5117 }
5118
5119 RtlZeroMemory(path,size);
5120 RtlCopyMemory(path, RegistryPath->Buffer, size - sizeof(WCHAR));
5121
5122
5123 //
5124 // Check for the Timeout value.
5125 //
5126
5127 RtlZeroMemory(parameters,
5128 (sizeof(RTL_QUERY_REGISTRY_TABLE)*2));
5129
5130 parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
5131 parameters[0].Name = L"TimeOutValue";
5132 parameters[0].EntryContext = &timeOut;
5133 parameters[0].DefaultType = REG_DWORD;
5134 parameters[0].DefaultData = &zero;
5135 parameters[0].DefaultLength = sizeof(ULONG);
5136
5137 status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
5138 path,
5139 parameters,
5140 NULL,
5141 NULL);
5142
5143 if (!(NT_SUCCESS(status))) {
5144 timeOut = 0;
5145 }
5146
5147 ExFreePool(parameters);
5148 ExFreePool(path);
5149
5150 DebugPrint((2,
5151 "ScsiClassQueryTimeOutRegistryValue: Timeout value %d\n",
5152 timeOut));
5153
5154
5155 return timeOut;
5156
5157 }
5158 \f
5159 NTSTATUS
5160 NTAPI
5161 ScsiClassCheckVerifyComplete(
5162 IN PDEVICE_OBJECT DeviceObject,
5163 IN PIRP Irp,
5164 IN PVOID Context
5165 )
5166
5167 /*++
5168
5169 Routine Description:
5170
5171 This routine executes when the port driver has completed a check verify
5172 ioctl. It will set the status of the master Irp, copy the media change
5173 count and complete the request.
5174
5175 Arguments:
5176
5177 DeviceObject - Supplies the device object which represents the logical
5178 unit.
5179
5180 Irp - Supplies the Irp which has completed.
5181
5182 Context - NULL
5183
5184 Return Value:
5185
5186 NT status
5187
5188 --*/
5189
5190 {
5191 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
5192 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
5193 PDEVICE_EXTENSION physicalExtension =
5194 deviceExtension->PhysicalDevice->DeviceExtension;
5195 PIRP originalIrp;
5196
5197 ASSERT(*(PULONG)deviceExtension != '2slc');
5198 ASSERT(*(PULONG)physicalExtension != '2slc');
5199
5200 originalIrp = irpStack->Parameters.Others.Argument1;
5201
5202 //
5203 // Copy the media change count and status
5204 //
5205
5206 *((PULONG) (originalIrp->AssociatedIrp.SystemBuffer)) =
5207 physicalExtension->MediaChangeCount;
5208
5209 DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change count for"
5210 "device %d is %d\n",
5211 physicalExtension->DeviceNumber,
5212 physicalExtension->MediaChangeCount));
5213
5214 originalIrp->IoStatus.Status = Irp->IoStatus.Status;
5215 originalIrp->IoStatus.Information = sizeof(ULONG);
5216
5217 IoCompleteRequest(originalIrp, IO_DISK_INCREMENT);
5218
5219 IoFreeIrp(Irp);
5220
5221 return STATUS_MORE_PROCESSING_REQUIRED;
5222 }
5223
5224 NTSTATUS
5225 NTAPI
5226 ClassCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,
5227 IN PIRP Irp,
5228 IN PVOID Context)
5229 {
5230 PIO_STATUS_BLOCK IoStatusBlock = Irp->UserIosb;
5231 PKEVENT Event = Irp->UserEvent;
5232 PMDL Mdl;
5233
5234 *IoStatusBlock = Irp->IoStatus;
5235 Irp->UserIosb = NULL;
5236 Irp->UserEvent = NULL;
5237
5238 if(Irp->MdlAddress)
5239 {
5240 Mdl = Irp->MdlAddress;
5241
5242 // if necessary - unlock pages
5243 if ((Mdl->MdlFlags & MDL_PAGES_LOCKED) &&
5244 !(Mdl->MdlFlags & MDL_PARTIAL_HAS_BEEN_MAPPED))
5245 {
5246 MmUnlockPages(Mdl);
5247 }
5248
5249 // free this mdl
5250 IoFreeMdl(Mdl);
5251 }
5252
5253 // free irp and set event to unsignaled state
5254 IoFreeIrp(Irp);
5255 KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
5256
5257 return STATUS_MORE_PROCESSING_REQUIRED;
5258 }