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