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