Release MDL on IRP-completion. Thanks to Hartmut Birr.
[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.17 2002/04/27 19:01:24 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 // #define ENABLE_RETRIES
43
44 #define VERSION "0.0.1"
45
46 #define TAG_SRBT TAG('S', 'r', 'b', 'T')
47
48 #define INQUIRY_DATA_SIZE 2048
49
50
51 static NTSTATUS STDCALL
52 ScsiClassCreateClose(IN PDEVICE_OBJECT DeviceObject,
53 IN PIRP Irp);
54
55 static NTSTATUS STDCALL
56 ScsiClassReadWrite(IN PDEVICE_OBJECT DeviceObject,
57 IN PIRP Irp);
58
59 static NTSTATUS STDCALL
60 ScsiClassScsiDispatch(IN PDEVICE_OBJECT DeviceObject,
61 IN PIRP Irp);
62
63 static NTSTATUS STDCALL
64 ScsiClassDeviceDispatch(IN PDEVICE_OBJECT DeviceObject,
65 IN PIRP Irp);
66
67 static NTSTATUS STDCALL
68 ScsiClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
69 IN PIRP Irp);
70
71 static VOID
72 ScsiClassRetryRequest(PDEVICE_OBJECT DeviceObject,
73 PIRP Irp,
74 PSCSI_REQUEST_BLOCK Srb);
75
76 /* FUNCTIONS ****************************************************************/
77
78 // DriverEntry
79 //
80 // DESCRIPTION:
81 // This function initializes the driver.
82 //
83 // RUN LEVEL:
84 // PASSIVE_LEVEL
85 //
86 // ARGUMENTS:
87 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
88 // for this driver
89 // IN PUNICODE_STRING RegistryPath Name of registry driver service
90 // key
91 //
92 // RETURNS:
93 // NTSTATUS
94
95 NTSTATUS STDCALL
96 DriverEntry(IN PDRIVER_OBJECT DriverObject,
97 IN PUNICODE_STRING RegistryPath)
98 {
99 DbgPrint("Class Driver %s\n", VERSION);
100 return(STATUS_SUCCESS);
101 }
102
103
104 VOID
105 ScsiClassDebugPrint(IN ULONG DebugPrintLevel,
106 IN PCHAR DebugMessage,
107 ...)
108 {
109 char Buffer[256];
110 va_list ap;
111
112 #if 0
113 if (DebugPrintLevel > InternalDebugLevel)
114 return;
115 #endif
116
117 va_start(ap, DebugMessage);
118 vsprintf(Buffer, DebugMessage, ap);
119 va_end(ap);
120
121 DbgPrint(Buffer);
122 }
123
124
125 NTSTATUS STDCALL
126 ScsiClassAsynchronousCompletion(IN PDEVICE_OBJECT DeviceObject,
127 IN PIRP Irp,
128 IN PVOID Context)
129 {
130 UNIMPLEMENTED;
131 }
132
133
134 VOID STDCALL
135 ScsiClassBuildRequest(PDEVICE_OBJECT DeviceObject,
136 PIRP Irp)
137 {
138 PDEVICE_EXTENSION DeviceExtension;
139 PIO_STACK_LOCATION CurrentIrpStack;
140 PIO_STACK_LOCATION NextIrpStack;
141 LARGE_INTEGER StartingOffset;
142 LARGE_INTEGER StartingBlock;
143 PSCSI_REQUEST_BLOCK Srb;
144 PCDB Cdb;
145 ULONG LogicalBlockAddress;
146 USHORT TransferBlocks;
147
148 DeviceExtension = DeviceObject->DeviceExtension;
149 CurrentIrpStack = IoGetCurrentIrpStackLocation(Irp);
150 NextIrpStack = IoGetNextIrpStackLocation(Irp);
151 StartingOffset = CurrentIrpStack->Parameters.Read.ByteOffset;
152
153 /* Calculate logical block address */
154 StartingBlock.QuadPart = StartingOffset.QuadPart >> DeviceExtension->SectorShift;
155 LogicalBlockAddress = (ULONG)StartingBlock.u.LowPart;
156
157 DPRINT("Logical block address: %lu\n", LogicalBlockAddress);
158
159 /* Allocate and initialize an SRB */
160 /* FIXME: use lookaside list instead */
161 Srb = ExAllocatePool(NonPagedPool,
162 sizeof(SCSI_REQUEST_BLOCK));
163
164 Srb->SrbFlags = 0;
165 Srb->Length = sizeof(SCSI_REQUEST_BLOCK); //SCSI_REQUEST_BLOCK_SIZE;
166 Srb->OriginalRequest = Irp;
167 Srb->PathId = DeviceExtension->PathId;
168 Srb->TargetId = DeviceExtension->TargetId;
169 Srb->Lun = DeviceExtension->Lun;
170 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
171 Srb->DataBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
172 Srb->DataTransferLength = CurrentIrpStack->Parameters.Read.Length;
173 Srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
174 Srb->QueueSortKey = LogicalBlockAddress;
175
176 Srb->SenseInfoBuffer = DeviceExtension->SenseData;
177 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
178
179 Srb->TimeOutValue =
180 ((Srb->DataTransferLength + 0xFFFF) >> 16) * DeviceExtension->TimeOutValue;
181
182 Srb->SrbStatus = SRB_STATUS_SUCCESS;
183 Srb->ScsiStatus = 0;
184 Srb->NextSrb = 0;
185
186 Srb->CdbLength = 10;
187 Cdb = (PCDB)Srb->Cdb;
188
189 /* Initialize ATAPI packet (12 bytes) */
190 RtlZeroMemory(Cdb,
191 MAXIMUM_CDB_SIZE);
192
193 Cdb->CDB10.LogicalUnitNumber = DeviceExtension->Lun;
194 TransferBlocks = (USHORT)(CurrentIrpStack->Parameters.Read.Length >> DeviceExtension->SectorShift);
195
196 /* Copy little endian values into CDB in big endian format */
197 Cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte3;
198 Cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte2;
199 Cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte1;
200 Cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte0;
201
202 Cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&TransferBlocks)->Byte1;
203 Cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&TransferBlocks)->Byte0;
204
205
206 if (CurrentIrpStack->MajorFunction == IRP_MJ_READ)
207 {
208 DPRINT("ScsiClassBuildRequest: Read Command\n");
209
210 Srb->SrbFlags |= SRB_FLAGS_DATA_IN;
211 Cdb->CDB10.OperationCode = SCSIOP_READ;
212 }
213 else
214 {
215 DPRINT("ScsiClassBuildRequest: Write Command\n");
216
217 Srb->SrbFlags |= SRB_FLAGS_DATA_OUT;
218 Cdb->CDB10.OperationCode = SCSIOP_WRITE;
219 }
220
221 #if 0
222 /* if this is not a write-through request, then allow caching */
223 if (!(CurrentIrpStack->Flags & SL_WRITE_THROUGH))
224 {
225 Srb->SrbFlags |= SRB_FLAGS_ADAPTER_CACHE_ENABLE;
226 }
227 else if (DeviceExtension->DeviceFlags & DEV_WRITE_CACHE)
228 {
229 /* if write caching is enable then force media access in the cdb */
230 Cdb->CDB10.ForceUnitAccess = TRUE;
231 }
232 #endif
233
234 /* Update srb flags */
235 Srb->SrbFlags |= DeviceExtension->SrbFlags;
236
237 /* Initialize next stack location */
238 NextIrpStack->MajorFunction = IRP_MJ_SCSI;
239 NextIrpStack->Parameters.Scsi.Srb = Srb;
240 NextIrpStack->DeviceObject = DeviceObject;
241
242 /* Set retry count */
243 NextIrpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
244
245 DPRINT("IoSetCompletionRoutine (Irp %p Srb %p)\n", Irp, Srb);
246 IoSetCompletionRoutine(Irp,
247 ScsiClassIoComplete,
248 Srb,
249 TRUE,
250 TRUE,
251 TRUE);
252 }
253
254
255 NTSTATUS STDCALL
256 ScsiClassClaimDevice(PDEVICE_OBJECT PortDeviceObject,
257 PSCSI_INQUIRY_DATA LunInfo,
258 BOOLEAN Release,
259 PDEVICE_OBJECT *NewPortDeviceObject OPTIONAL)
260 {
261 PIO_STACK_LOCATION IoStack;
262 IO_STATUS_BLOCK IoStatusBlock;
263 SCSI_REQUEST_BLOCK Srb;
264 KEVENT Event;
265 PIRP Irp;
266 NTSTATUS Status;
267
268 DPRINT("ScsiClassClaimDevice() called\n");
269
270 if (NewPortDeviceObject != NULL)
271 *NewPortDeviceObject = NULL;
272
273 /* initialize an SRB */
274 RtlZeroMemory(&Srb,
275 sizeof(SCSI_REQUEST_BLOCK));
276 Srb.Length = SCSI_REQUEST_BLOCK_SIZE;
277 Srb.PathId = LunInfo->PathId;
278 Srb.TargetId = LunInfo->TargetId;
279 Srb.Lun = LunInfo->Lun;
280 Srb.Function =
281 (Release == TRUE) ? SRB_FUNCTION_RELEASE_DEVICE : SRB_FUNCTION_CLAIM_DEVICE;
282
283 KeInitializeEvent(&Event,
284 NotificationEvent,
285 FALSE);
286
287 Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE,
288 PortDeviceObject,
289 NULL,
290 0,
291 NULL,
292 0,
293 TRUE,
294 &Event,
295 &IoStatusBlock);
296 if (Irp == NULL)
297 {
298 DPRINT1("Failed to allocate Irp!\n");
299 return(STATUS_INSUFFICIENT_RESOURCES);
300 }
301
302 /* Link Srb and Irp */
303 IoStack = IoGetNextIrpStackLocation(Irp);
304 IoStack->Parameters.Scsi.Srb = &Srb;
305 Srb.OriginalRequest = Irp;
306
307 /* Call SCSI port driver */
308 Status = IoCallDriver(PortDeviceObject,
309 Irp);
310 if (Status == STATUS_PENDING)
311 {
312 KeWaitForSingleObject(&Event,
313 Suspended,
314 KernelMode,
315 FALSE,
316 NULL);
317 Status = IoStatusBlock.Status;
318 }
319
320 if (Release == TRUE)
321 {
322 ObDereferenceObject(PortDeviceObject);
323 return(STATUS_SUCCESS);
324 }
325
326 // Status = ObReferenceObjectByPointer(Srb.DataBuffer,
327 Status = ObReferenceObjectByPointer(PortDeviceObject,
328 0,
329 NULL,
330 KernelMode);
331
332 if (NewPortDeviceObject != NULL)
333 {
334 // *NewPortDeviceObject = Srb.DataBuffer;
335 *NewPortDeviceObject = PortDeviceObject;
336 }
337
338 return(STATUS_SUCCESS);
339 }
340
341
342 NTSTATUS STDCALL
343 ScsiClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
344 IN PCCHAR ObjectNameBuffer,
345 IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL,
346 IN OUT PDEVICE_OBJECT *DeviceObject,
347 IN PCLASS_INIT_DATA InitializationData)
348 {
349 PDEVICE_OBJECT InternalDeviceObject;
350 PDEVICE_EXTENSION DeviceExtension;
351 ANSI_STRING AnsiName;
352 UNICODE_STRING DeviceName;
353 NTSTATUS Status;
354
355 DPRINT("ScsiClassCreateDeviceObject() called\n");
356
357 *DeviceObject = NULL;
358
359 RtlInitAnsiString(&AnsiName,
360 ObjectNameBuffer);
361
362 Status = RtlAnsiStringToUnicodeString(&DeviceName,
363 &AnsiName,
364 TRUE);
365 if (!NT_SUCCESS(Status))
366 {
367 return(Status);
368 }
369
370 DPRINT("Device name: '%wZ'\n", &DeviceName);
371
372 Status = IoCreateDevice(DriverObject,
373 InitializationData->DeviceExtensionSize,
374 &DeviceName,
375 InitializationData->DeviceType,
376 InitializationData->DeviceCharacteristics,
377 FALSE,
378 &InternalDeviceObject);
379 if (NT_SUCCESS(Status))
380 {
381 DeviceExtension = InternalDeviceObject->DeviceExtension;
382
383 DeviceExtension->ClassError = InitializationData->ClassError;
384 DeviceExtension->ClassReadWriteVerification = InitializationData->ClassReadWriteVerification;
385 DeviceExtension->ClassFindDevices = InitializationData->ClassFindDevices;
386 DeviceExtension->ClassDeviceControl = InitializationData->ClassDeviceControl;
387 DeviceExtension->ClassShutdownFlush = InitializationData->ClassShutdownFlush;
388 DeviceExtension->ClassCreateClose = InitializationData->ClassCreateClose;
389 DeviceExtension->ClassStartIo = InitializationData->ClassStartIo;
390
391 DeviceExtension->MediaChangeCount = 0;
392
393 if (PhysicalDeviceObject != NULL)
394 {
395 DeviceExtension->PhysicalDevice = PhysicalDeviceObject;
396 }
397 else
398 {
399 DeviceExtension->PhysicalDevice = InternalDeviceObject;
400 }
401
402 *DeviceObject = InternalDeviceObject;
403 }
404
405 RtlFreeUnicodeString(&DeviceName);
406
407 return(Status);
408 }
409
410
411 NTSTATUS STDCALL
412 ScsiClassDeviceControl(PDEVICE_OBJECT DeviceObject,
413 PIRP Irp)
414 {
415 UNIMPLEMENTED;
416 }
417
418
419 PVOID STDCALL
420 ScsiClassFindModePage(PCHAR ModeSenseBuffer,
421 ULONG Length,
422 UCHAR PageMode,
423 BOOLEAN Use6Byte)
424 {
425 UNIMPLEMENTED;
426 }
427
428
429 ULONG STDCALL
430 ScsiClassFindUnclaimedDevices(PCLASS_INIT_DATA InitializationData,
431 PSCSI_ADAPTER_BUS_INFO AdapterInformation)
432 {
433 PSCSI_INQUIRY_DATA UnitInfo;
434 PINQUIRYDATA InquiryData;
435 PUCHAR Buffer;
436 ULONG Bus;
437 ULONG UnclaimedDevices = 0;
438 NTSTATUS Status;
439
440 DPRINT("ScsiClassFindUnclaimedDevices() called!\n");
441
442 DPRINT("NumberOfBuses: %lu\n",AdapterInformation->NumberOfBuses);
443 Buffer = (PUCHAR)AdapterInformation;
444 for (Bus = 0; Bus < (ULONG)AdapterInformation->NumberOfBuses; Bus++)
445 {
446 DPRINT("Searching bus %lu\n", Bus);
447
448 UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + AdapterInformation->BusData[Bus].InquiryDataOffset);
449
450 while (AdapterInformation->BusData[Bus].InquiryDataOffset)
451 {
452 InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
453
454 DPRINT("Device: '%.8s'\n", InquiryData->VendorId);
455
456 if ((InitializationData->ClassFindDeviceCallBack(InquiryData) == TRUE) &&
457 (UnitInfo->DeviceClaimed == FALSE))
458 {
459 UnclaimedDevices++;
460 }
461
462 if (UnitInfo->NextInquiryDataOffset == 0)
463 break;
464
465 UnitInfo = (PSCSI_INQUIRY_DATA) (Buffer + UnitInfo->NextInquiryDataOffset);
466 }
467 }
468
469 return(UnclaimedDevices);
470 }
471
472
473 NTSTATUS STDCALL
474 ScsiClassGetCapabilities(PDEVICE_OBJECT PortDeviceObject,
475 PIO_SCSI_CAPABILITIES *PortCapabilities)
476 {
477 PIO_SCSI_CAPABILITIES Buffer;
478 IO_STATUS_BLOCK IoStatusBlock;
479 NTSTATUS Status;
480 KEVENT Event;
481 PIRP Irp;
482
483 *PortCapabilities = NULL;
484 Buffer = ExAllocatePool(NonPagedPool,
485 sizeof(IO_SCSI_CAPABILITIES));
486 if (Buffer == NULL)
487 {
488 return(STATUS_INSUFFICIENT_RESOURCES);
489 }
490
491 KeInitializeEvent(&Event,
492 NotificationEvent,
493 FALSE);
494
495 Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_CAPABILITIES,
496 PortDeviceObject,
497 NULL,
498 0,
499 Buffer,
500 sizeof(IO_SCSI_CAPABILITIES),
501 FALSE,
502 &Event,
503 &IoStatusBlock);
504 if (Irp == NULL)
505 {
506 ExFreePool(Buffer);
507 return(STATUS_INSUFFICIENT_RESOURCES);
508 }
509
510 Status = IoCallDriver(PortDeviceObject,
511 Irp);
512 if (Status == STATUS_PENDING)
513 {
514 KeWaitForSingleObject(&Event,
515 Suspended,
516 KernelMode,
517 FALSE,
518 NULL);
519 Status = IoStatusBlock.Status;
520 }
521
522 if (!NT_SUCCESS(Status))
523 {
524 ExFreePool(Buffer);
525 }
526 else
527 {
528 *PortCapabilities = Buffer;
529 }
530
531 return(Status);
532 }
533
534
535 NTSTATUS STDCALL
536 ScsiClassGetInquiryData(PDEVICE_OBJECT PortDeviceObject,
537 PSCSI_ADAPTER_BUS_INFO *ConfigInfo)
538 {
539 PSCSI_ADAPTER_BUS_INFO Buffer;
540 IO_STATUS_BLOCK IoStatusBlock;
541 NTSTATUS Status;
542 KEVENT Event;
543 PIRP Irp;
544
545 DPRINT("ScsiClassGetInquiryData() called\n");
546
547 *ConfigInfo = NULL;
548 Buffer = ExAllocatePool(NonPagedPool,
549 INQUIRY_DATA_SIZE);
550 if (Buffer == NULL)
551 {
552 return(STATUS_INSUFFICIENT_RESOURCES);
553 }
554
555 KeInitializeEvent(&Event,
556 NotificationEvent,
557 FALSE);
558
559 Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA,
560 PortDeviceObject,
561 NULL,
562 0,
563 Buffer,
564 INQUIRY_DATA_SIZE,
565 FALSE,
566 &Event,
567 &IoStatusBlock);
568 if (Irp == NULL)
569 {
570 ExFreePool(Buffer);
571 return(STATUS_INSUFFICIENT_RESOURCES);
572 }
573
574 Status = IoCallDriver(PortDeviceObject,
575 Irp);
576 if (Status == STATUS_PENDING)
577 {
578 KeWaitForSingleObject(&Event,
579 Suspended,
580 KernelMode,
581 FALSE,
582 NULL);
583 Status = IoStatusBlock.Status;
584 }
585
586 if (!NT_SUCCESS(Status))
587 {
588 ExFreePool(Buffer);
589 }
590 else
591 {
592 *ConfigInfo = Buffer;
593 }
594
595 DPRINT("ScsiClassGetInquiryData() done\n");
596
597 return(Status);
598 }
599
600
601 ULONG STDCALL
602 ScsiClassInitialize(PVOID Argument1,
603 PVOID Argument2,
604 PCLASS_INIT_DATA InitializationData)
605 {
606 PCONFIGURATION_INFORMATION ConfigInfo;
607 PDRIVER_OBJECT DriverObject = Argument1;
608 WCHAR NameBuffer[80];
609 UNICODE_STRING PortName;
610 ULONG PortNumber;
611 PDEVICE_OBJECT PortDeviceObject;
612 PFILE_OBJECT FileObject;
613 BOOLEAN DiskFound = FALSE;
614 NTSTATUS Status;
615
616 DPRINT("ScsiClassInitialize() called!\n");
617
618 DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiClassCreateClose;
619 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiClassCreateClose;
620 DriverObject->MajorFunction[IRP_MJ_READ] = ScsiClassReadWrite;
621 DriverObject->MajorFunction[IRP_MJ_WRITE] = ScsiClassReadWrite;
622 DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiClassScsiDispatch;
623 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiClassDeviceDispatch;
624 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = ScsiClassShutdownFlush;
625 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = ScsiClassShutdownFlush;
626 if (InitializationData->ClassStartIo)
627 {
628 DriverObject->DriverStartIo = InitializationData->ClassStartIo;
629 }
630
631 ConfigInfo = IoGetConfigurationInformation();
632
633 DPRINT("ScsiPorts: %lu\n", ConfigInfo->ScsiPortCount);
634
635 /* look for ScsiPortX scsi port devices */
636 for (PortNumber = 0; PortNumber < ConfigInfo->ScsiPortCount; PortNumber++)
637 {
638 swprintf(NameBuffer,
639 L"\\Device\\ScsiPort%lu",
640 PortNumber);
641 RtlInitUnicodeString(&PortName,
642 NameBuffer);
643 DPRINT("Checking scsi port %ld\n", PortNumber);
644 Status = IoGetDeviceObjectPointer(&PortName,
645 FILE_READ_ATTRIBUTES,
646 &FileObject,
647 &PortDeviceObject);
648 DPRINT("Status 0x%08lX\n", Status);
649 if (NT_SUCCESS(Status))
650 {
651 DPRINT("ScsiPort%lu found.\n", PortNumber);
652
653 /* check scsi port for attached disk drives */
654 if (InitializationData->ClassFindDevices(DriverObject,
655 Argument2,
656 InitializationData,
657 PortDeviceObject,
658 PortNumber))
659 {
660 DiskFound = TRUE;
661 }
662 }
663 else
664 {
665 DbgPrint("Couldn't find ScsiPort%lu (Status %lx)\n", PortNumber, Status);
666 }
667 }
668
669 DPRINT("ScsiClassInitialize() done!\n");
670
671 return((DiskFound == TRUE) ? STATUS_SUCCESS : STATUS_NO_SUCH_DEVICE);
672 }
673
674
675 /**********************************************************************
676 * NAME EXPORTED
677 * ScsiClassInitializeSrbLookasideList
678 *
679 * DESCRIPTION
680 * Initializes a lookaside list for SRBs.
681 *
682 * RUN LEVEL
683 * PASSIVE_LEVEL
684 *
685 * ARGUMENTS
686 * DeviceExtension
687 * Class specific device extension.
688 *
689 * NumberElements
690 * Maximum number of elements of the lookaside list.
691 *
692 * RETURN VALUE
693 * None.
694 */
695
696 VOID STDCALL
697 ScsiClassInitializeSrbLookasideList(PDEVICE_EXTENSION DeviceExtension,
698 ULONG NumberElements)
699 {
700 ExInitializeNPagedLookasideList(&DeviceExtension->SrbLookasideListHead,
701 NULL,
702 NULL,
703 NonPagedPool,
704 sizeof(SCSI_REQUEST_BLOCK),
705 TAG_SRBT,
706 (USHORT)NumberElements);
707 }
708
709
710 NTSTATUS STDCALL
711 ScsiClassInternalIoControl(PDEVICE_OBJECT DeviceObject,
712 PIRP Irp)
713 {
714 UNIMPLEMENTED;
715 }
716
717
718 BOOLEAN STDCALL
719 ScsiClassInterpretSenseInfo(PDEVICE_OBJECT DeviceObject,
720 PSCSI_REQUEST_BLOCK Srb,
721 UCHAR MajorFunctionCode,
722 ULONG IoDeviceCode,
723 ULONG RetryCount,
724 NTSTATUS *Status)
725 {
726 PDEVICE_EXTENSION DeviceExtension;
727 PSENSE_DATA SenseData;
728 BOOLEAN Retry;
729
730 DPRINT1("ScsiClassInterpretSenseInfo() called\n");
731
732 DPRINT1("Srb->SrbStatus %lx\n", Srb->SrbStatus);
733
734 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_PENDING)
735 {
736 *Status = STATUS_SUCCESS;
737 return(FALSE);
738 }
739
740 DeviceExtension = DeviceObject->DeviceExtension;
741 SenseData = Srb->SenseInfoBuffer;
742 Retry = TRUE;
743
744 if ((Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
745 (Srb->SenseInfoBufferLength > 0))
746 {
747 /* Got valid sense data, interpret them */
748
749 DPRINT1("ErrorCode: %x\n", SenseData->ErrorCode);
750 DPRINT1("SenseKey: %x\n", SenseData->SenseKey);
751 DPRINT1("SenseCode: %x\n", SenseData->AdditionalSenseCode);
752
753 switch (SenseData->SenseKey & 0xf)
754 {
755 /* FIXME: add more sense key codes */
756
757 case SCSI_SENSE_NOT_READY:
758 DPRINT1("SCSI_SENSE_NOT_READY\n");
759 *Status = STATUS_DEVICE_NOT_READY;
760 break;
761
762 case SCSI_SENSE_UNIT_ATTENTION:
763 DPRINT1("SCSI_SENSE_UNIT_ATTENTION\n");
764 if ((DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) &&
765 (DeviceObject->Vpb->Flags & VPB_MOUNTED))
766 {
767 DeviceObject->Flags |= DO_VERIFY_VOLUME;
768 *Status = STATUS_VERIFY_REQUIRED;
769 Retry = FALSE;
770 }
771 else
772 {
773 *Status = STATUS_IO_DEVICE_ERROR;
774 }
775 break;
776
777 case SCSI_SENSE_ILLEGAL_REQUEST:
778 DPRINT1("SCSI_SENSE_ILLEGAL_REQUEST\n");
779 *Status = STATUS_INVALID_DEVICE_REQUEST;
780 Retry = FALSE;
781 break;
782
783
784 default:
785 DPRINT1("SCSI error (sense key: %x)\n",
786 SenseData->SenseKey & 0xf);
787 *Status = STATUS_IO_DEVICE_ERROR;
788 break;
789 }
790 }
791 else
792 {
793 /* Got no/invalid sense data, return generic error codes */
794 switch (SRB_STATUS(Srb->SrbStatus))
795 {
796 /* FIXME: add more srb status codes */
797
798 case SRB_STATUS_DATA_OVERRUN:
799 *Status = STATUS_DATA_OVERRUN;
800 Retry = FALSE;
801 break;
802
803 default:
804 *Status = STATUS_IO_DEVICE_ERROR;
805 break;
806 }
807 }
808
809 /* Call the class driver specific error function */
810 if (DeviceExtension->ClassError != NULL)
811 {
812 DeviceExtension->ClassError(DeviceObject,
813 Srb,
814 Status,
815 &Retry);
816 }
817
818 /* FIXME: log severe errors */
819
820 DPRINT1("ScsiClassInterpretSenseInfo() done\n");
821
822 return(Retry);
823 }
824
825
826 NTSTATUS STDCALL
827 ScsiClassIoComplete(PDEVICE_OBJECT DeviceObject,
828 PIRP Irp,
829 PVOID Context)
830 {
831 PDEVICE_EXTENSION DeviceExtension;
832 PIO_STACK_LOCATION IrpStack;
833 PSCSI_REQUEST_BLOCK Srb;
834 BOOLEAN Retry;
835 NTSTATUS Status;
836
837 DPRINT("ScsiClassIoComplete(DeviceObject %p Irp %p Context %p) called\n",
838 DeviceObject, Irp, Context);
839
840 DeviceExtension = DeviceObject->DeviceExtension;
841 Srb = (PSCSI_REQUEST_BLOCK)Context;
842 DPRINT("Srb %p\n", Srb);
843
844 IrpStack = IoGetCurrentIrpStackLocation(Irp);
845
846 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
847 {
848 Status = STATUS_SUCCESS;
849 }
850 else
851 {
852 Retry = ScsiClassInterpretSenseInfo(DeviceObject,
853 Srb,
854 IrpStack->MajorFunction,
855 0,
856 MAXIMUM_RETRIES - ((ULONG)IrpStack->Parameters.Others.Argument4),
857 &Status);
858
859 DPRINT1("Retry count: %lu\n", (ULONG)IrpStack->Parameters.Others.Argument4);
860
861 if ((Retry == TRUE) &&
862 ((ULONG)IrpStack->Parameters.Others.Argument4 > 0))
863 {
864 ((ULONG)IrpStack->Parameters.Others.Argument4)--;
865 DPRINT1("Retry count: %lu\n", (ULONG)IrpStack->Parameters.Others.Argument4);
866
867 DPRINT1("Should try again!\n");
868 #ifdef ENABLE_RETRY
869 ScsiClassRetryRequest(DeviceObject,
870 Irp,
871 Srb);
872 return(STATUS_MORE_PROCESSING_REQUIRED);
873 #else
874 return(Status);
875 #endif
876 }
877 }
878
879 /* Free the IRP's MDL */
880 if (Irp->MdlAddress->MappedSystemVa != NULL)
881 {
882 MmUnmapLockedPages(Irp->MdlAddress->MappedSystemVa,
883 Irp->MdlAddress);
884 }
885 MmUnlockPages(Irp->MdlAddress);
886 ExFreePool(Irp->MdlAddress);
887
888 /* FIXME: use lookaside list instead */
889 DPRINT("Freed SRB %p\n", IrpStack->Parameters.Scsi.Srb);
890 ExFreePool(IrpStack->Parameters.Scsi.Srb);
891
892 Irp->IoStatus.Status = Status;
893 #if 0
894 if (!NT_SUCCESS(Status))
895 {
896 Irp->IoStatus.Information = 0;
897 if (IoIsErrorUserInduced(Status))
898 {
899 IoSetHardErrorOrVerifyDevice(Irp,
900 DeviceObject);
901 }
902 }
903
904 if (Irp->PendingReturned)
905 {
906 IoMarkIrpPending(Irp);
907 }
908 #endif
909
910 if (DeviceExtension->ClassStartIo != NULL)
911 {
912 if (IrpStack->MajorFunction != IRP_MJ_DEVICE_CONTROL)
913 {
914 IoStartNextPacket(DeviceObject,
915 FALSE);
916 }
917 }
918
919 DPRINT("ScsiClassIoComplete() done (Status %lx)\n", Status);
920
921 return(Status);
922 }
923
924
925 NTSTATUS STDCALL
926 ScsiClassIoCompleteAssociated(PDEVICE_OBJECT DeviceObject,
927 PIRP Irp,
928 PVOID Context)
929 {
930 PDEVICE_EXTENSION DeviceExtension;
931 PIO_STACK_LOCATION IrpStack;
932 PSCSI_REQUEST_BLOCK Srb;
933 PIRP MasterIrp;
934 BOOLEAN Retry;
935 LONG RequestCount;
936 NTSTATUS Status;
937
938 DPRINT("ScsiClassIoCompleteAssociated(DeviceObject %p Irp %p Context %p) called\n",
939 DeviceObject, Irp, Context);
940
941 MasterIrp = Irp->AssociatedIrp.MasterIrp;
942 DeviceExtension = DeviceObject->DeviceExtension;
943 Srb = (PSCSI_REQUEST_BLOCK)Context;
944 DPRINT("Srb %p\n", Srb);
945
946 IrpStack = IoGetCurrentIrpStackLocation(Irp);
947
948 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
949 {
950 Status = STATUS_SUCCESS;
951 }
952 else
953 {
954 /* Get more detailed status information */
955 Retry = ScsiClassInterpretSenseInfo(DeviceObject,
956 Srb,
957 IrpStack->MajorFunction,
958 0,
959 MAXIMUM_RETRIES - ((ULONG)IrpStack->Parameters.Others.Argument4),
960 &Status);
961
962 DPRINT1("Retry count: %lu\n", (ULONG)IrpStack->Parameters.Others.Argument4);
963
964 if ((Retry == TRUE) &&
965 ((ULONG)IrpStack->Parameters.Others.Argument4 > 0))
966 {
967 ((ULONG)IrpStack->Parameters.Others.Argument4)--;
968 DPRINT1("Retry count: %lu\n", (ULONG)IrpStack->Parameters.Others.Argument4);
969
970 DPRINT1("Should try again!\n");
971 #ifdef ENABLE_RETRY
972 ScsiClassRetryRequest(DeviceObject,
973 Irp,
974 Srb);
975 return(STATUS_MORE_PROCESSING_REQUIRED);
976 #else
977 return(Status);
978 #endif
979 }
980 }
981
982 /* FIXME: use lookaside list instead */
983 DPRINT("Freed SRB %p\n", IrpStack->Parameters.Scsi.Srb);
984 ExFreePool(IrpStack->Parameters.Scsi.Srb);
985
986 Irp->IoStatus.Status = Status;
987
988 IrpStack = IoGetNextIrpStackLocation(MasterIrp);
989 if (!NT_SUCCESS(Status))
990 {
991 MasterIrp->IoStatus.Status = Status;
992 MasterIrp->IoStatus.Information = 0;
993
994 if (IoIsErrorUserInduced(Status))
995 {
996 IoSetHardErrorOrVerifyDevice(MasterIrp,
997 DeviceObject);
998 }
999 }
1000
1001 /* Decrement the request counter in the Master IRP */
1002 RequestCount = InterlockedDecrement((PLONG)&IrpStack->Parameters.Others.Argument1);
1003
1004 if (RequestCount == 0)
1005 {
1006 /* Complete the Master IRP */
1007 IoCompleteRequest(MasterIrp,
1008 IO_DISK_INCREMENT);
1009
1010 if (DeviceExtension->ClassStartIo)
1011 {
1012 IoStartNextPacket(DeviceObject,
1013 FALSE);
1014 }
1015 }
1016
1017 /* Free the current IRP */
1018 IoFreeIrp(Irp);
1019
1020 return(STATUS_MORE_PROCESSING_REQUIRED);
1021 }
1022
1023
1024 ULONG STDCALL
1025 ScsiClassModeSense(PDEVICE_OBJECT DeviceObject,
1026 CHAR ModeSenseBuffer,
1027 ULONG Length,
1028 UCHAR PageMode)
1029 {
1030 UNIMPLEMENTED;
1031 }
1032
1033
1034 ULONG STDCALL
1035 ScsiClassQueryTimeOutRegistryValue(IN PUNICODE_STRING RegistryPath)
1036 {
1037 UNIMPLEMENTED;
1038 }
1039
1040
1041 NTSTATUS STDCALL
1042 ScsiClassReadDriveCapacity(IN PDEVICE_OBJECT DeviceObject)
1043 {
1044 PDEVICE_EXTENSION DeviceExtension;
1045 PREAD_CAPACITY_DATA CapacityBuffer;
1046 SCSI_REQUEST_BLOCK Srb;
1047 PCDB Cdb;
1048 NTSTATUS Status;
1049 ULONG LastSector;
1050 ULONG SectorSize;
1051
1052 DPRINT("ScsiClassReadDriveCapacity() called\n");
1053
1054 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1055
1056 CapacityBuffer = ExAllocatePool(NonPagedPool,
1057 sizeof(READ_CAPACITY_DATA));
1058 if (CapacityBuffer == NULL)
1059 {
1060 return(STATUS_INSUFFICIENT_RESOURCES);
1061 }
1062
1063 RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
1064
1065 Srb.CdbLength = 10;
1066 Srb.TimeOutValue = DeviceExtension->TimeOutValue;
1067
1068 Cdb = (PCDB)Srb.Cdb;
1069 Cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
1070
1071
1072 Status = ScsiClassSendSrbSynchronous(DeviceObject,
1073 &Srb,
1074 CapacityBuffer,
1075 sizeof(READ_CAPACITY_DATA),
1076 FALSE);
1077 DPRINT("Status: %lx\n", Status);
1078 DPRINT("Srb: %p\n", &Srb);
1079 if (NT_SUCCESS(Status))
1080 {
1081 SectorSize = (((PUCHAR)&CapacityBuffer->BytesPerBlock)[0] << 24) |
1082 (((PUCHAR)&CapacityBuffer->BytesPerBlock)[1] << 16) |
1083 (((PUCHAR)&CapacityBuffer->BytesPerBlock)[2] << 8) |
1084 ((PUCHAR)&CapacityBuffer->BytesPerBlock)[3];
1085
1086
1087 LastSector = (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[0] << 24) |
1088 (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[1] << 16) |
1089 (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[2] << 8) |
1090 ((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[3];
1091
1092 DeviceExtension->DiskGeometry->BytesPerSector = SectorSize;
1093
1094 DeviceExtension->PartitionLength.QuadPart = (LONGLONG)(LastSector + 1);
1095 WHICH_BIT(DeviceExtension->DiskGeometry->BytesPerSector,
1096 DeviceExtension->SectorShift);
1097 DeviceExtension->PartitionLength.QuadPart =
1098 (DeviceExtension->PartitionLength.QuadPart << DeviceExtension->SectorShift);
1099
1100 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
1101 {
1102 DeviceExtension->DiskGeometry->MediaType = RemovableMedia;
1103 }
1104 else
1105 {
1106 DeviceExtension->DiskGeometry->MediaType = FixedMedia;
1107 }
1108 DeviceExtension->DiskGeometry->Cylinders.QuadPart = (LONGLONG)((LastSector + 1)/(32 * 64));
1109 DeviceExtension->DiskGeometry->SectorsPerTrack = 32;
1110 DeviceExtension->DiskGeometry->TracksPerCylinder = 64;
1111
1112 DPRINT("SectorSize: %lu SectorCount: %lu\n", SectorSize, LastSector + 1);
1113 }
1114 else
1115 {
1116 /* Use default values if disk geometry cannot be read */
1117 RtlZeroMemory(&DeviceExtension->DiskGeometry,
1118 sizeof(DISK_GEOMETRY));
1119 DeviceExtension->DiskGeometry->BytesPerSector = 512;
1120 DeviceExtension->SectorShift = 9;
1121 DeviceExtension->PartitionLength.QuadPart = 0;
1122
1123 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
1124 {
1125 DeviceExtension->DiskGeometry->MediaType = RemovableMedia;
1126 }
1127 else
1128 {
1129 DeviceExtension->DiskGeometry->MediaType = FixedMedia;
1130 }
1131 }
1132
1133 ExFreePool(CapacityBuffer);
1134
1135 DPRINT("ScsiClassReadDriveCapacity() done\n");
1136
1137 return(Status);
1138 }
1139
1140
1141 VOID STDCALL
1142 ScsiClassReleaseQueue(IN PDEVICE_OBJECT DeviceObject)
1143 {
1144 UNIMPLEMENTED;
1145 }
1146
1147
1148 NTSTATUS STDCALL
1149 ScsiClassSendSrbAsynchronous(PDEVICE_OBJECT DeviceObject,
1150 PSCSI_REQUEST_BLOCK Srb,
1151 PIRP Irp,
1152 PVOID BufferAddress,
1153 ULONG BufferLength,
1154 BOOLEAN WriteToDevice)
1155 {
1156 UNIMPLEMENTED;
1157 }
1158
1159
1160 NTSTATUS STDCALL
1161 ScsiClassSendSrbSynchronous(PDEVICE_OBJECT DeviceObject,
1162 PSCSI_REQUEST_BLOCK Srb,
1163 PVOID BufferAddress,
1164 ULONG BufferLength,
1165 BOOLEAN WriteToDevice)
1166 {
1167 PDEVICE_EXTENSION DeviceExtension;
1168 IO_STATUS_BLOCK IoStatusBlock;
1169 PIO_STACK_LOCATION IoStack;
1170 ULONG RequestType;
1171 BOOLEAN Retry;
1172 ULONG RetryCount;
1173 PKEVENT Event;
1174 PIRP Irp;
1175 NTSTATUS Status;
1176
1177 DPRINT("ScsiClassSendSrbSynchronous() called\n");
1178
1179 RetryCount = MAXIMUM_RETRIES;
1180 DeviceExtension = DeviceObject->DeviceExtension;
1181
1182 Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1183 Srb->PathId = DeviceExtension->PathId;
1184 Srb->TargetId = DeviceExtension->TargetId;
1185 Srb->Lun = DeviceExtension->Lun;
1186 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1187
1188 /* FIXME: more srb initialization required? */
1189
1190 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1191 Srb->SenseInfoBuffer = ExAllocatePool(NonPagedPool,
1192 SENSE_BUFFER_SIZE);
1193 if (Srb->SenseInfoBuffer == NULL)
1194 return(STATUS_INSUFFICIENT_RESOURCES);
1195
1196 if (BufferAddress == NULL)
1197 {
1198 BufferLength = 0;
1199 RequestType = IOCTL_SCSI_EXECUTE_NONE;
1200 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
1201 }
1202 else
1203 {
1204 if (WriteToDevice == TRUE)
1205 {
1206 RequestType = IOCTL_SCSI_EXECUTE_OUT;
1207 Srb->SrbFlags = SRB_FLAGS_DATA_OUT;
1208 }
1209 else
1210 {
1211 RequestType = IOCTL_SCSI_EXECUTE_IN;
1212 Srb->SrbFlags = SRB_FLAGS_DATA_IN;
1213 }
1214 }
1215
1216 Srb->DataTransferLength = BufferLength;
1217 Srb->DataBuffer = BufferAddress;
1218
1219 Event = ExAllocatePool(NonPagedPool,
1220 sizeof(KEVENT));
1221 KeInitializeEvent(Event,
1222 NotificationEvent,
1223 FALSE);
1224
1225 Irp = IoBuildDeviceIoControlRequest(RequestType,
1226 DeviceExtension->PortDeviceObject,
1227 NULL,
1228 0,
1229 BufferAddress,
1230 BufferLength,
1231 TRUE,
1232 Event,
1233 &IoStatusBlock);
1234 if (Irp == NULL)
1235 {
1236 DPRINT1("IoBuildDeviceIoControlRequest() failed\n");
1237 ExFreePool(Srb->SenseInfoBuffer);
1238 ExFreePool(Event);
1239 return(STATUS_INSUFFICIENT_RESOURCES);
1240 }
1241
1242 /* FIXME: more irp initialization required? */
1243
1244
1245 /* Attach Srb to the Irp */
1246 IoStack = IoGetNextIrpStackLocation(Irp);
1247 IoStack->Parameters.Scsi.Srb = Srb;
1248 Srb->OriginalRequest = Irp;
1249
1250
1251 /* Call the SCSI port driver */
1252 Status = IoCallDriver(DeviceExtension->PortDeviceObject,
1253 Irp);
1254 if (Status == STATUS_PENDING)
1255 {
1256 KeWaitForSingleObject(Event,
1257 Suspended,
1258 KernelMode,
1259 FALSE,
1260 NULL);
1261 }
1262
1263 if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS)
1264 {
1265 Retry = ScsiClassInterpretSenseInfo(DeviceObject,
1266 Srb,
1267 IRP_MJ_SCSI,
1268 0,
1269 MAXIMUM_RETRIES - RetryCount,
1270 &Status);
1271 if (Retry == TRUE)
1272 {
1273 /* FIXME!! */
1274 DPRINT1("Should try again!\n");
1275
1276 }
1277 }
1278 else
1279 {
1280 Status = STATUS_SUCCESS;
1281 }
1282
1283 ExFreePool(Srb->SenseInfoBuffer);
1284 ExFreePool(Event);
1285
1286 DPRINT("ScsiClassSendSrbSynchronous() done\n");
1287
1288 return(Status);
1289 }
1290
1291
1292 VOID STDCALL
1293 ScsiClassSplitRequest(PDEVICE_OBJECT DeviceObject,
1294 PIRP Irp,
1295 ULONG MaximumBytes)
1296 {
1297 PDEVICE_EXTENSION DeviceExtension;
1298 PIO_STACK_LOCATION CurrentStack;
1299 PIO_STACK_LOCATION NextStack;
1300 PIO_STACK_LOCATION NewStack;
1301 PSCSI_REQUEST_BLOCK Srb;
1302 LARGE_INTEGER Offset;
1303 PIRP NewIrp;
1304 PVOID DataBuffer;
1305 ULONG TransferLength;
1306 ULONG RequestCount;
1307 ULONG DataLength;
1308 ULONG i;
1309
1310 DPRINT("ScsiClassSplitRequest(DeviceObject %lx Irp %lx MaximumBytes %lu)\n",
1311 DeviceObject, Irp, MaximumBytes);
1312
1313 DeviceExtension = DeviceObject->DeviceExtension;
1314 CurrentStack = IoGetCurrentIrpStackLocation(Irp);
1315 NextStack = IoGetNextIrpStackLocation(Irp);
1316 DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
1317
1318 /* Initialize transfer data for first request */
1319 Offset = CurrentStack->Parameters.Read.ByteOffset;
1320 TransferLength = CurrentStack->Parameters.Read.Length;
1321 DataLength = MaximumBytes;
1322 RequestCount = ROUND_UP(TransferLength, MaximumBytes) / MaximumBytes;
1323
1324 /* Save request count in the original IRP */
1325 NextStack->Parameters.Others.Argument1 = (PVOID)RequestCount;
1326
1327 DPRINT("RequestCount %lu\n", RequestCount);
1328
1329 for (i = 0; i < RequestCount; i++)
1330 {
1331 /* Create a new IRP */
1332 NewIrp = IoAllocateIrp(DeviceObject->StackSize,
1333 FALSE);
1334 if (NewIrp == NULL)
1335 {
1336 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1337 Irp->IoStatus.Information = 0;
1338
1339 if (i == 0)
1340 IoCompleteRequest(Irp,
1341 IO_NO_INCREMENT);
1342 return;
1343 }
1344
1345 /* Initialize the new IRP */
1346 NewIrp->MdlAddress = Irp->MdlAddress;
1347
1348 IoSetNextIrpStackLocation(NewIrp);
1349 NewStack = IoGetCurrentIrpStackLocation(NewIrp);
1350
1351 NewStack->MajorFunction = CurrentStack->MajorFunction;
1352 NewStack->Parameters.Read.ByteOffset = Offset;
1353 NewStack->Parameters.Read.Length = DataLength;
1354 NewStack->DeviceObject = DeviceObject;
1355
1356 ScsiClassBuildRequest(DeviceObject,
1357 NewIrp);
1358
1359 NewStack = IoGetNextIrpStackLocation(NewIrp);
1360 Srb = NewStack->Parameters.Others.Argument1;
1361 Srb->DataBuffer = DataBuffer;
1362
1363 NewIrp->AssociatedIrp.MasterIrp = Irp;
1364
1365 /* Initialize completion routine */
1366 IoSetCompletionRoutine(NewIrp,
1367 ScsiClassIoCompleteAssociated,
1368 Srb,
1369 TRUE,
1370 TRUE,
1371 TRUE);
1372
1373 /* Send the new IRP down to the port driver */
1374 IoCallDriver(DeviceExtension->PortDeviceObject,
1375 NewIrp);
1376
1377 /* Adjust transfer data for next request */
1378 DataBuffer = (PCHAR)DataBuffer + MaximumBytes;
1379 TransferLength -= MaximumBytes;
1380 DataLength = (TransferLength > MaximumBytes) ? MaximumBytes : TransferLength;
1381 Offset.QuadPart = Offset.QuadPart + MaximumBytes;
1382 }
1383 }
1384
1385
1386 /* INTERNAL FUNCTIONS *******************************************************/
1387
1388 static NTSTATUS STDCALL
1389 ScsiClassCreateClose(IN PDEVICE_OBJECT DeviceObject,
1390 IN PIRP Irp)
1391 {
1392 PDEVICE_EXTENSION DeviceExtension;
1393
1394 DPRINT("ScsiClassCreateClose() called\n");
1395
1396 DeviceExtension = DeviceObject->DeviceExtension;
1397
1398 if (DeviceExtension->ClassCreateClose)
1399 return(DeviceExtension->ClassCreateClose(DeviceObject,
1400 Irp));
1401
1402 Irp->IoStatus.Status = STATUS_SUCCESS;
1403 Irp->IoStatus.Information = 0;
1404 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1405
1406 return(STATUS_SUCCESS);
1407 }
1408
1409
1410 static NTSTATUS STDCALL
1411 ScsiClassReadWrite(IN PDEVICE_OBJECT DeviceObject,
1412 IN PIRP Irp)
1413 {
1414 PDEVICE_EXTENSION DeviceExtension;
1415 PIO_STACK_LOCATION IrpStack;
1416 ULONG MaximumTransferLength;
1417 ULONG CurrentTransferLength;
1418 ULONG MaximumTransferPages;
1419 ULONG CurrentTransferPages;
1420 NTSTATUS Status;
1421
1422 DPRINT("ScsiClassReadWrite() called\n");
1423
1424 DeviceExtension = DeviceObject->DeviceExtension;
1425 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1426
1427 DPRINT("Relative Offset: %I64u Length: %lu\n",
1428 IrpStack->Parameters.Read.ByteOffset.QuadPart,
1429 IrpStack->Parameters.Read.Length);
1430
1431 // MaximumTransferLength = DeviceExtension->PortCapabilities->MaximumTransferLength;
1432 // MaximumTransferPages = DeviceExtension->PortCapabilities->MaximumPhysicalPages;
1433 MaximumTransferLength = 0x10000; /* 64 kbytes */
1434 MaximumTransferPages = MaximumTransferLength / PAGESIZE;
1435
1436 CurrentTransferLength = IrpStack->Parameters.Read.Length;
1437
1438 if ((DeviceObject->Flags & DO_VERIFY_VOLUME) &&
1439 !(IrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME))
1440 {
1441 IoSetHardErrorOrVerifyDevice(Irp,
1442 DeviceObject);
1443
1444 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
1445 Irp->IoStatus.Information = 0;
1446
1447 IoCompleteRequest(Irp,
1448 IO_NO_INCREMENT);
1449 return(STATUS_VERIFY_REQUIRED);
1450 }
1451
1452 /* Class driver verifies the IRP */
1453 Status = DeviceExtension->ClassReadWriteVerification(DeviceObject,
1454 Irp);
1455 if (!NT_SUCCESS(Status))
1456 {
1457 IoCompleteRequest(Irp,
1458 IO_NO_INCREMENT);
1459 return(Status);
1460 }
1461 else if (Status == STATUS_PENDING)
1462 {
1463 IoMarkIrpPending(Irp);
1464 return(STATUS_PENDING);
1465 }
1466
1467 /* Finish a zero-byte transfer */
1468 if (CurrentTransferLength == 0)
1469 {
1470 Irp->IoStatus.Status = STATUS_SUCCESS;
1471 Irp->IoStatus.Information = 0;
1472 IoCompleteRequest(Irp,
1473 IO_NO_INCREMENT);
1474 return(STATUS_SUCCESS);
1475 }
1476
1477 if (DeviceExtension->ClassStartIo != NULL)
1478 {
1479 DPRINT("ScsiClassReadWrite() starting packet\n");
1480
1481 IoMarkIrpPending(Irp);
1482 IoStartPacket(DeviceObject,
1483 Irp,
1484 NULL,
1485 NULL);
1486
1487 return(STATUS_PENDING);
1488 }
1489
1490 /* Adjust partition-relative starting offset to absolute offset */
1491 IrpStack->Parameters.Read.ByteOffset.QuadPart += DeviceExtension->StartingOffset.QuadPart;
1492
1493 /* Calculate number of pages in this transfer */
1494 CurrentTransferPages =
1495 ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
1496 IrpStack->Parameters.Read.Length);
1497
1498 if (CurrentTransferLength > MaximumTransferLength ||
1499 CurrentTransferPages > MaximumTransferPages)
1500 {
1501 DPRINT("Split current request: MaximumTransferLength %lu CurrentTransferLength %lu\n",
1502 MaximumTransferLength, CurrentTransferLength);
1503
1504 /* Adjust the maximum transfer length */
1505 CurrentTransferPages = DeviceExtension->PortCapabilities->MaximumPhysicalPages - 1;
1506
1507 if (MaximumTransferLength > CurrentTransferPages * PAGESIZE)
1508 MaximumTransferLength = CurrentTransferPages * PAGESIZE;
1509
1510 if (MaximumTransferLength == 0)
1511 MaximumTransferLength = PAGESIZE;
1512
1513 IoMarkIrpPending(Irp);
1514
1515 /* Split current request */
1516 ScsiClassSplitRequest(DeviceObject,
1517 Irp,
1518 MaximumTransferLength);
1519
1520 return(STATUS_PENDING);
1521 }
1522
1523 ScsiClassBuildRequest(DeviceObject,
1524 Irp);
1525
1526 DPRINT("ScsiClassReadWrite() done\n");
1527
1528 /* Call the port driver */
1529 return(IoCallDriver(DeviceExtension->PortDeviceObject,
1530 Irp));
1531 }
1532
1533
1534 static NTSTATUS STDCALL
1535 ScsiClassScsiDispatch(IN PDEVICE_OBJECT DeviceObject,
1536 IN PIRP Irp)
1537 {
1538 DPRINT1("ScsiClassScsiDispatch() called\n");
1539
1540 Irp->IoStatus.Status = STATUS_SUCCESS;
1541 Irp->IoStatus.Information = 0;
1542 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1543
1544 return(STATUS_SUCCESS);
1545 }
1546
1547
1548 static NTSTATUS STDCALL
1549 ScsiClassDeviceDispatch(IN PDEVICE_OBJECT DeviceObject,
1550 IN PIRP Irp)
1551 {
1552 PDEVICE_EXTENSION DeviceExtension;
1553
1554 DPRINT("ScsiClassDeviceDispatch() called\n");
1555
1556 DeviceExtension = DeviceObject->DeviceExtension;
1557 if (DeviceExtension->ClassDeviceControl)
1558 {
1559 return(DeviceExtension->ClassDeviceControl(DeviceObject, Irp));
1560 }
1561
1562 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
1563 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1564
1565 return(STATUS_INVALID_DEVICE_REQUEST);
1566 }
1567
1568
1569 static NTSTATUS STDCALL
1570 ScsiClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
1571 IN PIRP Irp)
1572 {
1573 PDEVICE_EXTENSION DeviceExtension;
1574
1575 DPRINT("ScsiClassShutdownFlush() called\n");
1576
1577 DeviceExtension = DeviceObject->DeviceExtension;
1578 if (DeviceExtension->ClassShutdownFlush)
1579 {
1580 return(DeviceExtension->ClassShutdownFlush(DeviceObject, Irp));
1581 }
1582
1583 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
1584 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1585
1586 return(STATUS_INVALID_DEVICE_REQUEST);
1587 }
1588
1589
1590 static VOID
1591 ScsiClassRetryRequest(PDEVICE_OBJECT DeviceObject,
1592 PIRP Irp,
1593 PSCSI_REQUEST_BLOCK Srb)
1594 {
1595 PDEVICE_EXTENSION DeviceExtension;
1596 PIO_STACK_LOCATION CurrentIrpStack;
1597 PIO_STACK_LOCATION NextIrpStack;
1598 ULONG TransferLength;
1599
1600 DPRINT1("ScsiPortRetryRequest() called\n");
1601
1602 DeviceExtension = DeviceObject->DeviceExtension;
1603 CurrentIrpStack = IoGetCurrentIrpStackLocation(Irp);
1604 NextIrpStack = IoGetNextIrpStackLocation(Irp);
1605
1606 if (CurrentIrpStack->MajorFunction == IRP_MJ_READ ||
1607 CurrentIrpStack->MajorFunction == IRP_MJ_WRITE)
1608 {
1609 TransferLength = CurrentIrpStack->Parameters.Read.Length;
1610 }
1611 else if (Irp->MdlAddress != NULL)
1612 {
1613 TransferLength = Irp->MdlAddress->ByteCount;
1614 }
1615 else
1616 {
1617 TransferLength = 0;
1618 }
1619
1620 Srb->DataTransferLength = TransferLength;
1621 Srb->SrbStatus = 0;
1622 Srb->ScsiStatus = 0;
1623 // Srb->QueueTag = SP_UNTAGGED;
1624
1625 /* Don't modify the flags */
1626 // Srb->Flags =
1627
1628 // CurrentIrpStack->MajorFunction = IRP_MJ_SCSI;
1629 // CurrentIrpStack->Parameters.Scsi.Srb = Srb;
1630
1631 // IoSkipCurrentIrpStackLocation(Irp);
1632
1633 *NextIrpStack = *CurrentIrpStack;
1634 NextIrpStack->MajorFunction = IRP_MJ_SCSI;
1635 NextIrpStack->Parameters.Scsi.Srb = Srb;
1636
1637
1638 IoSetCompletionRoutine(Irp,
1639 ScsiClassIoComplete,
1640 Srb,
1641 TRUE,
1642 TRUE,
1643 TRUE);
1644
1645 DPRINT1("ScsiPortRetryRequest() done\n");
1646
1647 IoCallDriver(DeviceExtension->PortDeviceObject,
1648 Irp);
1649 }
1650
1651 /* EOF */