remove whitespace from end of lines
[reactos.git] / reactos / drivers / storage / class2 / class2.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: services/storage/class2/class2.c
24 * PURPOSE: SCSI class driver
25 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
26 */
27
28 /*
29 * TODO:
30 * - finish ScsiClassDeviceControl().
31 */
32
33 /* INCLUDES *****************************************************************/
34
35 #include <ddk/ntddk.h>
36 #include <ddk/scsi.h>
37 #include <ddk/class2.h>
38
39 #define NDEBUG
40 #include <debug.h>
41
42
43 #define VERSION "0.0.2"
44
45 #define TAG_SRBT TAG('S', 'r', 'b', 'T')
46
47 #define INQUIRY_DATA_SIZE 2048
48 #define START_UNIT_TIMEOUT 30
49 /*
50 * FIXME:
51 * Create a macro, which rounds up a size value to the next multiple of two.
52 */
53 #define SENSEINFO_ALIGNMENT 32
54
55 static NTSTATUS STDCALL
56 ScsiClassCreateClose(IN PDEVICE_OBJECT DeviceObject,
57 IN PIRP Irp);
58
59 static NTSTATUS STDCALL
60 ScsiClassReadWrite(IN PDEVICE_OBJECT DeviceObject,
61 IN PIRP Irp);
62
63 static NTSTATUS STDCALL
64 ScsiClassDeviceDispatch(IN PDEVICE_OBJECT DeviceObject,
65 IN PIRP Irp);
66
67 static NTSTATUS STDCALL
68 ScsiClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
69 IN PIRP Irp);
70
71 static VOID
72 ScsiClassRetryRequest (PDEVICE_OBJECT DeviceObject,
73 PIRP Irp,
74 PSCSI_REQUEST_BLOCK Srb,
75 BOOLEAN Associated);
76
77 static NTSTATUS STDCALL
78 ScsiClassCheckVerifyCompletion (IN PDEVICE_OBJECT DeviceObject,
79 IN PIRP Irp,
80 IN PVOID Context);
81
82 /* FUNCTIONS ****************************************************************/
83
84 /**********************************************************************
85 * NAME EXPORTED
86 * DriverEntry
87 *
88 * DESCRIPTION
89 * This function initializes the driver.
90 *
91 * RUN LEVEL
92 * PASSIVE_LEVEL
93 *
94 * ARGUMENTS
95 * DriverObject
96 * System allocated Driver Object for this driver.
97 * RegistryPath
98 * Name of registry driver service key.
99 *
100 * RETURNS
101 * Status
102 */
103
104 NTSTATUS STDCALL
105 DriverEntry(IN PDRIVER_OBJECT DriverObject,
106 IN PUNICODE_STRING RegistryPath)
107 {
108 DPRINT("Class Driver %s\n", VERSION);
109 return(STATUS_SUCCESS);
110 }
111
112
113 VOID
114 ScsiClassDebugPrint(IN ULONG DebugPrintLevel,
115 IN PCHAR DebugMessage,
116 ...)
117 {
118 char Buffer[256];
119 va_list ap;
120
121 #if 0
122 if (DebugPrintLevel > InternalDebugLevel)
123 return;
124 #endif
125
126 va_start(ap, DebugMessage);
127 vsprintf(Buffer, DebugMessage, ap);
128 va_end(ap);
129
130 DbgPrint(Buffer);
131 }
132
133
134 /*
135 * @implemented
136 */
137 NTSTATUS STDCALL
138 ScsiClassAsynchronousCompletion(IN PDEVICE_OBJECT DeviceObject,
139 IN PIRP Irp,
140 IN PVOID Context)
141 {
142 PCOMPLETION_CONTEXT CompletionContext;
143 PSCSI_REQUEST_BLOCK Srb;
144
145 CompletionContext = (PCOMPLETION_CONTEXT) Context;
146 Srb = &CompletionContext->Srb;
147
148 /* Release the queue if it is frozen */
149 if (Srb->Function == SRB_FUNCTION_EXECUTE_SCSI &&
150 Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN)
151 {
152 ScsiClassReleaseQueue (CompletionContext->DeviceObject);
153 }
154
155 /* Release the completion context and the IRP */
156 if (Irp->MdlAddress != NULL)
157 {
158 MmUnlockPages (Irp->MdlAddress);
159 IoFreeMdl (Irp->MdlAddress);
160 Irp->MdlAddress = NULL;
161 }
162 ExFreePool (CompletionContext);
163 IoFreeIrp (Irp);
164
165 return STATUS_MORE_PROCESSING_REQUIRED;
166 }
167
168
169 /*
170 * @implemented
171 */
172 VOID STDCALL
173 ScsiClassBuildRequest(IN PDEVICE_OBJECT DeviceObject,
174 IN PIRP Irp)
175 {
176 PDEVICE_EXTENSION DeviceExtension;
177 PIO_STACK_LOCATION CurrentIrpStack;
178 PIO_STACK_LOCATION NextIrpStack;
179 LARGE_INTEGER StartingOffset;
180 LARGE_INTEGER StartingBlock;
181 PSCSI_REQUEST_BLOCK Srb;
182 PCDB Cdb;
183 ULONG LogicalBlockAddress;
184 USHORT TransferBlocks;
185
186 DeviceExtension = DeviceObject->DeviceExtension;
187 CurrentIrpStack = IoGetCurrentIrpStackLocation(Irp);
188 NextIrpStack = IoGetNextIrpStackLocation(Irp);
189 StartingOffset = CurrentIrpStack->Parameters.Read.ByteOffset;
190
191 /* Calculate logical block address */
192 StartingBlock.QuadPart = StartingOffset.QuadPart >> DeviceExtension->SectorShift;
193 LogicalBlockAddress = (ULONG)StartingBlock.u.LowPart;
194
195 DPRINT("Logical block address: %lu\n", LogicalBlockAddress);
196
197 /* Allocate and initialize an SRB */
198 Srb = ExAllocateFromNPagedLookasideList(&DeviceExtension->SrbLookasideListHead);
199
200 Srb->SrbFlags = 0;
201 Srb->Length = sizeof(SCSI_REQUEST_BLOCK); //SCSI_REQUEST_BLOCK_SIZE;
202 Srb->OriginalRequest = Irp;
203 Srb->PathId = DeviceExtension->PathId;
204 Srb->TargetId = DeviceExtension->TargetId;
205 Srb->Lun = DeviceExtension->Lun;
206 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
207 //FIXME: NT4 DDK sample uses MmGetMdlVirtualAddress! Why shouldn't we?
208 Srb->DataBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
209 Srb->DataTransferLength = CurrentIrpStack->Parameters.Read.Length;
210 Srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
211 Srb->QueueSortKey = LogicalBlockAddress;
212
213 Srb->SenseInfoBuffer = (SENSE_DATA*)ROUND_UP((ULONG_PTR)(Srb + 1), SENSEINFO_ALIGNMENT);
214 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
215
216 Srb->TimeOutValue =
217 ((Srb->DataTransferLength + 0xFFFF) >> 16) * DeviceExtension->TimeOutValue;
218
219 Srb->SrbStatus = SRB_STATUS_SUCCESS;
220 Srb->ScsiStatus = 0;
221 Srb->NextSrb = 0;
222
223 Srb->CdbLength = 10;
224 Cdb = (PCDB)Srb->Cdb;
225
226 /* Initialize ATAPI packet (12 bytes) */
227 RtlZeroMemory(Cdb,
228 MAXIMUM_CDB_SIZE);
229
230 Cdb->CDB10.LogicalUnitNumber = DeviceExtension->Lun;
231 TransferBlocks = (USHORT)(CurrentIrpStack->Parameters.Read.Length >> DeviceExtension->SectorShift);
232
233 /* Copy little endian values into CDB in big endian format */
234 Cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte3;
235 Cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte2;
236 Cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte1;
237 Cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte0;
238
239 Cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&TransferBlocks)->Byte1;
240 Cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&TransferBlocks)->Byte0;
241
242
243 if (CurrentIrpStack->MajorFunction == IRP_MJ_READ)
244 {
245 DPRINT("ScsiClassBuildRequest: Read Command\n");
246
247 Srb->SrbFlags |= SRB_FLAGS_DATA_IN;
248 Cdb->CDB10.OperationCode = SCSIOP_READ;
249 }
250 else
251 {
252 DPRINT("ScsiClassBuildRequest: Write Command\n");
253
254 Srb->SrbFlags |= SRB_FLAGS_DATA_OUT;
255 Cdb->CDB10.OperationCode = SCSIOP_WRITE;
256 }
257
258 #if 0
259 /* if this is not a write-through request, then allow caching */
260 if (!(CurrentIrpStack->Flags & SL_WRITE_THROUGH))
261 {
262 Srb->SrbFlags |= SRB_FLAGS_ADAPTER_CACHE_ENABLE;
263 }
264 else if (DeviceExtension->DeviceFlags & DEV_WRITE_CACHE)
265 {
266 /* if write caching is enable then force media access in the cdb */
267 Cdb->CDB10.ForceUnitAccess = TRUE;
268 }
269 #endif
270
271 /* Update srb flags */
272 Srb->SrbFlags |= DeviceExtension->SrbFlags;
273
274 /* Initialize next stack location */
275 NextIrpStack->MajorFunction = IRP_MJ_SCSI;
276 NextIrpStack->Parameters.Scsi.Srb = Srb;
277
278 /* Set retry count */
279 CurrentIrpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
280
281 DPRINT("IoSetCompletionRoutine (Irp %p Srb %p)\n", Irp, Srb);
282 IoSetCompletionRoutine(Irp,
283 ScsiClassIoComplete,
284 Srb,
285 TRUE,
286 TRUE,
287 TRUE);
288 }
289
290
291 /*
292 * @implemented
293 */
294 NTSTATUS STDCALL
295 ScsiClassClaimDevice(PDEVICE_OBJECT PortDeviceObject,
296 PSCSI_INQUIRY_DATA LunInfo,
297 BOOLEAN Release,
298 PDEVICE_OBJECT *NewPortDeviceObject OPTIONAL)
299 {
300 PIO_STACK_LOCATION IoStack;
301 IO_STATUS_BLOCK IoStatusBlock;
302 SCSI_REQUEST_BLOCK Srb;
303 KEVENT Event;
304 PIRP Irp;
305 NTSTATUS Status;
306
307 DPRINT("ScsiClassClaimDevice() called\n");
308
309 if (NewPortDeviceObject != NULL)
310 *NewPortDeviceObject = NULL;
311
312 /* initialize an SRB */
313 RtlZeroMemory(&Srb,
314 sizeof(SCSI_REQUEST_BLOCK));
315 Srb.Length = SCSI_REQUEST_BLOCK_SIZE;
316 Srb.PathId = LunInfo->PathId;
317 Srb.TargetId = LunInfo->TargetId;
318 Srb.Lun = LunInfo->Lun;
319 Srb.Function =
320 (Release == TRUE) ? SRB_FUNCTION_RELEASE_DEVICE : SRB_FUNCTION_CLAIM_DEVICE;
321
322 KeInitializeEvent(&Event,
323 NotificationEvent,
324 FALSE);
325
326 Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE,
327 PortDeviceObject,
328 NULL,
329 0,
330 NULL,
331 0,
332 TRUE,
333 &Event,
334 &IoStatusBlock);
335 if (Irp == NULL)
336 {
337 DPRINT("Failed to allocate Irp!\n");
338 return(STATUS_INSUFFICIENT_RESOURCES);
339 }
340
341 /* Link Srb and Irp */
342 IoStack = IoGetNextIrpStackLocation(Irp);
343 IoStack->Parameters.Scsi.Srb = &Srb;
344 Srb.OriginalRequest = Irp;
345
346 /* Call SCSI port driver */
347 Status = IoCallDriver(PortDeviceObject,
348 Irp);
349 if (Status == STATUS_PENDING)
350 {
351 KeWaitForSingleObject(&Event,
352 Suspended,
353 KernelMode,
354 FALSE,
355 NULL);
356 Status = IoStatusBlock.Status;
357 }
358
359 if (Release == TRUE)
360 {
361 ObDereferenceObject(PortDeviceObject);
362 return(STATUS_SUCCESS);
363 }
364
365 // Status = ObReferenceObjectByPointer(Srb.DataBuffer,
366 Status = ObReferenceObjectByPointer(PortDeviceObject,
367 0,
368 NULL,
369 KernelMode);
370
371 if (NewPortDeviceObject != NULL)
372 {
373 // *NewPortDeviceObject = Srb.DataBuffer;
374 *NewPortDeviceObject = PortDeviceObject;
375 }
376
377 return(STATUS_SUCCESS);
378 }
379
380
381 /*
382 * @implemented
383 */
384 NTSTATUS STDCALL
385 ScsiClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
386 IN PCCHAR ObjectNameBuffer,
387 IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL,
388 IN OUT PDEVICE_OBJECT *DeviceObject,
389 IN PCLASS_INIT_DATA InitializationData)
390 {
391 PDEVICE_OBJECT InternalDeviceObject;
392 PDEVICE_EXTENSION DeviceExtension;
393 ANSI_STRING AnsiName;
394 UNICODE_STRING DeviceName;
395 NTSTATUS Status;
396
397 DPRINT("ScsiClassCreateDeviceObject() called\n");
398
399 *DeviceObject = NULL;
400
401 RtlInitAnsiString(&AnsiName,
402 ObjectNameBuffer);
403
404 Status = RtlAnsiStringToUnicodeString(&DeviceName,
405 &AnsiName,
406 TRUE);
407 if (!NT_SUCCESS(Status))
408 {
409 return(Status);
410 }
411
412 DPRINT("Device name: '%wZ'\n", &DeviceName);
413
414 Status = IoCreateDevice(DriverObject,
415 InitializationData->DeviceExtensionSize,
416 &DeviceName,
417 InitializationData->DeviceType,
418 InitializationData->DeviceCharacteristics,
419 FALSE,
420 &InternalDeviceObject);
421 if (NT_SUCCESS(Status))
422 {
423 DeviceExtension = InternalDeviceObject->DeviceExtension;
424
425 DeviceExtension->ClassError = InitializationData->ClassError;
426 DeviceExtension->ClassReadWriteVerification = InitializationData->ClassReadWriteVerification;
427 DeviceExtension->ClassFindDevices = InitializationData->ClassFindDevices;
428 DeviceExtension->ClassDeviceControl = InitializationData->ClassDeviceControl;
429 DeviceExtension->ClassShutdownFlush = InitializationData->ClassShutdownFlush;
430 DeviceExtension->ClassCreateClose = InitializationData->ClassCreateClose;
431 DeviceExtension->ClassStartIo = InitializationData->ClassStartIo;
432
433 DeviceExtension->MediaChangeCount = 0;
434
435 if (PhysicalDeviceObject != NULL)
436 {
437 DeviceExtension->PhysicalDevice = PhysicalDeviceObject;
438 }
439 else
440 {
441 DeviceExtension->PhysicalDevice = InternalDeviceObject;
442 }
443
444 *DeviceObject = InternalDeviceObject;
445 }
446
447 RtlFreeUnicodeString(&DeviceName);
448
449 return(Status);
450 }
451
452
453 /*
454 * @implemented
455 */
456 NTSTATUS STDCALL
457 ScsiClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
458 IN PIRP Irp)
459 {
460 PDEVICE_EXTENSION DeviceExtension;
461 PIO_STACK_LOCATION NextStack;
462 PIO_STACK_LOCATION Stack;
463 ULONG IoControlCode;
464 ULONG InputBufferLength;
465 ULONG OutputBufferLength;
466 ULONG ModifiedControlCode;
467 PSCSI_REQUEST_BLOCK Srb;
468 PCDB Cdb;
469 PIRP SubIrp;
470
471 DPRINT("ScsiClassDeviceControl() called\n");
472
473 DeviceExtension = DeviceObject->DeviceExtension;
474 Stack = IoGetCurrentIrpStackLocation(Irp);
475
476 IoControlCode = Stack->Parameters.DeviceIoControl.IoControlCode;
477 InputBufferLength = Stack->Parameters.DeviceIoControl.InputBufferLength;
478 OutputBufferLength = Stack->Parameters.DeviceIoControl.OutputBufferLength;
479
480 if (IoControlCode == IOCTL_SCSI_GET_DUMP_POINTERS)
481 {
482 PDUMP_POINTERS DumpPointers;
483
484 if (OutputBufferLength < sizeof(DUMP_POINTERS))
485 {
486 Irp->IoStatus.Information = 0;
487 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
488 IoCompleteRequest(Irp, IO_NO_INCREMENT);
489
490 return(STATUS_BUFFER_TOO_SMALL);
491 }
492 DumpPointers = (PDUMP_POINTERS)Irp->AssociatedIrp.SystemBuffer;
493
494 /* Initialize next stack location for call to the port driver */
495 NextStack = IoGetNextIrpStackLocation(Irp);
496
497 NextStack->Parameters = Stack->Parameters;
498 NextStack->MajorFunction = Stack->MajorFunction;
499 NextStack->MinorFunction = Stack->MinorFunction;
500
501 /* Call port driver */
502 return(IoCallDriver(DeviceExtension->PortDeviceObject,
503 Irp));
504 }
505 if (IoControlCode == IOCTL_SCSI_GET_ADDRESS)
506 {
507 PSCSI_ADDRESS ScsiAddress;
508
509 if (OutputBufferLength < sizeof(SCSI_ADDRESS))
510 {
511 Irp->IoStatus.Information = 0;
512 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
513 IoCompleteRequest(Irp, IO_NO_INCREMENT);
514
515 return(STATUS_BUFFER_TOO_SMALL);
516 }
517
518 ScsiAddress = Irp->AssociatedIrp.SystemBuffer;
519 ScsiAddress->Length = sizeof(SCSI_ADDRESS);
520 ScsiAddress->PortNumber = DeviceExtension->PortNumber;
521 ScsiAddress->PathId = DeviceExtension->PathId;
522 ScsiAddress->TargetId = DeviceExtension->TargetId;
523 ScsiAddress->Lun = DeviceExtension->Lun;
524
525 Irp->IoStatus.Information = sizeof(SCSI_ADDRESS);
526 Irp->IoStatus.Status = STATUS_SUCCESS;
527 IoCompleteRequest(Irp, IO_NO_INCREMENT);
528
529 return(STATUS_SUCCESS);
530 }
531
532 if (IoControlCode == IOCTL_SCSI_PASS_THROUGH ||
533 IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT)
534 {
535 PSCSI_PASS_THROUGH ScsiPassThrough;
536
537 DPRINT("IOCTL_SCSI_PASS_THROUGH/IOCTL_SCSI_PASS_THROUGH_DIRECT\n");
538
539 /* Check input size */
540 if (InputBufferLength < sizeof(SCSI_PASS_THROUGH))
541 {
542 Irp->IoStatus.Information = 0;
543 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
544 IoCompleteRequest(Irp, IO_NO_INCREMENT);
545 return(STATUS_INVALID_PARAMETER);
546 }
547
548 /* Initialize next stack location for call to the port driver */
549 NextStack = IoGetNextIrpStackLocation(Irp);
550
551 ScsiPassThrough = Irp->AssociatedIrp.SystemBuffer;
552 ScsiPassThrough->PathId = DeviceExtension->PathId;
553 ScsiPassThrough->TargetId = DeviceExtension->TargetId;
554 ScsiPassThrough->Lun = DeviceExtension->Lun;
555 ScsiPassThrough->Cdb[1] |= DeviceExtension->Lun << 5;
556
557 NextStack->Parameters = Stack->Parameters;
558 NextStack->MajorFunction = Stack->MajorFunction;
559 NextStack->MinorFunction = Stack->MinorFunction;
560
561 /* Call port driver */
562 return(IoCallDriver(DeviceExtension->PortDeviceObject,
563 Irp));
564 }
565
566 /* Allocate and initialize an SRB */
567 Srb = ExAllocateFromNPagedLookasideList(&DeviceExtension->SrbLookasideListHead);
568
569 if (Srb == NULL)
570 {
571 Irp->IoStatus.Information = 0;
572 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
573 IoCompleteRequest(Irp,
574 IO_NO_INCREMENT);
575 return(STATUS_INSUFFICIENT_RESOURCES);
576 }
577
578 /* Initialize the SRB */
579 RtlZeroMemory(Srb,
580 sizeof(SCSI_REQUEST_BLOCK));
581 Cdb = (PCDB)Srb->Cdb;
582
583 ModifiedControlCode = (IoControlCode & 0x0000FFFF) | (IOCTL_DISK_BASE << 16);
584 switch (ModifiedControlCode)
585 {
586 case IOCTL_DISK_CHECK_VERIFY:
587 DPRINT ("ScsiClassDeviceControl: IOCTL_DISK_CHECK_VERIFY\n");
588
589 if (OutputBufferLength != 0)
590 {
591 if (OutputBufferLength < sizeof(ULONG))
592 {
593 DPRINT ("ScsiClassDeviceControl: IOCTL_DISK_CHECK_VERIFY SMALL\n");
594 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
595 Irp->IoStatus.Information = 0;
596 /* Free the SRB */
597 ExFreeToNPagedLookasideList(&DeviceExtension->SrbLookasideListHead,
598 Srb);
599 IoCompleteRequest (Irp,
600 IO_NO_INCREMENT);
601 return STATUS_BUFFER_TOO_SMALL;
602 }
603
604 /* Allocate new IRP for TEST UNIT READY scsi command */
605 SubIrp = IoAllocateIrp ((CCHAR)DeviceObject->StackSize + 3,
606 FALSE);
607 if (SubIrp == NULL)
608 {
609 DPRINT ("ScsiClassDeviceControl: IOCTL_DISK_CHECK_VERIFY NotEnuf\n");
610 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
611 Irp->IoStatus.Information = 0;
612 /* Free the SRB */
613 ExFreeToNPagedLookasideList(&DeviceExtension->SrbLookasideListHead,
614 Srb);
615 IoCompleteRequest (Irp,
616 IO_NO_INCREMENT);
617 return STATUS_INSUFFICIENT_RESOURCES;
618 }
619
620 SubIrp->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread;
621 IoSetNextIrpStackLocation (SubIrp);
622
623 NextStack = IoGetCurrentIrpStackLocation (SubIrp);
624 NextStack->Parameters.Others.Argument1 = Irp;
625 NextStack->DeviceObject = DeviceObject;
626
627 IoSetCompletionRoutine (SubIrp,
628 ScsiClassCheckVerifyCompletion,
629 NULL,
630 TRUE,
631 TRUE,
632 TRUE);
633
634 DPRINT ("ScsiClassDeviceControl: IOCTL_DISK_CHECK_VERIFY IoSet\n");
635
636 IoSetNextIrpStackLocation (SubIrp);
637 NextStack = IoGetCurrentIrpStackLocation (SubIrp);
638 NextStack->DeviceObject = DeviceObject;
639
640 IoMarkIrpPending (Irp);
641
642 Irp = SubIrp;
643 }
644
645 /* Initialize SRB operation */
646 Srb->CdbLength = 6;
647 Srb->TimeOutValue = DeviceExtension->TimeOutValue;
648 Cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
649
650 DPRINT ("ScsiClassDeviceControl: IOCTL_DISK_CHECK_VERIFY SrbAsync\n");
651
652 return(ScsiClassSendSrbAsynchronous(DeviceObject,
653 Srb,
654 Irp,
655 NULL,
656 0,
657 FALSE));
658
659 default:
660 DPRINT("Unknown device io control code %lx\n",
661 ModifiedControlCode);
662 /* Free the SRB */
663 ExFreeToNPagedLookasideList(&DeviceExtension->SrbLookasideListHead,
664 Srb);
665 /* Pass the IOCTL down to the port driver */
666 NextStack = IoGetNextIrpStackLocation(Irp);
667 NextStack->Parameters = Stack->Parameters;
668 NextStack->MajorFunction = Stack->MajorFunction;
669 NextStack->MinorFunction = Stack->MinorFunction;
670
671 /* Call port driver */
672 return(IoCallDriver(DeviceExtension->PortDeviceObject,
673 Irp));
674 }
675
676 Irp->IoStatus.Information = 0;
677 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
678 IoCompleteRequest(Irp, IO_NO_INCREMENT);
679
680 return(STATUS_UNSUCCESSFUL);
681 }
682
683
684 /*
685 * @implemented
686 */
687 PVOID STDCALL
688 ScsiClassFindModePage(IN PCHAR ModeSenseBuffer,
689 IN ULONG Length,
690 IN UCHAR PageMode,
691 IN BOOLEAN Use6Byte)
692 {
693 ULONG DescriptorLength;
694 ULONG HeaderLength;
695 PCHAR End;
696 PCHAR Ptr;
697
698 DPRINT("ScsiClassFindModePage() called\n");
699
700 /* Get header length */
701 HeaderLength = (Use6Byte) ? sizeof(MODE_PARAMETER_HEADER) : sizeof(MODE_PARAMETER_HEADER10);
702
703 /* Check header length */
704 if (Length < HeaderLength)
705 return NULL;
706
707 /* Get descriptor length */
708 if (Use6Byte == TRUE)
709 {
710 DescriptorLength = ((PMODE_PARAMETER_HEADER)ModeSenseBuffer)->BlockDescriptorLength;
711 }
712 else
713 {
714 DescriptorLength = ((PMODE_PARAMETER_HEADER10)ModeSenseBuffer)->BlockDescriptorLength[1];
715 }
716
717 /* Set page pointers */
718 Ptr = ModeSenseBuffer + HeaderLength + DescriptorLength;
719 End = ModeSenseBuffer + Length;
720
721 /* Search for page */
722 while (Ptr < End)
723 {
724 /* Check page code */
725 if (((PMODE_DISCONNECT_PAGE)Ptr)->PageCode == PageMode)
726 return Ptr;
727
728 /* Skip to next page */
729 Ptr += ((PMODE_DISCONNECT_PAGE)Ptr)->PageLength;
730 }
731
732 return NULL;
733 }
734
735
736 /*
737 * @implemented
738 */
739 ULONG STDCALL
740 ScsiClassFindUnclaimedDevices(IN PCLASS_INIT_DATA InitializationData,
741 IN PSCSI_ADAPTER_BUS_INFO AdapterInformation)
742 {
743 PSCSI_INQUIRY_DATA UnitInfo;
744 PINQUIRYDATA InquiryData;
745 PUCHAR Buffer;
746 ULONG Bus;
747 ULONG UnclaimedDevices = 0;
748
749 DPRINT("ScsiClassFindUnclaimedDevices() called\n");
750
751 DPRINT("NumberOfBuses: %lu\n",AdapterInformation->NumberOfBuses);
752 Buffer = (PUCHAR)AdapterInformation;
753 for (Bus = 0; Bus < (ULONG)AdapterInformation->NumberOfBuses; Bus++)
754 {
755 DPRINT("Searching bus %lu\n", Bus);
756
757 UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + AdapterInformation->BusData[Bus].InquiryDataOffset);
758
759 while (AdapterInformation->BusData[Bus].InquiryDataOffset)
760 {
761 InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
762
763 DPRINT("Device: '%.8s'\n", InquiryData->VendorId);
764
765 if ((InitializationData->ClassFindDeviceCallBack(InquiryData) == TRUE) &&
766 (UnitInfo->DeviceClaimed == FALSE))
767 {
768 UnclaimedDevices++;
769 }
770
771 if (UnitInfo->NextInquiryDataOffset == 0)
772 break;
773
774 UnitInfo = (PSCSI_INQUIRY_DATA) (Buffer + UnitInfo->NextInquiryDataOffset);
775 }
776 }
777
778 return(UnclaimedDevices);
779 }
780
781
782 /*
783 * @implemented
784 */
785 NTSTATUS STDCALL
786 ScsiClassGetCapabilities(IN PDEVICE_OBJECT PortDeviceObject,
787 OUT PIO_SCSI_CAPABILITIES *PortCapabilities)
788 {
789 IO_STATUS_BLOCK IoStatusBlock;
790 NTSTATUS Status;
791 KEVENT Event;
792 PIRP Irp;
793
794 KeInitializeEvent(&Event,
795 NotificationEvent,
796 FALSE);
797
798 Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_CAPABILITIES,
799 PortDeviceObject,
800 NULL,
801 0,
802 PortCapabilities,
803 sizeof(PVOID),
804 FALSE,
805 &Event,
806 &IoStatusBlock);
807 if (Irp == NULL)
808 {
809 return(STATUS_INSUFFICIENT_RESOURCES);
810 }
811
812 Status = IoCallDriver(PortDeviceObject,
813 Irp);
814 if (Status == STATUS_PENDING)
815 {
816 KeWaitForSingleObject(&Event,
817 Suspended,
818 KernelMode,
819 FALSE,
820 NULL);
821 Status = IoStatusBlock.Status;
822 }
823
824 DPRINT("PortCapabilities at %p\n", *PortCapabilities);
825
826 return(Status);
827 }
828
829
830 /*
831 * @implemented
832 */
833 NTSTATUS STDCALL
834 ScsiClassGetInquiryData(IN PDEVICE_OBJECT PortDeviceObject,
835 IN PSCSI_ADAPTER_BUS_INFO *ConfigInfo)
836 {
837 PSCSI_ADAPTER_BUS_INFO Buffer;
838 IO_STATUS_BLOCK IoStatusBlock;
839 NTSTATUS Status;
840 KEVENT Event;
841 PIRP Irp;
842
843 DPRINT("ScsiClassGetInquiryData() called\n");
844
845 *ConfigInfo = NULL;
846 Buffer = ExAllocatePool(NonPagedPool,
847 INQUIRY_DATA_SIZE);
848 if (Buffer == NULL)
849 {
850 return(STATUS_INSUFFICIENT_RESOURCES);
851 }
852
853 KeInitializeEvent(&Event,
854 NotificationEvent,
855 FALSE);
856
857 Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA,
858 PortDeviceObject,
859 NULL,
860 0,
861 Buffer,
862 INQUIRY_DATA_SIZE,
863 FALSE,
864 &Event,
865 &IoStatusBlock);
866 if (Irp == NULL)
867 {
868 ExFreePool(Buffer);
869 return(STATUS_INSUFFICIENT_RESOURCES);
870 }
871
872 Status = IoCallDriver(PortDeviceObject,
873 Irp);
874 if (Status == STATUS_PENDING)
875 {
876 KeWaitForSingleObject(&Event,
877 Suspended,
878 KernelMode,
879 FALSE,
880 NULL);
881 Status = IoStatusBlock.Status;
882 }
883
884 if (!NT_SUCCESS(Status))
885 {
886 ExFreePool(Buffer);
887 }
888 else
889 {
890 *ConfigInfo = Buffer;
891 }
892
893 DPRINT("ScsiClassGetInquiryData() done\n");
894
895 return(Status);
896 }
897
898
899 /*
900 * @implemented
901 */
902 ULONG STDCALL
903 ScsiClassInitialize(IN PVOID Argument1,
904 IN PVOID Argument2,
905 IN PCLASS_INIT_DATA InitializationData)
906 {
907 PCONFIGURATION_INFORMATION ConfigInfo;
908 PDRIVER_OBJECT DriverObject = Argument1;
909 WCHAR NameBuffer[80];
910 UNICODE_STRING PortName;
911 ULONG PortNumber;
912 PDEVICE_OBJECT PortDeviceObject;
913 PFILE_OBJECT FileObject;
914 BOOLEAN DiskFound = FALSE;
915 NTSTATUS Status;
916
917 DPRINT("ScsiClassInitialize() called!\n");
918
919 DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiClassCreateClose;
920 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiClassCreateClose;
921 DriverObject->MajorFunction[IRP_MJ_READ] = ScsiClassReadWrite;
922 DriverObject->MajorFunction[IRP_MJ_WRITE] = ScsiClassReadWrite;
923 DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiClassInternalIoControl;
924 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiClassDeviceDispatch;
925 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = ScsiClassShutdownFlush;
926 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = ScsiClassShutdownFlush;
927 if (InitializationData->ClassStartIo)
928 {
929 DriverObject->DriverStartIo = InitializationData->ClassStartIo;
930 }
931
932 ConfigInfo = IoGetConfigurationInformation();
933
934 DPRINT("ScsiPorts: %lu\n", ConfigInfo->ScsiPortCount);
935
936 /* look for ScsiPortX scsi port devices */
937 for (PortNumber = 0; PortNumber < ConfigInfo->ScsiPortCount; PortNumber++)
938 {
939 swprintf(NameBuffer,
940 L"\\Device\\ScsiPort%lu",
941 PortNumber);
942 RtlInitUnicodeString(&PortName,
943 NameBuffer);
944 DPRINT("Checking scsi port %ld\n", PortNumber);
945 Status = IoGetDeviceObjectPointer(&PortName,
946 FILE_READ_ATTRIBUTES,
947 &FileObject,
948 &PortDeviceObject);
949 DPRINT("Status 0x%08lX\n", Status);
950 if (NT_SUCCESS(Status))
951 {
952 DPRINT("ScsiPort%lu found.\n", PortNumber);
953
954 /* check scsi port for attached disk drives */
955 if (InitializationData->ClassFindDevices(DriverObject,
956 Argument2,
957 InitializationData,
958 PortDeviceObject,
959 PortNumber))
960 {
961 DiskFound = TRUE;
962 }
963 }
964 else
965 {
966 DbgPrint("Couldn't find ScsiPort%lu (Status %lx)\n", PortNumber, Status);
967 }
968 }
969
970 DPRINT("ScsiClassInitialize() done!\n");
971
972 return((DiskFound == TRUE) ? STATUS_SUCCESS : STATUS_NO_SUCH_DEVICE);
973 }
974
975
976 /**********************************************************************
977 * NAME EXPORTED
978 * ScsiClassInitializeSrbLookasideList
979 *
980 * DESCRIPTION
981 * Initializes a lookaside list for SRBs.
982 *
983 * RUN LEVEL
984 * PASSIVE_LEVEL
985 *
986 * ARGUMENTS
987 * DeviceExtension
988 * Class specific device extension.
989 *
990 * NumberElements
991 * Maximum number of elements of the lookaside list.
992 *
993 * RETURN VALUE
994 * None.
995 *
996 * @implemented
997 */
998 VOID STDCALL
999 ScsiClassInitializeSrbLookasideList(IN PDEVICE_EXTENSION DeviceExtension,
1000 IN ULONG NumberElements)
1001 {
1002 ExInitializeNPagedLookasideList(&DeviceExtension->SrbLookasideListHead,
1003 NULL,
1004 NULL,
1005 NonPagedPool,
1006 sizeof(SCSI_REQUEST_BLOCK) + sizeof(SENSE_DATA) + SENSEINFO_ALIGNMENT - 1,
1007 TAG_SRBT,
1008 (USHORT)NumberElements);
1009 }
1010
1011
1012 /*
1013 * @unimplemented
1014 */
1015 NTSTATUS STDCALL
1016 ScsiClassInternalIoControl(IN PDEVICE_OBJECT DeviceObject,
1017 IN PIRP Irp)
1018 {
1019 DPRINT("ScsiClassInternalIoContol() called\n");
1020
1021 Irp->IoStatus.Status = STATUS_SUCCESS;
1022 Irp->IoStatus.Information = 0;
1023 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1024
1025 return(STATUS_SUCCESS);
1026 }
1027
1028
1029 /*
1030 * Implements part of the directives on:
1031 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/kmarch/hh/kmarch/other_c694d732-fa95-4841-8d61-2a55ee787905.xml.asp
1032 */
1033 static VOID
1034 ScsiClassInvalidateMedia(IN PDEVICE_OBJECT DeviceObject,
1035 OUT NTSTATUS *Status)
1036 {
1037 PDEVICE_EXTENSION DeviceExtension;
1038 PDEVICE_EXTENSION PhysicalExtension;
1039
1040 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1041 PhysicalExtension = (PDEVICE_EXTENSION)DeviceExtension->PhysicalDevice->DeviceExtension;
1042
1043 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
1044 {
1045 DPRINT("Invalidate: test char yields TRUE\n");
1046 }
1047 else
1048 {
1049 DPRINT("Invalidate: test char yields FALSE\n");
1050 }
1051
1052 if ((DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) &&
1053 (DeviceObject->Vpb->Flags & VPB_MOUNTED))
1054 {
1055 DPRINT("Set DO_VERIFY_VOLUME\n");
1056 DeviceObject->Flags |= DO_VERIFY_VOLUME;
1057 *Status = STATUS_VERIFY_REQUIRED;
1058 }
1059 else
1060 {
1061 *Status = STATUS_IO_DEVICE_ERROR;
1062 }
1063
1064 /* Increment the media change count */
1065 PhysicalExtension->MediaChangeCount++;
1066 }
1067
1068
1069 /*
1070 * @implemented
1071 */
1072 BOOLEAN STDCALL
1073 ScsiClassInterpretSenseInfo(IN PDEVICE_OBJECT DeviceObject,
1074 IN PSCSI_REQUEST_BLOCK Srb,
1075 IN UCHAR MajorFunctionCode,
1076 IN ULONG IoDeviceCode,
1077 IN ULONG RetryCount,
1078 OUT NTSTATUS *Status)
1079 {
1080 PDEVICE_EXTENSION DeviceExtension;
1081 PDEVICE_EXTENSION PhysicalExtension;
1082 #if 0
1083 PIO_ERROR_LOG_PACKET LogPacket;
1084 #endif
1085 PSENSE_DATA SenseData;
1086 BOOLEAN LogError;
1087 BOOLEAN Retry;
1088
1089 DPRINT("ScsiClassInterpretSenseInfo() called\n");
1090
1091 DPRINT("Srb->SrbStatus %lx\n", Srb->SrbStatus);
1092
1093 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_PENDING)
1094 {
1095 *Status = STATUS_SUCCESS;
1096 return(FALSE);
1097 }
1098
1099 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1100 PhysicalExtension = (PDEVICE_EXTENSION)DeviceExtension->PhysicalDevice->DeviceExtension;
1101 SenseData = Srb->SenseInfoBuffer;
1102 LogError = FALSE;
1103 Retry = TRUE;
1104
1105 if ((Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
1106 (Srb->SenseInfoBufferLength > 0))
1107 {
1108 /* Got valid sense data, interpret them */
1109
1110 DPRINT("ErrorCode: %x\n", SenseData->ErrorCode);
1111 DPRINT("SenseKey: %x\n", SenseData->SenseKey);
1112 DPRINT("SenseCode: %x\n", SenseData->AdditionalSenseCode);
1113
1114 switch (SenseData->SenseKey & 0xf)
1115 {
1116 case SCSI_SENSE_NO_SENSE:
1117 DPRINT("SCSI_SENSE_NO_SENSE\n");
1118 if (SenseData->IncorrectLength)
1119 {
1120 DPRINT("Incorrect block length\n");
1121 *Status = STATUS_INVALID_BLOCK_LENGTH;
1122 Retry = FALSE;
1123 }
1124 else
1125 {
1126 DPRINT("Unspecified error\n");
1127 *Status = STATUS_IO_DEVICE_ERROR;
1128 Retry = FALSE;
1129 }
1130 break;
1131
1132 case SCSI_SENSE_RECOVERED_ERROR:
1133 DPRINT("SCSI_SENSE_RECOVERED_ERROR\n");
1134 *Status = STATUS_SUCCESS;
1135 Retry = FALSE;
1136 break;
1137
1138 case SCSI_SENSE_NOT_READY:
1139 DPRINT("SCSI_SENSE_NOT_READY\n");
1140 *Status = STATUS_DEVICE_NOT_READY;
1141 switch (SenseData->AdditionalSenseCode)
1142 {
1143 case SCSI_ADSENSE_LUN_NOT_READY:
1144 DPRINT("SCSI_ADSENSE_LUN_NOT_READY\n");
1145 break;
1146
1147 case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE:
1148 DPRINT("SCSI_ADSENSE_NO_MEDIA_IN_DEVICE\n");
1149 ScsiClassInvalidateMedia(DeviceObject,
1150 Status);
1151
1152 *Status = STATUS_NO_MEDIA_IN_DEVICE;
1153 Retry = FALSE;
1154
1155 if((DeviceExtension->MediaChangeEvent != NULL) &&
1156 (!DeviceExtension->MediaChangeEvent))
1157 {
1158 KeSetEvent(DeviceExtension->MediaChangeEvent,
1159 0,
1160 FALSE);
1161 DeviceExtension->MediaChangeNoMedia = TRUE;
1162 }
1163 break;
1164 }
1165 break;
1166
1167 case SCSI_SENSE_MEDIUM_ERROR:
1168 DPRINT("SCSI_SENSE_MEDIUM_ERROR\n");
1169 *Status = STATUS_DEVICE_DATA_ERROR;
1170 Retry = FALSE;
1171 break;
1172
1173 case SCSI_SENSE_HARDWARE_ERROR:
1174 DPRINT("SCSI_SENSE_HARDWARE_ERROR\n");
1175 *Status = STATUS_IO_DEVICE_ERROR;
1176 break;
1177
1178 case SCSI_SENSE_ILLEGAL_REQUEST:
1179 DPRINT("SCSI_SENSE_ILLEGAL_REQUEST\n");
1180 *Status = STATUS_INVALID_DEVICE_REQUEST;
1181 switch (SenseData->AdditionalSenseCode)
1182 {
1183 case SCSI_ADSENSE_ILLEGAL_COMMAND:
1184 DPRINT("SCSI_ADSENSE_ILLEGAL_COMMAND\n");
1185 Retry = FALSE;
1186 break;
1187
1188 case SCSI_ADSENSE_ILLEGAL_BLOCK:
1189 DPRINT("SCSI_ADSENSE_ILLEGAL_BLOCK\n");
1190 *Status = STATUS_NONEXISTENT_SECTOR;
1191 Retry = FALSE;
1192 break;
1193
1194 case SCSI_ADSENSE_INVALID_LUN:
1195 DPRINT("SCSI_ADSENSE_INVALID_LUN\n");
1196 *Status = STATUS_NO_SUCH_DEVICE;
1197 Retry = FALSE;
1198 break;
1199
1200 case SCSI_ADSENSE_MUSIC_AREA:
1201 DPRINT("SCSI_ADSENSE_MUSIC_AREA\n");
1202 Retry = FALSE;
1203 break;
1204
1205 case SCSI_ADSENSE_DATA_AREA:
1206 DPRINT("SCSI_ADSENSE_DATA_AREA\n");
1207 Retry = FALSE;
1208 break;
1209
1210 case SCSI_ADSENSE_VOLUME_OVERFLOW:
1211 DPRINT("SCSI_ADSENSE_VOLUME_OVERFLOW\n");
1212 Retry = FALSE;
1213 break;
1214
1215 case SCSI_ADSENSE_INVALID_CDB:
1216 DPRINT("SCSI_ADSENSE_INVALID_CDB\n");
1217 Retry = FALSE;
1218 break;
1219 }
1220 break;
1221
1222 case SCSI_SENSE_UNIT_ATTENTION:
1223 DPRINT("SCSI_SENSE_UNIT_ATTENTION\n");
1224 switch (SenseData->AdditionalSenseCode)
1225 {
1226 case SCSI_ADSENSE_MEDIUM_CHANGED:
1227 DPRINT("SCSI_ADSENSE_MEDIUM_CHANGED\n");
1228 if(DeviceExtension->MediaChangeEvent != NULL)
1229 {
1230 KeSetEvent(DeviceExtension->MediaChangeEvent,
1231 0,
1232 FALSE);
1233 DeviceExtension->MediaChangeNoMedia = FALSE;
1234 }
1235 break;
1236
1237 case SCSI_ADSENSE_BUS_RESET:
1238 DPRINT("SCSI_ADSENSE_BUS_RESET\n");
1239 break;
1240
1241 default:
1242 DPRINT("Unit attention\n");
1243 break;
1244 }
1245
1246 ScsiClassInvalidateMedia(DeviceObject,
1247 Status);
1248 Retry = FALSE;
1249 break;
1250
1251 case SCSI_SENSE_DATA_PROTECT:
1252 DPRINT("SCSI_SENSE_DATA_PROTECT\n");
1253 *Status = STATUS_MEDIA_WRITE_PROTECTED;
1254 Retry = FALSE;
1255 break;
1256
1257 case SCSI_SENSE_ABORTED_COMMAND:
1258 DPRINT("SCSI_SENSE_ABORTED_COMMAND\n");
1259 *Status = STATUS_IO_DEVICE_ERROR;
1260 break;
1261
1262 default:
1263 DPRINT("SCSI error (sense key: %x)\n",
1264 SenseData->SenseKey & 0xf);
1265 *Status = STATUS_IO_DEVICE_ERROR;
1266 break;
1267 }
1268 }
1269 else
1270 {
1271 /* Got no or invalid sense data, return generic error codes */
1272 switch (SRB_STATUS(Srb->SrbStatus))
1273 {
1274 /* FIXME: add more srb status codes */
1275
1276 case SRB_STATUS_INVALID_PATH_ID:
1277 case SRB_STATUS_INVALID_TARGET_ID:
1278 case SRB_STATUS_INVALID_LUN:
1279 case SRB_STATUS_NO_DEVICE:
1280 case SRB_STATUS_NO_HBA:
1281 *Status = STATUS_NO_SUCH_DEVICE;
1282 Retry = FALSE;
1283 break;
1284
1285 case SRB_STATUS_BUSY:
1286 *Status = STATUS_DEVICE_BUSY;
1287 Retry = TRUE;
1288 break;
1289
1290 case SRB_STATUS_DATA_OVERRUN:
1291 *Status = STATUS_DATA_OVERRUN;
1292 Retry = FALSE;
1293 break;
1294
1295 case SRB_STATUS_INVALID_REQUEST:
1296 *Status = STATUS_INVALID_DEVICE_REQUEST;
1297 Retry = FALSE;
1298 break;
1299
1300 default:
1301 DPRINT("SCSI error (SRB status: %x)\n",
1302 SRB_STATUS(Srb->SrbStatus));
1303 LogError = TRUE;
1304 *Status = STATUS_IO_DEVICE_ERROR;
1305 break;
1306 }
1307 }
1308
1309 /* Call the class driver specific error function */
1310 if (DeviceExtension->ClassError != NULL)
1311 {
1312 DeviceExtension->ClassError(DeviceObject,
1313 Srb,
1314 Status,
1315 &Retry);
1316 }
1317
1318 if (LogError == TRUE)
1319 {
1320 #if 0
1321 /* Allocate error packet */
1322 LogPacket = IoAllocateErrorLogEntry (DeviceObject,
1323 sizeof(IO_ERROR_LOG_PACKET) +
1324 5 * sizeof(ULONG));
1325 if (LogPacket == NULL)
1326 {
1327 DPRINT ("Failed to allocate a log packet!\n");
1328 return Retry;
1329 }
1330
1331 /* Initialize error packet */
1332 LogPacket->MajorFunctionCode = MajorFunctionCode;
1333 LogPacket->RetryCount = (UCHAR)RetryCount;
1334 LogPacket->DumpDataSize = 6 * sizeof(ULONG);
1335 LogPacket->ErrorCode = 0; /* FIXME */
1336 LogPacket->FinalStatus = *Status;
1337 LogPacket->IoControlCode = IoDeviceCode;
1338 LogPacket->DeviceOffset.QuadPart = 0; /* FIXME */
1339 LogPacket->DumpData[0] = Srb->PathId;
1340 LogPacket->DumpData[1] = Srb->TargetId;
1341 LogPacket->DumpData[2] = Srb->Lun;
1342 LogPacket->DumpData[3] = 0;
1343 LogPacket->DumpData[4] = (Srb->SrbStatus << 8) | Srb->ScsiStatus;
1344 if (SenseData != NULL)
1345 {
1346 LogPacket->DumpData[5] = (SenseData->SenseKey << 16) |
1347 (SenseData->AdditionalSenseCode << 8) |
1348 SenseData->AdditionalSenseCodeQualifier;
1349 }
1350
1351 /* Write error packet */
1352 IoWriteErrorLogEntry (LogPacket);
1353 #endif
1354 }
1355
1356 DPRINT("ScsiClassInterpretSenseInfo() done\n");
1357
1358 return Retry;
1359 }
1360
1361
1362 /*
1363 * @implemented
1364 */
1365 NTSTATUS STDCALL
1366 ScsiClassIoComplete(IN PDEVICE_OBJECT DeviceObject,
1367 IN PIRP Irp,
1368 IN PVOID Context)
1369 {
1370 PDEVICE_EXTENSION DeviceExtension;
1371 PIO_STACK_LOCATION IrpStack;
1372 PSCSI_REQUEST_BLOCK Srb;
1373 BOOLEAN Retry;
1374 NTSTATUS Status;
1375
1376 DPRINT("ScsiClassIoComplete(DeviceObject %p Irp %p Context %p) called\n",
1377 DeviceObject, Irp, Context);
1378
1379 DeviceExtension = DeviceObject->DeviceExtension;
1380
1381 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1382
1383 /*
1384 * BUGBUG -> Srb = IrpStack->Parameters.Scsi.Srb;
1385 * Must pass Srb as Context arg!! See comment about Completion routines in
1386 * IofCallDriver for more info.
1387 */
1388
1389 Srb = (PSCSI_REQUEST_BLOCK)Context;
1390
1391 DPRINT("Srb %p\n", Srb);
1392
1393 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
1394 {
1395 Status = STATUS_SUCCESS;
1396 }
1397 else
1398 {
1399 /* Release the queue if it is frozen */
1400 if (Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN)
1401 {
1402 ScsiClassReleaseQueue (DeviceObject);
1403 }
1404
1405 /* Get more detailed status information */
1406 Retry = ScsiClassInterpretSenseInfo(DeviceObject,
1407 Srb,
1408 IrpStack->MajorFunction,
1409 0,
1410 MAXIMUM_RETRIES - ((ULONG)IrpStack->Parameters.Others.Argument4),
1411 &Status);
1412
1413 /* Retry the request if verify should be overridden */
1414 if ((IrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME) &&
1415 Status == STATUS_VERIFY_REQUIRED)
1416 {
1417 Status = STATUS_IO_DEVICE_ERROR;
1418 Retry = TRUE;
1419 }
1420
1421 /* Retry the request */
1422 if ((Retry) &&
1423 ((ULONG_PTR)IrpStack->Parameters.Others.Argument4 > 0))
1424 {
1425 IrpStack->Parameters.Others.Argument4 = (PVOID) ((ULONG_PTR)IrpStack->Parameters.Others.Argument4 - 1);
1426
1427 ScsiClassRetryRequest(DeviceObject,
1428 Irp,
1429 Srb,
1430 FALSE);
1431
1432 return(STATUS_MORE_PROCESSING_REQUIRED);
1433 }
1434 }
1435
1436 /* Free the SRB */
1437 ExFreeToNPagedLookasideList(&DeviceExtension->SrbLookasideListHead,
1438 Srb);
1439
1440 Irp->IoStatus.Status = Status;
1441 if (!NT_SUCCESS(Status))
1442 {
1443 Irp->IoStatus.Information = 0;
1444 if (IoIsErrorUserInduced(Status))
1445 {
1446 IoSetHardErrorOrVerifyDevice(Irp,
1447 DeviceObject);
1448 }
1449 }
1450
1451 if (Irp->PendingReturned)
1452 {
1453 IoMarkIrpPending (Irp);
1454 }
1455
1456 if (DeviceExtension->ClassStartIo != NULL)
1457 {
1458 if (IrpStack->MajorFunction != IRP_MJ_DEVICE_CONTROL)
1459 {
1460 KIRQL oldIrql;
1461 oldIrql = KeGetCurrentIrql();
1462 if (oldIrql < DISPATCH_LEVEL)
1463 {
1464 KeRaiseIrql (DISPATCH_LEVEL, &oldIrql);
1465 IoStartNextPacket (DeviceObject, FALSE);
1466 KeLowerIrql(oldIrql);
1467 }
1468 else
1469 {
1470 IoStartNextPacket (DeviceObject, FALSE);
1471 }
1472 }
1473 }
1474
1475 DPRINT("ScsiClassIoComplete() done (Status %lx)\n", Status);
1476
1477 return(Status);
1478 }
1479
1480
1481 /*
1482 * @implemented
1483 */
1484 NTSTATUS STDCALL
1485 ScsiClassIoCompleteAssociated(IN PDEVICE_OBJECT DeviceObject,
1486 IN PIRP Irp,
1487 IN PVOID Context)
1488 {
1489 PDEVICE_EXTENSION DeviceExtension;
1490 PIO_STACK_LOCATION IrpStack;
1491 PSCSI_REQUEST_BLOCK Srb;
1492 PIRP MasterIrp;
1493 BOOLEAN Retry;
1494 LONG RequestCount;
1495 NTSTATUS Status;
1496
1497 DPRINT("ScsiClassIoCompleteAssociated(DeviceObject %p Irp %p Context %p) called\n",
1498 DeviceObject, Irp, Context);
1499
1500 MasterIrp = Irp->AssociatedIrp.MasterIrp;
1501 DeviceExtension = DeviceObject->DeviceExtension;
1502
1503 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1504
1505 /*
1506 * BUGBUG -> Srb = Srb = IrpStack->Parameters.Scsi.Srb;
1507 * Must pass Srb as Context arg!! See comment about Completion routines in
1508 * IofCallDriver for more info.
1509 */
1510
1511 Srb = (PSCSI_REQUEST_BLOCK)Context;
1512
1513 DPRINT("Srb %p\n", Srb);
1514
1515 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
1516 {
1517 Status = STATUS_SUCCESS;
1518 }
1519 else
1520 {
1521 /* Release the queue if it is frozen */
1522 if (Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN)
1523 {
1524 ScsiClassReleaseQueue (DeviceObject);
1525 }
1526
1527 /* Get more detailed status information */
1528 Retry = ScsiClassInterpretSenseInfo(DeviceObject,
1529 Srb,
1530 IrpStack->MajorFunction,
1531 0,
1532 MAXIMUM_RETRIES - ((ULONG)IrpStack->Parameters.Others.Argument4),
1533 &Status);
1534
1535 /* Retry the request if verify should be overridden */
1536 if ((IrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME) &&
1537 Status == STATUS_VERIFY_REQUIRED)
1538 {
1539 Status = STATUS_IO_DEVICE_ERROR;
1540 Retry = TRUE;
1541 }
1542
1543 /* Retry the request */
1544 if ((Retry) &&
1545 ((ULONG_PTR)IrpStack->Parameters.Others.Argument4 > 0))
1546 {
1547 IrpStack->Parameters.Others.Argument4 = (PVOID) ((ULONG_PTR)IrpStack->Parameters.Others.Argument4 - 1);
1548
1549 ScsiClassRetryRequest(DeviceObject,
1550 Irp,
1551 Srb,
1552 TRUE);
1553
1554 return(STATUS_MORE_PROCESSING_REQUIRED);
1555 }
1556 }
1557
1558 /* Free the SRB */
1559 ExFreeToNPagedLookasideList(&DeviceExtension->SrbLookasideListHead,
1560 Srb);
1561
1562 Irp->IoStatus.Status = Status;
1563
1564 IrpStack = IoGetNextIrpStackLocation(MasterIrp);
1565 if (!NT_SUCCESS(Status))
1566 {
1567 MasterIrp->IoStatus.Status = Status;
1568 MasterIrp->IoStatus.Information = 0;
1569
1570 if (IoIsErrorUserInduced(Status))
1571 {
1572 IoSetHardErrorOrVerifyDevice(MasterIrp,
1573 DeviceObject);
1574 }
1575 }
1576
1577 /* Decrement the request counter in the Master IRP */
1578 RequestCount = InterlockedDecrement((PLONG)&IrpStack->Parameters.Others.Argument1);
1579
1580 if (RequestCount == 0)
1581 {
1582 /* Complete the Master IRP */
1583 IoCompleteRequest(MasterIrp,
1584 IO_DISK_INCREMENT);
1585
1586 if (DeviceExtension->ClassStartIo)
1587 {
1588 KIRQL oldIrql;
1589 oldIrql = KeGetCurrentIrql();
1590 if (oldIrql < DISPATCH_LEVEL)
1591 {
1592 KeRaiseIrql (DISPATCH_LEVEL, &oldIrql);
1593 IoStartNextPacket (DeviceObject, FALSE);
1594 KeLowerIrql(oldIrql);
1595 }
1596 else
1597 {
1598 IoStartNextPacket (DeviceObject, FALSE);
1599 }
1600 }
1601 }
1602
1603 /* Free the current IRP */
1604 IoFreeIrp(Irp);
1605
1606 return(STATUS_MORE_PROCESSING_REQUIRED);
1607 }
1608
1609
1610 /*
1611 * @implemented
1612 */
1613 ULONG STDCALL
1614 ScsiClassModeSense(IN PDEVICE_OBJECT DeviceObject,
1615 IN PCHAR ModeSenseBuffer,
1616 IN ULONG Length,
1617 IN UCHAR PageMode)
1618 {
1619 PDEVICE_EXTENSION DeviceExtension;
1620 SCSI_REQUEST_BLOCK Srb;
1621 ULONG RetryCount;
1622 PCDB Cdb;
1623 NTSTATUS Status;
1624
1625 DPRINT("ScsiClassModeSense() called\n");
1626
1627 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1628 RetryCount = 1;
1629
1630 /* Initialize the SRB */
1631 RtlZeroMemory (&Srb,
1632 sizeof(SCSI_REQUEST_BLOCK));
1633 Srb.CdbLength = 6;
1634 Srb.TimeOutValue = DeviceExtension->TimeOutValue;
1635
1636 /* Initialize the CDB */
1637 Cdb = (PCDB)&Srb.Cdb;
1638 Cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
1639 Cdb->MODE_SENSE.PageCode = PageMode;
1640 Cdb->MODE_SENSE.AllocationLength = (UCHAR)Length;
1641
1642 TryAgain:
1643 Status = ScsiClassSendSrbSynchronous (DeviceObject,
1644 &Srb,
1645 ModeSenseBuffer,
1646 Length,
1647 FALSE);
1648 if (Status == STATUS_VERIFY_REQUIRED)
1649 {
1650 if (RetryCount != 0)
1651 {
1652 RetryCount--;
1653 goto TryAgain;
1654 }
1655 }
1656 else if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN)
1657 {
1658 Status = STATUS_SUCCESS;
1659 }
1660
1661 if (!NT_SUCCESS(Status))
1662 {
1663 return 0;
1664 }
1665
1666 return Srb.DataTransferLength;
1667 }
1668
1669
1670 /*
1671 * @implemented
1672 */
1673 ULONG STDCALL
1674 ScsiClassQueryTimeOutRegistryValue(IN PUNICODE_STRING RegistryPath)
1675 {
1676 PRTL_QUERY_REGISTRY_TABLE Table;
1677 ULONG TimeOutValue;
1678 ULONG ZeroTimeOut;
1679 ULONG Size;
1680 PWSTR Path;
1681 NTSTATUS Status;
1682
1683 if (RegistryPath == NULL)
1684 {
1685 return 0;
1686 }
1687
1688 TimeOutValue = 0;
1689 ZeroTimeOut = 0;
1690
1691 /* Allocate zero-terminated path string */
1692 Size = RegistryPath->Length + sizeof(WCHAR);
1693 Path = (PWSTR)ExAllocatePool (NonPagedPool,
1694 Size);
1695 if (Path == NULL)
1696 {
1697 return 0;
1698 }
1699 RtlZeroMemory (Path,
1700 Size);
1701 RtlCopyMemory (Path,
1702 RegistryPath->Buffer,
1703 Size - sizeof(WCHAR));
1704
1705 /* Allocate query table */
1706 Size = sizeof(RTL_QUERY_REGISTRY_TABLE) * 2;
1707 Table = (PRTL_QUERY_REGISTRY_TABLE)ExAllocatePool (NonPagedPool,
1708 Size);
1709 if (Table == NULL)
1710 {
1711 ExFreePool (Path);
1712 return 0;
1713 }
1714 RtlZeroMemory (Table,
1715 Size);
1716
1717 Table[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
1718 Table[0].Name = L"TimeOutValue";
1719 Table[0].EntryContext = &TimeOutValue;
1720 Table[0].DefaultType = REG_DWORD;
1721 Table[0].DefaultData = &ZeroTimeOut;
1722 Table[0].DefaultLength = sizeof(ULONG);
1723
1724 Status = RtlQueryRegistryValues (RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
1725 Path,
1726 Table,
1727 NULL,
1728 NULL);
1729 if (!NT_SUCCESS(Status))
1730 {
1731 DPRINT("RtlQueryRegistryValue() failed (Status %lx)\n", Status);
1732 TimeOutValue = 0;
1733 }
1734
1735 ExFreePool (Table);
1736 ExFreePool (Path);
1737
1738 DPRINT("TimeOut: %lu\n", TimeOutValue);
1739
1740 return TimeOutValue;
1741 }
1742
1743
1744 /*
1745 * @implemented
1746 */
1747 NTSTATUS STDCALL
1748 ScsiClassReadDriveCapacity(IN PDEVICE_OBJECT DeviceObject)
1749 {
1750 PDEVICE_EXTENSION DeviceExtension;
1751 PREAD_CAPACITY_DATA CapacityBuffer;
1752 SCSI_REQUEST_BLOCK Srb;
1753 PCDB Cdb;
1754 NTSTATUS Status;
1755 ULONG LastSector;
1756 ULONG SectorSize;
1757 ULONG RetryCount = 1;
1758
1759 DPRINT("ScsiClassReadDriveCapacity() called\n");
1760
1761 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1762
1763 CapacityBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
1764 sizeof(READ_CAPACITY_DATA));
1765 if (CapacityBuffer == NULL)
1766 {
1767 return(STATUS_INSUFFICIENT_RESOURCES);
1768 }
1769
1770 RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
1771
1772 Srb.CdbLength = 10;
1773 Srb.TimeOutValue = DeviceExtension->TimeOutValue;
1774
1775 Cdb = (PCDB)Srb.Cdb;
1776 Cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
1777
1778 TryAgain:
1779 Status = ScsiClassSendSrbSynchronous(DeviceObject,
1780 &Srb,
1781 CapacityBuffer,
1782 sizeof(READ_CAPACITY_DATA),
1783 FALSE);
1784 DPRINT("Status: %lx\n", Status);
1785 DPRINT("Srb: %p\n", &Srb);
1786 if (NT_SUCCESS(Status))
1787 {
1788 SectorSize = (((PUCHAR)&CapacityBuffer->BytesPerBlock)[0] << 24) |
1789 (((PUCHAR)&CapacityBuffer->BytesPerBlock)[1] << 16) |
1790 (((PUCHAR)&CapacityBuffer->BytesPerBlock)[2] << 8) |
1791 ((PUCHAR)&CapacityBuffer->BytesPerBlock)[3];
1792
1793
1794 LastSector = (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[0] << 24) |
1795 (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[1] << 16) |
1796 (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[2] << 8) |
1797 ((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[3];
1798
1799 DeviceExtension->DiskGeometry->BytesPerSector = SectorSize;
1800
1801 DeviceExtension->PartitionLength.QuadPart = (LONGLONG)(LastSector + 1);
1802 WHICH_BIT(DeviceExtension->DiskGeometry->BytesPerSector,
1803 DeviceExtension->SectorShift);
1804 DeviceExtension->PartitionLength.QuadPart =
1805 (DeviceExtension->PartitionLength.QuadPart << DeviceExtension->SectorShift);
1806
1807 DeviceExtension->PartitionLength.QuadPart =
1808 (DeviceExtension->PartitionLength.QuadPart -
1809 DeviceExtension->StartingOffset.QuadPart);
1810
1811 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
1812 {
1813 DeviceExtension->DiskGeometry->MediaType = RemovableMedia;
1814 }
1815 else
1816 {
1817 DeviceExtension->DiskGeometry->MediaType = FixedMedia;
1818 }
1819 DeviceExtension->DiskGeometry->Cylinders.QuadPart = (LONGLONG)((LastSector + 1)/(32 * 64));
1820 DeviceExtension->DiskGeometry->SectorsPerTrack = 32;
1821 DeviceExtension->DiskGeometry->TracksPerCylinder = 64;
1822
1823 DPRINT("SectorSize: %lu SectorCount: %lu PartitionLenght %I64d\n", SectorSize, LastSector + 1,
1824 DeviceExtension->PartitionLength.QuadPart / 512 );
1825 }
1826
1827 /* Try again if device needs to be verified */
1828 if (Status == STATUS_VERIFY_REQUIRED)
1829 {
1830 if (RetryCount > 0)
1831 {
1832 RetryCount--;
1833 goto TryAgain;
1834 }
1835 }
1836
1837 if (!NT_SUCCESS(Status))
1838 {
1839 /* Use default values if disk geometry cannot be read */
1840 RtlZeroMemory(DeviceExtension->DiskGeometry,
1841 sizeof(DISK_GEOMETRY));
1842 DeviceExtension->DiskGeometry->BytesPerSector = 512;
1843 DeviceExtension->SectorShift = 9;
1844 DeviceExtension->PartitionLength.QuadPart = 0;
1845
1846 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
1847 {
1848 DeviceExtension->DiskGeometry->MediaType = RemovableMedia;
1849 }
1850 else
1851 {
1852 DeviceExtension->DiskGeometry->MediaType = FixedMedia;
1853 }
1854
1855 DPRINT("SectorSize: 512 SectorCount: 0\n");
1856 }
1857
1858 ExFreePool(CapacityBuffer);
1859
1860 DPRINT("ScsiClassReadDriveCapacity() done\n");
1861
1862 return(Status);
1863 }
1864
1865
1866 /*
1867 * @implemented
1868 */
1869 VOID STDCALL
1870 ScsiClassReleaseQueue(IN PDEVICE_OBJECT DeviceObject)
1871 {
1872 PDEVICE_EXTENSION DeviceExtension;
1873 PCOMPLETION_CONTEXT Context;
1874 PIO_STACK_LOCATION Stack;
1875 PSCSI_REQUEST_BLOCK Srb;
1876 KIRQL Irql;
1877 PCDB Cdb;
1878 PIRP Irp;
1879
1880 DPRINT("ScsiClassReleaseQueue() called\n");
1881
1882 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1883
1884 /* Allocate and initialize the completion context */
1885 Context = ExAllocatePool (NonPagedPoolMustSucceed,
1886 sizeof (COMPLETION_CONTEXT));
1887 Context->DeviceObject = DeviceObject;
1888
1889 /* Initialize the SRB */
1890 Srb = &Context->Srb;
1891 RtlZeroMemory (Srb,
1892 sizeof (SCSI_REQUEST_BLOCK));
1893 Srb->Length = sizeof (SCSI_REQUEST_BLOCK);
1894 Srb->PathId = DeviceExtension->PathId;
1895 Srb->TargetId = DeviceExtension->TargetId;
1896 Srb->Lun = DeviceExtension->Lun;
1897 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1898 Srb->TimeOutValue = START_UNIT_TIMEOUT;
1899 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER |
1900 SRB_FLAGS_DISABLE_AUTOSENSE |
1901 SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
1902 Srb->CdbLength = 6;
1903
1904 /* Initialize the CDB */
1905 Cdb = (PCDB)&Srb->Cdb;
1906 Cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
1907 Cdb->START_STOP.Start = 1;
1908 Cdb->START_STOP.LogicalUnitNumber = Srb->Lun;
1909
1910 /* Build the IRP */
1911 Irp = IoAllocateIrp (DeviceObject->StackSize, FALSE);
1912 IoSetCompletionRoutine (Irp,
1913 (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion,
1914 Context,
1915 NULL,
1916 NULL,
1917 NULL);
1918
1919 /* Attach SRB to the IRP */
1920 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1921 Stack = IoGetNextIrpStackLocation(Irp);
1922 Stack->MajorFunction = IRP_MJ_SCSI;
1923 Stack->Parameters.Scsi.Srb = Srb;
1924 Srb->OriginalRequest = Irp;
1925
1926 /* Call the port driver */
1927 Irql = KeGetCurrentIrql ();
1928 if (Irql < DISPATCH_LEVEL)
1929 {
1930 KeRaiseIrql (DISPATCH_LEVEL, &Irql);
1931 IoCallDriver (DeviceExtension->PortDeviceObject, Irp);
1932 KeLowerIrql (Irql);
1933 }
1934 else
1935 {
1936 IoCallDriver (DeviceExtension->PortDeviceObject, Irp);
1937 }
1938
1939 DPRINT("ScsiClassReleaseQueue() done\n");
1940 }
1941
1942
1943 /*
1944 * @implemented
1945 */
1946 NTSTATUS STDCALL
1947 ScsiClassSendSrbAsynchronous(PDEVICE_OBJECT DeviceObject,
1948 PSCSI_REQUEST_BLOCK Srb,
1949 PIRP Irp,
1950 PVOID BufferAddress,
1951 ULONG BufferLength,
1952 BOOLEAN WriteToDevice)
1953 {
1954 PDEVICE_EXTENSION DeviceExtension;
1955 PIO_STACK_LOCATION Stack;
1956
1957 DPRINT("ScsiClassSendSrbAsynchronous() called\n");
1958
1959 DeviceExtension = DeviceObject->DeviceExtension;
1960
1961 /* Initialize the SRB */
1962 Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1963 Srb->PathId = DeviceExtension->PathId;
1964 Srb->TargetId = DeviceExtension->TargetId;
1965 Srb->Lun = DeviceExtension->Lun;
1966 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1967 Srb->Cdb[1] |= DeviceExtension->Lun << 5;
1968
1969 Srb->SenseInfoBuffer = (SENSE_DATA*)ROUND_UP((ULONG_PTR)(Srb + 1), SENSEINFO_ALIGNMENT);
1970 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1971
1972 Srb->DataBuffer = BufferAddress;
1973 Srb->DataTransferLength = BufferLength;
1974
1975 Srb->ScsiStatus = 0;
1976 Srb->SrbStatus = 0;
1977 Srb->NextSrb = NULL;
1978
1979 if (BufferAddress != NULL)
1980 {
1981 if (Irp->MdlAddress == NULL)
1982 {
1983 /* Allocate an MDL */
1984 if (!IoAllocateMdl(BufferAddress,
1985 BufferLength,
1986 FALSE,
1987 FALSE,
1988 Irp))
1989 {
1990 DPRINT("Mdl-Allocation failed\n");
1991 return(STATUS_INSUFFICIENT_RESOURCES);
1992 }
1993
1994 MmBuildMdlForNonPagedPool(Irp->MdlAddress);
1995 }
1996
1997 /* Set data direction */
1998 Srb->SrbFlags = (WriteToDevice) ? SRB_FLAGS_DATA_OUT : SRB_FLAGS_DATA_IN;
1999 }
2000 else
2001 {
2002 /* Set data direction */
2003 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
2004 }
2005
2006 /* Set the retry counter */
2007 Stack = IoGetCurrentIrpStackLocation(Irp);
2008 Stack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
2009
2010 /* Set the completion routine */
2011 IoSetCompletionRoutine(Irp,
2012 ScsiClassIoComplete,
2013 Srb,
2014 TRUE,
2015 TRUE,
2016 TRUE);
2017
2018 /* Attach Srb to the Irp */
2019 Stack = IoGetNextIrpStackLocation(Irp);
2020 Stack->MajorFunction = IRP_MJ_SCSI;
2021 Stack->Parameters.Scsi.Srb = Srb;
2022 Srb->OriginalRequest = Irp;
2023
2024 /* Call the port driver */
2025 return(IoCallDriver(DeviceExtension->PortDeviceObject,
2026 Irp));
2027 }
2028
2029
2030 /*
2031 * @implemented
2032 */
2033 NTSTATUS STDCALL
2034 ScsiClassSendSrbSynchronous(PDEVICE_OBJECT DeviceObject,
2035 PSCSI_REQUEST_BLOCK Srb,
2036 PVOID BufferAddress,
2037 ULONG BufferLength,
2038 BOOLEAN WriteToDevice)
2039 {
2040 PDEVICE_EXTENSION DeviceExtension;
2041 IO_STATUS_BLOCK IoStatusBlock;
2042 PIO_STACK_LOCATION IrpStack;
2043 ULONG RequestType;
2044 BOOLEAN Retry;
2045 ULONG RetryCount;
2046 KEVENT Event;
2047 PIRP Irp;
2048 NTSTATUS Status;
2049 LARGE_INTEGER RetryWait;
2050
2051 DPRINT("ScsiClassSendSrbSynchronous() called\n");
2052
2053 RetryCount = MAXIMUM_RETRIES;
2054 DeviceExtension = DeviceObject->DeviceExtension;
2055
2056 Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
2057 Srb->PathId = DeviceExtension->PathId;
2058 Srb->TargetId = DeviceExtension->TargetId;
2059 Srb->Lun = DeviceExtension->Lun;
2060 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
2061
2062 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
2063 Srb->SenseInfoBuffer = ExAllocatePool(NonPagedPool,
2064 SENSE_BUFFER_SIZE);
2065 if (Srb->SenseInfoBuffer == NULL)
2066 return(STATUS_INSUFFICIENT_RESOURCES);
2067
2068 if (BufferAddress == NULL)
2069 {
2070 BufferLength = 0;
2071 RequestType = IOCTL_SCSI_EXECUTE_NONE;
2072 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
2073 }
2074 else
2075 {
2076 if (WriteToDevice == TRUE)
2077 {
2078 RequestType = IOCTL_SCSI_EXECUTE_IN; // needs _in_ to the device
2079 Srb->SrbFlags = SRB_FLAGS_DATA_OUT; // needs _out_ from the caller
2080 }
2081 else
2082 {
2083 RequestType = IOCTL_SCSI_EXECUTE_OUT;
2084 Srb->SrbFlags = SRB_FLAGS_DATA_IN;
2085 }
2086 }
2087
2088 Srb->DataBuffer = BufferAddress;
2089
2090 TryAgain:
2091 Srb->DataTransferLength = BufferLength;
2092 KeInitializeEvent(&Event,
2093 NotificationEvent,
2094 FALSE);
2095
2096 Irp = IoBuildDeviceIoControlRequest(RequestType,
2097 DeviceExtension->PortDeviceObject,
2098 NULL,
2099 0,
2100 BufferAddress,
2101 BufferLength,
2102 TRUE,
2103 &Event,
2104 &IoStatusBlock);
2105 if (Irp == NULL)
2106 {
2107 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
2108 ExFreePool(Srb->SenseInfoBuffer);
2109 Srb->SenseInfoBuffer = NULL;
2110 Srb->SenseInfoBufferLength = 0;
2111 return(STATUS_INSUFFICIENT_RESOURCES);
2112 }
2113
2114 /* Attach Srb to the Irp */
2115 IrpStack = IoGetNextIrpStackLocation(Irp);
2116 IrpStack->Parameters.Scsi.Srb = Srb;
2117 Srb->OriginalRequest = Irp;
2118
2119 /* Call the SCSI port driver */
2120 Status = IoCallDriver(DeviceExtension->PortDeviceObject,
2121 Irp);
2122 if (Status == STATUS_PENDING)
2123 {
2124 KeWaitForSingleObject(&Event,
2125 Suspended,
2126 KernelMode,
2127 FALSE,
2128 NULL);
2129 }
2130
2131 if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS)
2132 {
2133 /* Release the queue if it is frozen */
2134 if (Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN)
2135 {
2136 ScsiClassReleaseQueue (DeviceObject);
2137 }
2138
2139 /* Get more detailed status information */
2140 Retry = ScsiClassInterpretSenseInfo(DeviceObject,
2141 Srb,
2142 IRP_MJ_SCSI,
2143 0,
2144 MAXIMUM_RETRIES - RetryCount,
2145 &Status);
2146 if (Retry == TRUE)
2147 {
2148 DPRINT("Try again (RetryCount %lu)\n", RetryCount);
2149
2150 /* FIXME: Wait a little if we got a timeout error */
2151
2152 if (RetryCount--)
2153 {
2154 RetryWait.QuadPart = - RETRY_WAIT;
2155 KeDelayExecutionThread(KernelMode, FALSE, &RetryWait);
2156 goto TryAgain;
2157 }
2158 }
2159 }
2160 else
2161 {
2162 Status = STATUS_SUCCESS;
2163 }
2164
2165 ExFreePool(Srb->SenseInfoBuffer);
2166
2167 DPRINT("ScsiClassSendSrbSynchronous() done\n");
2168
2169 return(Status);
2170 }
2171
2172
2173 /*
2174 * @implemented
2175 */
2176 VOID STDCALL
2177 ScsiClassSplitRequest(IN PDEVICE_OBJECT DeviceObject,
2178 IN PIRP Irp,
2179 IN ULONG MaximumBytes)
2180 {
2181 PDEVICE_EXTENSION DeviceExtension;
2182 PIO_STACK_LOCATION CurrentStack;
2183 PIO_STACK_LOCATION NextStack;
2184 PIO_STACK_LOCATION NewStack;
2185 PSCSI_REQUEST_BLOCK Srb;
2186 LARGE_INTEGER Offset;
2187 PIRP NewIrp;
2188 PVOID DataBuffer;
2189 ULONG TransferLength;
2190 ULONG RequestCount;
2191 ULONG DataLength;
2192 ULONG i;
2193
2194 DPRINT("ScsiClassSplitRequest(DeviceObject %lx Irp %lx MaximumBytes %lu)\n",
2195 DeviceObject, Irp, MaximumBytes);
2196
2197 DeviceExtension = DeviceObject->DeviceExtension;
2198 CurrentStack = IoGetCurrentIrpStackLocation(Irp);
2199 NextStack = IoGetNextIrpStackLocation(Irp);
2200 DataBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
2201
2202 /* Initialize transfer data for first request */
2203 Offset = CurrentStack->Parameters.Read.ByteOffset;
2204 TransferLength = CurrentStack->Parameters.Read.Length;
2205
2206 /* Set the result length */
2207 Irp->IoStatus.Information = TransferLength;
2208
2209 DataLength = MaximumBytes;
2210 RequestCount = ROUND_UP(TransferLength, MaximumBytes) / MaximumBytes;
2211
2212 /* Save request count in the original IRP */
2213 NextStack->Parameters.Others.Argument1 = (PVOID)RequestCount;
2214
2215 DPRINT("RequestCount %lu\n", RequestCount);
2216
2217 for (i = 0; i < RequestCount; i++)
2218 {
2219 /* Create a new IRP */
2220 NewIrp = IoAllocateIrp(DeviceObject->StackSize,
2221 FALSE);
2222 if (NewIrp == NULL)
2223 {
2224 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
2225 Irp->IoStatus.Information = 0;
2226
2227 if (i == 0)
2228 IoCompleteRequest(Irp,
2229 IO_NO_INCREMENT);
2230 return;
2231 }
2232
2233 /* Initialize the new IRP */
2234 NewIrp->MdlAddress = Irp->MdlAddress;
2235 NewIrp->Tail.Overlay.Thread = PsGetCurrentThread();
2236
2237 IoSetNextIrpStackLocation(NewIrp);
2238 NewStack = IoGetCurrentIrpStackLocation(NewIrp);
2239
2240 NewStack->MajorFunction = CurrentStack->MajorFunction;
2241 NewStack->Parameters.Read.ByteOffset = Offset;
2242 NewStack->Parameters.Read.Length = DataLength;
2243 NewStack->DeviceObject = DeviceObject;
2244
2245 ScsiClassBuildRequest(DeviceObject,
2246 NewIrp);
2247
2248 NewStack = IoGetNextIrpStackLocation(NewIrp);
2249 Srb = NewStack->Parameters.Others.Argument1;
2250 Srb->DataBuffer = DataBuffer;
2251
2252 NewIrp->AssociatedIrp.MasterIrp = Irp;
2253
2254 /* Initialize completion routine */
2255 IoSetCompletionRoutine(NewIrp,
2256 ScsiClassIoCompleteAssociated,
2257 Srb,
2258 TRUE,
2259 TRUE,
2260 TRUE);
2261
2262 /* Send the new IRP down to the port driver */
2263 IoCallDriver(DeviceExtension->PortDeviceObject,
2264 NewIrp);
2265
2266 /* Adjust transfer data for next request */
2267 DataBuffer = (PCHAR)DataBuffer + MaximumBytes;
2268 TransferLength -= MaximumBytes;
2269 DataLength = (TransferLength > MaximumBytes) ? MaximumBytes : TransferLength;
2270 Offset.QuadPart = Offset.QuadPart + MaximumBytes;
2271 }
2272 }
2273
2274
2275 /* INTERNAL FUNCTIONS *******************************************************/
2276
2277 static NTSTATUS STDCALL
2278 ScsiClassCreateClose(IN PDEVICE_OBJECT DeviceObject,
2279 IN PIRP Irp)
2280 {
2281 PDEVICE_EXTENSION DeviceExtension;
2282
2283 DPRINT("ScsiClassCreateClose() called\n");
2284
2285 DeviceExtension = DeviceObject->DeviceExtension;
2286
2287 if (DeviceExtension->ClassCreateClose)
2288 return(DeviceExtension->ClassCreateClose(DeviceObject,
2289 Irp));
2290
2291 Irp->IoStatus.Status = STATUS_SUCCESS;
2292 Irp->IoStatus.Information = 0;
2293 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2294
2295 return(STATUS_SUCCESS);
2296 }
2297
2298
2299 static NTSTATUS STDCALL
2300 ScsiClassReadWrite(IN PDEVICE_OBJECT DeviceObject,
2301 IN PIRP Irp)
2302 {
2303 PDEVICE_EXTENSION DeviceExtension;
2304 PIO_STACK_LOCATION IrpStack;
2305 ULONG MaximumTransferLength;
2306 ULONG CurrentTransferLength;
2307 ULONG MaximumTransferPages;
2308 ULONG CurrentTransferPages;
2309 NTSTATUS Status;
2310
2311 DPRINT("ScsiClassReadWrite() called\n");
2312
2313 DeviceExtension = DeviceObject->DeviceExtension;
2314 IrpStack = IoGetCurrentIrpStackLocation(Irp);
2315
2316 DPRINT("Relative Offset: %I64u Length: %lu\n",
2317 IrpStack->Parameters.Read.ByteOffset.QuadPart,
2318 IrpStack->Parameters.Read.Length);
2319
2320 MaximumTransferLength = DeviceExtension->PortCapabilities->MaximumTransferLength;
2321 MaximumTransferPages = DeviceExtension->PortCapabilities->MaximumPhysicalPages;
2322
2323 CurrentTransferLength = IrpStack->Parameters.Read.Length;
2324
2325 if ((DeviceObject->Flags & DO_VERIFY_VOLUME) &&
2326 !(IrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME))
2327 {
2328 IoSetHardErrorOrVerifyDevice(Irp,
2329 DeviceObject);
2330
2331 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
2332 Irp->IoStatus.Information = 0;
2333
2334 IoCompleteRequest(Irp,
2335 IO_NO_INCREMENT);
2336 return(STATUS_VERIFY_REQUIRED);
2337 }
2338
2339 /* Class driver verifies the IRP */
2340 Status = DeviceExtension->ClassReadWriteVerification(DeviceObject,
2341 Irp);
2342 if (!NT_SUCCESS(Status))
2343 {
2344 IoCompleteRequest(Irp,
2345 IO_NO_INCREMENT);
2346 return(Status);
2347 }
2348 else if (Status == STATUS_PENDING)
2349 {
2350 IoMarkIrpPending(Irp);
2351 return(STATUS_PENDING);
2352 }
2353
2354 /* Finish a zero-byte transfer */
2355 if (CurrentTransferLength == 0)
2356 {
2357 Irp->IoStatus.Status = STATUS_SUCCESS;
2358 Irp->IoStatus.Information = 0;
2359 IoCompleteRequest(Irp,
2360 IO_NO_INCREMENT);
2361 return(STATUS_SUCCESS);
2362 }
2363
2364 if (DeviceExtension->ClassStartIo != NULL)
2365 {
2366 DPRINT("ScsiClassReadWrite() starting packet\n");
2367
2368 IoMarkIrpPending(Irp);
2369 IoStartPacket(DeviceObject,
2370 Irp,
2371 NULL,
2372 NULL);
2373
2374 return(STATUS_PENDING);
2375 }
2376
2377 /* Adjust partition-relative starting offset to absolute offset */
2378 IrpStack->Parameters.Read.ByteOffset.QuadPart +=
2379 (DeviceExtension->StartingOffset.QuadPart + DeviceExtension->DMByteSkew);
2380
2381 /* Calculate number of pages in this transfer */
2382 CurrentTransferPages =
2383 ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
2384 IrpStack->Parameters.Read.Length);
2385
2386 if (CurrentTransferLength > MaximumTransferLength ||
2387 CurrentTransferPages > MaximumTransferPages)
2388 {
2389 DPRINT("Split current request: MaximumTransferLength %lu CurrentTransferLength %lu\n",
2390 MaximumTransferLength, CurrentTransferLength);
2391
2392 /* Adjust the maximum transfer length */
2393 CurrentTransferPages = DeviceExtension->PortCapabilities->MaximumPhysicalPages;
2394
2395 if (MaximumTransferLength > CurrentTransferPages * PAGE_SIZE)
2396 MaximumTransferLength = CurrentTransferPages * PAGE_SIZE;
2397
2398 if (MaximumTransferLength == 0)
2399 MaximumTransferLength = PAGE_SIZE;
2400
2401 IoMarkIrpPending(Irp);
2402
2403 /* Split current request */
2404 ScsiClassSplitRequest(DeviceObject,
2405 Irp,
2406 MaximumTransferLength);
2407
2408 return(STATUS_PENDING);
2409 }
2410
2411 ScsiClassBuildRequest(DeviceObject,
2412 Irp);
2413
2414 DPRINT("ScsiClassReadWrite() done\n");
2415
2416 /* Call the port driver */
2417 return(IoCallDriver(DeviceExtension->PortDeviceObject,
2418 Irp));
2419 }
2420
2421
2422 static NTSTATUS STDCALL
2423 ScsiClassDeviceDispatch(IN PDEVICE_OBJECT DeviceObject,
2424 IN PIRP Irp)
2425 {
2426 PDEVICE_EXTENSION DeviceExtension;
2427
2428 DPRINT("ScsiClassDeviceDispatch() called\n");
2429
2430 DeviceExtension = DeviceObject->DeviceExtension;
2431 if (DeviceExtension->ClassDeviceControl)
2432 {
2433 return(DeviceExtension->ClassDeviceControl(DeviceObject, Irp));
2434 }
2435
2436 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
2437 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2438
2439 return(STATUS_INVALID_DEVICE_REQUEST);
2440 }
2441
2442
2443 static NTSTATUS STDCALL
2444 ScsiClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
2445 IN PIRP Irp)
2446 {
2447 PDEVICE_EXTENSION DeviceExtension;
2448
2449 DPRINT("ScsiClassShutdownFlush() called\n");
2450
2451 DeviceExtension = DeviceObject->DeviceExtension;
2452 if (DeviceExtension->ClassShutdownFlush)
2453 {
2454 return(DeviceExtension->ClassShutdownFlush(DeviceObject, Irp));
2455 }
2456
2457 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
2458 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2459
2460 return(STATUS_INVALID_DEVICE_REQUEST);
2461 }
2462
2463
2464 static VOID
2465 ScsiClassRetryRequest(PDEVICE_OBJECT DeviceObject,
2466 PIRP Irp,
2467 PSCSI_REQUEST_BLOCK Srb,
2468 BOOLEAN Associated)
2469 {
2470 PDEVICE_EXTENSION DeviceExtension;
2471 PIO_STACK_LOCATION CurrentIrpStack;
2472 PIO_STACK_LOCATION NextIrpStack;
2473
2474 DPRINT ("ScsiPortRetryRequest() called\n");
2475
2476 DeviceExtension = DeviceObject->DeviceExtension;
2477 CurrentIrpStack = IoGetCurrentIrpStackLocation(Irp);
2478 NextIrpStack = IoGetNextIrpStackLocation(Irp);
2479
2480 if (CurrentIrpStack->MajorFunction == IRP_MJ_READ)
2481 {
2482 Srb->DataTransferLength = CurrentIrpStack->Parameters.Read.Length;
2483 }
2484 else if (CurrentIrpStack->MajorFunction == IRP_MJ_WRITE)
2485 {
2486 Srb->DataTransferLength = CurrentIrpStack->Parameters.Write.Length;
2487 }
2488 else if (Irp->MdlAddress != NULL)
2489 {
2490 Srb->DataTransferLength = Irp->MdlAddress->ByteCount;
2491 }
2492 else
2493 {
2494 Srb->DataTransferLength = 0;
2495 }
2496
2497 Srb->SrbStatus = 0;
2498 Srb->ScsiStatus = 0;
2499
2500 /* Don't modify the flags */
2501 // Srb->Flags =
2502 // Srb->QueueTag = SP_UNTAGGED;
2503
2504 NextIrpStack->MajorFunction = IRP_MJ_SCSI;
2505 NextIrpStack->Parameters.Scsi.Srb = Srb;
2506
2507 if (Associated == FALSE)
2508 {
2509 IoSetCompletionRoutine(Irp,
2510 ScsiClassIoComplete,
2511 Srb,
2512 TRUE,
2513 TRUE,
2514 TRUE);
2515 }
2516 else
2517 {
2518 IoSetCompletionRoutine(Irp,
2519 ScsiClassIoCompleteAssociated,
2520 Srb,
2521 TRUE,
2522 TRUE,
2523 TRUE);
2524 }
2525
2526 IoCallDriver(DeviceExtension->PortDeviceObject,
2527 Irp);
2528
2529 DPRINT("ScsiPortRetryRequest() done\n");
2530 }
2531
2532
2533 static NTSTATUS STDCALL
2534 ScsiClassCheckVerifyCompletion (IN PDEVICE_OBJECT DeviceObject,
2535 IN PIRP Irp,
2536 IN PVOID Context)
2537 {
2538 PDEVICE_EXTENSION DeviceExtension;
2539 PDEVICE_EXTENSION PhysicalExtension;
2540 PIO_STACK_LOCATION Stack;
2541 PIRP OrigIrp;
2542
2543 DPRINT ("ScsiClassCheckVerifyCompletion() called\n");
2544
2545 /* Get the physical device extension */
2546 DeviceExtension = DeviceObject->DeviceExtension;
2547 PhysicalExtension = DeviceExtension->PhysicalDevice->DeviceExtension;
2548
2549 /* Get the original IRP */
2550 Stack = IoGetCurrentIrpStackLocation (Irp);
2551 OrigIrp = (PIRP)Stack->Parameters.Others.Argument1;
2552
2553 /* Copy the media change count */
2554 *((PULONG)(OrigIrp->AssociatedIrp.SystemBuffer)) =
2555 PhysicalExtension->MediaChangeCount;
2556
2557 /* Complete the original IRP */
2558 OrigIrp->IoStatus.Status = Irp->IoStatus.Status;
2559 OrigIrp->IoStatus.Information = sizeof(ULONG);
2560
2561 IoCompleteRequest (OrigIrp,
2562 IO_DISK_INCREMENT);
2563
2564 /* Release the current IRP */
2565 IoFreeIrp (Irp);
2566
2567 return STATUS_MORE_PROCESSING_REQUIRED;
2568 }
2569
2570 /* EOF */