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