Disk driver stack update.
[reactos.git] / reactos / drivers / storage / class2 / class2.c
1 /* $Id: class2.c,v 1.4 2002/01/31 14:57:58 ekohl Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: services/storage/class2/class2.c
6 * PURPOSE: SCSI class driver
7 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
8 */
9
10 /*
11 * TODO:
12 * - a lot ;-)
13 */
14
15 /* INCLUDES *****************************************************************/
16
17 #include <ddk/ntddk.h>
18 #include "../include/scsi.h"
19 #include "../include/class2.h"
20
21 #define NDEBUG
22 #include <debug.h>
23
24
25 #define VERSION "0.0.1"
26
27 #define INQUIRY_DATA_SIZE 2048
28
29
30 static NTSTATUS STDCALL
31 ScsiClassCreateClose(IN PDEVICE_OBJECT DeviceObject,
32 IN PIRP Irp);
33
34 static NTSTATUS STDCALL
35 ScsiClassReadWrite(IN PDEVICE_OBJECT DeviceObject,
36 IN PIRP Irp);
37
38 static NTSTATUS STDCALL
39 ScsiClassScsiDispatch(IN PDEVICE_OBJECT DeviceObject,
40 IN PIRP Irp);
41
42 static NTSTATUS STDCALL
43 ScsiClassDeviceDispatch(IN PDEVICE_OBJECT DeviceObject,
44 IN PIRP Irp);
45
46 static NTSTATUS STDCALL
47 ScsiClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
48 IN PIRP Irp);
49
50
51 /* FUNCTIONS ****************************************************************/
52
53 // DriverEntry
54 //
55 // DESCRIPTION:
56 // This function initializes the driver.
57 //
58 // RUN LEVEL:
59 // PASSIVE_LEVEL
60 //
61 // ARGUMENTS:
62 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
63 // for this driver
64 // IN PUNICODE_STRING RegistryPath Name of registry driver service
65 // key
66 //
67 // RETURNS:
68 // NTSTATUS
69
70 NTSTATUS STDCALL
71 DriverEntry(IN PDRIVER_OBJECT DriverObject,
72 IN PUNICODE_STRING RegistryPath)
73 {
74 DbgPrint("Class Driver %s\n", VERSION);
75 return(STATUS_SUCCESS);
76 }
77
78
79 VOID
80 ScsiClassDebugPrint(IN ULONG DebugPrintLevel,
81 IN PCHAR DebugMessage,
82 ...)
83 {
84 char Buffer[256];
85 va_list ap;
86
87 #if 0
88 if (DebugPrintLevel > InternalDebugLevel)
89 return;
90 #endif
91
92 va_start(ap, DebugMessage);
93 vsprintf(Buffer, DebugMessage, ap);
94 va_end(ap);
95
96 DbgPrint(Buffer);
97 }
98
99
100 NTSTATUS STDCALL
101 ScsiClassAsynchronousCompletion(IN PDEVICE_OBJECT DeviceObject,
102 IN PIRP Irp,
103 IN PVOID Context)
104 {
105 UNIMPLEMENTED;
106 }
107
108
109 VOID STDCALL
110 ScsiClassBuildRequest(PDEVICE_OBJECT DeviceObject,
111 PIRP Irp)
112 {
113 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
114 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
115 PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
116 LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
117 LARGE_INTEGER startingBlock;
118 PSCSI_REQUEST_BLOCK Srb;
119 PCDB Cdb;
120 ULONG logicalBlockAddress;
121 USHORT transferBlocks;
122
123 //
124 // Calculate relative sector address.
125 //
126
127 // logicalBlockAddress = (ULONG)(Int64ShrlMod32(startingOffset.QuadPart, deviceExtension->SectorShift));
128
129 startingBlock.QuadPart = startingOffset.QuadPart >> deviceExtension->SectorShift;
130 logicalBlockAddress = (ULONG)startingBlock.u.LowPart;
131
132 //
133 // Allocate an Srb.
134 //
135
136 // Srb = ExAllocateFromNPagedLookasideList(&deviceExtension->SrbLookasideListHead);
137 Srb = ExAllocatePool(NonPagedPool,
138 sizeof(SCSI_REQUEST_BLOCK));
139
140
141 Srb->SrbFlags = 0;
142
143 //
144 // Write length to SRB.
145 //
146
147 Srb->Length = sizeof(SCSI_REQUEST_BLOCK); //SCSI_REQUEST_BLOCK_SIZE;
148
149 //
150 // Set up IRP Address.
151 //
152
153 Srb->OriginalRequest = Irp;
154
155 //
156 // Set up target ID and logical unit number.
157 //
158
159 Srb->PathId = deviceExtension->PathId;
160 Srb->TargetId = deviceExtension->TargetId;
161 Srb->Lun = deviceExtension->Lun;
162 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
163 Srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
164
165 //
166 // Save byte count of transfer in SRB Extension.
167 //
168
169 Srb->DataTransferLength = currentIrpStack->Parameters.Read.Length;
170
171 //
172 // Initialize the queue actions field.
173 //
174
175 Srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
176
177 //
178 // Queue sort key is Relative Block Address.
179 //
180
181 Srb->QueueSortKey = logicalBlockAddress;
182
183 //
184 // Indicate auto request sense by specifying buffer and size.
185 //
186
187 Srb->SenseInfoBuffer = deviceExtension->SenseData;
188 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
189
190 //
191 // Set timeout value of one unit per 64k bytes of data.
192 //
193
194 Srb->TimeOutValue = ((Srb->DataTransferLength + 0xFFFF) >> 16) *
195 deviceExtension->TimeOutValue;
196
197 //
198 // Zero statuses.
199 //
200
201 Srb->SrbStatus = 0;
202 Srb->ScsiStatus = 0;
203 Srb->NextSrb = 0;
204
205 //
206 // Indicate that 10-byte CDB's will be used.
207 //
208
209 Srb->CdbLength = 10;
210
211 //
212 // Fill in CDB fields.
213 //
214
215 Cdb = (PCDB)Srb->Cdb;
216
217 //
218 // Zero 12 bytes for Atapi Packets
219 //
220
221 RtlZeroMemory(Cdb,
222 MAXIMUM_CDB_SIZE);
223
224 Cdb->CDB10.LogicalUnitNumber = deviceExtension->Lun;
225 transferBlocks = (USHORT)(currentIrpStack->Parameters.Read.Length >> deviceExtension->SectorShift);
226
227 //
228 // Move little endian values into CDB in big endian format.
229 //
230
231 Cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte3;
232 Cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte2;
233 Cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte1;
234 Cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte0;
235
236 Cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&transferBlocks)->Byte1;
237 Cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&transferBlocks)->Byte0;
238
239 //
240 // Set transfer direction flag and Cdb command.
241 //
242
243 if (currentIrpStack->MajorFunction == IRP_MJ_READ)
244 {
245 DPRINT1("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 //
259 // If this is not a write-through request, then allow caching.
260 //
261
262 #if 0
263 if (!(currentIrpStack->Flags & SL_WRITE_THROUGH))
264 {
265 Srb->SrbFlags |= SRB_FLAGS_ADAPTER_CACHE_ENABLE;
266 }
267 else
268 {
269 /* If write caching is enable then force media access in the cdb. */
270 if (deviceExtension->DeviceFlags & DEV_WRITE_CACHE)
271 {
272 Cdb->CDB10.ForceUnitAccess = TRUE;
273 }
274 }
275 #endif
276
277 /* Or in the default flags from the device object. */
278 Srb->SrbFlags |= deviceExtension->SrbFlags;
279
280 //
281 // Set up major SCSI function.
282 //
283
284 nextIrpStack->MajorFunction = IRP_MJ_SCSI;
285
286 //
287 // Save SRB address in next stack for port driver.
288 //
289
290 nextIrpStack->Parameters.Scsi.Srb = Srb;
291
292 //
293 // Save retry count in current IRP stack.
294 //
295 #if 0
296 currentIrpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
297 #endif
298
299 /* Set up IoCompletion routine address. */
300 IoSetCompletionRoutine(Irp,
301 ScsiClassIoComplete,
302 Srb,
303 TRUE,
304 TRUE,
305 TRUE);
306 }
307
308
309 NTSTATUS STDCALL
310 ScsiClassClaimDevice(PDEVICE_OBJECT PortDeviceObject,
311 PSCSI_INQUIRY_DATA LunInfo,
312 BOOLEAN Release,
313 PDEVICE_OBJECT *NewPortDeviceObject OPTIONAL)
314 {
315 PIO_STACK_LOCATION IoStack;
316 IO_STATUS_BLOCK IoStatusBlock;
317 SCSI_REQUEST_BLOCK Srb;
318 KEVENT Event;
319 PIRP Irp;
320 NTSTATUS Status;
321
322 DPRINT1("ScsiClassClaimDevice() called\n");
323
324 if (NewPortDeviceObject != NULL)
325 *NewPortDeviceObject = NULL;
326
327 /* Initialize an SRB */
328 RtlZeroMemory(&Srb,
329 sizeof(SCSI_REQUEST_BLOCK));
330 Srb.Length = SCSI_REQUEST_BLOCK_SIZE;
331 Srb.PathId = LunInfo->PathId;
332 Srb.TargetId = LunInfo->TargetId;
333 Srb.Lun = LunInfo->Lun;
334 Srb.Function =
335 (Release == TRUE) ? SRB_FUNCTION_RELEASE_DEVICE : SRB_FUNCTION_CLAIM_DEVICE;
336
337 KeInitializeEvent(&Event,
338 NotificationEvent,
339 FALSE);
340
341 Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE,
342 PortDeviceObject,
343 NULL,
344 0,
345 NULL,
346 0,
347 TRUE,
348 &Event,
349 &IoStatusBlock);
350 if (Irp == NULL)
351 {
352 DPRINT1("Failed to allocate Irp!\n");
353 return(STATUS_INSUFFICIENT_RESOURCES);
354 }
355
356 /* Link Srb and Irp */
357 IoStack = IoGetNextIrpStackLocation(Irp);
358 IoStack->Parameters.Scsi.Srb = &Srb;
359 Srb.OriginalRequest = Irp;
360
361 /* Call SCSI port driver */
362 Status = IoCallDriver(PortDeviceObject,
363 Irp);
364 if (Status == STATUS_PENDING)
365 {
366 KeWaitForSingleObject(&Event,
367 Suspended,
368 KernelMode,
369 FALSE,
370 NULL);
371 Status = IoStatusBlock.Status;
372 }
373
374 if (Release == TRUE)
375 {
376 ObDereferenceObject(PortDeviceObject);
377 return(STATUS_SUCCESS);
378 }
379
380 // Status = ObReferenceObjectByPointer(Srb.DataBuffer,
381 Status = ObReferenceObjectByPointer(PortDeviceObject,
382 0,
383 NULL,
384 KernelMode);
385
386 if (NewPortDeviceObject != NULL)
387 {
388 // *NewPortDeviceObject = Srb.DataBuffer;
389 *NewPortDeviceObject = PortDeviceObject;
390 }
391
392 return(STATUS_SUCCESS);
393 }
394
395
396 NTSTATUS STDCALL
397 ScsiClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
398 IN PCCHAR ObjectNameBuffer,
399 IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL,
400 IN OUT PDEVICE_OBJECT *DeviceObject,
401 IN PCLASS_INIT_DATA InitializationData)
402 {
403 PDEVICE_OBJECT InternalDeviceObject;
404 PDEVICE_EXTENSION DeviceExtension;
405 ANSI_STRING AnsiName;
406 UNICODE_STRING DeviceName;
407 NTSTATUS Status;
408
409 DPRINT1("ScsiClassCreateDeviceObject() called\n");
410
411 *DeviceObject = NULL;
412
413 RtlInitAnsiString(&AnsiName,
414 ObjectNameBuffer);
415
416 Status = RtlAnsiStringToUnicodeString(&DeviceName,
417 &AnsiName,
418 TRUE);
419 if (!NT_SUCCESS(Status))
420 {
421 return(Status);
422 }
423
424 DPRINT1("Device name: '%wZ'\n", &DeviceName);
425
426 Status = IoCreateDevice(DriverObject,
427 InitializationData->DeviceExtensionSize,
428 &DeviceName,
429 InitializationData->DeviceType,
430 InitializationData->DeviceCharacteristics,
431 FALSE,
432 &InternalDeviceObject);
433 if (NT_SUCCESS(Status))
434 {
435 PDEVICE_EXTENSION deviceExtension = InternalDeviceObject->DeviceExtension;
436
437 DeviceExtension->ClassError = InitializationData->ClassError;
438 DeviceExtension->ClassReadWriteVerification = InitializationData->ClassReadWriteVerification;
439 DeviceExtension->ClassFindDevices = InitializationData->ClassFindDevices;
440 DeviceExtension->ClassDeviceControl = InitializationData->ClassDeviceControl;
441 DeviceExtension->ClassShutdownFlush = InitializationData->ClassShutdownFlush;
442 DeviceExtension->ClassCreateClose = InitializationData->ClassCreateClose;
443 DeviceExtension->ClassStartIo = InitializationData->ClassStartIo;
444
445 DeviceExtension->MediaChangeCount = 0;
446
447 if (PhysicalDeviceObject != NULL)
448 {
449 DeviceExtension->PhysicalDevice = PhysicalDeviceObject;
450 }
451 else
452 {
453 DeviceExtension->PhysicalDevice = InternalDeviceObject;
454 }
455
456 *DeviceObject = InternalDeviceObject;
457 }
458
459 RtlFreeUnicodeString(&DeviceName);
460
461 return(Status);
462 }
463
464
465 NTSTATUS STDCALL
466 ScsiClassDeviceControl(PDEVICE_OBJECT DeviceObject,
467 PIRP Irp)
468 {
469 UNIMPLEMENTED;
470 }
471
472
473 PVOID STDCALL
474 ScsiClassFindModePage(PCHAR ModeSenseBuffer,
475 ULONG Length,
476 UCHAR PageMode,
477 BOOLEAN Use6Byte)
478 {
479 UNIMPLEMENTED;
480 }
481
482
483 ULONG STDCALL
484 ScsiClassFindUnclaimedDevices(PCLASS_INIT_DATA InitializationData,
485 PSCSI_ADAPTER_BUS_INFO AdapterInformation)
486 {
487 PSCSI_INQUIRY_DATA UnitInfo;
488 PINQUIRYDATA InquiryData;
489 PUCHAR Buffer;
490 ULONG Bus;
491 ULONG UnclaimedDevices = 0;
492 NTSTATUS Status;
493
494 DPRINT("ScsiClassFindUnclaimedDevices() called!\n");
495
496 DPRINT("NumberOfBuses: %lu\n",AdapterInformation->NumberOfBuses);
497 Buffer = (PUCHAR)AdapterInformation;
498 for (Bus = 0; Bus < (ULONG)AdapterInformation->NumberOfBuses; Bus++)
499 {
500 DPRINT("Searching bus %lu\n", Bus);
501
502 UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + AdapterInformation->BusData[Bus].InquiryDataOffset);
503
504 while (AdapterInformation->BusData[Bus].InquiryDataOffset)
505 {
506 InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
507
508 DPRINT("Device: '%.8s'\n", InquiryData->VendorId);
509
510 if ((InitializationData->ClassFindDeviceCallBack(InquiryData) == TRUE) &&
511 (UnitInfo->DeviceClaimed == FALSE))
512 {
513 UnclaimedDevices++;
514 }
515
516 if (UnitInfo->NextInquiryDataOffset == 0)
517 break;
518
519 UnitInfo = (PSCSI_INQUIRY_DATA) (Buffer + UnitInfo->NextInquiryDataOffset);
520 }
521 }
522
523 return(UnclaimedDevices);
524 }
525
526
527 NTSTATUS STDCALL
528 ScsiClassGetCapabilities(PDEVICE_OBJECT PortDeviceObject,
529 PIO_SCSI_CAPABILITIES *PortCapabilities)
530 {
531 PIO_SCSI_CAPABILITIES Buffer;
532 IO_STATUS_BLOCK IoStatusBlock;
533 NTSTATUS Status;
534 KEVENT Event;
535 PIRP Irp;
536
537 *PortCapabilities = NULL;
538 Buffer = ExAllocatePool(NonPagedPool, /* FIXME: use paged pool */
539 sizeof(IO_SCSI_CAPABILITIES));
540 if (Buffer == NULL)
541 {
542 return(STATUS_INSUFFICIENT_RESOURCES);
543 }
544
545 KeInitializeEvent(&Event,
546 NotificationEvent,
547 FALSE);
548
549 Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_CAPABILITIES,
550 PortDeviceObject,
551 NULL,
552 0,
553 Buffer,
554 sizeof(IO_SCSI_CAPABILITIES),
555 FALSE,
556 &Event,
557 &IoStatusBlock);
558 if (Irp == NULL)
559 {
560 ExFreePool(Buffer);
561 return(STATUS_INSUFFICIENT_RESOURCES);
562 }
563
564 Status = IoCallDriver(PortDeviceObject,
565 Irp);
566 if (Status == STATUS_PENDING)
567 {
568 KeWaitForSingleObject(&Event,
569 Suspended,
570 KernelMode,
571 FALSE,
572 NULL);
573 Status = IoStatusBlock.Status;
574 }
575
576 if (!NT_SUCCESS(Status))
577 {
578 ExFreePool(Buffer);
579 }
580 else
581 {
582 *PortCapabilities = Buffer;
583 }
584
585 return(Status);
586 }
587
588
589 NTSTATUS STDCALL
590 ScsiClassGetInquiryData(PDEVICE_OBJECT PortDeviceObject,
591 PSCSI_ADAPTER_BUS_INFO *ConfigInfo)
592 {
593 PSCSI_ADAPTER_BUS_INFO Buffer;
594 IO_STATUS_BLOCK IoStatusBlock;
595 NTSTATUS Status;
596 KEVENT Event;
597 PIRP Irp;
598
599 *ConfigInfo = NULL;
600 Buffer = ExAllocatePool(NonPagedPool,
601 INQUIRY_DATA_SIZE);
602 if (Buffer == NULL)
603 {
604 return(STATUS_INSUFFICIENT_RESOURCES);
605 }
606
607 KeInitializeEvent(&Event,
608 NotificationEvent,
609 FALSE);
610
611 Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA,
612 PortDeviceObject,
613 NULL,
614 0,
615 Buffer,
616 INQUIRY_DATA_SIZE,
617 FALSE,
618 &Event,
619 &IoStatusBlock);
620 if (Irp == NULL)
621 {
622 ExFreePool(Buffer);
623 return(STATUS_INSUFFICIENT_RESOURCES);
624 }
625
626 Status = IoCallDriver(PortDeviceObject,
627 Irp);
628 if (Status == STATUS_PENDING)
629 {
630 KeWaitForSingleObject(&Event,
631 Suspended,
632 KernelMode,
633 FALSE,
634 NULL);
635 Status = IoStatusBlock.Status;
636 }
637
638 if (!NT_SUCCESS(Status))
639 {
640 ExFreePool(Buffer);
641 }
642 else
643 {
644 *ConfigInfo = Buffer;
645 }
646
647 return(Status);
648 }
649
650
651 ULONG STDCALL
652 ScsiClassInitialize(PVOID Argument1,
653 PVOID Argument2,
654 PCLASS_INIT_DATA InitializationData)
655 {
656 PCONFIGURATION_INFORMATION ConfigInfo;
657 PDRIVER_OBJECT DriverObject = Argument1;
658 WCHAR NameBuffer[80];
659 UNICODE_STRING PortName;
660 ULONG PortNumber;
661 PDEVICE_OBJECT PortDeviceObject;
662 PFILE_OBJECT FileObject;
663 BOOLEAN DiskFound = FALSE;
664 NTSTATUS Status;
665
666 DPRINT("ScsiClassInitialize() called!\n");
667
668 DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiClassCreateClose;
669 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiClassCreateClose;
670 DriverObject->MajorFunction[IRP_MJ_READ] = ScsiClassReadWrite;
671 DriverObject->MajorFunction[IRP_MJ_WRITE] = ScsiClassReadWrite;
672 DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiClassScsiDispatch;
673 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiClassDeviceDispatch;
674 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = ScsiClassShutdownFlush;
675 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = ScsiClassShutdownFlush;
676 if (InitializationData->ClassStartIo)
677 {
678 DriverObject->DriverStartIo = InitializationData->ClassStartIo;
679 }
680
681 ConfigInfo = IoGetConfigurationInformation();
682
683 /* look for ScsiPortX scsi port devices */
684 for (PortNumber = 0; PortNumber < ConfigInfo->ScsiPortCount; PortNumber++)
685 {
686 swprintf(NameBuffer,
687 L"\\Device\\ScsiPort%lu",
688 PortNumber);
689 RtlInitUnicodeString(&PortName,
690 NameBuffer);
691 DPRINT("Checking scsi port %ld\n", PortNumber);
692 Status = IoGetDeviceObjectPointer(&PortName,
693 FILE_READ_ATTRIBUTES,
694 &FileObject,
695 &PortDeviceObject);
696 DPRINT("Status 0x%08lX\n", Status);
697 if (NT_SUCCESS(Status))
698 {
699 DPRINT1("ScsiPort%lu found.\n", PortNumber);
700
701 /* Check scsi port for attached disk drives */
702 if (InitializationData->ClassFindDevices(DriverObject,
703 Argument2,
704 InitializationData,
705 PortDeviceObject,
706 PortNumber))
707 {
708 DiskFound = TRUE;
709 }
710 }
711 }
712
713 DPRINT("ScsiClassInitialize() done!\n");
714 for(;;);
715
716 return((DiskFound == TRUE) ? STATUS_SUCCESS : STATUS_NO_SUCH_DEVICE);
717 }
718
719
720 VOID STDCALL
721 ScsiClassInitializeSrbLookasideList(PDEVICE_EXTENSION DeviceExtension,
722 ULONG NumberElements)
723 {
724 UNIMPLEMENTED;
725 }
726
727
728 NTSTATUS STDCALL
729 ScsiClassInternalIoControl(PDEVICE_OBJECT DeviceObject,
730 PIRP Irp)
731 {
732 UNIMPLEMENTED;
733 }
734
735
736 BOOLEAN STDCALL
737 ScsiClassInterpretSenseInfo(PDEVICE_OBJECT DeviceObject,
738 PSCSI_REQUEST_BLOCK Srb,
739 UCHAR MajorFunctionCode,
740 ULONG IoDeviceCode,
741 ULONG RetryCount,
742 NTSTATUS *Status)
743 {
744 UNIMPLEMENTED;
745 }
746
747
748 NTSTATUS STDCALL
749 ScsiClassIoComplete(PDEVICE_OBJECT DeviceObject,
750 PIRP Irp,
751 PVOID Context)
752 {
753 DPRINT1("ScsiClassIoComplete() called\n");
754
755 if (Irp->PendingReturned)
756 {
757 IoMarkIrpPending(Irp);
758 }
759
760 return(Irp->IoStatus.Status);
761 }
762
763
764 NTSTATUS STDCALL
765 ScsiClassIoCompleteAssociated(PDEVICE_OBJECT DeviceObject,
766 PIRP Irp,
767 PVOID Context)
768 {
769 UNIMPLEMENTED;
770 }
771
772
773 ULONG STDCALL
774 ScsiClassModeSense(PDEVICE_OBJECT DeviceObject,
775 CHAR ModeSenseBuffer,
776 ULONG Length,
777 UCHAR PageMode)
778 {
779 UNIMPLEMENTED;
780 }
781
782
783 ULONG STDCALL
784 ScsiClassQueryTimeOutRegistryValue(IN PUNICODE_STRING RegistryPath)
785 {
786 UNIMPLEMENTED;
787 }
788
789
790 NTSTATUS STDCALL
791 ScsiClassReadDriveCapacity(IN PDEVICE_OBJECT DeviceObject)
792 {
793 PDEVICE_EXTENSION DeviceExtension;
794 PREAD_CAPACITY_DATA CapacityBuffer;
795 SCSI_REQUEST_BLOCK Srb;
796 PCDB Cdb;
797 NTSTATUS Status;
798 ULONG LastSector;
799 ULONG SectorSize;
800
801 DPRINT1("ScsiClassReadDriveCapacity() called\n");
802
803 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
804
805 CapacityBuffer = ExAllocatePool(NonPagedPool, //NonPagedPoolCacheAligned,
806 sizeof(READ_CAPACITY_DATA));
807 if (CapacityBuffer == NULL)
808 {
809 return(STATUS_INSUFFICIENT_RESOURCES);
810 }
811
812 RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
813
814 Srb.CdbLength = 10;
815 Srb.TimeOutValue = DeviceExtension->TimeOutValue;
816
817 Cdb = (PCDB)Srb.Cdb;
818 Cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
819
820
821 Status = ScsiClassSendSrbSynchronous(DeviceObject,
822 &Srb,
823 CapacityBuffer,
824 sizeof(READ_CAPACITY_DATA),
825 FALSE);
826 DPRINT("Status: %lx\n", Status);
827 DPRINT("Srb: %p\n", &Srb);
828 if (NT_SUCCESS(Status))
829 {
830 SectorSize = (((PUCHAR)&CapacityBuffer->BytesPerBlock)[0] << 24) |
831 (((PUCHAR)&CapacityBuffer->BytesPerBlock)[1] << 16) |
832 (((PUCHAR)&CapacityBuffer->BytesPerBlock)[2] << 8) |
833 ((PUCHAR)&CapacityBuffer->BytesPerBlock)[3];
834
835
836 LastSector = (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[0] << 24) |
837 (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[1] << 16) |
838 (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[2] << 8) |
839 ((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[3];
840
841 DeviceExtension->DiskGeometry->BytesPerSector = SectorSize;
842
843 DeviceExtension->PartitionLength.QuadPart = (LONGLONG)(LastSector + 1);
844 WHICH_BIT(DeviceExtension->DiskGeometry->BytesPerSector, DeviceExtension->SectorShift);
845 DeviceExtension->PartitionLength.QuadPart =
846 (DeviceExtension->PartitionLength.QuadPart << DeviceExtension->SectorShift);
847
848 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
849 {
850 DeviceExtension->DiskGeometry->MediaType = RemovableMedia;
851 }
852 else
853 {
854 DeviceExtension->DiskGeometry->MediaType = FixedMedia;
855 }
856 DeviceExtension->DiskGeometry->Cylinders.QuadPart = (LONGLONG)((LastSector + 1)/(32 * 64));
857 DeviceExtension->DiskGeometry->SectorsPerTrack = 32;
858 DeviceExtension->DiskGeometry->TracksPerCylinder = 64;
859
860 DPRINT1("SectorSize: %lu SectorCount: %lu\n", SectorSize, LastSector + 1);
861 }
862
863 ExFreePool(CapacityBuffer);
864
865 DPRINT1("ScsiClassReadDriveCapacity() done\n");
866
867 return(Status);
868 }
869
870
871 VOID STDCALL
872 ScsiClassReleaseQueue(IN PDEVICE_OBJECT DeviceObject)
873 {
874 UNIMPLEMENTED;
875 }
876
877
878 NTSTATUS STDCALL
879 ScsiClassSendSrbAsynchronous(PDEVICE_OBJECT DeviceObject,
880 PSCSI_REQUEST_BLOCK Srb,
881 PIRP Irp,
882 PVOID BufferAddress,
883 ULONG BufferLength,
884 BOOLEAN WriteToDevice)
885 {
886 UNIMPLEMENTED;
887 }
888
889
890 NTSTATUS STDCALL
891 ScsiClassSendSrbSynchronous(PDEVICE_OBJECT DeviceObject,
892 PSCSI_REQUEST_BLOCK Srb,
893 PVOID BufferAddress,
894 ULONG BufferLength,
895 BOOLEAN WriteToDevice)
896 {
897 PDEVICE_EXTENSION DeviceExtension;
898 IO_STATUS_BLOCK IoStatusBlock;
899 PIO_STACK_LOCATION IoStack;
900 ULONG RequestType;
901 KEVENT Event;
902 PIRP Irp;
903 NTSTATUS Status;
904
905
906 DPRINT1("ScsiClassSendSrbSynchronous() called\n");
907
908 DeviceExtension = DeviceObject->DeviceExtension;
909
910 Srb->PathId = DeviceExtension->PathId;
911 Srb->TargetId = DeviceExtension->TargetId;
912 Srb->Lun = DeviceExtension->Lun;
913 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
914
915 /* FIXME: more srb initialization required? */
916
917
918 if (BufferAddress == NULL)
919 {
920 BufferLength = 0;
921 RequestType = IOCTL_SCSI_EXECUTE_NONE;
922 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
923 }
924 else
925 {
926 if (WriteToDevice == TRUE)
927 {
928 RequestType = IOCTL_SCSI_EXECUTE_OUT;
929 Srb->SrbFlags = SRB_FLAGS_DATA_OUT;
930 }
931 else
932 {
933 RequestType = IOCTL_SCSI_EXECUTE_IN;
934 Srb->SrbFlags = SRB_FLAGS_DATA_IN;
935 }
936 }
937
938 Srb->DataTransferLength = BufferLength;
939 Srb->DataBuffer = BufferAddress;
940
941
942 KeInitializeEvent(&Event,
943 NotificationEvent,
944 FALSE);
945
946 Irp = IoBuildDeviceIoControlRequest(RequestType,
947 DeviceExtension->PortDeviceObject,
948 NULL,
949 0,
950 BufferAddress,
951 BufferLength,
952 TRUE,
953 &Event,
954 &IoStatusBlock);
955 if (Irp == NULL)
956 {
957 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
958 return(STATUS_INSUFFICIENT_RESOURCES);
959 }
960
961 /* FIXME: more irp initialization required? */
962
963
964 /* Attach Srb to the Irp */
965 IoStack = IoGetNextIrpStackLocation(Irp);
966 IoStack->Parameters.Scsi.Srb = Srb;
967 Srb->OriginalRequest = Irp;
968
969
970 /* Call the SCSI port driver */
971 Status = IoCallDriver(DeviceExtension->PortDeviceObject,
972 Irp);
973 if (Status == STATUS_PENDING)
974 {
975 KeWaitForSingleObject(&Event,
976 Suspended,
977 KernelMode,
978 FALSE,
979 NULL);
980 }
981
982 if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS)
983 {
984
985 }
986 else
987 {
988 Status = STATUS_SUCCESS;
989 }
990
991 DPRINT1("ScsiClassSendSrbSynchronous() done\n");
992
993 return(Status);
994 }
995
996
997 VOID STDCALL
998 ScsiClassSplitRequest(PDEVICE_OBJECT DeviceObject,
999 PIRP Irp,
1000 ULONG MaximumBytes)
1001 {
1002 UNIMPLEMENTED;
1003 }
1004
1005
1006 /* INTERNAL FUNCTIONS *******************************************************/
1007
1008 static NTSTATUS STDCALL
1009 ScsiClassCreateClose(IN PDEVICE_OBJECT DeviceObject,
1010 IN PIRP Irp)
1011 {
1012 PDEVICE_EXTENSION DeviceExtension;
1013
1014 DPRINT("ScsiClassCreateClose() called\n");
1015
1016 DeviceExtension = DeviceObject->DeviceExtension;
1017
1018 if (DeviceExtension->ClassCreateClose)
1019 return(DeviceExtension->ClassCreateClose(DeviceObject,
1020 Irp));
1021
1022 Irp->IoStatus.Status = STATUS_SUCCESS;
1023 Irp->IoStatus.Information = 0;
1024 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1025
1026 return(STATUS_SUCCESS);
1027 }
1028
1029
1030 static NTSTATUS STDCALL
1031 ScsiClassReadWrite(IN PDEVICE_OBJECT DeviceObject,
1032 IN PIRP Irp)
1033 {
1034 PDEVICE_EXTENSION DeviceExtension;
1035 PIO_STACK_LOCATION IrpStack;
1036 ULONG TransferLength;
1037 ULONG TransferPages;
1038 NTSTATUS Status;
1039
1040 DPRINT1("ScsiClassReadWrite() called\n");
1041
1042 DeviceExtension = DeviceObject->DeviceExtension;
1043 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1044
1045 TransferLength = IrpStack->Parameters.Read.Length;
1046
1047
1048
1049 if ((DeviceObject->Flags & DO_VERIFY_VOLUME) &&
1050 !(IrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME))
1051 {
1052 IoSetHardErrorOrVerifyDevice(Irp,
1053 DeviceObject);
1054
1055 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
1056 Irp->IoStatus.Information = 0;
1057
1058 IoCompleteRequest(Irp,
1059 IO_NO_INCREMENT);
1060 return(STATUS_VERIFY_REQUIRED);
1061 }
1062
1063 #if 0
1064 /* let the class driver perform its verification */
1065 Status = DeviceExtension->ClassReadWriteVerification(DeviceObject,
1066 Irp);
1067 if (!NT_SUCCESS(Status))
1068 {
1069 IoCompleteRequest(Irp,
1070 IO_NO_INCREMENT);
1071 return(Status);
1072 }
1073 else if (Status == STATUS_PENDING)
1074 {
1075 IoMarkIrpPending(Irp);
1076 return(STATUS_PENDING);
1077 }
1078 #endif
1079
1080 /* Finish a zero-byte transfer. */
1081 if (TransferLength == 0)
1082 {
1083 Irp->IoStatus.Status = STATUS_SUCCESS;
1084 Irp->IoStatus.Information = 0;
1085 IoCompleteRequest(Irp,
1086 IO_NO_INCREMENT);
1087 return(STATUS_SUCCESS);
1088 }
1089
1090 if (DeviceExtension->ClassStartIo != NULL)
1091 {
1092 IoMarkIrpPending(Irp);
1093 IoStartPacket(DeviceObject,
1094 Irp,
1095 NULL,
1096 NULL);
1097
1098 return(STATUS_PENDING);
1099 }
1100
1101 IoMarkIrpPending(Irp);
1102
1103 /* Adjust partition-relative starting offset to absolute offset */
1104 IrpStack->Parameters.Read.ByteOffset.QuadPart += DeviceExtension->StartingOffset.QuadPart;
1105
1106 /* Calculate number of pages in this transfer. */
1107 TransferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
1108 IrpStack->Parameters.Read.Length);
1109
1110 #if 0
1111 if (IrpStack->Parameters.Read.Length > maximumTransferLength ||
1112 TransferPages > DeviceExtension->PortCapabilities->MaximumPhysicalPages)
1113 {
1114
1115 }
1116 #endif
1117
1118 ScsiClassBuildRequest(DeviceObject,
1119 Irp);
1120
1121 DPRINT1("ScsiClassReadWrite() done\n");
1122
1123 /* Call the port driver */
1124 return(IoCallDriver(DeviceExtension->PortDeviceObject,
1125 Irp));
1126 }
1127
1128
1129 static NTSTATUS STDCALL
1130 ScsiClassScsiDispatch(IN PDEVICE_OBJECT DeviceObject,
1131 IN PIRP Irp)
1132 {
1133 DPRINT1("ScsiClassScsiDispatch() called\n");
1134
1135 Irp->IoStatus.Status = STATUS_SUCCESS;
1136 Irp->IoStatus.Information = 0;
1137 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1138
1139 return(STATUS_SUCCESS);
1140 }
1141
1142
1143 static NTSTATUS STDCALL
1144 ScsiClassDeviceDispatch(IN PDEVICE_OBJECT DeviceObject,
1145 IN PIRP Irp)
1146 {
1147 DPRINT1("ScsiClassDeviceDispatch() called\n");
1148
1149 Irp->IoStatus.Status = STATUS_SUCCESS;
1150 Irp->IoStatus.Information = 0;
1151 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1152
1153 return(STATUS_SUCCESS);
1154 }
1155
1156
1157 static NTSTATUS STDCALL
1158 ScsiClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
1159 IN PIRP Irp)
1160 {
1161 DPRINT1("ScsiClassShutdownFlush() called\n");
1162
1163 Irp->IoStatus.Status = STATUS_SUCCESS;
1164 Irp->IoStatus.Information = 0;
1165 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1166
1167 return(STATUS_SUCCESS);
1168 }
1169
1170 /* EOF */