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