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