43757f7b990c02db76e9cff67da5b60e30ed057a
[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.14 2002/03/25 21:55:51 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 TAG_SRBT TAG('S', 'r', 'b', 'T')
46
47 #define INQUIRY_DATA_SIZE 2048
48
49
50 static NTSTATUS STDCALL
51 ScsiClassCreateClose(IN PDEVICE_OBJECT DeviceObject,
52 IN PIRP Irp);
53
54 static NTSTATUS STDCALL
55 ScsiClassReadWrite(IN PDEVICE_OBJECT DeviceObject,
56 IN PIRP Irp);
57
58 static NTSTATUS STDCALL
59 ScsiClassScsiDispatch(IN PDEVICE_OBJECT DeviceObject,
60 IN PIRP Irp);
61
62 static NTSTATUS STDCALL
63 ScsiClassDeviceDispatch(IN PDEVICE_OBJECT DeviceObject,
64 IN PIRP Irp);
65
66 static NTSTATUS STDCALL
67 ScsiClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
68 IN PIRP Irp);
69
70
71 /* FUNCTIONS ****************************************************************/
72
73 // DriverEntry
74 //
75 // DESCRIPTION:
76 // This function initializes the driver.
77 //
78 // RUN LEVEL:
79 // PASSIVE_LEVEL
80 //
81 // ARGUMENTS:
82 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
83 // for this driver
84 // IN PUNICODE_STRING RegistryPath Name of registry driver service
85 // key
86 //
87 // RETURNS:
88 // NTSTATUS
89
90 NTSTATUS STDCALL
91 DriverEntry(IN PDRIVER_OBJECT DriverObject,
92 IN PUNICODE_STRING RegistryPath)
93 {
94 DbgPrint("Class Driver %s\n", VERSION);
95 return(STATUS_SUCCESS);
96 }
97
98
99 VOID
100 ScsiClassDebugPrint(IN ULONG DebugPrintLevel,
101 IN PCHAR DebugMessage,
102 ...)
103 {
104 char Buffer[256];
105 va_list ap;
106
107 #if 0
108 if (DebugPrintLevel > InternalDebugLevel)
109 return;
110 #endif
111
112 va_start(ap, DebugMessage);
113 vsprintf(Buffer, DebugMessage, ap);
114 va_end(ap);
115
116 DbgPrint(Buffer);
117 }
118
119
120 NTSTATUS STDCALL
121 ScsiClassAsynchronousCompletion(IN PDEVICE_OBJECT DeviceObject,
122 IN PIRP Irp,
123 IN PVOID Context)
124 {
125 UNIMPLEMENTED;
126 }
127
128
129 VOID STDCALL
130 ScsiClassBuildRequest(PDEVICE_OBJECT DeviceObject,
131 PIRP Irp)
132 {
133 PDEVICE_EXTENSION DeviceExtension;
134 PIO_STACK_LOCATION CurrentIrpStack;
135 PIO_STACK_LOCATION NextIrpStack;
136 LARGE_INTEGER StartingOffset;
137 LARGE_INTEGER StartingBlock;
138 PSCSI_REQUEST_BLOCK Srb;
139 PCDB Cdb;
140 ULONG LogicalBlockAddress;
141 USHORT TransferBlocks;
142
143 DeviceExtension = DeviceObject->DeviceExtension;
144 CurrentIrpStack = IoGetCurrentIrpStackLocation(Irp);
145 NextIrpStack = IoGetNextIrpStackLocation(Irp);
146 StartingOffset = CurrentIrpStack->Parameters.Read.ByteOffset;
147
148 /* Calculate logical block address */
149 StartingBlock.QuadPart = StartingOffset.QuadPart >> DeviceExtension->SectorShift;
150 LogicalBlockAddress = (ULONG)StartingBlock.u.LowPart;
151
152 DPRINT("Logical block address: %lu\n", LogicalBlockAddress);
153
154 /* Allocate and initialize an SRB */
155 /* FIXME: use lookaside list instead */
156 Srb = ExAllocatePool(NonPagedPool,
157 sizeof(SCSI_REQUEST_BLOCK));
158
159 Srb->SrbFlags = 0;
160 Srb->Length = sizeof(SCSI_REQUEST_BLOCK); //SCSI_REQUEST_BLOCK_SIZE;
161 Srb->OriginalRequest = Irp;
162 Srb->PathId = DeviceExtension->PathId;
163 Srb->TargetId = DeviceExtension->TargetId;
164 Srb->Lun = DeviceExtension->Lun;
165 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
166 Srb->DataBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
167 Srb->DataTransferLength = CurrentIrpStack->Parameters.Read.Length;
168 Srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
169 Srb->QueueSortKey = LogicalBlockAddress;
170
171 Srb->SenseInfoBuffer = DeviceExtension->SenseData;
172 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
173
174 Srb->TimeOutValue =
175 ((Srb->DataTransferLength + 0xFFFF) >> 16) * DeviceExtension->TimeOutValue;
176
177 Srb->SrbStatus = SRB_STATUS_SUCCESS;
178 Srb->ScsiStatus = 0;
179 Srb->NextSrb = 0;
180
181 Srb->CdbLength = 10;
182 Cdb = (PCDB)Srb->Cdb;
183
184 /* Initialize ATAPI packet (12 bytes) */
185 RtlZeroMemory(Cdb,
186 MAXIMUM_CDB_SIZE);
187
188 Cdb->CDB10.LogicalUnitNumber = DeviceExtension->Lun;
189 TransferBlocks = (USHORT)(CurrentIrpStack->Parameters.Read.Length >> DeviceExtension->SectorShift);
190
191 /* Copy little endian values into CDB in big endian format */
192 Cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte3;
193 Cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte2;
194 Cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte1;
195 Cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte0;
196
197 Cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&TransferBlocks)->Byte1;
198 Cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&TransferBlocks)->Byte0;
199
200
201 if (CurrentIrpStack->MajorFunction == IRP_MJ_READ)
202 {
203 DPRINT("ScsiClassBuildRequest: Read Command\n");
204
205 Srb->SrbFlags |= SRB_FLAGS_DATA_IN;
206 Cdb->CDB10.OperationCode = SCSIOP_READ;
207 }
208 else
209 {
210 DPRINT("ScsiClassBuildRequest: Write Command\n");
211
212 Srb->SrbFlags |= SRB_FLAGS_DATA_OUT;
213 Cdb->CDB10.OperationCode = SCSIOP_WRITE;
214 }
215
216
217 #if 0
218 /* if this is not a write-through request, then allow caching */
219 if (!(CurrentIrpStack->Flags & SL_WRITE_THROUGH))
220 {
221 Srb->SrbFlags |= SRB_FLAGS_ADAPTER_CACHE_ENABLE;
222 }
223 else
224 {
225 /* if write caching is enable then force media access in the cdb */
226 if (DeviceExtension->DeviceFlags & DEV_WRITE_CACHE)
227 {
228 Cdb->CDB10.ForceUnitAccess = TRUE;
229 }
230 }
231 #endif
232
233 /* Update srb flags */
234 Srb->SrbFlags |= DeviceExtension->SrbFlags;
235
236
237 NextIrpStack->MajorFunction = IRP_MJ_SCSI;
238 NextIrpStack->Parameters.Scsi.Srb = Srb;
239 NextIrpStack->DeviceObject = DeviceObject;
240
241 /* Save retry count in current IRP stack */
242 CurrentIrpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
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 /**********************************************************************
675 * NAME EXPORTED
676 * ScsiClassInitializeSrbLookasideList
677 *
678 * DESCRIPTION
679 * Initializes a lookaside list for SRBs.
680 *
681 * RUN LEVEL
682 * PASSIVE_LEVEL
683 *
684 * ARGUMENTS
685 * DeviceExtension
686 * Class specific device extension.
687 *
688 * NumberElements
689 * Maximum number of elements of the lookaside list.
690 *
691 * RETURN VALUE
692 * None.
693 */
694
695 VOID STDCALL
696 ScsiClassInitializeSrbLookasideList(PDEVICE_EXTENSION DeviceExtension,
697 ULONG NumberElements)
698 {
699 ExInitializeNPagedLookasideList(&DeviceExtension->SrbLookasideListHead,
700 NULL,
701 NULL,
702 NonPagedPool,
703 sizeof(SCSI_REQUEST_BLOCK),
704 TAG_SRBT,
705 (USHORT)NumberElements);
706 }
707
708
709 NTSTATUS STDCALL
710 ScsiClassInternalIoControl(PDEVICE_OBJECT DeviceObject,
711 PIRP Irp)
712 {
713 UNIMPLEMENTED;
714 }
715
716
717 BOOLEAN STDCALL
718 ScsiClassInterpretSenseInfo(PDEVICE_OBJECT DeviceObject,
719 PSCSI_REQUEST_BLOCK Srb,
720 UCHAR MajorFunctionCode,
721 ULONG IoDeviceCode,
722 ULONG RetryCount,
723 NTSTATUS *Status)
724 {
725
726 DPRINT1("ScsiClassInterpretSenseInfo() called\n");
727
728 DPRINT1("Srb->SrbStatus %lx\n", Srb->SrbStatus);
729
730 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_PENDING)
731 {
732 *Status = STATUS_SUCCESS;
733 }
734 else
735 {
736 *Status = STATUS_UNSUCCESSFUL;
737 }
738
739 DPRINT1("ScsiClassInterpretSenseInfo() done\n");
740
741 return(FALSE);
742 }
743
744
745 NTSTATUS STDCALL
746 ScsiClassIoComplete(PDEVICE_OBJECT DeviceObject,
747 PIRP Irp,
748 PVOID Context)
749 {
750 PDEVICE_EXTENSION DeviceExtension;
751 PIO_STACK_LOCATION IrpStack;
752 PSCSI_REQUEST_BLOCK Srb;
753 BOOLEAN Retry;
754 NTSTATUS Status;
755
756 DPRINT("ScsiClassIoComplete(DeviceObject %p Irp %p Context %p) called\n",
757 DeviceObject, Irp, Context);
758
759 DeviceExtension = DeviceObject->DeviceExtension;
760 Srb = (PSCSI_REQUEST_BLOCK)Context;
761 DPRINT("Srb %p\n", Srb);
762
763 IrpStack = IoGetCurrentIrpStackLocation(Irp);
764
765 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
766 {
767 Status = STATUS_SUCCESS;
768 }
769 else
770 {
771 Retry = ScsiClassInterpretSenseInfo(DeviceObject,
772 Srb,
773 IrpStack->MajorFunction,
774 0,
775 MAXIMUM_RETRIES - ((ULONG)IrpStack->Parameters.Others.Argument4),
776 &Status);
777 #if 0
778 irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? irpStack->Parameters.DeviceIoControl.IoControlCode : 0,
779
780 #endif
781
782 if (Retry == TRUE)
783 {
784 /* FIXME!! */
785 DPRINT1("Should try again!\n");
786
787 }
788 }
789
790 /* FIXME: use lookaside list instead */
791 DPRINT("Freed SRB %p\n", IrpStack->Parameters.Scsi.Srb);
792 ExFreePool(IrpStack->Parameters.Scsi.Srb);
793
794 Irp->IoStatus.Status = Status;
795 #if 0
796 if (!NT_SUCCESS(Status) &&
797 IoIsErrorUserInduced(Status))
798 {
799 IoSetHardErrorOrVerifyDevice(Irp,
800 DeviceObject);
801 Irp->IoStatus.Information = 0;
802 }
803
804 if (Irp->PendingReturned)
805 {
806 IoMarkIrpPending(Irp);
807 }
808 #endif
809
810 if (DeviceExtension->ClassStartIo != NULL)
811 {
812 if (IrpStack->MajorFunction != IRP_MJ_DEVICE_CONTROL)
813 {
814 IoStartNextPacket(DeviceObject,
815 FALSE);
816 }
817 }
818
819 DPRINT("ScsiClassIoComplete() done (Status %lx)\n", Status);
820
821 return(Status);
822 }
823
824
825 NTSTATUS STDCALL
826 ScsiClassIoCompleteAssociated(PDEVICE_OBJECT DeviceObject,
827 PIRP Irp,
828 PVOID Context)
829 {
830 UNIMPLEMENTED;
831 }
832
833
834 ULONG STDCALL
835 ScsiClassModeSense(PDEVICE_OBJECT DeviceObject,
836 CHAR ModeSenseBuffer,
837 ULONG Length,
838 UCHAR PageMode)
839 {
840 UNIMPLEMENTED;
841 }
842
843
844 ULONG STDCALL
845 ScsiClassQueryTimeOutRegistryValue(IN PUNICODE_STRING RegistryPath)
846 {
847 UNIMPLEMENTED;
848 }
849
850
851 NTSTATUS STDCALL
852 ScsiClassReadDriveCapacity(IN PDEVICE_OBJECT DeviceObject)
853 {
854 PDEVICE_EXTENSION DeviceExtension;
855 PREAD_CAPACITY_DATA CapacityBuffer;
856 SCSI_REQUEST_BLOCK Srb;
857 PCDB Cdb;
858 NTSTATUS Status;
859 ULONG LastSector;
860 ULONG SectorSize;
861
862 DPRINT("ScsiClassReadDriveCapacity() called\n");
863
864 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
865
866 CapacityBuffer = ExAllocatePool(NonPagedPool,
867 sizeof(READ_CAPACITY_DATA));
868 if (CapacityBuffer == NULL)
869 {
870 return(STATUS_INSUFFICIENT_RESOURCES);
871 }
872
873 RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
874
875 Srb.CdbLength = 10;
876 Srb.TimeOutValue = DeviceExtension->TimeOutValue;
877
878 Cdb = (PCDB)Srb.Cdb;
879 Cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
880
881
882 Status = ScsiClassSendSrbSynchronous(DeviceObject,
883 &Srb,
884 CapacityBuffer,
885 sizeof(READ_CAPACITY_DATA),
886 FALSE);
887 DPRINT("Status: %lx\n", Status);
888 DPRINT("Srb: %p\n", &Srb);
889 if (NT_SUCCESS(Status))
890 {
891 SectorSize = (((PUCHAR)&CapacityBuffer->BytesPerBlock)[0] << 24) |
892 (((PUCHAR)&CapacityBuffer->BytesPerBlock)[1] << 16) |
893 (((PUCHAR)&CapacityBuffer->BytesPerBlock)[2] << 8) |
894 ((PUCHAR)&CapacityBuffer->BytesPerBlock)[3];
895
896
897 LastSector = (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[0] << 24) |
898 (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[1] << 16) |
899 (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[2] << 8) |
900 ((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[3];
901
902 DeviceExtension->DiskGeometry->BytesPerSector = SectorSize;
903
904 DeviceExtension->PartitionLength.QuadPart = (LONGLONG)(LastSector + 1);
905 WHICH_BIT(DeviceExtension->DiskGeometry->BytesPerSector,
906 DeviceExtension->SectorShift);
907 DeviceExtension->PartitionLength.QuadPart =
908 (DeviceExtension->PartitionLength.QuadPart << DeviceExtension->SectorShift);
909
910 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
911 {
912 DeviceExtension->DiskGeometry->MediaType = RemovableMedia;
913 }
914 else
915 {
916 DeviceExtension->DiskGeometry->MediaType = FixedMedia;
917 }
918 DeviceExtension->DiskGeometry->Cylinders.QuadPart = (LONGLONG)((LastSector + 1)/(32 * 64));
919 DeviceExtension->DiskGeometry->SectorsPerTrack = 32;
920 DeviceExtension->DiskGeometry->TracksPerCylinder = 64;
921
922 DPRINT("SectorSize: %lu SectorCount: %lu\n", SectorSize, LastSector + 1);
923 }
924 else
925 {
926 /* Use default values if disk geometry cannot be read */
927 RtlZeroMemory(&DeviceExtension->DiskGeometry,
928 sizeof(DISK_GEOMETRY));
929 DeviceExtension->DiskGeometry->BytesPerSector = 512;
930 DeviceExtension->SectorShift = 9;
931 DeviceExtension->PartitionLength.QuadPart = 0;
932
933 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
934 {
935 DeviceExtension->DiskGeometry->MediaType = RemovableMedia;
936 }
937 else
938 {
939 DeviceExtension->DiskGeometry->MediaType = FixedMedia;
940 }
941 }
942
943 ExFreePool(CapacityBuffer);
944
945 DPRINT("ScsiClassReadDriveCapacity() done\n");
946
947 return(Status);
948 }
949
950
951 VOID STDCALL
952 ScsiClassReleaseQueue(IN PDEVICE_OBJECT DeviceObject)
953 {
954 UNIMPLEMENTED;
955 }
956
957
958 NTSTATUS STDCALL
959 ScsiClassSendSrbAsynchronous(PDEVICE_OBJECT DeviceObject,
960 PSCSI_REQUEST_BLOCK Srb,
961 PIRP Irp,
962 PVOID BufferAddress,
963 ULONG BufferLength,
964 BOOLEAN WriteToDevice)
965 {
966 UNIMPLEMENTED;
967 }
968
969
970 NTSTATUS STDCALL
971 ScsiClassSendSrbSynchronous(PDEVICE_OBJECT DeviceObject,
972 PSCSI_REQUEST_BLOCK Srb,
973 PVOID BufferAddress,
974 ULONG BufferLength,
975 BOOLEAN WriteToDevice)
976 {
977 PDEVICE_EXTENSION DeviceExtension;
978 IO_STATUS_BLOCK IoStatusBlock;
979 PIO_STACK_LOCATION IoStack;
980 ULONG RequestType;
981 BOOLEAN Retry;
982 ULONG RetryCount;
983 KEVENT Event;
984 PIRP Irp;
985 NTSTATUS Status;
986
987
988 DPRINT("ScsiClassSendSrbSynchronous() called\n");
989
990 RetryCount = MAXIMUM_RETRIES;
991 DeviceExtension = DeviceObject->DeviceExtension;
992
993 Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
994 Srb->PathId = DeviceExtension->PathId;
995 Srb->TargetId = DeviceExtension->TargetId;
996 Srb->Lun = DeviceExtension->Lun;
997 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
998
999 /* FIXME: more srb initialization required? */
1000
1001 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1002 Srb->SenseInfoBuffer = ExAllocatePool(NonPagedPool,
1003 SENSE_BUFFER_SIZE);
1004 if (Srb->SenseInfoBuffer == NULL)
1005 return(STATUS_INSUFFICIENT_RESOURCES);
1006
1007 if (BufferAddress == NULL)
1008 {
1009 BufferLength = 0;
1010 RequestType = IOCTL_SCSI_EXECUTE_NONE;
1011 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
1012 }
1013 else
1014 {
1015 if (WriteToDevice == TRUE)
1016 {
1017 RequestType = IOCTL_SCSI_EXECUTE_OUT;
1018 Srb->SrbFlags = SRB_FLAGS_DATA_OUT;
1019 }
1020 else
1021 {
1022 RequestType = IOCTL_SCSI_EXECUTE_IN;
1023 Srb->SrbFlags = SRB_FLAGS_DATA_IN;
1024 }
1025 }
1026
1027 Srb->DataTransferLength = BufferLength;
1028 Srb->DataBuffer = BufferAddress;
1029
1030
1031 KeInitializeEvent(&Event,
1032 NotificationEvent,
1033 FALSE);
1034
1035 Irp = IoBuildDeviceIoControlRequest(RequestType,
1036 DeviceExtension->PortDeviceObject,
1037 NULL,
1038 0,
1039 BufferAddress,
1040 BufferLength,
1041 TRUE,
1042 &Event,
1043 &IoStatusBlock);
1044 if (Irp == NULL)
1045 {
1046 DPRINT1("IoBuildDeviceIoControlRequest() failed\n");
1047 ExFreePool(Srb->SenseInfoBuffer);
1048 return(STATUS_INSUFFICIENT_RESOURCES);
1049 }
1050
1051 /* FIXME: more irp initialization required? */
1052
1053
1054 /* Attach Srb to the Irp */
1055 IoStack = IoGetNextIrpStackLocation(Irp);
1056 IoStack->Parameters.Scsi.Srb = Srb;
1057 Srb->OriginalRequest = Irp;
1058
1059
1060 /* Call the SCSI port driver */
1061 Status = IoCallDriver(DeviceExtension->PortDeviceObject,
1062 Irp);
1063 if (Status == STATUS_PENDING)
1064 {
1065 KeWaitForSingleObject(&Event,
1066 Suspended,
1067 KernelMode,
1068 FALSE,
1069 NULL);
1070 }
1071
1072 if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS)
1073 {
1074 Retry = ScsiClassInterpretSenseInfo(DeviceObject,
1075 Srb,
1076 IRP_MJ_SCSI,
1077 0,
1078 MAXIMUM_RETRIES - RetryCount,
1079 &Status);
1080 if (Retry == TRUE)
1081 {
1082 /* FIXME!! */
1083 DPRINT1("Should try again!\n");
1084
1085 }
1086 }
1087 else
1088 {
1089 Status = STATUS_SUCCESS;
1090 }
1091
1092 ExFreePool(Srb->SenseInfoBuffer);
1093
1094 DPRINT("ScsiClassSendSrbSynchronous() done\n");
1095
1096 return(Status);
1097 }
1098
1099
1100 VOID STDCALL
1101 ScsiClassSplitRequest(PDEVICE_OBJECT DeviceObject,
1102 PIRP Irp,
1103 ULONG MaximumBytes)
1104 {
1105 UNIMPLEMENTED;
1106 }
1107
1108
1109 /* INTERNAL FUNCTIONS *******************************************************/
1110
1111 static NTSTATUS STDCALL
1112 ScsiClassCreateClose(IN PDEVICE_OBJECT DeviceObject,
1113 IN PIRP Irp)
1114 {
1115 PDEVICE_EXTENSION DeviceExtension;
1116
1117 DPRINT("ScsiClassCreateClose() called\n");
1118
1119 DeviceExtension = DeviceObject->DeviceExtension;
1120
1121 if (DeviceExtension->ClassCreateClose)
1122 return(DeviceExtension->ClassCreateClose(DeviceObject,
1123 Irp));
1124
1125 Irp->IoStatus.Status = STATUS_SUCCESS;
1126 Irp->IoStatus.Information = 0;
1127 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1128
1129 return(STATUS_SUCCESS);
1130 }
1131
1132
1133 static NTSTATUS STDCALL
1134 ScsiClassReadWrite(IN PDEVICE_OBJECT DeviceObject,
1135 IN PIRP Irp)
1136 {
1137 PDEVICE_EXTENSION DeviceExtension;
1138 PIO_STACK_LOCATION IrpStack;
1139 ULONG TransferLength;
1140 ULONG TransferPages;
1141 NTSTATUS Status;
1142
1143 DPRINT("ScsiClassReadWrite() called\n");
1144
1145 DeviceExtension = DeviceObject->DeviceExtension;
1146 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1147
1148 DPRINT("Relative Offset: %I64u Length: %lu\n",
1149 IrpStack->Parameters.Read.ByteOffset.QuadPart,
1150 IrpStack->Parameters.Read.Length);
1151
1152 TransferLength = IrpStack->Parameters.Read.Length;
1153
1154 if ((DeviceObject->Flags & DO_VERIFY_VOLUME) &&
1155 !(IrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME))
1156 {
1157 IoSetHardErrorOrVerifyDevice(Irp,
1158 DeviceObject);
1159
1160 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
1161 Irp->IoStatus.Information = 0;
1162
1163 IoCompleteRequest(Irp,
1164 IO_NO_INCREMENT);
1165 return(STATUS_VERIFY_REQUIRED);
1166 }
1167
1168 /* Class driver verifies the IRP */
1169 Status = DeviceExtension->ClassReadWriteVerification(DeviceObject,
1170 Irp);
1171 if (!NT_SUCCESS(Status))
1172 {
1173 IoCompleteRequest(Irp,
1174 IO_NO_INCREMENT);
1175 return(Status);
1176 }
1177 else if (Status == STATUS_PENDING)
1178 {
1179 IoMarkIrpPending(Irp);
1180 return(STATUS_PENDING);
1181 }
1182
1183 /* Finish a zero-byte transfer */
1184 if (TransferLength == 0)
1185 {
1186 Irp->IoStatus.Status = STATUS_SUCCESS;
1187 Irp->IoStatus.Information = 0;
1188 IoCompleteRequest(Irp,
1189 IO_NO_INCREMENT);
1190 return(STATUS_SUCCESS);
1191 }
1192
1193 if (DeviceExtension->ClassStartIo != NULL)
1194 {
1195 DPRINT("ScsiClassReadWrite() starting packet\n");
1196
1197 IoMarkIrpPending(Irp);
1198 IoStartPacket(DeviceObject,
1199 Irp,
1200 NULL,
1201 NULL);
1202
1203 return(STATUS_PENDING);
1204 }
1205
1206 IoMarkIrpPending(Irp);
1207
1208 /* Adjust partition-relative starting offset to absolute offset */
1209 IrpStack->Parameters.Read.ByteOffset.QuadPart += DeviceExtension->StartingOffset.QuadPart;
1210
1211 /* Calculate number of pages in this transfer */
1212 TransferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
1213 IrpStack->Parameters.Read.Length);
1214
1215 #if 0
1216 if (TransferLength > maximumTransferLength ||
1217 TransferPages > DeviceExtension->PortCapabilities->MaximumPhysicalPages)
1218 {
1219 /* FIXME: split request */
1220 }
1221 #endif
1222
1223 ScsiClassBuildRequest(DeviceObject,
1224 Irp);
1225
1226 DPRINT("ScsiClassReadWrite() done\n");
1227
1228 /* Call the port driver */
1229 return(IoCallDriver(DeviceExtension->PortDeviceObject,
1230 Irp));
1231 }
1232
1233
1234 static NTSTATUS STDCALL
1235 ScsiClassScsiDispatch(IN PDEVICE_OBJECT DeviceObject,
1236 IN PIRP Irp)
1237 {
1238 DPRINT1("ScsiClassScsiDispatch() called\n");
1239
1240 Irp->IoStatus.Status = STATUS_SUCCESS;
1241 Irp->IoStatus.Information = 0;
1242 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1243
1244 return(STATUS_SUCCESS);
1245 }
1246
1247
1248 static NTSTATUS STDCALL
1249 ScsiClassDeviceDispatch(IN PDEVICE_OBJECT DeviceObject,
1250 IN PIRP Irp)
1251 {
1252 PDEVICE_EXTENSION DeviceExtension;
1253
1254 DPRINT("ScsiClassDeviceDispatch() called\n");
1255
1256 DeviceExtension = DeviceObject->DeviceExtension;
1257 if (DeviceExtension->ClassDeviceControl)
1258 {
1259 return(DeviceExtension->ClassDeviceControl(DeviceObject, Irp));
1260 }
1261
1262 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
1263 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1264
1265 return(STATUS_INVALID_DEVICE_REQUEST);
1266 }
1267
1268
1269 static NTSTATUS STDCALL
1270 ScsiClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
1271 IN PIRP Irp)
1272 {
1273 PDEVICE_EXTENSION DeviceExtension;
1274
1275 DPRINT("ScsiClassShutdownFlush() called\n");
1276
1277 DeviceExtension = DeviceObject->DeviceExtension;
1278 if (DeviceExtension->ClassShutdownFlush)
1279 {
1280 return(DeviceExtension->ClassShutdownFlush(DeviceObject, Irp));
1281 }
1282
1283 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
1284 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1285
1286 return(STATUS_INVALID_DEVICE_REQUEST);
1287 }
1288
1289 /* EOF */