f8f3b7401fd407d7bb599a3c33616518b41e1928
[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.16 2002/04/24 22:20:50 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 /* FIXME: use lookaside list instead */
880 DPRINT("Freed SRB %p\n", IrpStack->Parameters.Scsi.Srb);
881 ExFreePool(IrpStack->Parameters.Scsi.Srb);
882
883 Irp->IoStatus.Status = Status;
884 #if 0
885 if (!NT_SUCCESS(Status))
886 {
887 Irp->IoStatus.Information = 0;
888 if (IoIsErrorUserInduced(Status))
889 {
890 IoSetHardErrorOrVerifyDevice(Irp,
891 DeviceObject);
892 }
893 }
894
895 if (Irp->PendingReturned)
896 {
897 IoMarkIrpPending(Irp);
898 }
899 #endif
900
901 if (DeviceExtension->ClassStartIo != NULL)
902 {
903 if (IrpStack->MajorFunction != IRP_MJ_DEVICE_CONTROL)
904 {
905 IoStartNextPacket(DeviceObject,
906 FALSE);
907 }
908 }
909
910 DPRINT("ScsiClassIoComplete() done (Status %lx)\n", Status);
911
912 return(Status);
913 }
914
915
916 NTSTATUS STDCALL
917 ScsiClassIoCompleteAssociated(PDEVICE_OBJECT DeviceObject,
918 PIRP Irp,
919 PVOID Context)
920 {
921 PDEVICE_EXTENSION DeviceExtension;
922 PIO_STACK_LOCATION IrpStack;
923 PSCSI_REQUEST_BLOCK Srb;
924 PIRP MasterIrp;
925 BOOLEAN Retry;
926 LONG RequestCount;
927 NTSTATUS Status;
928
929 DPRINT("ScsiClassIoCompleteAssociated(DeviceObject %p Irp %p Context %p) called\n",
930 DeviceObject, Irp, Context);
931
932 MasterIrp = Irp->AssociatedIrp.MasterIrp;
933 DeviceExtension = DeviceObject->DeviceExtension;
934 Srb = (PSCSI_REQUEST_BLOCK)Context;
935 DPRINT("Srb %p\n", Srb);
936
937 IrpStack = IoGetCurrentIrpStackLocation(Irp);
938
939 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
940 {
941 Status = STATUS_SUCCESS;
942 }
943 else
944 {
945 /* Get more detailed status information */
946 Retry = ScsiClassInterpretSenseInfo(DeviceObject,
947 Srb,
948 IrpStack->MajorFunction,
949 0,
950 MAXIMUM_RETRIES - ((ULONG)IrpStack->Parameters.Others.Argument4),
951 &Status);
952
953 DPRINT1("Retry count: %lu\n", (ULONG)IrpStack->Parameters.Others.Argument4);
954
955 if ((Retry == TRUE) &&
956 ((ULONG)IrpStack->Parameters.Others.Argument4 > 0))
957 {
958 ((ULONG)IrpStack->Parameters.Others.Argument4)--;
959 DPRINT1("Retry count: %lu\n", (ULONG)IrpStack->Parameters.Others.Argument4);
960
961 DPRINT1("Should try again!\n");
962 #ifdef ENABLE_RETRY
963 ScsiClassRetryRequest(DeviceObject,
964 Irp,
965 Srb);
966 return(STATUS_MORE_PROCESSING_REQUIRED);
967 #else
968 return(Status);
969 #endif
970 }
971 }
972
973 /* FIXME: use lookaside list instead */
974 DPRINT("Freed SRB %p\n", IrpStack->Parameters.Scsi.Srb);
975 ExFreePool(IrpStack->Parameters.Scsi.Srb);
976
977 Irp->IoStatus.Status = Status;
978
979 IrpStack = IoGetNextIrpStackLocation(MasterIrp);
980 if (!NT_SUCCESS(Status))
981 {
982 MasterIrp->IoStatus.Status = Status;
983 MasterIrp->IoStatus.Information = 0;
984
985 if (IoIsErrorUserInduced(Status))
986 {
987 IoSetHardErrorOrVerifyDevice(MasterIrp,
988 DeviceObject);
989 }
990 }
991
992 /* Decrement the request counter in the Master IRP */
993 RequestCount = InterlockedDecrement((PLONG)&IrpStack->Parameters.Others.Argument1);
994
995 if (RequestCount == 0)
996 {
997 /* Complete the Master IRP */
998 IoCompleteRequest(MasterIrp,
999 IO_DISK_INCREMENT);
1000
1001 if (DeviceExtension->ClassStartIo)
1002 {
1003 IoStartNextPacket(DeviceObject,
1004 FALSE);
1005 }
1006 }
1007
1008 /* Free the current IRP */
1009 IoFreeIrp(Irp);
1010
1011 return(STATUS_MORE_PROCESSING_REQUIRED);
1012 }
1013
1014
1015 ULONG STDCALL
1016 ScsiClassModeSense(PDEVICE_OBJECT DeviceObject,
1017 CHAR ModeSenseBuffer,
1018 ULONG Length,
1019 UCHAR PageMode)
1020 {
1021 UNIMPLEMENTED;
1022 }
1023
1024
1025 ULONG STDCALL
1026 ScsiClassQueryTimeOutRegistryValue(IN PUNICODE_STRING RegistryPath)
1027 {
1028 UNIMPLEMENTED;
1029 }
1030
1031
1032 NTSTATUS STDCALL
1033 ScsiClassReadDriveCapacity(IN PDEVICE_OBJECT DeviceObject)
1034 {
1035 PDEVICE_EXTENSION DeviceExtension;
1036 PREAD_CAPACITY_DATA CapacityBuffer;
1037 SCSI_REQUEST_BLOCK Srb;
1038 PCDB Cdb;
1039 NTSTATUS Status;
1040 ULONG LastSector;
1041 ULONG SectorSize;
1042
1043 DPRINT("ScsiClassReadDriveCapacity() called\n");
1044
1045 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1046
1047 CapacityBuffer = ExAllocatePool(NonPagedPool,
1048 sizeof(READ_CAPACITY_DATA));
1049 if (CapacityBuffer == NULL)
1050 {
1051 return(STATUS_INSUFFICIENT_RESOURCES);
1052 }
1053
1054 RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
1055
1056 Srb.CdbLength = 10;
1057 Srb.TimeOutValue = DeviceExtension->TimeOutValue;
1058
1059 Cdb = (PCDB)Srb.Cdb;
1060 Cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
1061
1062
1063 Status = ScsiClassSendSrbSynchronous(DeviceObject,
1064 &Srb,
1065 CapacityBuffer,
1066 sizeof(READ_CAPACITY_DATA),
1067 FALSE);
1068 DPRINT("Status: %lx\n", Status);
1069 DPRINT("Srb: %p\n", &Srb);
1070 if (NT_SUCCESS(Status))
1071 {
1072 SectorSize = (((PUCHAR)&CapacityBuffer->BytesPerBlock)[0] << 24) |
1073 (((PUCHAR)&CapacityBuffer->BytesPerBlock)[1] << 16) |
1074 (((PUCHAR)&CapacityBuffer->BytesPerBlock)[2] << 8) |
1075 ((PUCHAR)&CapacityBuffer->BytesPerBlock)[3];
1076
1077
1078 LastSector = (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[0] << 24) |
1079 (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[1] << 16) |
1080 (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[2] << 8) |
1081 ((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[3];
1082
1083 DeviceExtension->DiskGeometry->BytesPerSector = SectorSize;
1084
1085 DeviceExtension->PartitionLength.QuadPart = (LONGLONG)(LastSector + 1);
1086 WHICH_BIT(DeviceExtension->DiskGeometry->BytesPerSector,
1087 DeviceExtension->SectorShift);
1088 DeviceExtension->PartitionLength.QuadPart =
1089 (DeviceExtension->PartitionLength.QuadPart << DeviceExtension->SectorShift);
1090
1091 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
1092 {
1093 DeviceExtension->DiskGeometry->MediaType = RemovableMedia;
1094 }
1095 else
1096 {
1097 DeviceExtension->DiskGeometry->MediaType = FixedMedia;
1098 }
1099 DeviceExtension->DiskGeometry->Cylinders.QuadPart = (LONGLONG)((LastSector + 1)/(32 * 64));
1100 DeviceExtension->DiskGeometry->SectorsPerTrack = 32;
1101 DeviceExtension->DiskGeometry->TracksPerCylinder = 64;
1102
1103 DPRINT("SectorSize: %lu SectorCount: %lu\n", SectorSize, LastSector + 1);
1104 }
1105 else
1106 {
1107 /* Use default values if disk geometry cannot be read */
1108 RtlZeroMemory(&DeviceExtension->DiskGeometry,
1109 sizeof(DISK_GEOMETRY));
1110 DeviceExtension->DiskGeometry->BytesPerSector = 512;
1111 DeviceExtension->SectorShift = 9;
1112 DeviceExtension->PartitionLength.QuadPart = 0;
1113
1114 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
1115 {
1116 DeviceExtension->DiskGeometry->MediaType = RemovableMedia;
1117 }
1118 else
1119 {
1120 DeviceExtension->DiskGeometry->MediaType = FixedMedia;
1121 }
1122 }
1123
1124 ExFreePool(CapacityBuffer);
1125
1126 DPRINT("ScsiClassReadDriveCapacity() done\n");
1127
1128 return(Status);
1129 }
1130
1131
1132 VOID STDCALL
1133 ScsiClassReleaseQueue(IN PDEVICE_OBJECT DeviceObject)
1134 {
1135 UNIMPLEMENTED;
1136 }
1137
1138
1139 NTSTATUS STDCALL
1140 ScsiClassSendSrbAsynchronous(PDEVICE_OBJECT DeviceObject,
1141 PSCSI_REQUEST_BLOCK Srb,
1142 PIRP Irp,
1143 PVOID BufferAddress,
1144 ULONG BufferLength,
1145 BOOLEAN WriteToDevice)
1146 {
1147 UNIMPLEMENTED;
1148 }
1149
1150
1151 NTSTATUS STDCALL
1152 ScsiClassSendSrbSynchronous(PDEVICE_OBJECT DeviceObject,
1153 PSCSI_REQUEST_BLOCK Srb,
1154 PVOID BufferAddress,
1155 ULONG BufferLength,
1156 BOOLEAN WriteToDevice)
1157 {
1158 PDEVICE_EXTENSION DeviceExtension;
1159 IO_STATUS_BLOCK IoStatusBlock;
1160 PIO_STACK_LOCATION IoStack;
1161 ULONG RequestType;
1162 BOOLEAN Retry;
1163 ULONG RetryCount;
1164 PKEVENT Event;
1165 PIRP Irp;
1166 NTSTATUS Status;
1167
1168
1169 DPRINT("ScsiClassSendSrbSynchronous() called\n");
1170
1171 RetryCount = MAXIMUM_RETRIES;
1172 DeviceExtension = DeviceObject->DeviceExtension;
1173
1174 Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1175 Srb->PathId = DeviceExtension->PathId;
1176 Srb->TargetId = DeviceExtension->TargetId;
1177 Srb->Lun = DeviceExtension->Lun;
1178 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1179
1180 /* FIXME: more srb initialization required? */
1181
1182 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1183 Srb->SenseInfoBuffer = ExAllocatePool(NonPagedPool,
1184 SENSE_BUFFER_SIZE);
1185 if (Srb->SenseInfoBuffer == NULL)
1186 return(STATUS_INSUFFICIENT_RESOURCES);
1187
1188 if (BufferAddress == NULL)
1189 {
1190 BufferLength = 0;
1191 RequestType = IOCTL_SCSI_EXECUTE_NONE;
1192 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
1193 }
1194 else
1195 {
1196 if (WriteToDevice == TRUE)
1197 {
1198 RequestType = IOCTL_SCSI_EXECUTE_OUT;
1199 Srb->SrbFlags = SRB_FLAGS_DATA_OUT;
1200 }
1201 else
1202 {
1203 RequestType = IOCTL_SCSI_EXECUTE_IN;
1204 Srb->SrbFlags = SRB_FLAGS_DATA_IN;
1205 }
1206 }
1207
1208 Srb->DataTransferLength = BufferLength;
1209 Srb->DataBuffer = BufferAddress;
1210
1211 Event = ExAllocatePool(NonPagedPool,
1212 sizeof(KEVENT));
1213 KeInitializeEvent(Event,
1214 NotificationEvent,
1215 FALSE);
1216
1217 Irp = IoBuildDeviceIoControlRequest(RequestType,
1218 DeviceExtension->PortDeviceObject,
1219 NULL,
1220 0,
1221 BufferAddress,
1222 BufferLength,
1223 TRUE,
1224 Event,
1225 &IoStatusBlock);
1226 if (Irp == NULL)
1227 {
1228 DPRINT1("IoBuildDeviceIoControlRequest() failed\n");
1229 ExFreePool(Srb->SenseInfoBuffer);
1230 ExFreePool(Event);
1231 return(STATUS_INSUFFICIENT_RESOURCES);
1232 }
1233
1234 /* FIXME: more irp initialization required? */
1235
1236
1237 /* Attach Srb to the Irp */
1238 IoStack = IoGetNextIrpStackLocation(Irp);
1239 IoStack->Parameters.Scsi.Srb = Srb;
1240 Srb->OriginalRequest = Irp;
1241
1242
1243 /* Call the SCSI port driver */
1244 Status = IoCallDriver(DeviceExtension->PortDeviceObject,
1245 Irp);
1246 if (Status == STATUS_PENDING)
1247 {
1248 KeWaitForSingleObject(Event,
1249 Suspended,
1250 KernelMode,
1251 FALSE,
1252 NULL);
1253 }
1254
1255 if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS)
1256 {
1257 Retry = ScsiClassInterpretSenseInfo(DeviceObject,
1258 Srb,
1259 IRP_MJ_SCSI,
1260 0,
1261 MAXIMUM_RETRIES - RetryCount,
1262 &Status);
1263 if (Retry == TRUE)
1264 {
1265 /* FIXME!! */
1266 DPRINT1("Should try again!\n");
1267
1268 }
1269 }
1270 else
1271 {
1272 Status = STATUS_SUCCESS;
1273 }
1274
1275 ExFreePool(Srb->SenseInfoBuffer);
1276 ExFreePool(Event);
1277
1278 DPRINT("ScsiClassSendSrbSynchronous() done\n");
1279
1280 return(Status);
1281 }
1282
1283
1284 VOID STDCALL
1285 ScsiClassSplitRequest(PDEVICE_OBJECT DeviceObject,
1286 PIRP Irp,
1287 ULONG MaximumBytes)
1288 {
1289 PDEVICE_EXTENSION DeviceExtension;
1290 PIO_STACK_LOCATION CurrentStack;
1291 PIO_STACK_LOCATION NextStack;
1292 PIO_STACK_LOCATION NewStack;
1293 PSCSI_REQUEST_BLOCK Srb;
1294 LARGE_INTEGER Offset;
1295 PIRP NewIrp;
1296 PVOID DataBuffer;
1297 ULONG TransferLength;
1298 ULONG RequestCount;
1299 ULONG DataLength;
1300 ULONG i;
1301
1302 DPRINT1("ScsiClassSplitRequest(DeviceObject %lx Irp %lx MaximumBytes %lu)\n",
1303 DeviceObject, Irp, MaximumBytes);
1304
1305 DeviceExtension = DeviceObject->DeviceExtension;
1306 CurrentStack = IoGetCurrentIrpStackLocation(Irp);
1307 NextStack = IoGetNextIrpStackLocation(Irp);
1308 DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
1309
1310 /* Initialize transfer data for first request */
1311 Offset = CurrentStack->Parameters.Read.ByteOffset;
1312 TransferLength = CurrentStack->Parameters.Read.Length;
1313 DataLength = MaximumBytes;
1314 RequestCount = ROUND_UP(TransferLength, MaximumBytes) / MaximumBytes;
1315
1316 /* Save request count in the original IRP */
1317 NextStack->Parameters.Others.Argument1 = (PVOID)RequestCount;
1318
1319 DPRINT1("RequestCount %lu\n", RequestCount);
1320
1321 for (i = 0; i < RequestCount; i++)
1322 {
1323 /* Create a new IRP */
1324 NewIrp = IoAllocateIrp(DeviceObject->StackSize,
1325 FALSE);
1326 if (NewIrp == NULL)
1327 {
1328 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1329 Irp->IoStatus.Information = 0;
1330
1331 if (i == 0)
1332 IoCompleteRequest(Irp,
1333 IO_NO_INCREMENT);
1334 return;
1335 }
1336
1337 /* Initialize the new IRP */
1338 NewIrp->MdlAddress = Irp->MdlAddress;
1339
1340 IoSetNextIrpStackLocation(NewIrp);
1341 NewStack = IoGetCurrentIrpStackLocation(NewIrp);
1342
1343 NewStack->MajorFunction = CurrentStack->MajorFunction;
1344 NewStack->Parameters.Read.ByteOffset = Offset;
1345 NewStack->Parameters.Read.Length = DataLength;
1346 NewStack->DeviceObject = DeviceObject;
1347
1348 ScsiClassBuildRequest(DeviceObject,
1349 NewIrp);
1350
1351 NewStack = IoGetNextIrpStackLocation(NewIrp);
1352 Srb = NewStack->Parameters.Others.Argument1;
1353 Srb->DataBuffer = DataBuffer;
1354
1355 NewIrp->AssociatedIrp.MasterIrp = Irp;
1356
1357 /* Initialize completion routine */
1358 IoSetCompletionRoutine(NewIrp,
1359 ScsiClassIoCompleteAssociated,
1360 Srb,
1361 TRUE,
1362 TRUE,
1363 TRUE);
1364
1365 /* Send the new IRP down to the port driver */
1366 IoCallDriver(DeviceExtension->PortDeviceObject,
1367 NewIrp);
1368
1369 /* Adjust transfer data for next request */
1370 DataBuffer = (PCHAR)DataBuffer + MaximumBytes;
1371 TransferLength -= MaximumBytes;
1372 DataLength = (TransferLength > MaximumBytes) ? MaximumBytes : TransferLength;
1373 Offset.QuadPart = Offset.QuadPart + MaximumBytes;
1374 }
1375 }
1376
1377
1378 /* INTERNAL FUNCTIONS *******************************************************/
1379
1380 static NTSTATUS STDCALL
1381 ScsiClassCreateClose(IN PDEVICE_OBJECT DeviceObject,
1382 IN PIRP Irp)
1383 {
1384 PDEVICE_EXTENSION DeviceExtension;
1385
1386 DPRINT("ScsiClassCreateClose() called\n");
1387
1388 DeviceExtension = DeviceObject->DeviceExtension;
1389
1390 if (DeviceExtension->ClassCreateClose)
1391 return(DeviceExtension->ClassCreateClose(DeviceObject,
1392 Irp));
1393
1394 Irp->IoStatus.Status = STATUS_SUCCESS;
1395 Irp->IoStatus.Information = 0;
1396 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1397
1398 return(STATUS_SUCCESS);
1399 }
1400
1401
1402 static NTSTATUS STDCALL
1403 ScsiClassReadWrite(IN PDEVICE_OBJECT DeviceObject,
1404 IN PIRP Irp)
1405 {
1406 PDEVICE_EXTENSION DeviceExtension;
1407 PIO_STACK_LOCATION IrpStack;
1408 ULONG MaximumTransferLength;
1409 ULONG CurrentTransferLength;
1410 ULONG MaximumTransferPages;
1411 ULONG CurrentTransferPages;
1412 NTSTATUS Status;
1413
1414 DPRINT("ScsiClassReadWrite() called\n");
1415
1416 DeviceExtension = DeviceObject->DeviceExtension;
1417 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1418
1419 DPRINT("Relative Offset: %I64u Length: %lu\n",
1420 IrpStack->Parameters.Read.ByteOffset.QuadPart,
1421 IrpStack->Parameters.Read.Length);
1422
1423 // MaximumTransferLength = DeviceExtension->PortCapabilities->MaximumTransferLength;
1424 // MaximumTransferPages = DeviceExtension->PortCapabilities->MaximumPhysicalPages;
1425 MaximumTransferLength = 0x10000; /* 64 kbytes */
1426 MaximumTransferPages = MaximumTransferLength / PAGESIZE;
1427
1428 CurrentTransferLength = IrpStack->Parameters.Read.Length;
1429
1430 if ((DeviceObject->Flags & DO_VERIFY_VOLUME) &&
1431 !(IrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME))
1432 {
1433 IoSetHardErrorOrVerifyDevice(Irp,
1434 DeviceObject);
1435
1436 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
1437 Irp->IoStatus.Information = 0;
1438
1439 IoCompleteRequest(Irp,
1440 IO_NO_INCREMENT);
1441 return(STATUS_VERIFY_REQUIRED);
1442 }
1443
1444 /* Class driver verifies the IRP */
1445 Status = DeviceExtension->ClassReadWriteVerification(DeviceObject,
1446 Irp);
1447 if (!NT_SUCCESS(Status))
1448 {
1449 IoCompleteRequest(Irp,
1450 IO_NO_INCREMENT);
1451 return(Status);
1452 }
1453 else if (Status == STATUS_PENDING)
1454 {
1455 IoMarkIrpPending(Irp);
1456 return(STATUS_PENDING);
1457 }
1458
1459 /* Finish a zero-byte transfer */
1460 if (CurrentTransferLength == 0)
1461 {
1462 Irp->IoStatus.Status = STATUS_SUCCESS;
1463 Irp->IoStatus.Information = 0;
1464 IoCompleteRequest(Irp,
1465 IO_NO_INCREMENT);
1466 return(STATUS_SUCCESS);
1467 }
1468
1469 if (DeviceExtension->ClassStartIo != NULL)
1470 {
1471 DPRINT("ScsiClassReadWrite() starting packet\n");
1472
1473 IoMarkIrpPending(Irp);
1474 IoStartPacket(DeviceObject,
1475 Irp,
1476 NULL,
1477 NULL);
1478
1479 return(STATUS_PENDING);
1480 }
1481
1482 IoMarkIrpPending(Irp);
1483
1484 /* Adjust partition-relative starting offset to absolute offset */
1485 IrpStack->Parameters.Read.ByteOffset.QuadPart += DeviceExtension->StartingOffset.QuadPart;
1486
1487 /* Calculate number of pages in this transfer */
1488 CurrentTransferPages =
1489 ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
1490 IrpStack->Parameters.Read.Length);
1491
1492 if (CurrentTransferLength > MaximumTransferLength ||
1493 CurrentTransferPages > MaximumTransferPages)
1494 {
1495 DPRINT1("Split current request: MaximumTransferLength %lu CurrentTransferLength %lu\n",
1496 MaximumTransferLength, CurrentTransferLength);
1497
1498 /* Adjust the maximum transfer length */
1499 CurrentTransferPages = DeviceExtension->PortCapabilities->MaximumPhysicalPages - 1;
1500
1501 if (MaximumTransferLength > CurrentTransferPages * PAGESIZE)
1502 MaximumTransferLength = CurrentTransferPages * PAGESIZE;
1503
1504 if (MaximumTransferLength == 0)
1505 MaximumTransferLength = PAGESIZE;
1506
1507 IoMarkIrpPending(Irp);
1508
1509 /* Split current request */
1510 ScsiClassSplitRequest(DeviceObject,
1511 Irp,
1512 MaximumTransferLength);
1513
1514 return(STATUS_PENDING);
1515 }
1516
1517 ScsiClassBuildRequest(DeviceObject,
1518 Irp);
1519
1520 DPRINT("ScsiClassReadWrite() done\n");
1521
1522 /* Call the port driver */
1523 return(IoCallDriver(DeviceExtension->PortDeviceObject,
1524 Irp));
1525 }
1526
1527
1528 static NTSTATUS STDCALL
1529 ScsiClassScsiDispatch(IN PDEVICE_OBJECT DeviceObject,
1530 IN PIRP Irp)
1531 {
1532 DPRINT1("ScsiClassScsiDispatch() called\n");
1533
1534 Irp->IoStatus.Status = STATUS_SUCCESS;
1535 Irp->IoStatus.Information = 0;
1536 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1537
1538 return(STATUS_SUCCESS);
1539 }
1540
1541
1542 static NTSTATUS STDCALL
1543 ScsiClassDeviceDispatch(IN PDEVICE_OBJECT DeviceObject,
1544 IN PIRP Irp)
1545 {
1546 PDEVICE_EXTENSION DeviceExtension;
1547
1548 DPRINT("ScsiClassDeviceDispatch() called\n");
1549
1550 DeviceExtension = DeviceObject->DeviceExtension;
1551 if (DeviceExtension->ClassDeviceControl)
1552 {
1553 return(DeviceExtension->ClassDeviceControl(DeviceObject, Irp));
1554 }
1555
1556 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
1557 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1558
1559 return(STATUS_INVALID_DEVICE_REQUEST);
1560 }
1561
1562
1563 static NTSTATUS STDCALL
1564 ScsiClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
1565 IN PIRP Irp)
1566 {
1567 PDEVICE_EXTENSION DeviceExtension;
1568
1569 DPRINT("ScsiClassShutdownFlush() called\n");
1570
1571 DeviceExtension = DeviceObject->DeviceExtension;
1572 if (DeviceExtension->ClassShutdownFlush)
1573 {
1574 return(DeviceExtension->ClassShutdownFlush(DeviceObject, Irp));
1575 }
1576
1577 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
1578 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1579
1580 return(STATUS_INVALID_DEVICE_REQUEST);
1581 }
1582
1583
1584 static VOID
1585 ScsiClassRetryRequest(PDEVICE_OBJECT DeviceObject,
1586 PIRP Irp,
1587 PSCSI_REQUEST_BLOCK Srb)
1588 {
1589 PDEVICE_EXTENSION DeviceExtension;
1590 PIO_STACK_LOCATION CurrentIrpStack;
1591 PIO_STACK_LOCATION NextIrpStack;
1592 ULONG TransferLength;
1593
1594 DPRINT1("ScsiPortRetryRequest() called\n");
1595
1596 DeviceExtension = DeviceObject->DeviceExtension;
1597 CurrentIrpStack = IoGetCurrentIrpStackLocation(Irp);
1598 NextIrpStack = IoGetNextIrpStackLocation(Irp);
1599
1600 if (CurrentIrpStack->MajorFunction == IRP_MJ_READ ||
1601 CurrentIrpStack->MajorFunction == IRP_MJ_WRITE)
1602 {
1603 TransferLength = CurrentIrpStack->Parameters.Read.Length;
1604 }
1605 else if (Irp->MdlAddress != NULL)
1606 {
1607 TransferLength = Irp->MdlAddress->ByteCount;
1608 }
1609 else
1610 {
1611 TransferLength = 0;
1612 }
1613
1614 Srb->DataTransferLength = TransferLength;
1615 Srb->SrbStatus = 0;
1616 Srb->ScsiStatus = 0;
1617 // Srb->QueueTag = SP_UNTAGGED;
1618
1619 /* Don't modify the flags */
1620 // Srb->Flags =
1621
1622 // CurrentIrpStack->MajorFunction = IRP_MJ_SCSI;
1623 // CurrentIrpStack->Parameters.Scsi.Srb = Srb;
1624
1625 // IoSkipCurrentIrpStackLocation(Irp);
1626
1627 *NextIrpStack = *CurrentIrpStack;
1628 NextIrpStack->MajorFunction = IRP_MJ_SCSI;
1629 NextIrpStack->Parameters.Scsi.Srb = Srb;
1630
1631
1632 IoSetCompletionRoutine(Irp,
1633 ScsiClassIoComplete,
1634 Srb,
1635 TRUE,
1636 TRUE,
1637 TRUE);
1638
1639 DPRINT1("ScsiPortRetryRequest() done\n");
1640
1641 IoCallDriver(DeviceExtension->PortDeviceObject,
1642 Irp);
1643 }
1644
1645 /* EOF */