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