0a4c3d7ad55b6cb4009ef20d5341015c0678e0ac
[reactos.git] / reactos / drivers / storage / class / class2 / class2.c
1 /*
2 * PROJECT: ReactOS Storage Stack
3 * LICENSE: DDK - see license.txt in the root dir
4 * FILE: drivers/storage/class2/class2.c
5 * PURPOSE: SCSI Class driver routines
6 * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK
7 */
8
9 #include <ntddk.h>
10 #include <ntdddisk.h>
11 #include <scsi.h>
12 #include <include/class2.h>
13 #include <stdio.h>
14
15 /* Part of the drive letter hack */
16 #include <ntifs.h>
17 #include <ketypes.h>
18
19 //#define NDEBUG
20 #include <debug.h>
21
22 #ifdef ALLOC_PRAGMA
23 #pragma alloc_text(PAGE, ScsiClassGetInquiryData)
24 #pragma alloc_text(PAGE, ScsiClassInitialize)
25 #pragma alloc_text(PAGE, ScsiClassGetCapabilities)
26 #pragma alloc_text(PAGE, ScsiClassSendSrbSynchronous)
27 #pragma alloc_text(PAGE, ScsiClassClaimDevice)
28 #pragma alloc_text(PAGE, ScsiClassSendSrbAsynchronous)
29 #endif
30
31
32 #define INQUIRY_DATA_SIZE 2048
33 #define START_UNIT_TIMEOUT 30
34
35 /* Disk layout used by Windows NT4 and earlier versions. */
36 //#define DEFAULT_SECTORS_PER_TRACK 32
37 //#define DEFAULT_TRACKS_PER_CYLINDER 64
38
39 /* Disk layout used by Windows 2000 and later versions. */
40 #define DEFAULT_SECTORS_PER_TRACK 63
41 #define DEFAULT_TRACKS_PER_CYLINDER 255
42
43 NTSTATUS
44 NTAPI
45 ScsiClassCreateClose(
46 IN PDEVICE_OBJECT DeviceObject,
47 IN PIRP Irp
48 );
49
50 NTSTATUS
51 NTAPI
52 ScsiClassReadWrite(
53 IN PDEVICE_OBJECT DeviceObject,
54 IN PIRP Irp
55 );
56
57 NTSTATUS
58 NTAPI
59 ScsiClassDeviceControlDispatch(
60 PDEVICE_OBJECT DeviceObject,
61 PIRP Irp
62 );
63
64 NTSTATUS
65 NTAPI
66 ScsiClassDeviceControl(
67 PDEVICE_OBJECT DeviceObject,
68 PIRP Irp
69 );
70
71 NTSTATUS
72 NTAPI
73 ScsiClassInternalIoControl (
74 IN PDEVICE_OBJECT DeviceObject,
75 IN PIRP Irp
76 );
77
78 NTSTATUS
79 NTAPI
80 ScsiClassShutdownFlush(
81 IN PDEVICE_OBJECT DeviceObject,
82 IN PIRP Irp
83 );
84
85 NTSTATUS
86 NTAPI
87 DriverEntry(
88 IN PDRIVER_OBJECT DriverObject,
89 IN PUNICODE_STRING RegistryPath
90 );
91
92 //
93 // Class internal routines
94 //
95
96
97 VOID
98 NTAPI
99 RetryRequest(
100 PDEVICE_OBJECT DeviceObject,
101 PIRP Irp,
102 PSCSI_REQUEST_BLOCK Srb,
103 BOOLEAN Associated
104 );
105
106 VOID
107 NTAPI
108 StartUnit(
109 IN PDEVICE_OBJECT DeviceObject
110 );
111
112 NTSTATUS
113 NTAPI
114 ClassIoCompletion(
115 IN PDEVICE_OBJECT DeviceObject,
116 IN PIRP Irp,
117 IN PVOID Context
118 );
119
120 NTSTATUS
121 NTAPI
122 ClassCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,
123 IN PIRP Irp,
124 IN PVOID Context);
125
126
127 NTSTATUS
128 NTAPI
129 DriverEntry(
130 IN PDRIVER_OBJECT DriverObject,
131 IN PUNICODE_STRING RegistryPath
132 )
133 {
134 return STATUS_SUCCESS;
135 }
136
137 /* The following hack to assign drive letters with a non-PnP storage stack */
138
139 typedef struct _CLASS_DEVICE_INFO {
140 ULONG Signature;
141 ULONG DeviceType;
142 ULONG Partitions;
143 ULONG DeviceNumber;
144 ULONG DriveNumber;
145 PDEVICE_OBJECT LowerDevice;
146 } CLASS_DEVICE_INFO, *PCLASS_DEVICE_INFO;
147
148 typedef struct _CLASS_DRIVER_EXTENSION {
149 ULONG PortNumber;
150 UNICODE_STRING RegistryPath;
151 CLASS_INIT_DATA InitializationData;
152 } CLASS_DRIVER_EXTENSION, *PCLASS_DRIVER_EXTENSION;
153
154 VOID
155 NTAPI
156 ScsiClassRemoveDriveLetter(PCLASS_DEVICE_INFO DeviceInfo)
157 {
158 WCHAR Buffer1[100];
159 UNICODE_STRING DriveLetterU;
160 ULONG Index;
161
162 DriveLetterU.Buffer = Buffer1;
163 DriveLetterU.MaximumLength = sizeof(Buffer1);
164
165 /* Delete the symbolic link to PhysicalDriveX */
166 DriveLetterU.Length = swprintf(DriveLetterU.Buffer, L"\\??\\PhysicalDrive%d", DeviceInfo->DriveNumber) * sizeof(WCHAR);
167 IoDeleteSymbolicLink(&DriveLetterU);
168
169 DbgPrint("HACK: Deleted symbolic link %wZ\n", &DriveLetterU);
170
171 for (Index = 0; Index < sizeof(ULONG) * 8; Index++)
172 {
173 if (DeviceInfo->Partitions & (1 << Index))
174 {
175 DriveLetterU.Length = swprintf(DriveLetterU.Buffer, L"\\??\\%C:", ('C' + Index)) * sizeof(WCHAR);
176 IoDeleteSymbolicLink(&DriveLetterU);
177 DbgPrint("HACK: Deleted symbolic link %wZ\n", &DriveLetterU);
178 }
179 }
180 }
181
182 NTSTATUS
183 NTAPI
184 ScsiClassAssignDriveLetter(PCLASS_DEVICE_INFO DeviceInfo)
185 {
186 WCHAR Buffer1[100];
187 WCHAR Buffer2[100];
188 UNICODE_STRING DriveLetterU, PartitionU;
189 NTSTATUS Status;
190 ULONG Index, PartitionNumber, DeviceNumber, DriveNumber;
191 OBJECT_ATTRIBUTES ObjectAttributes;
192 IO_STATUS_BLOCK Iosb;
193 HANDLE PartitionHandle;
194
195 /* We assume this device does not current have a drive letter */
196
197 Index = 0;
198 DeviceNumber = 0;
199 DriveNumber = 0;
200 PartitionNumber = 1;
201 DriveLetterU.Buffer = Buffer1;
202 DriveLetterU.MaximumLength = sizeof(Buffer1);
203 PartitionU.Buffer = Buffer2;
204 PartitionU.MaximumLength = sizeof(Buffer2);
205
206 /* Determine the correct disk number */
207 do
208 {
209 /* Check that the disk exists */
210 if (DeviceInfo->DeviceType == FILE_DEVICE_DISK)
211 {
212 PartitionU.Length = swprintf(PartitionU.Buffer, L"\\Device\\HardDisk%d\\Partition0", DeviceNumber) * sizeof(WCHAR);
213 }
214 else if (DeviceInfo->DeviceType == FILE_DEVICE_CD_ROM)
215 {
216 PartitionU.Length = swprintf(PartitionU.Buffer, L"\\Device\\CdRom%d", DeviceNumber) * sizeof(WCHAR);
217 }
218
219 InitializeObjectAttributes(&ObjectAttributes,
220 &PartitionU,
221 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
222 NULL,
223 NULL);
224 Status = ZwOpenFile(&PartitionHandle,
225 FILE_READ_ATTRIBUTES,
226 &ObjectAttributes,
227 &Iosb,
228 0,
229 0);
230 if (!NT_SUCCESS(Status))
231 {
232 /* Return the last one that worked */
233 DeviceNumber--;
234 }
235 else
236 {
237 ZwClose(PartitionHandle);
238 DeviceNumber++;
239 }
240 } while (Status == STATUS_SUCCESS);
241
242 /* Determine the correct drive number */
243 do
244 {
245 /* Check that the drive exists */
246 if (DeviceInfo->DeviceType == FILE_DEVICE_DISK)
247 {
248 PartitionU.Length = swprintf(PartitionU.Buffer, L"\\??\\PhysicalDrive%d", DriveNumber) * sizeof(WCHAR);
249 }
250 else if (DeviceInfo->DeviceType == FILE_DEVICE_CD_ROM)
251 {
252 PartitionU.Length = swprintf(PartitionU.Buffer, L"\\??\\%C:", ('C' + DriveNumber)) * sizeof(WCHAR);
253 }
254 InitializeObjectAttributes(&ObjectAttributes,
255 &PartitionU,
256 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
257 NULL,
258 NULL);
259 Status = ZwOpenFile(&PartitionHandle,
260 FILE_READ_ATTRIBUTES,
261 &ObjectAttributes,
262 &Iosb,
263 0,
264 0);
265 if (NT_SUCCESS(Status))
266 {
267 ZwClose(PartitionHandle);
268 DriveNumber++;
269 }
270 } while (Status == STATUS_SUCCESS);
271
272 if (DeviceInfo->DeviceType == FILE_DEVICE_DISK)
273 {
274 PartitionU.Length = swprintf(PartitionU.Buffer, L"\\Device\\Harddisk%d\\Partition0", DeviceNumber) * sizeof(WCHAR);
275 DriveLetterU.Length = swprintf(DriveLetterU.Buffer, L"\\??\\PhysicalDrive%d", DriveNumber) * sizeof(WCHAR);
276 }
277 else if (DeviceInfo->DeviceType == FILE_DEVICE_CD_ROM)
278 {
279 PartitionU.Length = swprintf(PartitionU.Buffer, L"\\Device\\CdRom%d", DeviceNumber) * sizeof(WCHAR);
280 DriveLetterU.Length = swprintf(DriveLetterU.Buffer, L"\\??\\%C:", ('C' + DriveNumber)) * sizeof(WCHAR);
281 }
282
283 /* Create the symbolic link to PhysicalDriveX */
284 Status = IoCreateSymbolicLink(&DriveLetterU, &PartitionU);
285 if (!NT_SUCCESS(Status))
286 {
287 /* Failed to create symbolic link */
288 DbgPrint("Failed to create symbolic link %wZ -> %wZ with %lx\n", &PartitionU, &DriveLetterU, Status);
289 return Status;
290 }
291
292 DbgPrint("HACK: Created symbolic link %wZ -> %wZ\n", &PartitionU, &DriveLetterU);
293
294 DeviceInfo->DeviceNumber = DeviceNumber;
295 DeviceInfo->DriveNumber = DriveNumber;
296
297 if (DeviceInfo->DeviceType == FILE_DEVICE_CD_ROM)
298 {
299 /* done for cdroms */
300 return STATUS_SUCCESS;
301 }
302
303 while (TRUE)
304 {
305 /* Check that the disk exists */
306 PartitionU.Length = swprintf(PartitionU.Buffer, L"\\Device\\Harddisk%d\\Partition%d", DeviceNumber, PartitionNumber) * sizeof(WCHAR);
307 InitializeObjectAttributes(&ObjectAttributes,
308 &PartitionU,
309 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
310 NULL,
311 NULL);
312 Status = ZwOpenFile(&PartitionHandle,
313 FILE_READ_ATTRIBUTES,
314 &ObjectAttributes,
315 &Iosb,
316 0,
317 0);
318 if (!NT_SUCCESS(Status))
319 break;
320 else
321 {
322 ZwClose(PartitionHandle);
323
324 /* Assign it a drive letter */
325 do
326 {
327 DriveLetterU.Length = swprintf(DriveLetterU.Buffer, L"\\??\\%C:", ('C' + Index)) * sizeof(WCHAR);
328
329 Status = IoCreateSymbolicLink(&DriveLetterU, &PartitionU);
330
331 Index++;
332 } while (Status != STATUS_SUCCESS);
333
334 DeviceInfo->Partitions |= (1 << (Index - 1));
335
336 DbgPrint("HACK: Created symbolic link %wZ -> %wZ\n", &PartitionU, &DriveLetterU);
337 PartitionNumber++;
338 }
339 }
340
341 return STATUS_SUCCESS;
342 }
343
344 NTSTATUS
345 NTAPI
346 ScsiClassPlugPlay(
347 IN PDEVICE_OBJECT DeviceObject,
348 IN PIRP Irp)
349 {
350 PCLASS_DEVICE_INFO DeviceInfo = DeviceObject->DeviceExtension;
351 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
352
353 if (IrpSp->MinorFunction == IRP_MN_START_DEVICE)
354 {
355 ASSERT(DeviceInfo->Signature == '2slc');
356 IoSkipCurrentIrpStackLocation(Irp);
357 return IoCallDriver(DeviceInfo->LowerDevice, Irp);
358 }
359 else if (IrpSp->MinorFunction == IRP_MN_REMOVE_DEVICE)
360 {
361 ASSERT(DeviceInfo->Signature == '2slc');
362 ScsiClassRemoveDriveLetter(DeviceInfo);
363
364 IoForwardIrpSynchronously(DeviceInfo->LowerDevice, Irp);
365
366 Irp->IoStatus.Status = STATUS_SUCCESS;
367 IoCompleteRequest(Irp, IO_NO_INCREMENT);
368
369 IoDetachDevice(DeviceInfo->LowerDevice);
370 IoDeleteDevice(DeviceObject);
371 return STATUS_SUCCESS;
372 }
373 else
374 {
375 if (DeviceInfo->Signature == '2slc')
376 {
377 IoSkipCurrentIrpStackLocation(Irp);
378 return IoCallDriver(DeviceInfo->LowerDevice, Irp);
379 }
380
381 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
382 IoCompleteRequest(Irp, IO_NO_INCREMENT);
383 return STATUS_NOT_SUPPORTED;
384 }
385 }
386
387 NTSTATUS
388 NTAPI
389 ScsiClassAddDevice(
390 IN PDRIVER_OBJECT DriverObject,
391 IN PDEVICE_OBJECT PhysicalDeviceObject)
392 {
393 PCLASS_DRIVER_EXTENSION DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
394 PCLASS_DEVICE_INFO DeviceInfo;
395 PDEVICE_OBJECT DeviceObject;
396 NTSTATUS Status;
397
398 if (DriverExtension->InitializationData.ClassFindDevices(DriverObject, &DriverExtension->RegistryPath, &DriverExtension->InitializationData,
399 PhysicalDeviceObject, DriverExtension->PortNumber))
400 {
401 /* Create a device object */
402 Status = IoCreateDevice(DriverObject,
403 sizeof(CLASS_DEVICE_INFO),
404 NULL,
405 DriverExtension->InitializationData.DeviceType,
406 0,
407 FALSE,
408 &DeviceObject);
409 if (!NT_SUCCESS(Status))
410 {
411 return Status;
412 }
413
414 DeviceInfo = DeviceObject->DeviceExtension;
415 RtlZeroMemory(DeviceInfo, sizeof(CLASS_DEVICE_INFO));
416 DeviceInfo->Signature = '2slc';
417
418 /* Attach it to the PDO */
419 DeviceInfo->LowerDevice = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject);
420 DeviceInfo->DeviceType = DriverExtension->InitializationData.DeviceType;
421
422 /* Check that the kernel has already assigned drive letters */
423 if (KeLoaderBlock == NULL)
424 {
425 /* Assign a drive letter */
426 ScsiClassAssignDriveLetter(DeviceInfo);
427 }
428 else
429 {
430 /* The kernel will handle it */
431 }
432
433 /* Move to the next port number */
434 DriverExtension->PortNumber++;
435 }
436 else
437 {
438 /* Failed to find device */
439 DbgPrint("FAILED TO FIND DEVICE!\n");
440 }
441
442 return STATUS_SUCCESS;
443 }
444 /* ---- End hack ---- */
445
446
447 \f
448 ULONG
449 NTAPI
450 ScsiClassInitialize(
451 IN PVOID Argument1,
452 IN PVOID Argument2,
453 IN PCLASS_INIT_DATA InitializationData
454 )
455
456 /*++
457
458 Routine Description:
459
460 This routine is called by a class driver during its
461 DriverEntry routine to initialize the driver.
462
463 Arguments:
464
465 Argument1 - Driver Object.
466 Argument2 - Registry Path.
467 InitializationData - Device-specific driver's initialization data.
468
469 Return Value:
470
471 A valid return code for a DriverEntry routine.
472
473 --*/
474
475 {
476
477
478 PDRIVER_OBJECT DriverObject = Argument1;
479 PDEVICE_OBJECT portDeviceObject;
480 NTSTATUS status;
481 STRING deviceNameString;
482 UNICODE_STRING unicodeDeviceName;
483 PFILE_OBJECT fileObject;
484 CCHAR deviceNameBuffer[256];
485 /* BOOLEAN deviceFound = FALSE; See note at the end */
486 PCLASS_DRIVER_EXTENSION DriverExtension;
487 PUNICODE_STRING RegistryPath = Argument2;
488
489 DebugPrint((3,"\n\nSCSI Class Driver\n"));
490
491 //
492 // Validate the length of this structure. This is effectively a
493 // version check.
494 //
495
496 if (InitializationData->InitializationDataSize > sizeof(CLASS_INIT_DATA)) {
497
498 DebugPrint((0,"ScsiClassInitialize: Class driver wrong version\n"));
499 return (ULONG) STATUS_REVISION_MISMATCH;
500 }
501
502 //
503 // Check that each required entry is not NULL. Note that Shutdown, Flush and Error
504 // are not required entry points.
505 //
506
507 if ((!InitializationData->ClassFindDevices) ||
508 (!InitializationData->ClassDeviceControl) ||
509 (!((InitializationData->ClassReadWriteVerification) ||
510 (InitializationData->ClassStartIo)))) {
511
512 DebugPrint((0,
513 "ScsiClassInitialize: Class device-specific driver missing required entry\n"));
514
515 return (ULONG) STATUS_REVISION_MISMATCH;
516 }
517
518 status = IoAllocateDriverObjectExtension(DriverObject,
519 DriverObject,
520 sizeof(CLASS_DRIVER_EXTENSION),
521 (PVOID *)&DriverExtension);
522 if (!NT_SUCCESS(status))
523 return status;
524
525 RtlCopyMemory(&DriverExtension->InitializationData, InitializationData, sizeof(CLASS_INIT_DATA));
526 DriverExtension->PortNumber = 0;
527
528 DriverExtension->RegistryPath.Buffer = ExAllocatePool(PagedPool, RegistryPath->MaximumLength);
529 if (!DriverExtension->RegistryPath.Buffer)
530 return STATUS_NO_MEMORY;
531
532 DriverExtension->RegistryPath.Length = RegistryPath->Length;
533 DriverExtension->RegistryPath.MaximumLength = RegistryPath->MaximumLength;
534
535 RtlCopyMemory(DriverExtension->RegistryPath.Buffer,
536 RegistryPath->Buffer,
537 RegistryPath->Length);
538
539 //
540 // Update driver object with entry points.
541 //
542
543 DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiClassCreateClose;
544 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiClassCreateClose;
545 DriverObject->MajorFunction[IRP_MJ_READ] = ScsiClassReadWrite;
546 DriverObject->MajorFunction[IRP_MJ_WRITE] = ScsiClassReadWrite;
547 DriverObject->MajorFunction[IRP_MJ_PNP] = ScsiClassPlugPlay;
548 DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiClassInternalIoControl;
549 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiClassDeviceControlDispatch;
550 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = ScsiClassShutdownFlush;
551 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = ScsiClassShutdownFlush;
552 DriverObject->DriverExtension->AddDevice = ScsiClassAddDevice;
553
554 if (InitializationData->ClassStartIo) {
555 DriverObject->DriverStartIo = InitializationData->ClassStartIo;
556 }
557
558 //
559 // Open port driver controller device objects by name.
560 //
561
562 do {
563
564 sprintf(deviceNameBuffer, "\\Device\\ScsiPort%lu", DriverExtension->PortNumber);
565
566 DebugPrint((2, "ScsiClassInitialize: Open Port %s\n", deviceNameBuffer));
567
568 RtlInitString(&deviceNameString, deviceNameBuffer);
569
570 status = RtlAnsiStringToUnicodeString(&unicodeDeviceName,
571 &deviceNameString,
572 TRUE);
573
574 if (!NT_SUCCESS(status)){
575 break;
576 }
577
578 status = IoGetDeviceObjectPointer(&unicodeDeviceName,
579 FILE_READ_ATTRIBUTES,
580 &fileObject,
581 &portDeviceObject);
582
583 if (NT_SUCCESS(status)) {
584
585 //
586 // Call the device-specific driver's FindDevice routine.
587 //
588
589 if (InitializationData->ClassFindDevices(DriverObject, Argument2, InitializationData,
590 portDeviceObject, DriverExtension->PortNumber)) {
591
592 /* deviceFound = TRUE; See note at the end */
593 }
594 }
595
596 //
597 // Check next SCSI adapter.
598 //
599
600 DriverExtension->PortNumber++;
601
602 } while(NT_SUCCESS(status));
603
604 /* We don't want to fail init just because we don't have devices right now */
605 return STATUS_SUCCESS; /*deviceFound ? STATUS_SUCCESS : STATUS_NO_SUCH_DEVICE;*/
606 }
607
608 \f
609 NTSTATUS
610 NTAPI
611 ScsiClassCreateClose(
612 IN PDEVICE_OBJECT DeviceObject,
613 IN PIRP Irp
614 )
615
616 /*++
617
618 Routine Description:
619
620 SCSI class driver create and close routine. This is called by the I/O system
621 when the device is opened or closed.
622
623 Arguments:
624
625 DriverObject - Pointer to driver object created by system.
626
627 Irp - IRP involved.
628
629 Return Value:
630
631 Device-specific drivers return value or STATUS_SUCCESS.
632
633 --*/
634
635 {
636 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
637
638 ASSERT(*(PULONG)deviceExtension != '2slc');
639
640 //
641 // Invoke the device-specific routine, if one exists. Otherwise complete
642 // with SUCCESS
643 //
644
645 if (deviceExtension->ClassCreateClose) {
646
647 return deviceExtension->ClassCreateClose(DeviceObject, Irp);
648
649 } else {
650 Irp->IoStatus.Status = STATUS_SUCCESS;
651
652 IoCompleteRequest(Irp, IO_NO_INCREMENT);
653 return(STATUS_SUCCESS);
654 }
655 }
656
657
658 \f
659 NTSTATUS
660 NTAPI
661 ScsiClassReadWrite(
662 IN PDEVICE_OBJECT DeviceObject,
663 IN PIRP Irp
664 )
665
666 /*++
667
668 Routine Description:
669
670 This is the system entry point for read and write requests. The device-specific handler is invoked
671 to perform any validation necessary. The number of bytes in the request are
672 checked against the maximum byte counts that the adapter supports and requests are broken up into
673 smaller sizes if necessary.
674
675 Arguments:
676
677 DeviceObject
678 Irp - IO request
679
680 Return Value:
681
682 NT Status
683
684 --*/
685
686 {
687 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
688 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
689 ULONG transferPages;
690 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
691 ULONG maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength;
692 NTSTATUS status;
693
694 ASSERT(*(PULONG)deviceExtension != '2slc');
695
696 if (DeviceObject->Flags & DO_VERIFY_VOLUME &&
697 !(currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) {
698
699 //
700 // if DO_VERIFY_VOLUME bit is set
701 // in device object flags, fail request.
702 //
703
704 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
705
706 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
707 Irp->IoStatus.Information = 0;
708
709 IoCompleteRequest(Irp, 0);
710 return STATUS_VERIFY_REQUIRED;
711 }
712
713 //
714 // Invoke the device specific routine to do whatever it needs to verify
715 // this request.
716 //
717
718 ASSERT(deviceExtension->ClassReadWriteVerification);
719
720 status = deviceExtension->ClassReadWriteVerification(DeviceObject,Irp);
721
722 if (!NT_SUCCESS(status)) {
723
724 //
725 // It is up to the device specific driver to set the Irp status.
726 //
727
728 IoCompleteRequest (Irp, IO_NO_INCREMENT);
729 return status;
730 } else if (status == STATUS_PENDING) {
731
732 IoMarkIrpPending(Irp);
733 return STATUS_PENDING;
734 }
735
736 //
737 // Check for a zero length IO, as several macros will turn this into
738 // seemingly a 0xffffffff length request.
739 //
740
741 if (transferByteCount == 0) {
742 Irp->IoStatus.Status = STATUS_SUCCESS;
743 Irp->IoStatus.Information = 0;
744 IoCompleteRequest(Irp, IO_NO_INCREMENT);
745 return STATUS_SUCCESS;
746
747 }
748
749 if (deviceExtension->ClassStartIo) {
750
751 IoMarkIrpPending(Irp);
752
753 IoStartPacket(DeviceObject,
754 Irp,
755 NULL,
756 NULL);
757
758 return STATUS_PENDING;
759 }
760
761 //
762 // Mark IRP with status pending.
763 //
764
765 IoMarkIrpPending(Irp);
766
767 //
768 // Add partition byte offset to make starting byte relative to
769 // beginning of disk. In addition, add in skew for DM Driver, if any.
770 //
771
772 currentIrpStack->Parameters.Read.ByteOffset.QuadPart += (deviceExtension->StartingOffset.QuadPart +
773 deviceExtension->DMByteSkew);
774
775 //
776 // Calculate number of pages in this transfer.
777 //
778
779 transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
780 currentIrpStack->Parameters.Read.Length);
781
782 //
783 // Check if request length is greater than the maximum number of
784 // bytes that the hardware can transfer.
785 //
786
787 if (currentIrpStack->Parameters.Read.Length > maximumTransferLength ||
788 transferPages > deviceExtension->PortCapabilities->MaximumPhysicalPages) {
789
790 DebugPrint((2,"ScsiClassReadWrite: Request greater than maximum\n"));
791 DebugPrint((2,"ScsiClassReadWrite: Maximum is %lx\n",
792 maximumTransferLength));
793 DebugPrint((2,"ScsiClassReadWrite: Byte count is %lx\n",
794 currentIrpStack->Parameters.Read.Length));
795
796 transferPages =
797 deviceExtension->PortCapabilities->MaximumPhysicalPages - 1;
798
799 if (maximumTransferLength > transferPages << PAGE_SHIFT ) {
800 maximumTransferLength = transferPages << PAGE_SHIFT;
801 }
802
803 //
804 // Check that maximum transfer size is not zero.
805 //
806
807 if (maximumTransferLength == 0) {
808 maximumTransferLength = PAGE_SIZE;
809 }
810
811 //
812 // Mark IRP with status pending.
813 //
814
815 IoMarkIrpPending(Irp);
816
817 //
818 // Request greater than port driver maximum.
819 // Break up into smaller routines.
820 //
821
822 ScsiClassSplitRequest(DeviceObject, Irp, maximumTransferLength);
823
824
825 return STATUS_PENDING;
826 }
827
828 //
829 // Build SRB and CDB for this IRP.
830 //
831
832 ScsiClassBuildRequest(DeviceObject, Irp);
833
834 //
835 // Return the results of the call to the port driver.
836 //
837
838 return IoCallDriver(deviceExtension->PortDeviceObject, Irp);
839
840 } // end ScsiClassReadWrite()
841
842 \f
843 NTSTATUS
844 NTAPI
845 ScsiClassGetCapabilities(
846 IN PDEVICE_OBJECT PortDeviceObject,
847 OUT PIO_SCSI_CAPABILITIES *PortCapabilities
848 )
849
850 /*++
851
852 Routine Description:
853
854 This routine builds and sends a request to the port driver to
855 get a pointer to a structure that describes the adapter's
856 capabilities/limitations. This routine is synchronous.
857
858 Arguments:
859
860 PortDeviceObject - Port driver device object representing the HBA.
861
862 PortCapabilities - Location to store pointer to capabilities structure.
863
864 Return Value:
865
866 Nt status indicating the results of the operation.
867
868 Notes:
869
870 This routine should only be called at initialization time.
871
872 --*/
873
874 {
875 PIRP irp;
876 IO_STATUS_BLOCK ioStatus;
877 KEVENT event;
878 NTSTATUS status;
879
880 PAGED_CODE();
881
882 //
883 // Create notification event object to be used to signal the
884 // request completion.
885 //
886
887 KeInitializeEvent(&event, NotificationEvent, FALSE);
888
889 //
890 // Build the synchronous request to be sent to the port driver
891 // to perform the request.
892 //
893
894 irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_CAPABILITIES,
895 PortDeviceObject,
896 NULL,
897 0,
898 PortCapabilities,
899 sizeof(PVOID),
900 FALSE,
901 &event,
902 &ioStatus);
903
904 if (irp == NULL) {
905 return STATUS_INSUFFICIENT_RESOURCES;
906 }
907
908 //
909 // Pass request to port driver and wait for request to complete.
910 //
911
912 status = IoCallDriver(PortDeviceObject, irp);
913
914 if (status == STATUS_PENDING) {
915 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
916 return(ioStatus.Status);
917 }
918
919 return status;
920
921 } // end ScsiClassGetCapabilities()
922
923 \f
924 NTSTATUS
925 NTAPI
926 ScsiClassGetInquiryData(
927 IN PDEVICE_OBJECT PortDeviceObject,
928 OUT PSCSI_ADAPTER_BUS_INFO *ConfigInfo
929 )
930
931 /*++
932
933 Routine Description:
934
935 This routine sends a request to a port driver to return
936 configuration information. Space for the information is
937 allocated by this routine. The caller is responsible for
938 freeing the configuration information. This routine is
939 synchronous.
940
941 Arguments:
942
943 PortDeviceObject - Port driver device object representing the HBA.
944
945 ConfigInfo - Returns a pointer to the configuration information.
946
947 Return Value:
948
949 Nt status indicating the results of the operation.
950
951 Notes:
952
953 This routine should be called only at initialization time.
954
955 --*/
956
957 {
958 PIRP irp;
959 IO_STATUS_BLOCK ioStatus;
960 KEVENT event;
961 NTSTATUS status;
962 PSCSI_ADAPTER_BUS_INFO buffer;
963
964 PAGED_CODE();
965
966 buffer = ExAllocatePool(PagedPool, INQUIRY_DATA_SIZE);
967 *ConfigInfo = buffer;
968
969 if (buffer == NULL) {
970 return(STATUS_INSUFFICIENT_RESOURCES);
971 }
972
973 //
974 // Create notification event object to be used to signal the inquiry
975 // request completion.
976 //
977
978 KeInitializeEvent(&event, NotificationEvent, FALSE);
979
980 //
981 // Build the synchronous request to be sent to the port driver
982 // to perform the inquiries.
983 //
984
985 irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA,
986 PortDeviceObject,
987 NULL,
988 0,
989 buffer,
990 INQUIRY_DATA_SIZE,
991 FALSE,
992 &event,
993 &ioStatus);
994
995 if (irp == NULL) {
996 return(STATUS_INSUFFICIENT_RESOURCES);
997 }
998
999 //
1000 // Pass request to port driver and wait for request to complete.
1001 //
1002
1003 status = IoCallDriver(PortDeviceObject, irp);
1004
1005 if (status == STATUS_PENDING) {
1006 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
1007 status = ioStatus.Status;
1008 }
1009
1010 if (!NT_SUCCESS(status)) {
1011
1012 //
1013 // Free the buffer on an error.
1014 //
1015
1016 ExFreePool(buffer);
1017 *ConfigInfo = NULL;
1018
1019 }
1020
1021 return status;
1022
1023 } // end ScsiClassGetInquiryData()
1024
1025 \f
1026 NTSTATUS
1027 NTAPI
1028 ScsiClassReadDriveCapacity(
1029 IN PDEVICE_OBJECT DeviceObject
1030 )
1031
1032 /*++
1033
1034 Routine Description:
1035
1036 This routine sends a READ CAPACITY to the requested device, updates
1037 the geometry information in the device object and returns
1038 when it is complete. This routine is synchronous.
1039
1040 Arguments:
1041
1042 DeviceObject - Supplies a pointer to the device object that represents
1043 the device whose capacity is to be read.
1044
1045 Return Value:
1046
1047 Status is returned.
1048
1049 --*/
1050 {
1051 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1052 ULONG retries = 1;
1053 ULONG lastSector;
1054 PCDB cdb;
1055 PREAD_CAPACITY_DATA readCapacityBuffer;
1056 SCSI_REQUEST_BLOCK srb;
1057 NTSTATUS status;
1058
1059 ASSERT(*(PULONG)deviceExtension != '2slc');
1060
1061 //
1062 // Allocate read capacity buffer from nonpaged pool.
1063 //
1064
1065 readCapacityBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
1066 sizeof(READ_CAPACITY_DATA));
1067
1068 if (!readCapacityBuffer) {
1069 return(STATUS_INSUFFICIENT_RESOURCES);
1070 }
1071
1072 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
1073
1074 //
1075 // Build the read capacity CDB.
1076 //
1077
1078 srb.CdbLength = 10;
1079 cdb = (PCDB)srb.Cdb;
1080
1081 //
1082 // Set timeout value from device extension.
1083 //
1084
1085 srb.TimeOutValue = deviceExtension->TimeOutValue;
1086
1087 cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
1088
1089 Retry:
1090
1091 status = ScsiClassSendSrbSynchronous(DeviceObject,
1092 &srb,
1093 readCapacityBuffer,
1094 sizeof(READ_CAPACITY_DATA),
1095 FALSE);
1096
1097 if (NT_SUCCESS(status)) {
1098
1099 //
1100 // Copy sector size from read capacity buffer to device extension
1101 // in reverse byte order.
1102 //
1103
1104 ((PFOUR_BYTE)&deviceExtension->DiskGeometry->Geometry.BytesPerSector)->Byte0 =
1105 ((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte3;
1106
1107 ((PFOUR_BYTE)&deviceExtension->DiskGeometry->Geometry.BytesPerSector)->Byte1 =
1108 ((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte2;
1109
1110 ((PFOUR_BYTE)&deviceExtension->DiskGeometry->Geometry.BytesPerSector)->Byte2 =
1111 ((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte1;
1112
1113 ((PFOUR_BYTE)&deviceExtension->DiskGeometry->Geometry.BytesPerSector)->Byte3 =
1114 ((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte0;
1115
1116 //
1117 // Copy last sector in reverse byte order.
1118 //
1119
1120 ((PFOUR_BYTE)&lastSector)->Byte0 =
1121 ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte3;
1122
1123 ((PFOUR_BYTE)&lastSector)->Byte1 =
1124 ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte2;
1125
1126 ((PFOUR_BYTE)&lastSector)->Byte2 =
1127 ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte1;
1128
1129 ((PFOUR_BYTE)&lastSector)->Byte3 =
1130 ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte0;
1131
1132 //
1133 // Calculate sector to byte shift.
1134 //
1135
1136 WHICH_BIT(deviceExtension->DiskGeometry->Geometry.BytesPerSector, deviceExtension->SectorShift);
1137
1138 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
1139 deviceExtension->DiskGeometry->Geometry.BytesPerSector));
1140
1141 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
1142 lastSector + 1));
1143
1144 //
1145 // Calculate media capacity in bytes.
1146 //
1147
1148 deviceExtension->PartitionLength.QuadPart = (LONGLONG)(lastSector + 1);
1149
1150 //
1151 // Calculate number of cylinders.
1152 //
1153
1154 deviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = (LONGLONG)((lastSector + 1)/(DEFAULT_SECTORS_PER_TRACK * DEFAULT_TRACKS_PER_CYLINDER));
1155
1156 deviceExtension->PartitionLength.QuadPart =
1157 (deviceExtension->PartitionLength.QuadPart << deviceExtension->SectorShift);
1158
1159 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
1160
1161 //
1162 // This device supports removable media.
1163 //
1164
1165 deviceExtension->DiskGeometry->Geometry.MediaType = RemovableMedia;
1166
1167 } else {
1168
1169 //
1170 // Assume media type is fixed disk.
1171 //
1172
1173 deviceExtension->DiskGeometry->Geometry.MediaType = FixedMedia;
1174 }
1175
1176 //
1177 // Assume sectors per track are DEFAULT_SECTORS_PER_TRACK;
1178 //
1179
1180 deviceExtension->DiskGeometry->Geometry.SectorsPerTrack = DEFAULT_SECTORS_PER_TRACK;
1181
1182 //
1183 // Assume tracks per cylinder (number of heads) is DEFAULT_TRACKS_PER_CYLINDER.
1184 //
1185
1186 deviceExtension->DiskGeometry->Geometry.TracksPerCylinder = DEFAULT_TRACKS_PER_CYLINDER;
1187 }
1188
1189 if (status == STATUS_VERIFY_REQUIRED) {
1190
1191 //
1192 // Routine ScsiClassSendSrbSynchronous does not retry
1193 // requests returned with this status.
1194 // Read Capacities should be retried
1195 // anyway.
1196 //
1197
1198 if (retries--) {
1199
1200 //
1201 // Retry request.
1202 //
1203
1204 goto Retry;
1205 }
1206 }
1207
1208 if (!NT_SUCCESS(status)) {
1209
1210 //
1211 // If the read capacity fails, set the geometry to reasonable parameter
1212 // so things don't fail at unexpected places. Zero the geometry
1213 // except for the bytes per sector and sector shift.
1214 //
1215
1216 RtlZeroMemory(deviceExtension->DiskGeometry, sizeof(DISK_GEOMETRY_EX));
1217 deviceExtension->DiskGeometry->Geometry.BytesPerSector = 512;
1218 deviceExtension->SectorShift = 9;
1219 deviceExtension->PartitionLength.QuadPart = (LONGLONG) 0;
1220
1221 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
1222
1223 //
1224 // This device supports removable media.
1225 //
1226
1227 deviceExtension->DiskGeometry->Geometry.MediaType = RemovableMedia;
1228
1229 } else {
1230
1231 //
1232 // Assume media type is fixed disk.
1233 //
1234
1235 deviceExtension->DiskGeometry->Geometry.MediaType = FixedMedia;
1236 }
1237 }
1238
1239 //
1240 // Deallocate read capacity buffer.
1241 //
1242
1243 ExFreePool(readCapacityBuffer);
1244
1245 return status;
1246
1247 } // end ScsiClassReadDriveCapacity()
1248
1249 \f
1250 VOID
1251 NTAPI
1252 ScsiClassReleaseQueue(
1253 IN PDEVICE_OBJECT DeviceObject
1254 )
1255
1256 /*++
1257
1258 Routine Description:
1259
1260 This routine issues an internal device control command
1261 to the port driver to release a frozen queue. The call
1262 is issued asynchronously as ScsiClassReleaseQueue will be invoked
1263 from the IO completion DPC (and will have no context to
1264 wait for a synchronous call to complete).
1265
1266 Arguments:
1267
1268 DeviceObject - The device object for the logical unit with
1269 the frozen queue.
1270
1271 Return Value:
1272
1273 None.
1274
1275 --*/
1276 {
1277 PIO_STACK_LOCATION irpStack;
1278 PIRP irp;
1279 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1280 PCOMPLETION_CONTEXT context;
1281 PSCSI_REQUEST_BLOCK srb;
1282 KIRQL currentIrql;
1283
1284 ASSERT(*(PULONG)deviceExtension != '2slc');
1285
1286 //
1287 // Allocate context from nonpaged pool.
1288 //
1289
1290 context = ExAllocatePool(NonPagedPoolMustSucceed,
1291 sizeof(COMPLETION_CONTEXT));
1292
1293 //
1294 // Save the device object in the context for use by the completion
1295 // routine.
1296 //
1297
1298 context->DeviceObject = DeviceObject;
1299 srb = &context->Srb;
1300
1301 //
1302 // Zero out srb.
1303 //
1304
1305 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
1306
1307 //
1308 // Write length to SRB.
1309 //
1310
1311 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1312
1313 //
1314 // Set up SCSI bus address.
1315 //
1316
1317 srb->PathId = deviceExtension->PathId;
1318 srb->TargetId = deviceExtension->TargetId;
1319 srb->Lun = deviceExtension->Lun;
1320
1321 //
1322 // If this device is removable then flush the queue. This will also
1323 // release it.
1324 //
1325
1326 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
1327
1328 srb->Function = SRB_FUNCTION_FLUSH_QUEUE;
1329
1330 } else {
1331
1332 srb->Function = SRB_FUNCTION_RELEASE_QUEUE;
1333
1334 }
1335
1336 //
1337 // Build the asynchronous request to be sent to the port driver.
1338 //
1339
1340 irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1341
1342 if(irp == NULL) {
1343
1344 //
1345 // We have no better way of dealing with this at the moment
1346 //
1347
1348 KeBugCheck((ULONG)0x0000002DL);
1349
1350 }
1351
1352 IoSetCompletionRoutine(irp,
1353 (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion,
1354 context,
1355 TRUE,
1356 TRUE,
1357 TRUE);
1358
1359 irpStack = IoGetNextIrpStackLocation(irp);
1360
1361 irpStack->MajorFunction = IRP_MJ_SCSI;
1362
1363 srb->OriginalRequest = irp;
1364
1365 //
1366 // Store the SRB address in next stack for port driver.
1367 //
1368
1369 irpStack->Parameters.Scsi.Srb = srb;
1370
1371 //
1372 // Since this routine can cause outstanding requests to be completed, and
1373 // calling a completion routine at < DISPATCH_LEVEL is dangerous (if they
1374 // call IoStartNextPacket we will bugcheck) raise up to dispatch level before
1375 // issuing the request
1376 //
1377
1378 currentIrql = KeGetCurrentIrql();
1379
1380 if(currentIrql < DISPATCH_LEVEL) {
1381 KeRaiseIrql(DISPATCH_LEVEL, &currentIrql);
1382 IoCallDriver(deviceExtension->PortDeviceObject, irp);
1383 KeLowerIrql(currentIrql);
1384 } else {
1385 IoCallDriver(deviceExtension->PortDeviceObject, irp);
1386 }
1387
1388 return;
1389
1390 } // end ScsiClassReleaseQueue()
1391
1392 \f
1393 VOID
1394 NTAPI
1395 StartUnit(
1396 IN PDEVICE_OBJECT DeviceObject
1397 )
1398
1399 /*++
1400
1401 Routine Description:
1402
1403 Send command to SCSI unit to start or power up.
1404 Because this command is issued asynchronously, that is, without
1405 waiting on it to complete, the IMMEDIATE flag is not set. This
1406 means that the CDB will not return until the drive has powered up.
1407 This should keep subsequent requests from being submitted to the
1408 device before it has completely spun up.
1409 This routine is called from the InterpretSense routine, when a
1410 request sense returns data indicating that a drive must be
1411 powered up.
1412
1413 Arguments:
1414
1415 DeviceObject - The device object for the logical unit with
1416 the frozen queue.
1417
1418 Return Value:
1419
1420 None.
1421
1422 --*/
1423 {
1424 PIO_STACK_LOCATION irpStack;
1425 PIRP irp;
1426 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1427 PSCSI_REQUEST_BLOCK srb;
1428 PCOMPLETION_CONTEXT context;
1429 PCDB cdb;
1430
1431 ASSERT(*(PULONG)deviceExtension != '2slc');
1432
1433 //
1434 // Allocate Srb from nonpaged pool.
1435 //
1436
1437 context = ExAllocatePool(NonPagedPoolMustSucceed,
1438 sizeof(COMPLETION_CONTEXT));
1439
1440 //
1441 // Save the device object in the context for use by the completion
1442 // routine.
1443 //
1444
1445 context->DeviceObject = DeviceObject;
1446 srb = &context->Srb;
1447
1448 //
1449 // Zero out srb.
1450 //
1451
1452 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
1453
1454 //
1455 // Write length to SRB.
1456 //
1457
1458 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1459
1460 //
1461 // Set up SCSI bus address.
1462 //
1463
1464 srb->PathId = deviceExtension->PathId;
1465 srb->TargetId = deviceExtension->TargetId;
1466 srb->Lun = deviceExtension->Lun;
1467
1468 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1469
1470 //
1471 // Set timeout value large enough for drive to spin up.
1472 //
1473
1474 srb->TimeOutValue = START_UNIT_TIMEOUT;
1475
1476 //
1477 // Set the transfer length.
1478 //
1479
1480 srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER | SRB_FLAGS_DISABLE_AUTOSENSE | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
1481
1482 //
1483 // Build the start unit CDB.
1484 //
1485
1486 srb->CdbLength = 6;
1487 cdb = (PCDB)srb->Cdb;
1488
1489 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
1490 cdb->START_STOP.Start = 1;
1491 cdb->START_STOP.LogicalUnitNumber = srb->Lun;
1492
1493 //
1494 // Build the asynchronous request to be sent to the port driver.
1495 // Since this routine is called from a DPC the IRP should always be
1496 // available.
1497 //
1498
1499 irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1500 IoSetCompletionRoutine(irp,
1501 (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion,
1502 context,
1503 TRUE,
1504 TRUE,
1505 TRUE);
1506
1507 irpStack = IoGetNextIrpStackLocation(irp);
1508 irpStack->MajorFunction = IRP_MJ_SCSI;
1509 srb->OriginalRequest = irp;
1510
1511 //
1512 // Store the SRB address in next stack for port driver.
1513 //
1514
1515 irpStack->Parameters.Scsi.Srb = srb;
1516
1517 //
1518 // Call the port driver with the IRP.
1519 //
1520
1521 IoCallDriver(deviceExtension->PortDeviceObject, irp);
1522
1523 return;
1524
1525 } // end StartUnit()
1526
1527 \f
1528 NTSTATUS
1529 NTAPI
1530 ScsiClassAsynchronousCompletion(
1531 PDEVICE_OBJECT DeviceObject,
1532 PIRP Irp,
1533 PVOID Context
1534 )
1535 /*++
1536
1537 Routine Description:
1538
1539 This routine is called when an asynchronous I/O request
1540 which was issued by the class driver completes. Examples of such requests
1541 are release queue or START UNIT. This routine releases the queue if
1542 necessary. It then frees the context and the IRP.
1543
1544 Arguments:
1545
1546 DeviceObject - The device object for the logical unit; however since this
1547 is the top stack location the value is NULL.
1548
1549 Irp - Supplies a pointer to the Irp to be processed.
1550
1551 Context - Supplies the context to be used to process this request.
1552
1553 Return Value:
1554
1555 None.
1556
1557 --*/
1558
1559 {
1560 PCOMPLETION_CONTEXT context = Context;
1561 PSCSI_REQUEST_BLOCK srb;
1562
1563 srb = &context->Srb;
1564
1565 //
1566 // If this is an execute srb, then check the return status and make sure.
1567 // the queue is not frozen.
1568 //
1569
1570 if (srb->Function == SRB_FUNCTION_EXECUTE_SCSI) {
1571
1572 //
1573 // Check for a frozen queue.
1574 //
1575
1576 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
1577
1578 //
1579 // Unfreeze the queue getting the device object from the context.
1580 //
1581
1582 ScsiClassReleaseQueue(context->DeviceObject);
1583 }
1584 }
1585
1586 //
1587 // Free the context and the Irp.
1588 //
1589
1590 if (Irp->MdlAddress != NULL) {
1591 MmUnlockPages(Irp->MdlAddress);
1592 IoFreeMdl(Irp->MdlAddress);
1593
1594 Irp->MdlAddress = NULL;
1595 }
1596
1597 ExFreePool(context);
1598 IoFreeIrp(Irp);
1599
1600 //
1601 // Indicate the I/O system should stop processing the Irp completion.
1602 //
1603
1604 return STATUS_MORE_PROCESSING_REQUIRED;
1605
1606 } // ScsiClassAsynchronousCompletion()
1607
1608 \f
1609 VOID
1610 NTAPI
1611 ScsiClassSplitRequest(
1612 IN PDEVICE_OBJECT DeviceObject,
1613 IN PIRP Irp,
1614 IN ULONG MaximumBytes
1615 )
1616
1617 /*++
1618
1619 Routine Description:
1620
1621 Break request into smaller requests. Each new request will be the
1622 maximum transfer size that the port driver can handle or if it
1623 is the final request, it may be the residual size.
1624
1625 The number of IRPs required to process this request is written in the
1626 current stack of the original IRP. Then as each new IRP completes
1627 the count in the original IRP is decremented. When the count goes to
1628 zero, the original IRP is completed.
1629
1630 Arguments:
1631
1632 DeviceObject - Pointer to the class device object to be addressed.
1633
1634 Irp - Pointer to Irp the original request.
1635
1636 Return Value:
1637
1638 None.
1639
1640 --*/
1641
1642 {
1643 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1644 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
1645 PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
1646 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
1647 LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
1648 PVOID dataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
1649 ULONG dataLength = MaximumBytes;
1650 ULONG irpCount = (transferByteCount + MaximumBytes - 1) / MaximumBytes;
1651 ULONG i;
1652 PSCSI_REQUEST_BLOCK srb;
1653
1654 DebugPrint((2, "ScsiClassSplitRequest: Requires %d IRPs\n", irpCount));
1655 DebugPrint((2, "ScsiClassSplitRequest: Original IRP %lx\n", Irp));
1656
1657 ASSERT(*(PULONG)deviceExtension != '2slc');
1658
1659 //
1660 // If all partial transfers complete successfully then the status and
1661 // bytes transferred are already set up. Failing a partial-transfer IRP
1662 // will set status to error and bytes transferred to 0 during
1663 // IoCompletion. Setting bytes transferred to 0 if an IRP fails allows
1664 // asynchronous partial transfers. This is an optimization for the
1665 // successful case.
1666 //
1667
1668 Irp->IoStatus.Status = STATUS_SUCCESS;
1669 Irp->IoStatus.Information = transferByteCount;
1670
1671 //
1672 // Save number of IRPs to complete count on current stack
1673 // of original IRP.
1674 //
1675
1676 nextIrpStack->Parameters.Others.Argument1 = (PVOID)(ULONG_PTR) irpCount;
1677
1678 for (i = 0; i < irpCount; i++) {
1679
1680 PIRP newIrp;
1681 PIO_STACK_LOCATION newIrpStack;
1682
1683 //
1684 // Allocate new IRP.
1685 //
1686
1687 newIrp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1688
1689 if (newIrp == NULL) {
1690
1691 DebugPrint((1,"ScsiClassSplitRequest: Can't allocate Irp\n"));
1692
1693 //
1694 // If an Irp can't be allocated then the original request cannot
1695 // be executed. If this is the first request then just fail the
1696 // original request; otherwise just return. When the pending
1697 // requests complete, they will complete the original request.
1698 // In either case set the IRP status to failure.
1699 //
1700
1701 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1702 Irp->IoStatus.Information = 0;
1703
1704 if (i == 0) {
1705 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1706 }
1707
1708 return;
1709 }
1710
1711 DebugPrint((2, "ScsiClassSplitRequest: New IRP %lx\n", newIrp));
1712
1713 //
1714 // Write MDL address to new IRP. In the port driver the SRB data
1715 // buffer field is used as an offset into the MDL, so the same MDL
1716 // can be used for each partial transfer. This saves having to build
1717 // a new MDL for each partial transfer.
1718 //
1719
1720 newIrp->MdlAddress = Irp->MdlAddress;
1721
1722 //
1723 // At this point there is no current stack. IoSetNextIrpStackLocation
1724 // will make the first stack location the current stack so that the
1725 // SRB address can be written there.
1726 //
1727
1728 IoSetNextIrpStackLocation(newIrp);
1729 newIrpStack = IoGetCurrentIrpStackLocation(newIrp);
1730
1731 newIrpStack->MajorFunction = currentIrpStack->MajorFunction;
1732 newIrpStack->Parameters.Read.Length = dataLength;
1733 newIrpStack->Parameters.Read.ByteOffset = startingOffset;
1734 newIrpStack->DeviceObject = DeviceObject;
1735
1736 //
1737 // Build SRB and CDB.
1738 //
1739
1740 ScsiClassBuildRequest(DeviceObject, newIrp);
1741
1742 //
1743 // Adjust SRB for this partial transfer.
1744 //
1745
1746 newIrpStack = IoGetNextIrpStackLocation(newIrp);
1747
1748 srb = newIrpStack->Parameters.Others.Argument1;
1749 srb->DataBuffer = dataBuffer;
1750
1751 //
1752 // Write original IRP address to new IRP.
1753 //
1754
1755 newIrp->AssociatedIrp.MasterIrp = Irp;
1756
1757 //
1758 // Set the completion routine to ScsiClassIoCompleteAssociated.
1759 //
1760
1761 IoSetCompletionRoutine(newIrp,
1762 ScsiClassIoCompleteAssociated,
1763 srb,
1764 TRUE,
1765 TRUE,
1766 TRUE);
1767
1768 //
1769 // Call port driver with new request.
1770 //
1771
1772 IoCallDriver(deviceExtension->PortDeviceObject, newIrp);
1773
1774 //
1775 // Set up for next request.
1776 //
1777
1778 dataBuffer = (PCHAR)dataBuffer + MaximumBytes;
1779
1780 transferByteCount -= MaximumBytes;
1781
1782 if (transferByteCount > MaximumBytes) {
1783
1784 dataLength = MaximumBytes;
1785
1786 } else {
1787
1788 dataLength = transferByteCount;
1789 }
1790
1791 //
1792 // Adjust disk byte offset.
1793 //
1794
1795 startingOffset.QuadPart = startingOffset.QuadPart + MaximumBytes;
1796 }
1797
1798 return;
1799
1800 } // end ScsiClassSplitRequest()
1801
1802 \f
1803 NTSTATUS
1804 NTAPI
1805 ScsiClassIoComplete(
1806 IN PDEVICE_OBJECT DeviceObject,
1807 IN PIRP Irp,
1808 IN PVOID Context
1809 )
1810
1811 /*++
1812
1813 Routine Description:
1814
1815 This routine executes when the port driver has completed a request.
1816 It looks at the SRB status in the completing SRB and if not success
1817 it checks for valid request sense buffer information. If valid, the
1818 info is used to update status with more precise message of type of
1819 error. This routine deallocates the SRB.
1820
1821 Arguments:
1822
1823 DeviceObject - Supplies the device object which represents the logical
1824 unit.
1825
1826 Irp - Supplies the Irp which has completed.
1827
1828 Context - Supplies a pointer to the SRB.
1829
1830 Return Value:
1831
1832 NT status
1833
1834 --*/
1835
1836 {
1837 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
1838 PSCSI_REQUEST_BLOCK srb = Context;
1839 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1840 NTSTATUS status;
1841 BOOLEAN retry;
1842
1843 ASSERT(*(PULONG)deviceExtension != '2slc');
1844
1845 //
1846 // Check SRB status for success of completing request.
1847 //
1848
1849 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
1850
1851 DebugPrint((2,"ScsiClassIoComplete: IRP %lx, SRB %lx\n", Irp, srb));
1852
1853 //
1854 // Release the queue if it is frozen.
1855 //
1856
1857 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
1858 ScsiClassReleaseQueue(DeviceObject);
1859 }
1860
1861 retry = ScsiClassInterpretSenseInfo(
1862 DeviceObject,
1863 srb,
1864 irpStack->MajorFunction,
1865 irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? irpStack->Parameters.DeviceIoControl.IoControlCode : 0,
1866 MAXIMUM_RETRIES - PtrToUlong(irpStack->Parameters.Others.Argument4),
1867 &status);
1868
1869 //
1870 // If the status is verified required and the this request
1871 // should bypass verify required then retry the request.
1872 //
1873
1874 if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
1875 status == STATUS_VERIFY_REQUIRED) {
1876
1877 status = STATUS_IO_DEVICE_ERROR;
1878 retry = TRUE;
1879 }
1880
1881 if (retry && (irpStack->Parameters.Others.Argument4 = (PVOID)((ULONG_PTR)irpStack->Parameters.Others.Argument4-1))) {
1882
1883 //
1884 // Retry request.
1885 //
1886
1887 DebugPrint((1, "Retry request %lx\n", Irp));
1888 RetryRequest(DeviceObject, Irp, srb, FALSE);
1889 return STATUS_MORE_PROCESSING_REQUIRED;
1890 }
1891 } else {
1892
1893 //
1894 // Set status for successful request.
1895 //
1896
1897 status = STATUS_SUCCESS;
1898
1899 } // end if (SRB_STATUS(srb->SrbStatus) ...
1900
1901 //
1902 // Return SRB to list.
1903 //
1904
1905 ExFreeToNPagedLookasideList(&deviceExtension->SrbLookasideListHead,
1906 srb);
1907
1908 //
1909 // Set status in completing IRP.
1910 //
1911
1912 Irp->IoStatus.Status = status;
1913 if ((NT_SUCCESS(status)) && (Irp->Flags & IRP_PAGING_IO)) {
1914 ASSERT(Irp->IoStatus.Information);
1915 }
1916
1917 //
1918 // Set the hard error if necessary.
1919 //
1920
1921 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
1922
1923 //
1924 // Store DeviceObject for filesystem, and clear
1925 // in IoStatus.Information field.
1926 //
1927
1928 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
1929 Irp->IoStatus.Information = 0;
1930 }
1931
1932 //
1933 // If pending has be returned for this irp then mark the current stack as
1934 // pending.
1935 //
1936
1937 if (Irp->PendingReturned) {
1938 IoMarkIrpPending(Irp);
1939 }
1940
1941 if (deviceExtension->ClassStartIo) {
1942 if (irpStack->MajorFunction != IRP_MJ_DEVICE_CONTROL) {
1943 IoStartNextPacket(DeviceObject, FALSE);
1944 }
1945 }
1946
1947 return status;
1948
1949 } // end ScsiClassIoComplete()
1950
1951 \f
1952 NTSTATUS
1953 NTAPI
1954 ScsiClassIoCompleteAssociated(
1955 IN PDEVICE_OBJECT DeviceObject,
1956 IN PIRP Irp,
1957 IN PVOID Context
1958 )
1959
1960 /*++
1961
1962 Routine Description:
1963
1964 This routine executes when the port driver has completed a request.
1965 It looks at the SRB status in the completing SRB and if not success
1966 it checks for valid request sense buffer information. If valid, the
1967 info is used to update status with more precise message of type of
1968 error. This routine deallocates the SRB. This routine is used for
1969 requests which were build by split request. After it has processed
1970 the request it decrements the Irp count in the master Irp. If the
1971 count goes to zero then the master Irp is completed.
1972
1973 Arguments:
1974
1975 DeviceObject - Supplies the device object which represents the logical
1976 unit.
1977
1978 Irp - Supplies the Irp which has completed.
1979
1980 Context - Supplies a pointer to the SRB.
1981
1982 Return Value:
1983
1984 NT status
1985
1986 --*/
1987
1988 {
1989 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
1990 PSCSI_REQUEST_BLOCK srb = Context;
1991 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
1992 PIRP originalIrp = Irp->AssociatedIrp.MasterIrp;
1993 LONG irpCount;
1994 NTSTATUS status;
1995 BOOLEAN retry;
1996
1997 ASSERT(*(PULONG)deviceExtension != '2slc');
1998
1999 //
2000 // Check SRB status for success of completing request.
2001 //
2002
2003 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
2004
2005 DebugPrint((2,"ScsiClassIoCompleteAssociated: IRP %lx, SRB %lx", Irp, srb));
2006
2007 //
2008 // Release the queue if it is frozen.
2009 //
2010
2011 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
2012 ScsiClassReleaseQueue(DeviceObject);
2013 }
2014
2015 retry = ScsiClassInterpretSenseInfo(
2016 DeviceObject,
2017 srb,
2018 irpStack->MajorFunction,
2019 irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? irpStack->Parameters.DeviceIoControl.IoControlCode : 0,
2020 MAXIMUM_RETRIES - PtrToUlong(irpStack->Parameters.Others.Argument4),
2021 &status);
2022
2023 //
2024 // If the status is verified required and the this request
2025 // should bypass verify required then retry the request.
2026 //
2027
2028 if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME &&
2029 status == STATUS_VERIFY_REQUIRED) {
2030
2031 status = STATUS_IO_DEVICE_ERROR;
2032 retry = TRUE;
2033 }
2034
2035 if (retry && (irpStack->Parameters.Others.Argument4 = (PVOID)((ULONG_PTR)irpStack->Parameters.Others.Argument4-1))) {
2036
2037 //
2038 // Retry request. If the class driver has supplied a StartIo,
2039 // call it directly for retries.
2040 //
2041
2042 DebugPrint((1, "Retry request %lx\n", Irp));
2043
2044 /*
2045 if (!deviceExtension->ClassStartIo) {
2046 RetryRequest(DeviceObject, Irp, srb, TRUE);
2047 } else {
2048 deviceExtension->ClassStartIo(DeviceObject, Irp);
2049 }
2050 */
2051
2052 RetryRequest(DeviceObject, Irp, srb, TRUE);
2053
2054 return STATUS_MORE_PROCESSING_REQUIRED;
2055 }
2056
2057
2058
2059 } else {
2060
2061 //
2062 // Set status for successful request.
2063 //
2064
2065 status = STATUS_SUCCESS;
2066
2067 } // end if (SRB_STATUS(srb->SrbStatus) ...
2068
2069 //
2070 // Return SRB to list.
2071 //
2072
2073 ExFreeToNPagedLookasideList(&deviceExtension->SrbLookasideListHead,
2074 srb);
2075
2076 //
2077 // Set status in completing IRP.
2078 //
2079
2080 Irp->IoStatus.Status = status;
2081
2082 DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial xfer IRP %lx\n", Irp));
2083
2084 //
2085 // Get next stack location. This original request is unused
2086 // except to keep track of the completing partial IRPs so the
2087 // stack location is valid.
2088 //
2089
2090 irpStack = IoGetNextIrpStackLocation(originalIrp);
2091
2092 //
2093 // Update status only if error so that if any partial transfer
2094 // completes with error, then the original IRP will return with
2095 // error. If any of the asynchronous partial transfer IRPs fail,
2096 // with an error then the original IRP will return 0 bytes transfered.
2097 // This is an optimization for successful transfers.
2098 //
2099
2100 if (!NT_SUCCESS(status)) {
2101
2102 originalIrp->IoStatus.Status = status;
2103 originalIrp->IoStatus.Information = 0;
2104
2105 //
2106 // Set the hard error if necessary.
2107 //
2108
2109 if (IoIsErrorUserInduced(status)) {
2110
2111 //
2112 // Store DeviceObject for filesystem.
2113 //
2114
2115 IoSetHardErrorOrVerifyDevice(originalIrp, DeviceObject);
2116 }
2117 }
2118
2119 //
2120 // Decrement and get the count of remaining IRPs.
2121 //
2122
2123 irpCount = InterlockedDecrement((PLONG)&irpStack->Parameters.Others.Argument1);
2124
2125 DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial IRPs left %d\n",
2126 irpCount));
2127
2128 //
2129 // Old bug could cause irp count to negative
2130 //
2131
2132 ASSERT(irpCount >= 0);
2133
2134 if (irpCount == 0) {
2135
2136 //
2137 // All partial IRPs have completed.
2138 //
2139
2140 DebugPrint((2,
2141 "ScsiClassIoCompleteAssociated: All partial IRPs complete %lx\n",
2142 originalIrp));
2143
2144 IoCompleteRequest(originalIrp, IO_DISK_INCREMENT);
2145
2146 //
2147 // If the class driver has supplied a startio, start the
2148 // next request.
2149 //
2150
2151 if (deviceExtension->ClassStartIo) {
2152 IoStartNextPacket(DeviceObject, FALSE);
2153 }
2154 }
2155
2156 //
2157 // Deallocate IRP and indicate the I/O system should not attempt any more
2158 // processing.
2159 //
2160
2161 IoFreeIrp(Irp);
2162 return STATUS_MORE_PROCESSING_REQUIRED;
2163
2164 } // end ScsiClassIoCompleteAssociated()
2165
2166 \f
2167 NTSTATUS
2168 NTAPI
2169 ScsiClassSendSrbSynchronous(
2170 PDEVICE_OBJECT DeviceObject,
2171 PSCSI_REQUEST_BLOCK Srb,
2172 PVOID BufferAddress,
2173 ULONG BufferLength,
2174 BOOLEAN WriteToDevice
2175 )
2176
2177 /*++
2178
2179 Routine Description:
2180
2181 This routine is called by SCSI device controls to complete an
2182 SRB and send it to the port driver synchronously (ie wait for
2183 completion). The CDB is already completed along with the SRB CDB
2184 size and request timeout value.
2185
2186 Arguments:
2187
2188 DeviceObject - Supplies the device object which represents the logical
2189 unit.
2190
2191 Srb - Supplies a partially initialized SRB. The SRB cannot come from zone.
2192
2193 BufferAddress - Supplies the address of the buffer.
2194
2195 BufferLength - Supplies the length in bytes of the buffer.
2196
2197 WriteToDevice - Indicates the data should be transfer to the device.
2198
2199 Return Value:
2200
2201 Nt status indicating the final results of the operation.
2202
2203 --*/
2204
2205 {
2206 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2207 IO_STATUS_BLOCK ioStatus;
2208 ULONG controlType, mjFunction;
2209 PIRP irp;
2210 PIO_STACK_LOCATION irpStack;
2211 KEVENT event;
2212 PUCHAR senseInfoBuffer;
2213 ULONG retryCount = MAXIMUM_RETRIES;
2214 NTSTATUS status;
2215 BOOLEAN retry;
2216 LARGE_INTEGER dummy;
2217
2218 PAGED_CODE();
2219
2220 ASSERT(*(PULONG)deviceExtension != '2slc');
2221
2222 dummy.QuadPart = 0;
2223
2224 //
2225 // Write length to SRB.
2226 //
2227
2228 Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
2229
2230 //
2231 // Set SCSI bus address.
2232 //
2233
2234 Srb->PathId = deviceExtension->PathId;
2235 Srb->TargetId = deviceExtension->TargetId;
2236 Srb->Lun = deviceExtension->Lun;
2237 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
2238
2239 //
2240 // NOTICE: The SCSI-II specification indicates that this field should be
2241 // zero; however, some target controllers ignore the logical unit number
2242 // in the IDENTIFY message and only look at the logical unit number field
2243 // in the CDB.
2244 //
2245
2246 Srb->Cdb[1] |= deviceExtension->Lun << 5;
2247
2248 //
2249 // Enable auto request sense.
2250 //
2251
2252 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
2253
2254 //
2255 // Sense buffer is in aligned nonpaged pool.
2256 //
2257
2258 senseInfoBuffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
2259
2260 if (senseInfoBuffer == NULL) {
2261
2262 DebugPrint((1,
2263 "ScsiClassSendSrbSynchronous: Can't allocate request sense buffer\n"));
2264 return(STATUS_INSUFFICIENT_RESOURCES);
2265 }
2266
2267 Srb->SenseInfoBuffer = senseInfoBuffer;
2268 Srb->DataBuffer = BufferAddress;
2269
2270 //
2271 // Start retries here.
2272 //
2273
2274 retry:
2275
2276 //
2277 // Set the event object to the unsignaled state.
2278 // It will be used to signal request completion.
2279 //
2280
2281 KeInitializeEvent(&event, NotificationEvent, FALSE);
2282
2283 //
2284 // Set controlType and Srb direction flags.
2285 //
2286
2287 if (BufferAddress != NULL) {
2288
2289 if (WriteToDevice) {
2290
2291 controlType = IOCTL_SCSI_EXECUTE_OUT;
2292 Srb->SrbFlags = SRB_FLAGS_DATA_OUT;
2293 mjFunction = IRP_MJ_WRITE;
2294
2295 } else {
2296
2297 controlType = IOCTL_SCSI_EXECUTE_IN;
2298 Srb->SrbFlags = SRB_FLAGS_DATA_IN;
2299 mjFunction = IRP_MJ_READ;
2300 }
2301
2302 } else {
2303
2304 BufferLength = 0;
2305 controlType = IOCTL_SCSI_EXECUTE_NONE;
2306 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
2307 mjFunction = IRP_MJ_FLUSH_BUFFERS;
2308 }
2309
2310 //
2311 // Build device I/O control request with data transfer.
2312 //
2313 irp = IoBuildAsynchronousFsdRequest(
2314 mjFunction,
2315 deviceExtension->DeviceObject,
2316 BufferAddress,
2317 (BufferAddress) ? BufferLength : 0,
2318 &dummy,
2319 &ioStatus);
2320
2321 if (irp == NULL) {
2322 ExFreePool(senseInfoBuffer);
2323 DebugPrint((1, "ScsiClassSendSrbSynchronous: Can't allocate Irp\n"));
2324 return(STATUS_INSUFFICIENT_RESOURCES);
2325 }
2326
2327 // Set event field
2328 irp->UserEvent = &event;
2329
2330 //
2331 // Disable synchronous transfer for these requests.
2332 //
2333
2334 Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
2335
2336 //
2337 // Set the transfer length.
2338 //
2339
2340 Srb->DataTransferLength = BufferLength;
2341
2342 //
2343 // Zero out status.
2344 //
2345
2346 Srb->ScsiStatus = Srb->SrbStatus = 0;
2347 Srb->NextSrb = 0;
2348
2349 // Set completion routine
2350 IoSetCompletionRoutine(
2351 irp,
2352 ClassCompletionRoutine,
2353 NULL,
2354 TRUE,
2355 TRUE,
2356 TRUE);
2357
2358 //
2359 // Get next stack location.
2360 //
2361
2362 irpStack = IoGetNextIrpStackLocation(irp);
2363
2364 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
2365 irpStack->Parameters.DeviceIoControl.IoControlCode = controlType;
2366
2367 //
2368 // Set up SRB for execute scsi request. Save SRB address in next stack
2369 // for the port driver.
2370 //
2371
2372 irpStack->Parameters.Scsi.Srb = Srb;
2373
2374 //
2375 // Set up IRP Address.
2376 //
2377
2378 Srb->OriginalRequest = irp;
2379
2380 //
2381 // Call the port driver with the request and wait for it to complete.
2382 //
2383
2384 status = IoCallDriver(deviceExtension->PortDeviceObject, irp);
2385
2386 if (status == STATUS_PENDING) {
2387 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
2388 }
2389
2390 //
2391 // Check that request completed without error.
2392 //
2393
2394 if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) {
2395
2396 //
2397 // Release the queue if it is frozen.
2398 //
2399
2400 if (Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
2401 ScsiClassReleaseQueue(DeviceObject);
2402 }
2403
2404 //
2405 // Update status and determine if request should be retried.
2406 //
2407
2408 retry = ScsiClassInterpretSenseInfo(DeviceObject,
2409 Srb,
2410 IRP_MJ_SCSI,
2411 0,
2412 MAXIMUM_RETRIES - retryCount,
2413 &status);
2414
2415 if (retry) {
2416
2417 if ((status == STATUS_DEVICE_NOT_READY && ((PSENSE_DATA) senseInfoBuffer)
2418 ->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) ||
2419 SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT) {
2420
2421 LARGE_INTEGER delay;
2422
2423 //
2424 // Delay for 2 seconds.
2425 //
2426
2427 delay.QuadPart = (LONGLONG)( - 10 * 1000 * 1000 * 2 );
2428
2429 //
2430 // Stall for a while to let the controller spinup.
2431 //
2432
2433 KeDelayExecutionThread(KernelMode,
2434 FALSE,
2435 &delay);
2436
2437 }
2438
2439 //
2440 // If retries are not exhausted then retry this operation.
2441 //
2442
2443 if (retryCount--) {
2444 goto retry;
2445 }
2446 }
2447
2448 } else {
2449
2450 status = STATUS_SUCCESS;
2451 }
2452
2453 ExFreePool(senseInfoBuffer);
2454 return status;
2455
2456 } // end ScsiClassSendSrbSynchronous()
2457
2458 \f
2459 BOOLEAN
2460 NTAPI
2461 ScsiClassInterpretSenseInfo(
2462 IN PDEVICE_OBJECT DeviceObject,
2463 IN PSCSI_REQUEST_BLOCK Srb,
2464 IN UCHAR MajorFunctionCode,
2465 IN ULONG IoDeviceCode,
2466 IN ULONG RetryCount,
2467 OUT NTSTATUS *Status
2468 )
2469
2470 /*++
2471
2472 Routine Description:
2473
2474 This routine interprets the data returned from the SCSI
2475 request sense. It determines the status to return in the
2476 IRP and whether this request can be retried.
2477
2478 Arguments:
2479
2480 DeviceObject - Supplies the device object associated with this request.
2481
2482 Srb - Supplies the scsi request block which failed.
2483
2484 MajorFunctionCode - Supplies the function code to be used for logging.
2485
2486 IoDeviceCode - Supplies the device code to be used for logging.
2487
2488 Status - Returns the status for the request.
2489
2490 Return Value:
2491
2492 BOOLEAN TRUE: Drivers should retry this request.
2493 FALSE: Drivers should not retry this request.
2494
2495 --*/
2496
2497 {
2498 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
2499 PDEVICE_EXTENSION physicalExtension = deviceExtension->PhysicalDevice->DeviceExtension;
2500 PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
2501 BOOLEAN retry = TRUE;
2502 BOOLEAN logError = FALSE;
2503 ULONG badSector = 0;
2504 ULONG uniqueId = 0;
2505 NTSTATUS logStatus;
2506 ULONG readSector;
2507 ULONG index;
2508 PIO_ERROR_LOG_PACKET errorLogEntry;
2509 #if DBG
2510 ULONG i;
2511 #endif
2512
2513 ASSERT(*(PULONG)deviceExtension != '2slc');
2514
2515 //
2516 // Check that request sense buffer is valid.
2517 //
2518
2519 #if DBG
2520 DebugPrint((3, "Opcode %x\nParameters: ",Srb->Cdb[0]));
2521 for (i = 1; i < 12; i++) {
2522 DebugPrint((3,"%x ",Srb->Cdb[i]));
2523 }
2524 DebugPrint((3,"\n"));
2525 #endif
2526
2527 if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID &&
2528 Srb->SenseInfoBufferLength >= FIELD_OFFSET(SENSE_DATA, CommandSpecificInformation)) {
2529
2530 DebugPrint((1,"ScsiClassInterpretSenseInfo: Error code is %x\n",
2531 senseBuffer->ErrorCode));
2532 DebugPrint((1,"ScsiClassInterpretSenseInfo: Sense key is %x\n",
2533 senseBuffer->SenseKey));
2534 DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code is %x\n",
2535 senseBuffer->AdditionalSenseCode));
2536 DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code qualifier is %x\n",
2537 senseBuffer->AdditionalSenseCodeQualifier));
2538
2539 //
2540 // Zero the additional sense code and additional sense code qualifier
2541 // if they were not returned by the device.
2542 //
2543
2544 readSector = senseBuffer->AdditionalSenseLength +
2545 FIELD_OFFSET(SENSE_DATA, AdditionalSenseLength);
2546
2547 if (readSector > Srb->SenseInfoBufferLength) {
2548 readSector = Srb->SenseInfoBufferLength;
2549 }
2550
2551 if (readSector <= FIELD_OFFSET(SENSE_DATA, AdditionalSenseCode)) {
2552 senseBuffer->AdditionalSenseCode = 0;
2553 }
2554
2555 if (readSector <= FIELD_OFFSET(SENSE_DATA, AdditionalSenseCodeQualifier)) {
2556 senseBuffer->AdditionalSenseCodeQualifier = 0;
2557 }
2558
2559 switch (senseBuffer->SenseKey & 0xf) {
2560
2561 case SCSI_SENSE_NOT_READY:
2562
2563 DebugPrint((1,"ScsiClassInterpretSenseInfo: Device not ready\n"));
2564 *Status = STATUS_DEVICE_NOT_READY;
2565
2566 switch (senseBuffer->AdditionalSenseCode) {
2567
2568 case SCSI_ADSENSE_LUN_NOT_READY:
2569
2570 DebugPrint((1,"ScsiClassInterpretSenseInfo: Lun not ready\n"));
2571
2572 switch (senseBuffer->AdditionalSenseCodeQualifier) {
2573
2574 case SCSI_SENSEQ_BECOMING_READY:
2575
2576 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2577 " In process of becoming ready\n"));
2578 break;
2579
2580 case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED:
2581
2582 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2583 " Manual intervention required\n"));
2584 *Status = STATUS_NO_MEDIA_IN_DEVICE;
2585 retry = FALSE;
2586 break;
2587
2588 case SCSI_SENSEQ_FORMAT_IN_PROGRESS:
2589
2590 DebugPrint((1, "ScsiClassInterpretSenseInfo: Format in progress\n"));
2591 retry = FALSE;
2592 break;
2593
2594 case SCSI_SENSEQ_INIT_COMMAND_REQUIRED:
2595
2596 default:
2597
2598 DebugPrint((1, "ScsiClassInterpretSenseInfo:"
2599 " Initializing command required\n"));
2600
2601 //
2602 // This sense code/additional sense code
2603 // combination may indicate that the device
2604 // needs to be started. Send an start unit if this
2605 // is a disk device.
2606 //
2607
2608 if (deviceExtension->DeviceFlags & DEV_SAFE_START_UNIT) {
2609 StartUnit(DeviceObject);
2610 }
2611
2612 break;
2613
2614 } // end switch (senseBuffer->AdditionalSenseCodeQualifier)
2615
2616 break;
2617
2618 case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE:
2619
2620 DebugPrint((1,
2621 "ScsiClassInterpretSenseInfo:"
2622 " No Media in device.\n"));
2623 *Status = STATUS_NO_MEDIA_IN_DEVICE;
2624 retry = FALSE;
2625
2626 //
2627 // signal autorun that there isn't any media in the device
2628 //
2629
2630 if((deviceExtension->MediaChangeEvent != NULL)&&
2631 (!deviceExtension->MediaChangeNoMedia)) {
2632 KeSetEvent(deviceExtension->MediaChangeEvent,
2633 (KPRIORITY) 0,
2634 FALSE);
2635 DebugPrint((0, "ScsiClassInterpretSenseInfo:"
2636 "Detected No Media In Device "
2637 "[irp = 0x%lx]\n", Srb->OriginalRequest));
2638 deviceExtension->MediaChangeNoMedia = TRUE;
2639 }
2640
2641 break;
2642 } // end switch (senseBuffer->AdditionalSenseCode)
2643
2644 break;
2645
2646 case SCSI_SENSE_DATA_PROTECT:
2647
2648 DebugPrint((1, "ScsiClassInterpretSenseInfo: Media write protected\n"));
2649 *Status = STATUS_MEDIA_WRITE_PROTECTED;
2650 retry = FALSE;
2651 break;
2652
2653 case SCSI_SENSE_MEDIUM_ERROR:
2654
2655 DebugPrint((1,"ScsiClassInterpretSenseInfo: Bad media\n"));
2656 *Status = STATUS_DEVICE_DATA_ERROR;
2657
2658 retry = FALSE;
2659 logError = TRUE;
2660 uniqueId = 256;
2661 logStatus = 0;//IO_ERR_BAD_BLOCK;
2662 break;
2663
2664 case SCSI_SENSE_HARDWARE_ERROR:
2665
2666 DebugPrint((1,"ScsiClassInterpretSenseInfo: Hardware error\n"));
2667 *Status = STATUS_IO_DEVICE_ERROR;
2668
2669 logError = TRUE;
2670 uniqueId = 257;
2671 logStatus = 0;//IO_ERR_CONTROLLER_ERROR;
2672
2673 break;
2674
2675 case SCSI_SENSE_ILLEGAL_REQUEST:
2676
2677 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal SCSI request\n"));
2678 *Status = STATUS_INVALID_DEVICE_REQUEST;
2679
2680 switch (senseBuffer->AdditionalSenseCode) {
2681
2682 case SCSI_ADSENSE_ILLEGAL_COMMAND:
2683 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal command\n"));
2684 retry = FALSE;
2685 break;
2686
2687 case SCSI_ADSENSE_ILLEGAL_BLOCK:
2688 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal block address\n"));
2689 *Status = STATUS_NONEXISTENT_SECTOR;
2690 retry = FALSE;
2691 break;
2692
2693 case SCSI_ADSENSE_INVALID_LUN:
2694 DebugPrint((1,"ScsiClassInterpretSenseInfo: Invalid LUN\n"));
2695 *Status = STATUS_NO_SUCH_DEVICE;
2696 retry = FALSE;
2697 break;
2698
2699 case SCSI_ADSENSE_MUSIC_AREA:
2700 DebugPrint((1,"ScsiClassInterpretSenseInfo: Music area\n"));
2701 retry = FALSE;
2702 break;
2703
2704 case SCSI_ADSENSE_DATA_AREA:
2705 DebugPrint((1,"ScsiClassInterpretSenseInfo: Data area\n"));
2706 retry = FALSE;
2707 break;
2708
2709 case SCSI_ADSENSE_VOLUME_OVERFLOW:
2710 DebugPrint((1, "ScsiClassInterpretSenseInfo: Volume overflow\n"));
2711 retry = FALSE;
2712 break;
2713
2714 case SCSI_ADSENSE_INVALID_CDB:
2715 DebugPrint((1, "ScsiClassInterpretSenseInfo: Invalid CDB\n"));
2716
2717 //
2718 // Check if write cache enabled.
2719 //
2720
2721 if (deviceExtension->DeviceFlags & DEV_WRITE_CACHE) {
2722
2723 //
2724 // Assume FUA is not supported.
2725 //
2726
2727 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
2728 retry = TRUE;
2729
2730 } else {
2731 retry = FALSE;
2732 }
2733
2734 break;
2735
2736 } // end switch (senseBuffer->AdditionalSenseCode)
2737
2738 break;
2739
2740 case SCSI_SENSE_UNIT_ATTENTION:
2741
2742 switch (senseBuffer->AdditionalSenseCode) {
2743 case SCSI_ADSENSE_MEDIUM_CHANGED:
2744 DebugPrint((1, "ScsiClassInterpretSenseInfo: Media changed\n"));
2745
2746 if(deviceExtension->MediaChangeEvent != NULL) {
2747
2748 KeSetEvent(deviceExtension->MediaChangeEvent,
2749 (KPRIORITY) 0,
2750 FALSE);
2751 DebugPrint((0, "ScsiClassInterpretSenseInfo:"
2752 "New Media Found - Setting MediaChanged event"
2753 " [irp = 0x%lx]\n", Srb->OriginalRequest));
2754 deviceExtension->MediaChangeNoMedia = FALSE;
2755
2756 }
2757 break;
2758
2759 case SCSI_ADSENSE_BUS_RESET:
2760 DebugPrint((1,"ScsiClassInterpretSenseInfo: Bus reset\n"));
2761 break;
2762
2763 default:
2764 DebugPrint((1,"ScsiClassInterpretSenseInfo: Unit attention\n"));
2765 break;
2766
2767 } // end switch (senseBuffer->AdditionalSenseCode)
2768
2769 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA &&
2770 DeviceObject->Vpb->Flags & VPB_MOUNTED) {
2771
2772 //
2773 // Set bit to indicate that media may have changed
2774 // and volume needs verification.
2775 //
2776
2777 DeviceObject->Flags |= DO_VERIFY_VOLUME;
2778
2779 *Status = STATUS_VERIFY_REQUIRED;
2780 retry = FALSE;
2781
2782 } else {
2783
2784 *Status = STATUS_IO_DEVICE_ERROR;
2785
2786 }
2787
2788 //
2789 // A media change may have occured so increment the change
2790 // count for the physical device
2791 //
2792
2793 physicalExtension->MediaChangeCount++;
2794
2795 DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change "
2796 "count for device %d is %d\n",
2797 physicalExtension->DeviceNumber,
2798 physicalExtension->MediaChangeCount));
2799
2800 break;
2801
2802 case SCSI_SENSE_ABORTED_COMMAND:
2803
2804 DebugPrint((1,"ScsiClassInterpretSenseInfo: Command aborted\n"));
2805 *Status = STATUS_IO_DEVICE_ERROR;
2806 break;
2807
2808 case SCSI_SENSE_RECOVERED_ERROR:
2809
2810 DebugPrint((1,"ScsiClassInterpretSenseInfo: Recovered error\n"));
2811 *Status = STATUS_SUCCESS;
2812 retry = FALSE;
2813 logError = TRUE;
2814 uniqueId = 258;
2815
2816 switch(senseBuffer->AdditionalSenseCode) {
2817 case SCSI_ADSENSE_SEEK_ERROR:
2818 case SCSI_ADSENSE_TRACK_ERROR:
2819 logStatus = 0;//IO_ERR_SEEK_ERROR;
2820 break;
2821
2822 case SCSI_ADSENSE_REC_DATA_NOECC:
2823 case SCSI_ADSENSE_REC_DATA_ECC:
2824 logStatus = 0;//IO_RECOVERED_VIA_ECC;
2825 break;
2826
2827 default:
2828 logStatus = 0;//IO_ERR_CONTROLLER_ERROR;
2829 break;
2830
2831 } // end switch(senseBuffer->AdditionalSenseCode)
2832
2833 if (senseBuffer->IncorrectLength) {
2834
2835 DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
2836 *Status = STATUS_INVALID_BLOCK_LENGTH ;
2837 }
2838
2839 break;
2840
2841 case SCSI_SENSE_NO_SENSE:
2842
2843 //
2844 // Check other indicators.
2845 //
2846
2847 if (senseBuffer->IncorrectLength) {
2848
2849 DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n"));
2850 *Status = STATUS_INVALID_BLOCK_LENGTH ;
2851 retry = FALSE;
2852
2853 } else {
2854
2855 DebugPrint((1, "ScsiClassInterpretSenseInfo: No specific sense key\n"));
2856 *Status = STATUS_IO_DEVICE_ERROR;
2857 retry = TRUE;
2858 }
2859
2860 break;
2861
2862 default:
2863
2864 DebugPrint((1, "ScsiClassInterpretSenseInfo: Unrecognized sense code\n"));
2865 *Status = STATUS_IO_DEVICE_ERROR;
2866 break;
2867
2868 } // end switch (senseBuffer->SenseKey & 0xf)
2869
2870 //
2871 // Try to determine the bad sector from the inquiry data.
2872 //
2873
2874 if ((((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_READ ||
2875 ((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_VERIFY ||
2876 ((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_WRITE)) {
2877
2878 for (index = 0; index < 4; index++) {
2879 badSector = (badSector << 8) | senseBuffer->Information[index];
2880 }
2881
2882 readSector = 0;
2883 for (index = 0; index < 4; index++) {
2884 readSector = (readSector << 8) | Srb->Cdb[index+2];
2885 }
2886
2887 index = (((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb << 8) |
2888 ((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb;
2889
2890 //
2891 // Make sure the bad sector is within the read sectors.
2892 //
2893
2894 if (!(badSector >= readSector && badSector < readSector + index)) {
2895 badSector = readSector;
2896 }
2897 }
2898
2899 } else {
2900
2901 //
2902 // Request sense buffer not valid. No sense information
2903 // to pinpoint the error. Return general request fail.
2904 //
2905
2906 DebugPrint((1,"ScsiClassInterpretSenseInfo: Request sense info not valid. SrbStatus %2x\n",
2907 SRB_STATUS(Srb->SrbStatus)));
2908 retry = TRUE;
2909
2910 switch (SRB_STATUS(Srb->SrbStatus)) {
2911 case SRB_STATUS_INVALID_LUN:
2912 case SRB_STATUS_INVALID_TARGET_ID:
2913 case SRB_STATUS_NO_DEVICE:
2914 case SRB_STATUS_NO_HBA:
2915 case SRB_STATUS_INVALID_PATH_ID:
2916 *Status = STATUS_NO_SUCH_DEVICE;
2917 retry = FALSE;
2918 break;
2919
2920 case SRB_STATUS_COMMAND_TIMEOUT:
2921 case SRB_STATUS_ABORTED:
2922 case SRB_STATUS_TIMEOUT:
2923
2924 //
2925 // Update the error count for the device.
2926 //
2927
2928 deviceExtension->ErrorCount++;
2929 *Status = STATUS_IO_TIMEOUT;
2930 break;
2931
2932 case SRB_STATUS_SELECTION_TIMEOUT:
2933 logError = TRUE;
2934 logStatus = 0;//IO_ERR_NOT_READY;
2935 uniqueId = 260;
2936 *Status = STATUS_DEVICE_NOT_CONNECTED;
2937 retry = FALSE;
2938 break;
2939
2940 case SRB_STATUS_DATA_OVERRUN:
2941 *Status = STATUS_DATA_OVERRUN;
2942 retry = FALSE;
2943 break;
2944
2945 case SRB_STATUS_PHASE_SEQUENCE_FAILURE:
2946
2947 //
2948 // Update the error count for the device.
2949 //
2950
2951 deviceExtension->ErrorCount++;
2952 *Status = STATUS_IO_DEVICE_ERROR;
2953
2954 //
2955 // If there was phase sequence error then limit the number of
2956 // retries.
2957 //
2958
2959 if (RetryCount > 1 ) {
2960 retry = FALSE;
2961 }
2962
2963 break;
2964
2965 case SRB_STATUS_REQUEST_FLUSHED:
2966
2967 //
2968 // If the status needs verification bit is set. Then set
2969 // the status to need verification and no retry; otherwise,
2970 // just retry the request.
2971 //
2972
2973 if (DeviceObject->Flags & DO_VERIFY_VOLUME ) {
2974
2975 *Status = STATUS_VERIFY_REQUIRED;
2976 retry = FALSE;
2977 } else {
2978 *Status = STATUS_IO_DEVICE_ERROR;
2979 }
2980
2981 break;
2982
2983 case SRB_STATUS_INVALID_REQUEST:
2984
2985 //
2986 // An invalid request was attempted.
2987 //
2988
2989 *Status = STATUS_INVALID_DEVICE_REQUEST;
2990 retry = FALSE;
2991 break;
2992
2993 case SRB_STATUS_UNEXPECTED_BUS_FREE:
2994 case SRB_STATUS_PARITY_ERROR:
2995
2996 //
2997 // Update the error count for the device.
2998 //
2999
3000 deviceExtension->ErrorCount++;
3001
3002 //
3003 // Fall through to below.
3004 //
3005
3006 case SRB_STATUS_BUS_RESET:
3007 *Status = STATUS_IO_DEVICE_ERROR;
3008 break;
3009
3010 case SRB_STATUS_ERROR:
3011
3012 *Status = STATUS_IO_DEVICE_ERROR;
3013 if (Srb->ScsiStatus == 0) {
3014
3015 //
3016 // This is some strange return code. Update the error
3017 // count for the device.
3018 //
3019
3020 deviceExtension->ErrorCount++;
3021
3022 } if (Srb->ScsiStatus == SCSISTAT_BUSY) {
3023
3024 *Status = STATUS_DEVICE_NOT_READY;
3025
3026 } if (Srb->ScsiStatus == SCSISTAT_RESERVATION_CONFLICT) {
3027
3028 *Status = STATUS_DEVICE_BUSY;
3029 retry = FALSE;
3030
3031 }
3032
3033 break;
3034
3035 default:
3036 logError = TRUE;
3037 logStatus = 0;//IO_ERR_CONTROLLER_ERROR;
3038 uniqueId = 259;
3039 *Status = STATUS_IO_DEVICE_ERROR;
3040 break;
3041
3042 }
3043
3044 //
3045 // If the error count has exceeded the error limit, then disable
3046 // any tagged queuing, multiple requests per lu queueing
3047 // and synchronous data transfers.
3048 //
3049
3050 if (deviceExtension->ErrorCount == 4) {
3051
3052 //
3053 // Clearing the no queue freeze flag prevents the port driver
3054 // from sending multiple requests per logical unit.
3055 //
3056
3057 deviceExtension->SrbFlags &= ~(SRB_FLAGS_QUEUE_ACTION_ENABLE |
3058 SRB_FLAGS_NO_QUEUE_FREEZE);
3059
3060 deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
3061 DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling tagged queuing and synchronous data tranfers.\n"));
3062
3063 } else if (deviceExtension->ErrorCount == 8) {
3064
3065 //
3066 // If a second threshold is reached, disable disconnects.
3067 //
3068
3069 deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT;
3070 DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling disconnects.\n"));
3071 }
3072 }
3073
3074 //
3075 // If there is a class specific error handler call it.
3076 //
3077
3078 if (deviceExtension->ClassError != NULL) {
3079
3080 deviceExtension->ClassError(DeviceObject,
3081 Srb,
3082 Status,
3083 &retry);
3084 }
3085
3086 //
3087 // Log an error if necessary.
3088 //
3089
3090 if (logError) {
3091
3092 errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
3093 DeviceObject,
3094 sizeof(IO_ERROR_LOG_PACKET) + 5 * sizeof(ULONG));
3095
3096 if (errorLogEntry == NULL) {
3097
3098 //
3099 // Return if no packet could be allocated.
3100 //
3101
3102 return retry;
3103
3104 }
3105
3106 if (retry && RetryCount < MAXIMUM_RETRIES) {
3107 errorLogEntry->FinalStatus = STATUS_SUCCESS;
3108 } else {
3109 errorLogEntry->FinalStatus = *Status;
3110 }
3111
3112 //
3113 // Calculate the device offset if there is a geometry.
3114 //
3115
3116 if (deviceExtension->DiskGeometry != NULL) {
3117
3118 errorLogEntry->DeviceOffset.QuadPart = (LONGLONG) badSector;
3119 errorLogEntry->DeviceOffset = RtlExtendedIntegerMultiply(
3120 errorLogEntry->DeviceOffset,
3121 deviceExtension->DiskGeometry->Geometry.BytesPerSector);
3122 }
3123
3124 errorLogEntry->ErrorCode = logStatus;
3125 errorLogEntry->SequenceNumber = 0;
3126 errorLogEntry->MajorFunctionCode = MajorFunctionCode;
3127 errorLogEntry->IoControlCode = IoDeviceCode;
3128 errorLogEntry->RetryCount = (UCHAR) RetryCount;
3129 errorLogEntry->UniqueErrorValue = uniqueId;
3130 errorLogEntry->DumpDataSize = 6 * sizeof(ULONG);
3131 errorLogEntry->DumpData[0] = Srb->PathId;
3132 errorLogEntry->DumpData[1] = Srb->TargetId;
3133 errorLogEntry->DumpData[2] = Srb->Lun;
3134 errorLogEntry->DumpData[3] = 0;
3135 errorLogEntry->DumpData[4] = Srb->SrbStatus << 8 | Srb->ScsiStatus;
3136
3137 if (senseBuffer != NULL) {
3138 errorLogEntry->DumpData[5] = senseBuffer->SenseKey << 16 |
3139 senseBuffer->AdditionalSenseCode << 8 |
3140 senseBuffer->AdditionalSenseCodeQualifier;
3141
3142 }
3143
3144 //
3145 // Write the error log packet.
3146 //
3147
3148 IoWriteErrorLogEntry(errorLogEntry);
3149 }
3150
3151 return retry;
3152
3153 } // end ScsiClassInterpretSenseInfo()
3154
3155 \f
3156 VOID
3157 NTAPI
3158 RetryRequest(
3159 PDEVICE_OBJECT DeviceObject,
3160 PIRP Irp,
3161 PSCSI_REQUEST_BLOCK Srb,
3162 BOOLEAN Associated
3163 )
3164
3165 /*++
3166
3167 Routine Description:
3168
3169 This routine reinitializes the necessary fields, and sends the request
3170 to the port driver.
3171
3172 Arguments:
3173
3174 DeviceObject - Supplies the device object associated with this request.
3175
3176 Irp - Supplies the request to be retried.
3177
3178 Srb - Supplies a Pointer to the SCSI request block to be retied.
3179
3180 Associated - Indicates this is an associated Irp created by split request.
3181
3182 Return Value:
3183
3184 None
3185
3186 --*/
3187
3188 {
3189 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3190 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
3191 PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
3192 ULONG transferByteCount;
3193
3194 ASSERT(*(PULONG)deviceExtension != '2slc');
3195
3196 //
3197 // Determine the transfer count of the request. If this is a read or a
3198 // write then the transfer count is in the Irp stack. Otherwise assume
3199 // the MDL contains the correct length. If there is no MDL then the
3200 // transfer length must be zero.
3201 //
3202
3203 if (currentIrpStack->MajorFunction == IRP_MJ_READ ||
3204 currentIrpStack->MajorFunction == IRP_MJ_WRITE) {
3205
3206 transferByteCount = currentIrpStack->Parameters.Read.Length;
3207
3208 } else if (Irp->MdlAddress != NULL) {
3209
3210 //
3211 // Note this assumes that only read and write requests are spilt and
3212 // other request do not need to be. If the data buffer address in
3213 // the MDL and the SRB don't match then transfer length is most
3214 // likely incorrect.
3215 //
3216
3217 ASSERT(Srb->DataBuffer == MmGetMdlVirtualAddress(Irp->MdlAddress));
3218 transferByteCount = Irp->MdlAddress->ByteCount;
3219
3220 } else {
3221
3222 transferByteCount = 0;
3223 }
3224
3225 //
3226 // Reset byte count of transfer in SRB Extension.
3227 //
3228
3229 Srb->DataTransferLength = transferByteCount;
3230
3231 //
3232 // Zero SRB statuses.
3233 //
3234
3235 Srb->SrbStatus = Srb->ScsiStatus = 0;
3236
3237 //
3238 // Set the no disconnect flag, disable synchronous data transfers and
3239 // disable tagged queuing. This fixes some errors.
3240 //
3241
3242 Srb->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT |
3243 SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
3244
3245 Srb->SrbFlags &= ~SRB_FLAGS_QUEUE_ACTION_ENABLE;
3246 Srb->QueueTag = SP_UNTAGGED;
3247
3248 //
3249 // Set up major SCSI function.
3250 //
3251
3252 nextIrpStack->MajorFunction = IRP_MJ_SCSI;
3253
3254 //
3255 // Save SRB address in next stack for port driver.
3256 //
3257
3258 nextIrpStack->Parameters.Scsi.Srb = Srb;
3259
3260 //
3261 // Set up IoCompletion routine address.
3262 //
3263
3264 if (Associated) {
3265
3266 IoSetCompletionRoutine(Irp, ScsiClassIoCompleteAssociated, Srb, TRUE, TRUE, TRUE);
3267
3268 } else {
3269
3270 IoSetCompletionRoutine(Irp, ScsiClassIoComplete, Srb, TRUE, TRUE, TRUE);
3271 }
3272
3273 //
3274 // Pass the request to the port driver.
3275 //
3276
3277 (VOID)IoCallDriver(deviceExtension->PortDeviceObject, Irp);
3278
3279 } // end RetryRequest()
3280 \f
3281 VOID
3282 NTAPI
3283 ScsiClassBuildRequest(
3284 PDEVICE_OBJECT DeviceObject,
3285 PIRP Irp
3286 )
3287
3288 /*++
3289
3290 Routine Description:
3291
3292 This routine allocates and builds an Srb for a read or write request.
3293 The block address and length are supplied by the Irp. The retry count
3294 is stored in the current stack for use by ScsiClassIoComplete which
3295 processes these requests when they complete. The Irp is ready to be
3296 passed to the port driver when this routine returns.
3297
3298 Arguments:
3299
3300 DeviceObject - Supplies the device object associated with this request.
3301
3302 Irp - Supplies the request to be retried.
3303
3304 Note:
3305
3306 If the IRP is for a disk transfer, the byteoffset field
3307 will already have been adjusted to make it relative to
3308 the beginning of the disk.
3309
3310
3311 Return Value:
3312
3313 None.
3314
3315 --*/
3316
3317 {
3318 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3319 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
3320 PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
3321 LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
3322 PSCSI_REQUEST_BLOCK srb;
3323 PCDB cdb;
3324 ULONG logicalBlockAddress;
3325 USHORT transferBlocks;
3326
3327 ASSERT(*(PULONG)deviceExtension != '2slc');
3328
3329 //
3330 // Calculate relative sector address.
3331 //
3332
3333 logicalBlockAddress = (ULONG)(Int64ShrlMod32(startingOffset.QuadPart, deviceExtension->SectorShift));
3334
3335 //
3336 // Allocate an Srb.
3337 //
3338
3339 srb = ExAllocateFromNPagedLookasideList(&deviceExtension->SrbLookasideListHead);
3340
3341 srb->SrbFlags = 0;
3342
3343 //
3344 // Write length to SRB.
3345 //
3346
3347 srb->Length = SCSI_REQUEST_BLOCK_SIZE;
3348
3349 //
3350 // Set up IRP Address.
3351 //
3352
3353 srb->OriginalRequest = Irp;
3354
3355 //
3356 // Set up target ID and logical unit number.
3357 //
3358
3359 srb->PathId = deviceExtension->PathId;
3360 srb->TargetId = deviceExtension->TargetId;
3361 srb->Lun = deviceExtension->Lun;
3362 srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
3363 srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
3364
3365 //
3366 // Save byte count of transfer in SRB Extension.
3367 //
3368
3369 srb->DataTransferLength = currentIrpStack->Parameters.Read.Length;
3370
3371 //
3372 // Initialize the queue actions field.
3373 //
3374
3375 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
3376
3377 //
3378 // Queue sort key is Relative Block Address.
3379 //
3380
3381 srb->QueueSortKey = logicalBlockAddress;
3382
3383 //
3384 // Indicate auto request sense by specifying buffer and size.
3385 //
3386
3387 srb->SenseInfoBuffer = deviceExtension->SenseData;
3388 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
3389
3390 //
3391 // Set timeout value of one unit per 64k bytes of data.
3392 //
3393
3394 srb->TimeOutValue = ((srb->DataTransferLength + 0xFFFF) >> 16) *
3395 deviceExtension->TimeOutValue;
3396
3397 //
3398 // Zero statuses.
3399 //
3400
3401 srb->SrbStatus = srb->ScsiStatus = 0;
3402 srb->NextSrb = 0;
3403
3404 //
3405 // Indicate that 10-byte CDB's will be used.
3406 //
3407
3408 srb->CdbLength = 10;
3409
3410 //
3411 // Fill in CDB fields.
3412 //
3413
3414 cdb = (PCDB)srb->Cdb;
3415
3416 //
3417 // Zero 12 bytes for Atapi Packets
3418 //
3419
3420 RtlZeroMemory(cdb, MAXIMUM_CDB_SIZE);
3421
3422 cdb->CDB10.LogicalUnitNumber = deviceExtension->Lun;
3423 transferBlocks = (USHORT)(currentIrpStack->Parameters.Read.Length >> deviceExtension->SectorShift);
3424
3425 //
3426 // Move little endian values into CDB in big endian format.
3427 //
3428
3429 cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte3;
3430 cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte2;
3431 cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte1;
3432 cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte0;
3433
3434 cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&transferBlocks)->Byte1;
3435 cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&transferBlocks)->Byte0;
3436
3437 //
3438 // Set transfer direction flag and Cdb command.
3439 //
3440
3441 if (currentIrpStack->MajorFunction == IRP_MJ_READ) {
3442
3443 DebugPrint((3, "ScsiClassBuildRequest: Read Command\n"));
3444
3445 srb->SrbFlags |= SRB_FLAGS_DATA_IN;
3446 cdb->CDB10.OperationCode = SCSIOP_READ;
3447
3448 } else {
3449
3450 DebugPrint((3, "ScsiClassBuildRequest: Write Command\n"));
3451
3452 srb->SrbFlags |= SRB_FLAGS_DATA_OUT;
3453 cdb->CDB10.OperationCode = SCSIOP_WRITE;
3454 }
3455
3456 //
3457 // If this is not a write-through request, then allow caching.
3458 //
3459
3460 if (!(currentIrpStack->Flags & SL_WRITE_THROUGH)) {
3461
3462 srb->SrbFlags |= SRB_FLAGS_ADAPTER_CACHE_ENABLE;
3463
3464 } else {
3465
3466 //
3467 // If write caching is enable then force media access in the
3468 // cdb.
3469 //
3470
3471 if (deviceExtension->DeviceFlags & DEV_WRITE_CACHE) {
3472 cdb->CDB10.ForceUnitAccess = TRUE;
3473 }
3474 }
3475
3476 //
3477 // Or in the default flags from the device object.
3478 //
3479
3480 srb->SrbFlags |= deviceExtension->SrbFlags;
3481
3482 //
3483 // Set up major SCSI function.
3484 //
3485
3486 nextIrpStack->MajorFunction = IRP_MJ_SCSI;
3487
3488 //
3489 // Save SRB address in next stack for port driver.
3490 //
3491
3492 nextIrpStack->Parameters.Scsi.Srb = srb;
3493
3494 //
3495 // Save retry count in current IRP stack.
3496 //
3497
3498 currentIrpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
3499
3500 //
3501 // Set up IoCompletion routine address.
3502 //
3503
3504 IoSetCompletionRoutine(Irp, ScsiClassIoComplete, srb, TRUE, TRUE, TRUE);
3505
3506 return;
3507
3508 } // end ScsiClassBuildRequest()
3509 \f
3510 ULONG
3511 NTAPI
3512 ScsiClassModeSense(
3513 IN PDEVICE_OBJECT DeviceObject,
3514 IN PCHAR ModeSenseBuffer,
3515 IN ULONG Length,
3516 IN UCHAR PageMode
3517 )
3518
3519 /*++
3520
3521 Routine Description:
3522
3523 This routine sends a mode sense command to a target ID and returns
3524 when it is complete.
3525
3526 Arguments:
3527
3528 DeviceObject - Supplies the device object associated with this request.
3529
3530 ModeSenseBuffer - Supplies a buffer to store the sense data.
3531
3532 Length - Supplies the length in bytes of the mode sense buffer.
3533
3534 PageMode - Supplies the page or pages of mode sense data to be retrieved.
3535
3536 Return Value:
3537
3538 Length of the transferred data is returned.
3539
3540 --*/
3541 {
3542 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3543 PCDB cdb;
3544 SCSI_REQUEST_BLOCK srb;
3545 ULONG retries = 1;
3546 NTSTATUS status;
3547
3548 ASSERT(*(PULONG)deviceExtension != '2slc');
3549
3550 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
3551
3552 //
3553 // Build the MODE SENSE CDB.
3554 //
3555
3556 srb.CdbLength = 6;
3557 cdb = (PCDB)srb.Cdb;
3558
3559 //
3560 // Set timeout value from device extension.
3561 //
3562
3563 srb.TimeOutValue = deviceExtension->TimeOutValue;
3564
3565 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
3566 cdb->MODE_SENSE.PageCode = PageMode;
3567 cdb->MODE_SENSE.AllocationLength = (UCHAR)Length;
3568
3569 Retry:
3570
3571 status = ScsiClassSendSrbSynchronous(DeviceObject,
3572 &srb,
3573 ModeSenseBuffer,
3574 Length,
3575 FALSE);
3576
3577
3578 if (status == STATUS_VERIFY_REQUIRED) {
3579
3580 //
3581 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
3582 // this status. MODE SENSE commands should be retried anyway.
3583 //
3584
3585 if (retries--) {
3586
3587 //
3588 // Retry request.
3589 //
3590
3591 goto Retry;
3592 }
3593
3594 } else if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
3595 status = STATUS_SUCCESS;
3596 }
3597
3598 if (NT_SUCCESS(status)) {
3599 return(srb.DataTransferLength);
3600 } else {
3601 return(0);
3602 }
3603
3604 } // end ScsiClassModeSense()
3605
3606 \f
3607 PVOID
3608 NTAPI
3609 ScsiClassFindModePage(
3610 IN PCHAR ModeSenseBuffer,
3611 IN ULONG Length,
3612 IN UCHAR PageMode,
3613 IN BOOLEAN Use6Byte
3614 )
3615
3616 /*++
3617
3618 Routine Description:
3619
3620 This routine scans through the mode sense data and finds the requested
3621 mode sense page code.
3622
3623 Arguments:
3624 ModeSenseBuffer - Supplies a pointer to the mode sense data.
3625
3626 Length - Indicates the length of valid data.
3627
3628 PageMode - Supplies the page mode to be searched for.
3629
3630 Use6Byte - Indicates whether 6 or 10 byte mode sense was used.
3631
3632 Return Value:
3633
3634 A pointer to the the requested mode page. If the mode page was not found
3635 then NULL is return.
3636
3637 --*/
3638 {
3639 PUCHAR limit;
3640 ULONG parameterHeaderLength;
3641
3642 limit = (PUCHAR)ModeSenseBuffer + Length;
3643 parameterHeaderLength = (Use6Byte) ? sizeof(MODE_PARAMETER_HEADER) : sizeof(MODE_PARAMETER_HEADER10);
3644
3645
3646 //
3647 // Skip the mode select header and block descriptors.
3648 //
3649
3650 if (Length < parameterHeaderLength) {
3651 return(NULL);
3652 }
3653
3654
3655
3656 ModeSenseBuffer += parameterHeaderLength + ((Use6Byte) ? ((PMODE_PARAMETER_HEADER) ModeSenseBuffer)->BlockDescriptorLength :
3657 ((PMODE_PARAMETER_HEADER10) ModeSenseBuffer)->BlockDescriptorLength[1]);
3658
3659 //
3660 // ModeSenseBuffer now points at pages. Walk the pages looking for the
3661 // requested page until the limit is reached.
3662 //
3663
3664
3665 while ((PUCHAR)ModeSenseBuffer < limit) {
3666
3667 if (((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageCode == PageMode) {
3668 return(ModeSenseBuffer);
3669 }
3670
3671 //
3672 // Advance to the next page.
3673 //
3674
3675 ModeSenseBuffer += ((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageLength + 2;
3676 }
3677
3678 return(NULL);
3679 }
3680 \f
3681 NTSTATUS
3682 NTAPI
3683 ScsiClassSendSrbAsynchronous(
3684 PDEVICE_OBJECT DeviceObject,
3685 PSCSI_REQUEST_BLOCK Srb,
3686 PIRP Irp,
3687 PVOID BufferAddress,
3688 ULONG BufferLength,
3689 BOOLEAN WriteToDevice
3690 )
3691 /*++
3692
3693 Routine Description:
3694
3695 This routine takes a partially built Srb and an Irp and sends it down to
3696 the port driver.
3697
3698 Arguments:
3699 DeviceObject - Supplies the device object for the original request.
3700
3701 Srb - Supplies a partially built ScsiRequestBlock. In particular, the
3702 CDB and the SRB timeout value must be filled in. The SRB must not be
3703 allocated from zone.
3704
3705 Irp - Supplies the requesting Irp.
3706
3707 BufferAddress - Supplies a pointer to the buffer to be transfered.
3708
3709 BufferLength - Supplies the length of data transfer.
3710
3711 WriteToDevice - Indicates the data transfer will be from system memory to
3712 device.
3713
3714 Return Value:
3715
3716 Returns STATUS_INSUFFICIENT_RESOURCES or the status of IoCallDriver.
3717
3718 --*/
3719 {
3720
3721 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3722 PIO_STACK_LOCATION irpStack;
3723
3724 PAGED_CODE();
3725
3726 ASSERT(*(PULONG)deviceExtension != '2slc');
3727
3728 //
3729 // Write length to SRB.
3730 //
3731
3732 Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
3733
3734 //
3735 // Set SCSI bus address.
3736 //
3737
3738 Srb->PathId = deviceExtension->PathId;
3739 Srb->TargetId = deviceExtension->TargetId;
3740 Srb->Lun = deviceExtension->Lun;
3741
3742 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
3743
3744 //
3745 // This is a violation of the SCSI spec but it is required for
3746 // some targets.
3747 //
3748
3749 Srb->Cdb[1] |= deviceExtension->Lun << 5;
3750
3751 //
3752 // Indicate auto request sense by specifying buffer and size.
3753 //
3754
3755 Srb->SenseInfoBuffer = deviceExtension->SenseData;
3756 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
3757 Srb->DataBuffer = BufferAddress;
3758
3759 if (BufferAddress != NULL) {
3760
3761 //
3762 // Build Mdl if necessary.
3763 //
3764
3765 if (Irp->MdlAddress == NULL) {
3766
3767 if (IoAllocateMdl(BufferAddress,
3768 BufferLength,
3769 FALSE,
3770 FALSE,
3771 Irp) == NULL) {
3772
3773 return(STATUS_INSUFFICIENT_RESOURCES);
3774 }
3775
3776 MmBuildMdlForNonPagedPool(Irp->MdlAddress);
3777
3778 } else {
3779
3780 //
3781 // Make sure the buffer requested matches the MDL.
3782 //
3783
3784 ASSERT(BufferAddress == MmGetMdlVirtualAddress(Irp->MdlAddress));
3785 }
3786
3787 //
3788 // Set read flag.
3789 //
3790
3791 Srb->SrbFlags = WriteToDevice ? SRB_FLAGS_DATA_OUT : SRB_FLAGS_DATA_IN;
3792
3793 } else {
3794
3795 //
3796 // Clear flags.
3797 //
3798
3799 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
3800 }
3801
3802 //
3803 // Disable synchronous transfer for these requests.
3804 //
3805
3806 Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
3807
3808 //
3809 // Set the transfer length.
3810 //
3811
3812 Srb->DataTransferLength = BufferLength;
3813
3814 //
3815 // Zero out status.
3816 //
3817
3818 Srb->ScsiStatus = Srb->SrbStatus = 0;
3819
3820 Srb->NextSrb = 0;
3821
3822 //
3823 // Save a few parameters in the current stack location.
3824 //
3825
3826 irpStack = IoGetCurrentIrpStackLocation(Irp);
3827
3828 //
3829 // Save retry count in current Irp stack.
3830 //
3831
3832 irpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
3833
3834 //
3835 // Set up IoCompletion routine address.
3836 //
3837
3838 IoSetCompletionRoutine(Irp, ScsiClassIoComplete, Srb, TRUE, TRUE, TRUE);
3839
3840 //
3841 // Get next stack location and
3842 // set major function code.
3843 //
3844
3845 irpStack = IoGetNextIrpStackLocation(Irp);
3846
3847 irpStack->MajorFunction = IRP_MJ_SCSI;
3848
3849 //
3850 // Save SRB address in next stack for port driver.
3851 //
3852
3853 irpStack->Parameters.Scsi.Srb = Srb;
3854
3855 //
3856 // Set up Irp Address.
3857 //
3858
3859 Srb->OriginalRequest = Irp;
3860
3861 //
3862 // Call the port driver to process the request.
3863 //
3864
3865 return(IoCallDriver(deviceExtension->PortDeviceObject, Irp));
3866
3867 }
3868
3869 \f
3870 NTSTATUS
3871 NTAPI
3872 ScsiClassDeviceControlDispatch(
3873 PDEVICE_OBJECT DeviceObject,
3874 PIRP Irp
3875 )
3876
3877 /*++
3878
3879 Routine Description:
3880
3881 The routine is the common class driver device control dispatch entry point.
3882 This routine is invokes the device-specific drivers DeviceControl routine,
3883 (which may call the Class driver's common DeviceControl routine).
3884
3885 Arguments:
3886
3887 DeviceObject - Supplies a pointer to the device object for this request.
3888
3889 Irp - Supplies the Irp making the request.
3890
3891 Return Value:
3892
3893 Returns the status returned from the device-specific driver.
3894
3895 --*/
3896
3897 {
3898
3899 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3900
3901 ASSERT(*(PULONG)deviceExtension != '2slc');
3902
3903 //
3904 // Call the class specific driver DeviceControl routine.
3905 // If it doesn't handle it, it will call back into ScsiClassDeviceControl.
3906 //
3907
3908 ASSERT(deviceExtension->ClassDeviceControl);
3909
3910 return deviceExtension->ClassDeviceControl(DeviceObject,Irp);
3911 }
3912
3913 \f
3914 NTSTATUS
3915 NTAPI
3916 ScsiClassDeviceControl(
3917 PDEVICE_OBJECT DeviceObject,
3918 PIRP Irp
3919 )
3920 /*++
3921
3922 Routine Description:
3923
3924 The routine is the common class driver device control dispatch function.
3925 This routine is called by a class driver when it get an unrecognized
3926 device control request. This routine will perform the correct action for
3927 common requests such as lock media. If the device request is unknown it
3928 passed down to the next level.
3929
3930 Arguments:
3931
3932 DeviceObject - Supplies a pointer to the device object for this request.
3933
3934 Irp - Supplies the Irp making the request.
3935
3936 Return Value:
3937
3938 Returns back a STATUS_PENDING or a completion status.
3939
3940 --*/
3941
3942 {
3943 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
3944 PIO_STACK_LOCATION nextStack;
3945 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
3946 PSCSI_REQUEST_BLOCK srb;
3947 PCDB cdb;
3948 NTSTATUS status;
3949 ULONG modifiedIoControlCode;
3950
3951 ASSERT(*(PULONG)deviceExtension != '2slc');
3952
3953 if (irpStack->Parameters.DeviceIoControl.IoControlCode ==
3954 IOCTL_STORAGE_RESET_DEVICE) {
3955
3956 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
3957 IoCompleteRequest(Irp, IO_NO_INCREMENT);
3958 status = STATUS_UNSUCCESSFUL;
3959 goto SetStatusAndReturn;
3960 }
3961
3962 //
3963 // If this is a pass through I/O control, set the minor function code
3964 // and device address and pass it to the port driver.
3965 //
3966
3967 if (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH
3968 || irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT) {
3969
3970 PSCSI_PASS_THROUGH scsiPass;
3971
3972 nextStack = IoGetNextIrpStackLocation(Irp);
3973
3974 //
3975 // Validate the user buffer.
3976 //
3977
3978 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH)){
3979
3980 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
3981 IoCompleteRequest(Irp, IO_NO_INCREMENT);
3982 status = STATUS_INVALID_PARAMETER;
3983 goto SetStatusAndReturn;
3984 }
3985
3986 //
3987 // Force the SCSI address to the correct value.
3988 //
3989
3990 scsiPass = Irp->AssociatedIrp.SystemBuffer;
3991 scsiPass->PathId = deviceExtension->PathId;
3992 scsiPass->TargetId = deviceExtension->TargetId;
3993 scsiPass->Lun = deviceExtension->Lun;
3994
3995 //
3996 // NOTICE: The SCSI-II specification indicates that this field
3997 // should be zero; however, some target controllers ignore the logical
3998 // unit number in the IDENTIFY message and only look at the logical
3999 // unit number field in the CDB.
4000 //
4001
4002 scsiPass->Cdb[1