- Added support for crash dumps:-
[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.39 2003/08/27 21:28:08 dwelch 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 ScsiClassDeviceDispatch(IN PDEVICE_OBJECT DeviceObject,
60 IN PIRP Irp);
61
62 static NTSTATUS STDCALL
63 ScsiClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
64 IN PIRP Irp);
65
66 static VOID
67 ScsiClassRetryRequest(PDEVICE_OBJECT DeviceObject,
68 PIRP Irp, PSCSI_REQUEST_BLOCK Srb, BOOLEAN Associated);
69
70 /* FUNCTIONS ****************************************************************/
71
72 /**********************************************************************
73 * NAME EXPORTED
74 * DriverEntry
75 *
76 * DESCRIPTION
77 * This function initializes the driver.
78 *
79 * RUN LEVEL
80 * PASSIVE_LEVEL
81 *
82 * ARGUMENTS
83 * DriverObject
84 * System allocated Driver Object for this driver.
85 * RegistryPath
86 * Name of registry driver service key.
87 *
88 * RETURNS
89 * Status
90 */
91
92 NTSTATUS STDCALL
93 DriverEntry(IN PDRIVER_OBJECT DriverObject,
94 IN PUNICODE_STRING RegistryPath)
95 {
96 DPRINT("Class Driver %s\n", VERSION);
97 return(STATUS_SUCCESS);
98 }
99
100
101 VOID
102 ScsiClassDebugPrint(IN ULONG DebugPrintLevel,
103 IN PCHAR DebugMessage,
104 ...)
105 {
106 char Buffer[256];
107 va_list ap;
108
109 #if 0
110 if (DebugPrintLevel > InternalDebugLevel)
111 return;
112 #endif
113
114 va_start(ap, DebugMessage);
115 vsprintf(Buffer, DebugMessage, ap);
116 va_end(ap);
117
118 DbgPrint(Buffer);
119 }
120
121
122 /*
123 * @unimplemented
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 /*
135 * @implemented
136 */
137 VOID STDCALL
138 ScsiClassBuildRequest(IN PDEVICE_OBJECT DeviceObject,
139 IN 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 Srb = ExAllocateFromNPagedLookasideList(&DeviceExtension->SrbLookasideListHead);
164
165 Srb->SrbFlags = 0;
166 Srb->Length = sizeof(SCSI_REQUEST_BLOCK); //SCSI_REQUEST_BLOCK_SIZE;
167 Srb->OriginalRequest = Irp;
168 Srb->PathId = DeviceExtension->PathId;
169 Srb->TargetId = DeviceExtension->TargetId;
170 Srb->Lun = DeviceExtension->Lun;
171 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
172 //FIXME: NT4 DDK sample uses MmGetMdlVirtualAddress! Why shouldn't we?
173 Srb->DataBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
174 Srb->DataTransferLength = CurrentIrpStack->Parameters.Read.Length;
175 Srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
176 Srb->QueueSortKey = LogicalBlockAddress;
177
178 Srb->SenseInfoBuffer = DeviceExtension->SenseData;
179 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
180
181 Srb->TimeOutValue =
182 ((Srb->DataTransferLength + 0xFFFF) >> 16) * DeviceExtension->TimeOutValue;
183
184 Srb->SrbStatus = SRB_STATUS_SUCCESS;
185 Srb->ScsiStatus = 0;
186 Srb->NextSrb = 0;
187
188 Srb->CdbLength = 10;
189 Cdb = (PCDB)Srb->Cdb;
190
191 /* Initialize ATAPI packet (12 bytes) */
192 RtlZeroMemory(Cdb,
193 MAXIMUM_CDB_SIZE);
194
195 Cdb->CDB10.LogicalUnitNumber = DeviceExtension->Lun;
196 TransferBlocks = (USHORT)(CurrentIrpStack->Parameters.Read.Length >> DeviceExtension->SectorShift);
197
198 /* Copy little endian values into CDB in big endian format */
199 Cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte3;
200 Cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte2;
201 Cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte1;
202 Cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte0;
203
204 Cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&TransferBlocks)->Byte1;
205 Cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&TransferBlocks)->Byte0;
206
207
208 if (CurrentIrpStack->MajorFunction == IRP_MJ_READ)
209 {
210 DPRINT("ScsiClassBuildRequest: Read Command\n");
211
212 Srb->SrbFlags |= SRB_FLAGS_DATA_IN;
213 Cdb->CDB10.OperationCode = SCSIOP_READ;
214 }
215 else
216 {
217 DPRINT("ScsiClassBuildRequest: Write Command\n");
218
219 Srb->SrbFlags |= SRB_FLAGS_DATA_OUT;
220 Cdb->CDB10.OperationCode = SCSIOP_WRITE;
221 }
222
223 #if 0
224 /* if this is not a write-through request, then allow caching */
225 if (!(CurrentIrpStack->Flags & SL_WRITE_THROUGH))
226 {
227 Srb->SrbFlags |= SRB_FLAGS_ADAPTER_CACHE_ENABLE;
228 }
229 else if (DeviceExtension->DeviceFlags & DEV_WRITE_CACHE)
230 {
231 /* if write caching is enable then force media access in the cdb */
232 Cdb->CDB10.ForceUnitAccess = TRUE;
233 }
234 #endif
235
236 /* Update srb flags */
237 Srb->SrbFlags |= DeviceExtension->SrbFlags;
238
239 /* Initialize next stack location */
240 NextIrpStack->MajorFunction = IRP_MJ_SCSI;
241 NextIrpStack->Parameters.Scsi.Srb = Srb;
242
243 /* Set retry count */
244 CurrentIrpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
245
246 DPRINT("IoSetCompletionRoutine (Irp %p Srb %p)\n", Irp, Srb);
247 IoSetCompletionRoutine(Irp,
248 ScsiClassIoComplete,
249 Srb,
250 TRUE,
251 TRUE,
252 TRUE);
253 }
254
255
256 /*
257 * @implemented
258 */
259 NTSTATUS STDCALL
260 ScsiClassClaimDevice(PDEVICE_OBJECT PortDeviceObject,
261 PSCSI_INQUIRY_DATA LunInfo,
262 BOOLEAN Release,
263 PDEVICE_OBJECT *NewPortDeviceObject OPTIONAL)
264 {
265 PIO_STACK_LOCATION IoStack;
266 IO_STATUS_BLOCK IoStatusBlock;
267 SCSI_REQUEST_BLOCK Srb;
268 KEVENT Event;
269 PIRP Irp;
270 NTSTATUS Status;
271
272 DPRINT("ScsiClassClaimDevice() called\n");
273
274 if (NewPortDeviceObject != NULL)
275 *NewPortDeviceObject = NULL;
276
277 /* initialize an SRB */
278 RtlZeroMemory(&Srb,
279 sizeof(SCSI_REQUEST_BLOCK));
280 Srb.Length = SCSI_REQUEST_BLOCK_SIZE;
281 Srb.PathId = LunInfo->PathId;
282 Srb.TargetId = LunInfo->TargetId;
283 Srb.Lun = LunInfo->Lun;
284 Srb.Function =
285 (Release == TRUE) ? SRB_FUNCTION_RELEASE_DEVICE : SRB_FUNCTION_CLAIM_DEVICE;
286
287 KeInitializeEvent(&Event,
288 NotificationEvent,
289 FALSE);
290
291 Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE,
292 PortDeviceObject,
293 NULL,
294 0,
295 NULL,
296 0,
297 TRUE,
298 &Event,
299 &IoStatusBlock);
300 if (Irp == NULL)
301 {
302 DPRINT("Failed to allocate Irp!\n");
303 return(STATUS_INSUFFICIENT_RESOURCES);
304 }
305
306 /* Link Srb and Irp */
307 IoStack = IoGetNextIrpStackLocation(Irp);
308 IoStack->Parameters.Scsi.Srb = &Srb;
309 Srb.OriginalRequest = Irp;
310
311 /* Call SCSI port driver */
312 Status = IoCallDriver(PortDeviceObject,
313 Irp);
314 if (Status == STATUS_PENDING)
315 {
316 KeWaitForSingleObject(&Event,
317 Suspended,
318 KernelMode,
319 FALSE,
320 NULL);
321 Status = IoStatusBlock.Status;
322 }
323
324 if (Release == TRUE)
325 {
326 ObDereferenceObject(PortDeviceObject);
327 return(STATUS_SUCCESS);
328 }
329
330 // Status = ObReferenceObjectByPointer(Srb.DataBuffer,
331 Status = ObReferenceObjectByPointer(PortDeviceObject,
332 0,
333 NULL,
334 KernelMode);
335
336 if (NewPortDeviceObject != NULL)
337 {
338 // *NewPortDeviceObject = Srb.DataBuffer;
339 *NewPortDeviceObject = PortDeviceObject;
340 }
341
342 return(STATUS_SUCCESS);
343 }
344
345
346 /*
347 * @implemented
348 */
349 NTSTATUS STDCALL
350 ScsiClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
351 IN PCCHAR ObjectNameBuffer,
352 IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL,
353 IN OUT PDEVICE_OBJECT *DeviceObject,
354 IN PCLASS_INIT_DATA InitializationData)
355 {
356 PDEVICE_OBJECT InternalDeviceObject;
357 PDEVICE_EXTENSION DeviceExtension;
358 ANSI_STRING AnsiName;
359 UNICODE_STRING DeviceName;
360 NTSTATUS Status;
361
362 DPRINT("ScsiClassCreateDeviceObject() called\n");
363
364 *DeviceObject = NULL;
365
366 RtlInitAnsiString(&AnsiName,
367 ObjectNameBuffer);
368
369 Status = RtlAnsiStringToUnicodeString(&DeviceName,
370 &AnsiName,
371 TRUE);
372 if (!NT_SUCCESS(Status))
373 {
374 return(Status);
375 }
376
377 DPRINT("Device name: '%wZ'\n", &DeviceName);
378
379 Status = IoCreateDevice(DriverObject,
380 InitializationData->DeviceExtensionSize,
381 &DeviceName,
382 InitializationData->DeviceType,
383 InitializationData->DeviceCharacteristics,
384 FALSE,
385 &InternalDeviceObject);
386 if (NT_SUCCESS(Status))
387 {
388 DeviceExtension = InternalDeviceObject->DeviceExtension;
389
390 DeviceExtension->ClassError = InitializationData->ClassError;
391 DeviceExtension->ClassReadWriteVerification = InitializationData->ClassReadWriteVerification;
392 DeviceExtension->ClassFindDevices = InitializationData->ClassFindDevices;
393 DeviceExtension->ClassDeviceControl = InitializationData->ClassDeviceControl;
394 DeviceExtension->ClassShutdownFlush = InitializationData->ClassShutdownFlush;
395 DeviceExtension->ClassCreateClose = InitializationData->ClassCreateClose;
396 DeviceExtension->ClassStartIo = InitializationData->ClassStartIo;
397
398 DeviceExtension->MediaChangeCount = 0;
399
400 if (PhysicalDeviceObject != NULL)
401 {
402 DeviceExtension->PhysicalDevice = PhysicalDeviceObject;
403 }
404 else
405 {
406 DeviceExtension->PhysicalDevice = InternalDeviceObject;
407 }
408
409 *DeviceObject = InternalDeviceObject;
410 }
411
412 RtlFreeUnicodeString(&DeviceName);
413
414 return(Status);
415 }
416
417
418 /*
419 * @implemented
420 */
421 NTSTATUS STDCALL
422 ScsiClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
423 IN PIRP Irp)
424 {
425 PDEVICE_EXTENSION DeviceExtension;
426 PIO_STACK_LOCATION NextStack;
427 PIO_STACK_LOCATION Stack;
428 ULONG IoControlCode;
429 ULONG InputBufferLength;
430 ULONG OutputBufferLength;
431 ULONG ModifiedControlCode;
432 PSCSI_REQUEST_BLOCK Srb;
433 PCDB Cdb;
434
435 DPRINT("ScsiClassDeviceControl() called\n");
436
437 DeviceExtension = DeviceObject->DeviceExtension;
438 Stack = IoGetCurrentIrpStackLocation(Irp);
439
440 IoControlCode = Stack->Parameters.DeviceIoControl.IoControlCode;
441 InputBufferLength = Stack->Parameters.DeviceIoControl.InputBufferLength;
442 OutputBufferLength = Stack->Parameters.DeviceIoControl.OutputBufferLength;
443
444 if (IoControlCode == IOCTL_SCSI_GET_DUMP_POINTERS)
445 {
446 PDUMP_POINTERS DumpPointers;
447
448 if (OutputBufferLength < sizeof(DUMP_POINTERS))
449 {
450 Irp->IoStatus.Information = 0;
451 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
452 IoCompleteRequest(Irp, IO_NO_INCREMENT);
453
454 return(STATUS_BUFFER_TOO_SMALL);
455 }
456 DumpPointers = (PDUMP_POINTERS)Irp->AssociatedIrp.SystemBuffer;
457
458 /* Initialize next stack location for call to the port driver */
459 NextStack = IoGetNextIrpStackLocation(Irp);
460
461 NextStack->Parameters = Stack->Parameters;
462 NextStack->MajorFunction = Stack->MajorFunction;
463 NextStack->MinorFunction = Stack->MinorFunction;
464
465 /* Call port driver */
466 return(IoCallDriver(DeviceExtension->PortDeviceObject,
467 Irp));
468 }
469 if (IoControlCode == IOCTL_SCSI_GET_ADDRESS)
470 {
471 PSCSI_ADDRESS ScsiAddress;
472
473 if (OutputBufferLength < sizeof(SCSI_ADDRESS))
474 {
475 Irp->IoStatus.Information = 0;
476 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
477 IoCompleteRequest(Irp, IO_NO_INCREMENT);
478
479 return(STATUS_BUFFER_TOO_SMALL);
480 }
481
482 ScsiAddress = Irp->AssociatedIrp.SystemBuffer;
483 ScsiAddress->Length = sizeof(SCSI_ADDRESS);
484 ScsiAddress->PortNumber = DeviceExtension->PortNumber;
485 ScsiAddress->PathId = DeviceExtension->PathId;
486 ScsiAddress->TargetId = DeviceExtension->TargetId;
487 ScsiAddress->Lun = DeviceExtension->Lun;
488
489 Irp->IoStatus.Information = sizeof(SCSI_ADDRESS);
490 Irp->IoStatus.Status = STATUS_SUCCESS;
491 IoCompleteRequest(Irp, IO_NO_INCREMENT);
492
493 return(STATUS_SUCCESS);
494 }
495
496 if (IoControlCode == IOCTL_SCSI_PASS_THROUGH ||
497 IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT)
498 {
499 PSCSI_PASS_THROUGH ScsiPassThrough;
500
501 DPRINT("IOCTL_SCSI_PASS_THROUGH/IOCTL_SCSI_PASS_THROUGH_DIRECT\n");
502
503 /* Check input size */
504 if (InputBufferLength < sizeof(SCSI_PASS_THROUGH))
505 {
506 Irp->IoStatus.Information = 0;
507 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
508 IoCompleteRequest(Irp, IO_NO_INCREMENT);
509 return(STATUS_INVALID_PARAMETER);
510 }
511
512 /* Initialize next stack location for call to the port driver */
513 NextStack = IoGetNextIrpStackLocation(Irp);
514
515 ScsiPassThrough = Irp->AssociatedIrp.SystemBuffer;
516 ScsiPassThrough->PathId = DeviceExtension->PathId;
517 ScsiPassThrough->TargetId = DeviceExtension->TargetId;
518 ScsiPassThrough->Lun = DeviceExtension->Lun;
519 ScsiPassThrough->Cdb[1] |= DeviceExtension->Lun << 5;
520
521 NextStack->Parameters = Stack->Parameters;
522 NextStack->MajorFunction = Stack->MajorFunction;
523 NextStack->MinorFunction = Stack->MinorFunction;
524
525 /* Call port driver */
526 return(IoCallDriver(DeviceExtension->PortDeviceObject,
527 Irp));
528 }
529
530 /* Allocate an SRB */
531 Srb = ExAllocatePool (NonPagedPool,
532 sizeof(SCSI_REQUEST_BLOCK));
533 if (Srb == NULL)
534 {
535 Irp->IoStatus.Information = 0;
536 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
537 IoCompleteRequest(Irp,
538 IO_NO_INCREMENT);
539 return(STATUS_INSUFFICIENT_RESOURCES);
540 }
541
542 /* Initialize the SRB */
543 RtlZeroMemory(Srb,
544 sizeof(SCSI_REQUEST_BLOCK));
545 Cdb = (PCDB)Srb->Cdb;
546
547 ModifiedControlCode = (IoControlCode & 0x0000FFFF) | (IOCTL_DISK_BASE << 16);
548 switch (ModifiedControlCode)
549 {
550 case IOCTL_DISK_CHECK_VERIFY:
551 DPRINT("IOCTL_DISK_CHECK_VERIFY\n");
552
553 /* Initialize SRB operation */
554 Srb->CdbLength = 6;
555 Srb->TimeOutValue = DeviceExtension->TimeOutValue;
556 Cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
557
558 return(ScsiClassSendSrbAsynchronous(DeviceObject,
559 Srb,
560 Irp,
561 NULL,
562 0,
563 FALSE));
564
565 default:
566 DPRINT1("Unknown device io control code %lx\n",
567 ModifiedControlCode);
568 ExFreePool(Srb);
569
570 /* Pass the IOCTL down to the port driver */
571 NextStack = IoGetNextIrpStackLocation(Irp);
572 NextStack->Parameters = Stack->Parameters;
573 NextStack->MajorFunction = Stack->MajorFunction;
574 NextStack->MinorFunction = Stack->MinorFunction;
575
576 /* Call port driver */
577 return(IoCallDriver(DeviceExtension->PortDeviceObject,
578 Irp));
579 }
580
581 Irp->IoStatus.Information = 0;
582 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
583 IoCompleteRequest(Irp, IO_NO_INCREMENT);
584
585 return(STATUS_UNSUCCESSFUL);
586 }
587
588
589 /*
590 * @implemented
591 */
592 PVOID STDCALL
593 ScsiClassFindModePage(IN PCHAR ModeSenseBuffer,
594 IN ULONG Length,
595 IN UCHAR PageMode,
596 IN BOOLEAN Use6Byte)
597 {
598 ULONG DescriptorLength;
599 ULONG HeaderLength;
600 PCHAR End;
601 PCHAR Ptr;
602
603 DPRINT("ScsiClassFindModePage() called\n");
604
605 /* Get header length */
606 HeaderLength = (Use6Byte) ? sizeof(MODE_PARAMETER_HEADER) : sizeof(MODE_PARAMETER_HEADER10);
607
608 /* Check header length */
609 if (Length < HeaderLength)
610 return NULL;
611
612 /* Get descriptor length */
613 if (Use6Byte == TRUE)
614 {
615 DescriptorLength = ((PMODE_PARAMETER_HEADER)ModeSenseBuffer)->BlockDescriptorLength;
616 }
617 else
618 {
619 DescriptorLength = ((PMODE_PARAMETER_HEADER10)ModeSenseBuffer)->BlockDescriptorLength[1];
620 }
621
622 /* Set page pointers */
623 Ptr = ModeSenseBuffer + HeaderLength + DescriptorLength;
624 End = ModeSenseBuffer + Length;
625
626 /* Search for page */
627 while (Ptr < End)
628 {
629 /* Check page code */
630 if (((PMODE_DISCONNECT_PAGE)Ptr)->PageCode == PageMode)
631 return Ptr;
632
633 /* Skip to next page */
634 Ptr += ((PMODE_DISCONNECT_PAGE)Ptr)->PageLength;
635 }
636
637 return NULL;
638 }
639
640
641 /*
642 * @implemented
643 */
644 ULONG STDCALL
645 ScsiClassFindUnclaimedDevices(IN PCLASS_INIT_DATA InitializationData,
646 IN PSCSI_ADAPTER_BUS_INFO AdapterInformation)
647 {
648 PSCSI_INQUIRY_DATA UnitInfo;
649 PINQUIRYDATA InquiryData;
650 PUCHAR Buffer;
651 ULONG Bus;
652 ULONG UnclaimedDevices = 0;
653 NTSTATUS Status;
654
655 DPRINT("ScsiClassFindUnclaimedDevices() called\n");
656
657 DPRINT("NumberOfBuses: %lu\n",AdapterInformation->NumberOfBuses);
658 Buffer = (PUCHAR)AdapterInformation;
659 for (Bus = 0; Bus < (ULONG)AdapterInformation->NumberOfBuses; Bus++)
660 {
661 DPRINT("Searching bus %lu\n", Bus);
662
663 UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + AdapterInformation->BusData[Bus].InquiryDataOffset);
664
665 while (AdapterInformation->BusData[Bus].InquiryDataOffset)
666 {
667 InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
668
669 DPRINT("Device: '%.8s'\n", InquiryData->VendorId);
670
671 if ((InitializationData->ClassFindDeviceCallBack(InquiryData) == TRUE) &&
672 (UnitInfo->DeviceClaimed == FALSE))
673 {
674 UnclaimedDevices++;
675 }
676
677 if (UnitInfo->NextInquiryDataOffset == 0)
678 break;
679
680 UnitInfo = (PSCSI_INQUIRY_DATA) (Buffer + UnitInfo->NextInquiryDataOffset);
681 }
682 }
683
684 return(UnclaimedDevices);
685 }
686
687
688 /*
689 * @implemented
690 */
691 NTSTATUS STDCALL
692 ScsiClassGetCapabilities(IN PDEVICE_OBJECT PortDeviceObject,
693 OUT PIO_SCSI_CAPABILITIES *PortCapabilities)
694 {
695 IO_STATUS_BLOCK IoStatusBlock;
696 NTSTATUS Status;
697 KEVENT Event;
698 PIRP Irp;
699
700 KeInitializeEvent(&Event,
701 NotificationEvent,
702 FALSE);
703
704 Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_CAPABILITIES,
705 PortDeviceObject,
706 NULL,
707 0,
708 PortCapabilities,
709 sizeof(PVOID),
710 FALSE,
711 &Event,
712 &IoStatusBlock);
713 if (Irp == NULL)
714 {
715 return(STATUS_INSUFFICIENT_RESOURCES);
716 }
717
718 Status = IoCallDriver(PortDeviceObject,
719 Irp);
720 if (Status == STATUS_PENDING)
721 {
722 KeWaitForSingleObject(&Event,
723 Suspended,
724 KernelMode,
725 FALSE,
726 NULL);
727 Status = IoStatusBlock.Status;
728 }
729
730 DPRINT("PortCapabilities at %p\n", *PortCapabilities);
731
732 return(Status);
733 }
734
735
736 /*
737 * @implemented
738 */
739 NTSTATUS STDCALL
740 ScsiClassGetInquiryData(IN PDEVICE_OBJECT PortDeviceObject,
741 IN PSCSI_ADAPTER_BUS_INFO *ConfigInfo)
742 {
743 PSCSI_ADAPTER_BUS_INFO Buffer;
744 IO_STATUS_BLOCK IoStatusBlock;
745 NTSTATUS Status;
746 KEVENT Event;
747 PIRP Irp;
748
749 DPRINT("ScsiClassGetInquiryData() called\n");
750
751 *ConfigInfo = NULL;
752 Buffer = ExAllocatePool(NonPagedPool,
753 INQUIRY_DATA_SIZE);
754 if (Buffer == NULL)
755 {
756 return(STATUS_INSUFFICIENT_RESOURCES);
757 }
758
759 KeInitializeEvent(&Event,
760 NotificationEvent,
761 FALSE);
762
763 Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA,
764 PortDeviceObject,
765 NULL,
766 0,
767 Buffer,
768 INQUIRY_DATA_SIZE,
769 FALSE,
770 &Event,
771 &IoStatusBlock);
772 if (Irp == NULL)
773 {
774 ExFreePool(Buffer);
775 return(STATUS_INSUFFICIENT_RESOURCES);
776 }
777
778 Status = IoCallDriver(PortDeviceObject,
779 Irp);
780 if (Status == STATUS_PENDING)
781 {
782 KeWaitForSingleObject(&Event,
783 Suspended,
784 KernelMode,
785 FALSE,
786 NULL);
787 Status = IoStatusBlock.Status;
788 }
789
790 if (!NT_SUCCESS(Status))
791 {
792 ExFreePool(Buffer);
793 }
794 else
795 {
796 *ConfigInfo = Buffer;
797 }
798
799 DPRINT("ScsiClassGetInquiryData() done\n");
800
801 return(Status);
802 }
803
804
805 /*
806 * @implemented
807 */
808 ULONG STDCALL
809 ScsiClassInitialize(IN PVOID Argument1,
810 IN PVOID Argument2,
811 IN PCLASS_INIT_DATA InitializationData)
812 {
813 PCONFIGURATION_INFORMATION ConfigInfo;
814 PDRIVER_OBJECT DriverObject = Argument1;
815 WCHAR NameBuffer[80];
816 UNICODE_STRING PortName;
817 ULONG PortNumber;
818 PDEVICE_OBJECT PortDeviceObject;
819 PFILE_OBJECT FileObject;
820 BOOLEAN DiskFound = FALSE;
821 NTSTATUS Status;
822
823 DPRINT("ScsiClassInitialize() called!\n");
824
825 DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiClassCreateClose;
826 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiClassCreateClose;
827 DriverObject->MajorFunction[IRP_MJ_READ] = ScsiClassReadWrite;
828 DriverObject->MajorFunction[IRP_MJ_WRITE] = ScsiClassReadWrite;
829 DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiClassInternalIoControl;
830 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiClassDeviceDispatch;
831 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = ScsiClassShutdownFlush;
832 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = ScsiClassShutdownFlush;
833 if (InitializationData->ClassStartIo)
834 {
835 DriverObject->DriverStartIo = InitializationData->ClassStartIo;
836 }
837
838 ConfigInfo = IoGetConfigurationInformation();
839
840 DPRINT("ScsiPorts: %lu\n", ConfigInfo->ScsiPortCount);
841
842 /* look for ScsiPortX scsi port devices */
843 for (PortNumber = 0; PortNumber < ConfigInfo->ScsiPortCount; PortNumber++)
844 {
845 swprintf(NameBuffer,
846 L"\\Device\\ScsiPort%lu",
847 PortNumber);
848 RtlInitUnicodeString(&PortName,
849 NameBuffer);
850 DPRINT("Checking scsi port %ld\n", PortNumber);
851 Status = IoGetDeviceObjectPointer(&PortName,
852 FILE_READ_ATTRIBUTES,
853 &FileObject,
854 &PortDeviceObject);
855 DPRINT("Status 0x%08lX\n", Status);
856 if (NT_SUCCESS(Status))
857 {
858 DPRINT("ScsiPort%lu found.\n", PortNumber);
859
860 /* check scsi port for attached disk drives */
861 if (InitializationData->ClassFindDevices(DriverObject,
862 Argument2,
863 InitializationData,
864 PortDeviceObject,
865 PortNumber))
866 {
867 DiskFound = TRUE;
868 }
869 }
870 else
871 {
872 DbgPrint("Couldn't find ScsiPort%lu (Status %lx)\n", PortNumber, Status);
873 }
874 }
875
876 DPRINT("ScsiClassInitialize() done!\n");
877
878 return((DiskFound == TRUE) ? STATUS_SUCCESS : STATUS_NO_SUCH_DEVICE);
879 }
880
881
882 /**********************************************************************
883 * NAME EXPORTED
884 * ScsiClassInitializeSrbLookasideList
885 *
886 * DESCRIPTION
887 * Initializes a lookaside list for SRBs.
888 *
889 * RUN LEVEL
890 * PASSIVE_LEVEL
891 *
892 * ARGUMENTS
893 * DeviceExtension
894 * Class specific device extension.
895 *
896 * NumberElements
897 * Maximum number of elements of the lookaside list.
898 *
899 * RETURN VALUE
900 * None.
901 *
902 * @implemented
903 */
904 VOID STDCALL
905 ScsiClassInitializeSrbLookasideList(IN PDEVICE_EXTENSION DeviceExtension,
906 IN ULONG NumberElements)
907 {
908 ExInitializeNPagedLookasideList(&DeviceExtension->SrbLookasideListHead,
909 NULL,
910 NULL,
911 NonPagedPool,
912 sizeof(SCSI_REQUEST_BLOCK),
913 TAG_SRBT,
914 (USHORT)NumberElements);
915 }
916
917
918 /*
919 * @unimplemented
920 */
921 NTSTATUS STDCALL
922 ScsiClassInternalIoControl(IN PDEVICE_OBJECT DeviceObject,
923 IN PIRP Irp)
924 {
925 DPRINT1("ScsiClassInternalIoContol() called\n");
926
927 Irp->IoStatus.Status = STATUS_SUCCESS;
928 Irp->IoStatus.Information = 0;
929 IoCompleteRequest(Irp, IO_NO_INCREMENT);
930
931 return(STATUS_SUCCESS);
932 }
933
934
935 /*
936 * @implemented
937 */
938 BOOLEAN STDCALL
939 ScsiClassInterpretSenseInfo(IN PDEVICE_OBJECT DeviceObject,
940 IN PSCSI_REQUEST_BLOCK Srb,
941 IN UCHAR MajorFunctionCode,
942 IN ULONG IoDeviceCode,
943 IN ULONG RetryCount,
944 OUT NTSTATUS *Status)
945 {
946 PDEVICE_EXTENSION DeviceExtension;
947 #if 0
948 PIO_ERROR_LOG_PACKET LogPacket;
949 #endif
950 PSENSE_DATA SenseData;
951 NTSTATUS LogStatus;
952 BOOLEAN LogError;
953 BOOLEAN Retry;
954
955 DPRINT("ScsiClassInterpretSenseInfo() called\n");
956
957 DPRINT("Srb->SrbStatus %lx\n", Srb->SrbStatus);
958
959 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_PENDING)
960 {
961 *Status = STATUS_SUCCESS;
962 return(FALSE);
963 }
964
965 DeviceExtension = DeviceObject->DeviceExtension;
966 SenseData = Srb->SenseInfoBuffer;
967 LogError = FALSE;
968 Retry = TRUE;
969
970 if ((Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
971 (Srb->SenseInfoBufferLength > 0))
972 {
973 /* Got valid sense data, interpret them */
974
975 DPRINT("ErrorCode: %x\n", SenseData->ErrorCode);
976 DPRINT("SenseKey: %x\n", SenseData->SenseKey);
977 DPRINT("SenseCode: %x\n", SenseData->AdditionalSenseCode);
978
979 switch (SenseData->SenseKey & 0xf)
980 {
981 case SCSI_SENSE_NO_SENSE:
982 DPRINT("SCSI_SENSE_NO_SENSE\n");
983 if (SenseData->IncorrectLength)
984 {
985 DPRINT("Incorrect block length\n");
986 *Status = STATUS_INVALID_BLOCK_LENGTH;
987 Retry = FALSE;
988 }
989 else
990 {
991 DPRINT("Unspecified error\n");
992 *Status = STATUS_IO_DEVICE_ERROR;
993 Retry = FALSE;
994 }
995 break;
996
997 case SCSI_SENSE_RECOVERED_ERROR:
998 DPRINT("SCSI_SENSE_RECOVERED_ERROR\n");
999 *Status = STATUS_SUCCESS;
1000 Retry = FALSE;
1001 break;
1002
1003 case SCSI_SENSE_NOT_READY:
1004 DPRINT("SCSI_SENSE_NOT_READY\n");
1005 *Status = STATUS_DEVICE_NOT_READY;
1006 switch (SenseData->AdditionalSenseCode)
1007 {
1008 case SCSI_ADSENSE_LUN_NOT_READY:
1009 DPRINT("SCSI_ADSENSE_LUN_NOT_READY\n");
1010 break;
1011
1012 case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE:
1013 DPRINT("SCSI_ADSENSE_NO_MEDIA_IN_DEVICE\n");
1014 *Status = STATUS_NO_MEDIA_IN_DEVICE;
1015 Retry = FALSE;
1016 break;
1017 }
1018 break;
1019
1020 case SCSI_SENSE_MEDIUM_ERROR:
1021 DPRINT("SCSI_SENSE_MEDIUM_ERROR\n");
1022 *Status = STATUS_DEVICE_DATA_ERROR;
1023 Retry = FALSE;
1024 break;
1025
1026 case SCSI_SENSE_HARDWARE_ERROR:
1027 DPRINT("SCSI_SENSE_HARDWARE_ERROR\n");
1028 *Status = STATUS_IO_DEVICE_ERROR;
1029 break;
1030
1031 case SCSI_SENSE_ILLEGAL_REQUEST:
1032 DPRINT("SCSI_SENSE_ILLEGAL_REQUEST\n");
1033 *Status = STATUS_INVALID_DEVICE_REQUEST;
1034 switch (SenseData->AdditionalSenseCode)
1035 {
1036 case SCSI_ADSENSE_ILLEGAL_COMMAND:
1037 DPRINT("SCSI_ADSENSE_ILLEGAL_COMMAND\n");
1038 Retry = FALSE;
1039 break;
1040
1041 case SCSI_ADSENSE_ILLEGAL_BLOCK:
1042 DPRINT("SCSI_ADSENSE_ILLEGAL_BLOCK\n");
1043 *Status = STATUS_NONEXISTENT_SECTOR;
1044 Retry = FALSE;
1045 break;
1046
1047 case SCSI_ADSENSE_INVALID_LUN:
1048 DPRINT("SCSI_ADSENSE_INVALID_LUN\n");
1049 *Status = STATUS_NO_SUCH_DEVICE;
1050 Retry = FALSE;
1051 break;
1052
1053 case SCSI_ADSENSE_MUSIC_AREA:
1054 DPRINT("SCSI_ADSENSE_MUSIC_AREA\n");
1055 Retry = FALSE;
1056 break;
1057
1058 case SCSI_ADSENSE_DATA_AREA:
1059 DPRINT("SCSI_ADSENSE_DATA_AREA\n");
1060 Retry = FALSE;
1061 break;
1062
1063 case SCSI_ADSENSE_VOLUME_OVERFLOW:
1064 DPRINT("SCSI_ADSENSE_VOLUME_OVERFLOW\n");
1065 Retry = FALSE;
1066 break;
1067
1068 case SCSI_ADSENSE_INVALID_CDB:
1069 DPRINT("SCSI_ADSENSE_INVALID_CDB\n");
1070 Retry = FALSE;
1071 break;
1072 }
1073 break;
1074
1075 case SCSI_SENSE_UNIT_ATTENTION:
1076 DPRINT("SCSI_SENSE_UNIT_ATTENTION\n");
1077 if ((DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) &&
1078 (DeviceObject->Vpb->Flags & VPB_MOUNTED))
1079 {
1080 DeviceObject->Flags |= DO_VERIFY_VOLUME;
1081 *Status = STATUS_VERIFY_REQUIRED;
1082 Retry = FALSE;
1083 }
1084 else
1085 {
1086 *Status = STATUS_IO_DEVICE_ERROR;
1087 }
1088 break;
1089
1090 case SCSI_SENSE_DATA_PROTECT:
1091 DPRINT("SCSI_SENSE_DATA_PROTECT\n");
1092 *Status = STATUS_MEDIA_WRITE_PROTECTED;
1093 Retry = FALSE;
1094 break;
1095
1096 case SCSI_SENSE_ABORTED_COMMAND:
1097 DPRINT("SCSI_SENSE_ABORTED_COMMAND\n");
1098 *Status = STATUS_IO_DEVICE_ERROR;
1099 break;
1100
1101 default:
1102 DPRINT1("SCSI error (sense key: %x)\n",
1103 SenseData->SenseKey & 0xf);
1104 *Status = STATUS_IO_DEVICE_ERROR;
1105 break;
1106 }
1107 }
1108 else
1109 {
1110 /* Got no or invalid sense data, return generic error codes */
1111 switch (SRB_STATUS(Srb->SrbStatus))
1112 {
1113 /* FIXME: add more srb status codes */
1114
1115 case SRB_STATUS_INVALID_PATH_ID:
1116 case SRB_STATUS_INVALID_TARGET_ID:
1117 case SRB_STATUS_INVALID_LUN:
1118 case SRB_STATUS_NO_DEVICE:
1119 case SRB_STATUS_NO_HBA:
1120 *Status = STATUS_NO_SUCH_DEVICE;
1121 Retry = FALSE;
1122 break;
1123
1124 case SRB_STATUS_BUSY:
1125 *Status = STATUS_DEVICE_BUSY;
1126 Retry = TRUE;
1127 break;
1128
1129 case SRB_STATUS_DATA_OVERRUN:
1130 *Status = STATUS_DATA_OVERRUN;
1131 Retry = FALSE;
1132 break;
1133
1134 default:
1135 DPRINT1("SCSI error (SRB status: %x)\n",
1136 SRB_STATUS(Srb->SrbStatus));
1137 LogError = TRUE;
1138 *Status = STATUS_IO_DEVICE_ERROR;
1139 break;
1140 }
1141 }
1142
1143 /* Call the class driver specific error function */
1144 if (DeviceExtension->ClassError != NULL)
1145 {
1146 DeviceExtension->ClassError(DeviceObject,
1147 Srb,
1148 Status,
1149 &Retry);
1150 }
1151
1152 if (LogError == TRUE)
1153 {
1154 #if 0
1155 /* Allocate error packet */
1156 LogPacket = IoAllocateErrorLogEntry (DeviceObject,
1157 sizeof(IO_ERROR_LOG_PACKET) +
1158 5 * sizeof(ULONG));
1159 if (LogPacket == NULL)
1160 {
1161 DPRINT1 ("Failed to allocate a log packet!\n");
1162 return Retry;
1163 }
1164
1165 /* Initialize error packet */
1166 LogPacket->MajorFunctionCode = MajorFunctionCode;
1167 LogPacket->RetryCount = (UCHAR)RetryCount;
1168 LogPacket->DumpDataSize = 6 * sizeof(ULONG);
1169 LogPacket->ErrorCode = 0; /* FIXME */
1170 LogPacket->FinalStatus = *Status;
1171 LogPacket->IoControlCode = IoDeviceCode;
1172 LogPacket->DeviceOffset.QuadPart = 0; /* FIXME */
1173 LogPacket->DumpData[0] = Srb->PathId;
1174 LogPacket->DumpData[1] = Srb->TargetId;
1175 LogPacket->DumpData[2] = Srb->Lun;
1176 LogPacket->DumpData[3] = 0;
1177 LogPacket->DumpData[4] = (Srb->SrbStatus << 8) | Srb->ScsiStatus;
1178 if (SenseData != NULL)
1179 {
1180 LogPacket->DumpData[5] = (SenseData->SenseKey << 16) |
1181 (SenseData->AdditionalSenseCode << 8) |
1182 SenseData->AdditionalSenseCodeQualifier;
1183 }
1184
1185 /* Write error packet */
1186 IoWriteErrorLogEntry (LogPacket);
1187 #endif
1188 }
1189
1190 DPRINT("ScsiClassInterpretSenseInfo() done\n");
1191
1192 return Retry;
1193 }
1194
1195
1196 /*
1197 * @implemented
1198 */
1199 NTSTATUS STDCALL
1200 ScsiClassIoComplete(IN PDEVICE_OBJECT DeviceObject,
1201 IN PIRP Irp,
1202 IN PVOID Context)
1203 {
1204 PDEVICE_EXTENSION DeviceExtension;
1205 PIO_STACK_LOCATION IrpStack;
1206 PSCSI_REQUEST_BLOCK Srb;
1207 BOOLEAN Retry;
1208 NTSTATUS Status;
1209
1210 DPRINT("ScsiClassIoComplete(DeviceObject %p Irp %p Context %p) called\n",
1211 DeviceObject, Irp, Context);
1212
1213 DeviceExtension = DeviceObject->DeviceExtension;
1214
1215 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1216
1217 /*
1218 * BUGBUG -> Srb = IrpStack->Parameters.Scsi.Srb;
1219 * Must pass Srb as Context arg!! See comment about Completion routines in
1220 * IofCallDriver for more info.
1221 */
1222
1223 Srb = (PSCSI_REQUEST_BLOCK)Context;
1224
1225 DPRINT("Srb %p\n", Srb);
1226
1227 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
1228 {
1229 Status = STATUS_SUCCESS;
1230 }
1231 else
1232 {
1233 Retry = ScsiClassInterpretSenseInfo(DeviceObject,
1234 Srb,
1235 IrpStack->MajorFunction,
1236 0,
1237 MAXIMUM_RETRIES - ((ULONG)IrpStack->Parameters.Others.Argument4),
1238 &Status);
1239 if ((Retry) &&
1240 ((ULONG)IrpStack->Parameters.Others.Argument4 > 0))
1241 {
1242 ((ULONG)IrpStack->Parameters.Others.Argument4)--;
1243
1244 ScsiClassRetryRequest(DeviceObject,
1245 Irp,
1246 Srb,
1247 FALSE);
1248
1249 return(STATUS_MORE_PROCESSING_REQUIRED);
1250 }
1251 }
1252
1253 /* Free the SRB */
1254 ExFreeToNPagedLookasideList(&DeviceExtension->SrbLookasideListHead,
1255 Srb);
1256
1257 Irp->IoStatus.Status = Status;
1258 if (!NT_SUCCESS(Status))
1259 {
1260 Irp->IoStatus.Information = 0;
1261 if (IoIsErrorUserInduced(Status))
1262 {
1263 IoSetHardErrorOrVerifyDevice(Irp,
1264 DeviceObject);
1265 }
1266 }
1267
1268 if (DeviceExtension->ClassStartIo != NULL)
1269 {
1270 if (IrpStack->MajorFunction != IRP_MJ_DEVICE_CONTROL)
1271 {
1272 IoStartNextPacket(DeviceObject,
1273 FALSE);
1274 }
1275 }
1276
1277 DPRINT("ScsiClassIoComplete() done (Status %lx)\n", Status);
1278
1279 return(Status);
1280 }
1281
1282
1283 /*
1284 * @implemented
1285 */
1286 NTSTATUS STDCALL
1287 ScsiClassIoCompleteAssociated(IN PDEVICE_OBJECT DeviceObject,
1288 IN PIRP Irp,
1289 IN PVOID Context)
1290 {
1291 PDEVICE_EXTENSION DeviceExtension;
1292 PIO_STACK_LOCATION IrpStack;
1293 PSCSI_REQUEST_BLOCK Srb;
1294 PIRP MasterIrp;
1295 BOOLEAN Retry;
1296 LONG RequestCount;
1297 NTSTATUS Status;
1298
1299 DPRINT("ScsiClassIoCompleteAssociated(DeviceObject %p Irp %p Context %p) called\n",
1300 DeviceObject, Irp, Context);
1301
1302 MasterIrp = Irp->AssociatedIrp.MasterIrp;
1303 DeviceExtension = DeviceObject->DeviceExtension;
1304
1305 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1306
1307 /*
1308 * BUGBUG -> Srb = Srb = IrpStack->Parameters.Scsi.Srb;
1309 * Must pass Srb as Context arg!! See comment about Completion routines in
1310 * IofCallDriver for more info.
1311 */
1312
1313 Srb = (PSCSI_REQUEST_BLOCK)Context;
1314
1315 DPRINT("Srb %p\n", Srb);
1316
1317 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
1318 {
1319 Status = STATUS_SUCCESS;
1320 }
1321 else
1322 {
1323 /* Get more detailed status information */
1324 Retry = ScsiClassInterpretSenseInfo(DeviceObject,
1325 Srb,
1326 IrpStack->MajorFunction,
1327 0,
1328 MAXIMUM_RETRIES - ((ULONG)IrpStack->Parameters.Others.Argument4),
1329 &Status);
1330
1331 if ((Retry) &&
1332 ((ULONG)IrpStack->Parameters.Others.Argument4 > 0))
1333 {
1334 ((ULONG)IrpStack->Parameters.Others.Argument4)--;
1335
1336 ScsiClassRetryRequest(DeviceObject,
1337 Irp,
1338 Srb,
1339 TRUE);
1340
1341 return(STATUS_MORE_PROCESSING_REQUIRED);
1342 }
1343 }
1344
1345 /* Free the SRB */
1346 ExFreeToNPagedLookasideList(&DeviceExtension->SrbLookasideListHead,
1347 Srb);
1348
1349 Irp->IoStatus.Status = Status;
1350
1351 IrpStack = IoGetNextIrpStackLocation(MasterIrp);
1352 if (!NT_SUCCESS(Status))
1353 {
1354 MasterIrp->IoStatus.Status = Status;
1355 MasterIrp->IoStatus.Information = 0;
1356
1357 if (IoIsErrorUserInduced(Status))
1358 {
1359 IoSetHardErrorOrVerifyDevice(MasterIrp,
1360 DeviceObject);
1361 }
1362 }
1363
1364 /* Decrement the request counter in the Master IRP */
1365 RequestCount = InterlockedDecrement((PLONG)&IrpStack->Parameters.Others.Argument1);
1366
1367 if (RequestCount == 0)
1368 {
1369 /* Complete the Master IRP */
1370 IoCompleteRequest(MasterIrp,
1371 IO_DISK_INCREMENT);
1372
1373 if (DeviceExtension->ClassStartIo)
1374 {
1375 IoStartNextPacket(DeviceObject,
1376 FALSE);
1377 }
1378 }
1379
1380 /* Free the current IRP */
1381 IoFreeIrp(Irp);
1382
1383 return(STATUS_MORE_PROCESSING_REQUIRED);
1384 }
1385
1386
1387 /*
1388 * @implemented
1389 */
1390 ULONG STDCALL
1391 ScsiClassModeSense(IN PDEVICE_OBJECT DeviceObject,
1392 IN PCHAR ModeSenseBuffer,
1393 IN ULONG Length,
1394 IN UCHAR PageMode)
1395 {
1396 PDEVICE_EXTENSION DeviceExtension;
1397 SCSI_REQUEST_BLOCK Srb;
1398 ULONG RetryCount;
1399 PCDB Cdb;
1400 NTSTATUS Status;
1401
1402 DPRINT("ScsiClassModeSense() called\n");
1403
1404 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1405 RetryCount = 1;
1406
1407 /* Initialize the SRB */
1408 RtlZeroMemory (&Srb,
1409 sizeof(SCSI_REQUEST_BLOCK));
1410 Srb.CdbLength = 6;
1411 Srb.TimeOutValue = DeviceExtension->TimeOutValue;
1412
1413 /* Initialize the CDB */
1414 Cdb = (PCDB)&Srb.Cdb;
1415 Cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
1416 Cdb->MODE_SENSE.PageCode = PageMode;
1417 Cdb->MODE_SENSE.AllocationLength = (UCHAR)Length;
1418
1419 TryAgain:
1420 Status = ScsiClassSendSrbSynchronous (DeviceObject,
1421 &Srb,
1422 ModeSenseBuffer,
1423 Length,
1424 FALSE);
1425 if (Status == STATUS_VERIFY_REQUIRED)
1426 {
1427 if (RetryCount != 0)
1428 {
1429 RetryCount--;
1430 goto TryAgain;
1431 }
1432 }
1433 else if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN)
1434 {
1435 Status = STATUS_SUCCESS;
1436 }
1437
1438 if (!NT_SUCCESS(Status))
1439 {
1440 return 0;
1441 }
1442
1443 return Srb.DataTransferLength;
1444 }
1445
1446
1447 /*
1448 * @implemented
1449 */
1450 ULONG STDCALL
1451 ScsiClassQueryTimeOutRegistryValue(IN PUNICODE_STRING RegistryPath)
1452 {
1453 PRTL_QUERY_REGISTRY_TABLE Table;
1454 ULONG TimeOutValue;
1455 ULONG ZeroTimeOut;
1456 ULONG Size;
1457 PWSTR Path;
1458 NTSTATUS Status;
1459
1460 if (RegistryPath == NULL)
1461 {
1462 return 0;
1463 }
1464
1465 TimeOutValue = 0;
1466 ZeroTimeOut = 0;
1467
1468 /* Allocate zero-terminated path string */
1469 Size = RegistryPath->Length + sizeof(WCHAR);
1470 Path = (PWSTR)ExAllocatePool (NonPagedPool,
1471 Size);
1472 if (Path == NULL)
1473 {
1474 return 0;
1475 }
1476 RtlZeroMemory (Path,
1477 Size);
1478 RtlCopyMemory (Path,
1479 RegistryPath->Buffer,
1480 Size - sizeof(WCHAR));
1481
1482 /* Allocate query table */
1483 Size = sizeof(RTL_QUERY_REGISTRY_TABLE) * 2;
1484 Table = (PRTL_QUERY_REGISTRY_TABLE)ExAllocatePool (NonPagedPool,
1485 Size);
1486 if (Table == NULL)
1487 {
1488 ExFreePool (Path);
1489 return 0;
1490 }
1491 RtlZeroMemory (Table,
1492 Size);
1493
1494 Table[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
1495 Table[0].Name = L"TimeOutValue";
1496 Table[0].EntryContext = &TimeOutValue;
1497 Table[0].DefaultType = REG_DWORD;
1498 Table[0].DefaultData = &ZeroTimeOut;
1499 Table[0].DefaultLength = sizeof(ULONG);
1500
1501 Status = RtlQueryRegistryValues (RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
1502 Path,
1503 Table,
1504 NULL,
1505 NULL);
1506 if (!NT_SUCCESS(Status))
1507 {
1508 DPRINT("RtlQueryRegistryValue() failed (Status %lx)\n", Status);
1509 TimeOutValue = 0;
1510 }
1511
1512 ExFreePool (Table);
1513 ExFreePool (Path);
1514
1515 DPRINT("TimeOut: %lu\n", TimeOutValue);
1516
1517 return TimeOutValue;
1518 }
1519
1520
1521 /*
1522 * @implemented
1523 */
1524 NTSTATUS STDCALL
1525 ScsiClassReadDriveCapacity(IN PDEVICE_OBJECT DeviceObject)
1526 {
1527 PDEVICE_EXTENSION DeviceExtension;
1528 PREAD_CAPACITY_DATA CapacityBuffer;
1529 SCSI_REQUEST_BLOCK Srb;
1530 PCDB Cdb;
1531 NTSTATUS Status;
1532 ULONG LastSector;
1533 ULONG SectorSize;
1534
1535 DPRINT("ScsiClassReadDriveCapacity() called\n");
1536
1537 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1538
1539 CapacityBuffer = ExAllocatePool(NonPagedPool,
1540 sizeof(READ_CAPACITY_DATA));
1541 if (CapacityBuffer == NULL)
1542 {
1543 return(STATUS_INSUFFICIENT_RESOURCES);
1544 }
1545
1546 RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
1547
1548 Srb.CdbLength = 10;
1549 Srb.TimeOutValue = DeviceExtension->TimeOutValue;
1550
1551 Cdb = (PCDB)Srb.Cdb;
1552 Cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
1553
1554
1555 Status = ScsiClassSendSrbSynchronous(DeviceObject,
1556 &Srb,
1557 CapacityBuffer,
1558 sizeof(READ_CAPACITY_DATA),
1559 FALSE);
1560 DPRINT("Status: %lx\n", Status);
1561 DPRINT("Srb: %p\n", &Srb);
1562 if (NT_SUCCESS(Status))
1563 {
1564 SectorSize = (((PUCHAR)&CapacityBuffer->BytesPerBlock)[0] << 24) |
1565 (((PUCHAR)&CapacityBuffer->BytesPerBlock)[1] << 16) |
1566 (((PUCHAR)&CapacityBuffer->BytesPerBlock)[2] << 8) |
1567 ((PUCHAR)&CapacityBuffer->BytesPerBlock)[3];
1568
1569
1570 LastSector = (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[0] << 24) |
1571 (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[1] << 16) |
1572 (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[2] << 8) |
1573 ((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[3];
1574
1575 DeviceExtension->DiskGeometry->BytesPerSector = SectorSize;
1576
1577 DeviceExtension->PartitionLength.QuadPart = (LONGLONG)(LastSector + 1);
1578 WHICH_BIT(DeviceExtension->DiskGeometry->BytesPerSector,
1579 DeviceExtension->SectorShift);
1580 DeviceExtension->PartitionLength.QuadPart =
1581 (DeviceExtension->PartitionLength.QuadPart << DeviceExtension->SectorShift);
1582
1583 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
1584 {
1585 DeviceExtension->DiskGeometry->MediaType = RemovableMedia;
1586 }
1587 else
1588 {
1589 DeviceExtension->DiskGeometry->MediaType = FixedMedia;
1590 }
1591 DeviceExtension->DiskGeometry->Cylinders.QuadPart = (LONGLONG)((LastSector + 1)/(32 * 64));
1592 DeviceExtension->DiskGeometry->SectorsPerTrack = 32;
1593 DeviceExtension->DiskGeometry->TracksPerCylinder = 64;
1594
1595 DPRINT("SectorSize: %lu SectorCount: %lu\n", SectorSize, LastSector + 1);
1596 }
1597 else
1598 {
1599 /* Use default values if disk geometry cannot be read */
1600 RtlZeroMemory(DeviceExtension->DiskGeometry,
1601 sizeof(DISK_GEOMETRY));
1602 DeviceExtension->DiskGeometry->BytesPerSector = 512;
1603 DeviceExtension->SectorShift = 9;
1604 DeviceExtension->PartitionLength.QuadPart = 0;
1605
1606 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
1607 {
1608 DeviceExtension->DiskGeometry->MediaType = RemovableMedia;
1609 }
1610 else
1611 {
1612 DeviceExtension->DiskGeometry->MediaType = FixedMedia;
1613 }
1614
1615 DPRINT("SectorSize: 512 SectorCount: 0\n");
1616 }
1617
1618 ExFreePool(CapacityBuffer);
1619
1620 DPRINT("ScsiClassReadDriveCapacity() done\n");
1621
1622 return(Status);
1623 }
1624
1625
1626 /*
1627 * @unimplemented
1628 */
1629 VOID STDCALL
1630 ScsiClassReleaseQueue(IN PDEVICE_OBJECT DeviceObject)
1631 {
1632 UNIMPLEMENTED;
1633 }
1634
1635
1636 /*
1637 * @implemented
1638 */
1639 NTSTATUS STDCALL
1640 ScsiClassSendSrbAsynchronous(PDEVICE_OBJECT DeviceObject,
1641 PSCSI_REQUEST_BLOCK Srb,
1642 PIRP Irp,
1643 PVOID BufferAddress,
1644 ULONG BufferLength,
1645 BOOLEAN WriteToDevice)
1646 {
1647 PDEVICE_EXTENSION DeviceExtension;
1648 PIO_STACK_LOCATION Stack;
1649
1650 DPRINT("ScsiClassSendSrbAsynchronous() called\n");
1651
1652 DeviceExtension = DeviceObject->DeviceExtension;
1653
1654 /* Initialize the SRB */
1655 Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1656 Srb->PathId = DeviceExtension->PathId;
1657 Srb->TargetId = DeviceExtension->TargetId;
1658 Srb->Lun = DeviceExtension->Lun;
1659 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1660 Srb->Cdb[1] |= DeviceExtension->Lun << 5;
1661
1662 Srb->SenseInfoBuffer = DeviceExtension->SenseData;
1663 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1664
1665 Srb->DataBuffer = BufferAddress;
1666 Srb->DataTransferLength = BufferLength;
1667
1668 Srb->ScsiStatus = 0;
1669 Srb->SrbStatus = 0;
1670 Srb->NextSrb = NULL;
1671
1672 if (BufferAddress != NULL)
1673 {
1674 if (Irp->MdlAddress == NULL)
1675 {
1676 /* Allocate an MDL */
1677 if (!IoAllocateMdl(BufferAddress,
1678 BufferLength,
1679 FALSE,
1680 FALSE,
1681 Irp))
1682 {
1683 DPRINT1("Mdl-Allocation failed\n");
1684 return(STATUS_INSUFFICIENT_RESOURCES);
1685 }
1686
1687 MmBuildMdlForNonPagedPool(Irp->MdlAddress);
1688 }
1689
1690 /* Set data direction */
1691 Srb->SrbFlags = (WriteToDevice) ? SRB_FLAGS_DATA_OUT : SRB_FLAGS_DATA_IN;
1692 }
1693 else
1694 {
1695 /* Set data direction */
1696 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
1697 }
1698
1699 /* Set the retry counter */
1700 Stack = IoGetCurrentIrpStackLocation(Irp);
1701 Stack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
1702
1703 /* Set the completion routine */
1704 IoSetCompletionRoutine(Irp,
1705 ScsiClassIoComplete,
1706 Srb,
1707 TRUE,
1708 TRUE,
1709 TRUE);
1710
1711 /* Attach Srb to the Irp */
1712 Stack = IoGetNextIrpStackLocation(Irp);
1713 Stack->MajorFunction = IRP_MJ_SCSI;
1714 Stack->Parameters.Scsi.Srb = Srb;
1715 Srb->OriginalRequest = Irp;
1716
1717 /* Call the port driver */
1718 return(IoCallDriver(DeviceExtension->PortDeviceObject,
1719 Irp));
1720 }
1721
1722
1723 /*
1724 * @implemented
1725 */
1726 NTSTATUS STDCALL
1727 ScsiClassSendSrbSynchronous(PDEVICE_OBJECT DeviceObject,
1728 PSCSI_REQUEST_BLOCK Srb,
1729 PVOID BufferAddress,
1730 ULONG BufferLength,
1731 BOOLEAN WriteToDevice)
1732 {
1733 PDEVICE_EXTENSION DeviceExtension;
1734 IO_STATUS_BLOCK IoStatusBlock;
1735 PIO_STACK_LOCATION IrpStack;
1736 ULONG RequestType;
1737 BOOLEAN Retry;
1738 ULONG RetryCount;
1739 PKEVENT Event;
1740 PIRP Irp;
1741 NTSTATUS Status;
1742
1743 DPRINT("ScsiClassSendSrbSynchronous() called\n");
1744
1745 RetryCount = MAXIMUM_RETRIES;
1746 DeviceExtension = DeviceObject->DeviceExtension;
1747
1748 Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1749 Srb->PathId = DeviceExtension->PathId;
1750 Srb->TargetId = DeviceExtension->TargetId;
1751 Srb->Lun = DeviceExtension->Lun;
1752 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1753
1754 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1755 Srb->SenseInfoBuffer = ExAllocatePool(NonPagedPool,
1756 SENSE_BUFFER_SIZE);
1757 if (Srb->SenseInfoBuffer == NULL)
1758 return(STATUS_INSUFFICIENT_RESOURCES);
1759
1760 if (BufferAddress == NULL)
1761 {
1762 BufferLength = 0;
1763 RequestType = IOCTL_SCSI_EXECUTE_NONE;
1764 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
1765 }
1766 else
1767 {
1768 if (WriteToDevice == TRUE)
1769 {
1770 RequestType = IOCTL_SCSI_EXECUTE_IN; // needs _in_ to the device
1771 Srb->SrbFlags = SRB_FLAGS_DATA_OUT; // needs _out_ from the caller
1772 }
1773 else
1774 {
1775 RequestType = IOCTL_SCSI_EXECUTE_OUT;
1776 Srb->SrbFlags = SRB_FLAGS_DATA_IN;
1777 }
1778 }
1779
1780 Srb->DataTransferLength = BufferLength;
1781 Srb->DataBuffer = BufferAddress;
1782
1783 Event = ExAllocatePool(NonPagedPool,
1784 sizeof(KEVENT));
1785 TryAgain:
1786 KeInitializeEvent(Event,
1787 NotificationEvent,
1788 FALSE);
1789
1790 Irp = IoBuildDeviceIoControlRequest(RequestType,
1791 DeviceExtension->PortDeviceObject,
1792 NULL,
1793 0,
1794 BufferAddress,
1795 BufferLength,
1796 TRUE,
1797 Event,
1798 &IoStatusBlock);
1799 if (Irp == NULL)
1800 {
1801 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
1802 ExFreePool(Srb->SenseInfoBuffer);
1803 ExFreePool(Event);
1804 return(STATUS_INSUFFICIENT_RESOURCES);
1805 }
1806
1807 /* Attach Srb to the Irp */
1808 IrpStack = IoGetNextIrpStackLocation(Irp);
1809 IrpStack->Parameters.Scsi.Srb = Srb;
1810 Srb->OriginalRequest = Irp;
1811
1812 /* Call the SCSI port driver */
1813 Status = IoCallDriver(DeviceExtension->PortDeviceObject,
1814 Irp);
1815 if (Status == STATUS_PENDING)
1816 {
1817 KeWaitForSingleObject(Event,
1818 Suspended,
1819 KernelMode,
1820 FALSE,
1821 NULL);
1822 }
1823
1824 if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS)
1825 {
1826 Retry = ScsiClassInterpretSenseInfo(DeviceObject,
1827 Srb,
1828 IRP_MJ_SCSI,
1829 0,
1830 MAXIMUM_RETRIES - RetryCount,
1831 &Status);
1832 if (Retry == TRUE)
1833 {
1834 DPRINT("Try again (RetryCount %lu)\n", RetryCount);
1835
1836 /* FIXME: Wait a little if we got a timeout error */
1837
1838 if (RetryCount--)
1839 goto TryAgain;
1840 }
1841 }
1842 else
1843 {
1844 Status = STATUS_SUCCESS;
1845 }
1846
1847 ExFreePool(Srb->SenseInfoBuffer);
1848 ExFreePool(Event);
1849
1850 DPRINT("ScsiClassSendSrbSynchronous() done\n");
1851
1852 return(Status);
1853 }
1854
1855
1856 /*
1857 * @implemented
1858 */
1859 VOID STDCALL
1860 ScsiClassSplitRequest(IN PDEVICE_OBJECT DeviceObject,
1861 IN PIRP Irp,
1862 IN ULONG MaximumBytes)
1863 {
1864 PDEVICE_EXTENSION DeviceExtension;
1865 PIO_STACK_LOCATION CurrentStack;
1866 PIO_STACK_LOCATION NextStack;
1867 PIO_STACK_LOCATION NewStack;
1868 PSCSI_REQUEST_BLOCK Srb;
1869 LARGE_INTEGER Offset;
1870 PIRP NewIrp;
1871 PVOID DataBuffer;
1872 ULONG TransferLength;
1873 ULONG RequestCount;
1874 ULONG DataLength;
1875 ULONG i;
1876
1877 DPRINT("ScsiClassSplitRequest(DeviceObject %lx Irp %lx MaximumBytes %lu)\n",
1878 DeviceObject, Irp, MaximumBytes);
1879
1880 DeviceExtension = DeviceObject->DeviceExtension;
1881 CurrentStack = IoGetCurrentIrpStackLocation(Irp);
1882 NextStack = IoGetNextIrpStackLocation(Irp);
1883 DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
1884
1885 /* Initialize transfer data for first request */
1886 Offset = CurrentStack->Parameters.Read.ByteOffset;
1887 TransferLength = CurrentStack->Parameters.Read.Length;
1888 DataLength = MaximumBytes;
1889 RequestCount = ROUND_UP(TransferLength, MaximumBytes) / MaximumBytes;
1890
1891 /* Save request count in the original IRP */
1892 NextStack->Parameters.Others.Argument1 = (PVOID)RequestCount;
1893
1894 DPRINT("RequestCount %lu\n", RequestCount);
1895
1896 for (i = 0; i < RequestCount; i++)
1897 {
1898 /* Create a new IRP */
1899 NewIrp = IoAllocateIrp(DeviceObject->StackSize,
1900 FALSE);
1901 if (NewIrp == NULL)
1902 {
1903 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1904 Irp->IoStatus.Information = 0;
1905
1906 if (i == 0)
1907 IoCompleteRequest(Irp,
1908 IO_NO_INCREMENT);
1909 return;
1910 }
1911
1912 /* Initialize the new IRP */
1913 NewIrp->MdlAddress = Irp->MdlAddress;
1914
1915 IoSetNextIrpStackLocation(NewIrp);
1916 NewStack = IoGetCurrentIrpStackLocation(NewIrp);
1917
1918 NewStack->MajorFunction = CurrentStack->MajorFunction;
1919 NewStack->Parameters.Read.ByteOffset = Offset;
1920 NewStack->Parameters.Read.Length = DataLength;
1921 NewStack->DeviceObject = DeviceObject;
1922
1923 ScsiClassBuildRequest(DeviceObject,
1924 NewIrp);
1925
1926 NewStack = IoGetNextIrpStackLocation(NewIrp);
1927 Srb = NewStack->Parameters.Others.Argument1;
1928 Srb->DataBuffer = DataBuffer;
1929
1930 NewIrp->AssociatedIrp.MasterIrp = Irp;
1931
1932 /* Initialize completion routine */
1933 IoSetCompletionRoutine(NewIrp,
1934 ScsiClassIoCompleteAssociated,
1935 Srb,
1936 TRUE,
1937 TRUE,
1938 TRUE);
1939
1940 /* Send the new IRP down to the port driver */
1941 IoCallDriver(DeviceExtension->PortDeviceObject,
1942 NewIrp);
1943
1944 /* Adjust transfer data for next request */
1945 DataBuffer = (PCHAR)DataBuffer + MaximumBytes;
1946 TransferLength -= MaximumBytes;
1947 DataLength = (TransferLength > MaximumBytes) ? MaximumBytes : TransferLength;
1948 Offset.QuadPart = Offset.QuadPart + MaximumBytes;
1949 }
1950 }
1951
1952
1953 /* INTERNAL FUNCTIONS *******************************************************/
1954
1955 static NTSTATUS STDCALL
1956 ScsiClassCreateClose(IN PDEVICE_OBJECT DeviceObject,
1957 IN PIRP Irp)
1958 {
1959 PDEVICE_EXTENSION DeviceExtension;
1960
1961 DPRINT("ScsiClassCreateClose() called\n");
1962
1963 DeviceExtension = DeviceObject->DeviceExtension;
1964
1965 if (DeviceExtension->ClassCreateClose)
1966 return(DeviceExtension->ClassCreateClose(DeviceObject,
1967 Irp));
1968
1969 Irp->IoStatus.Status = STATUS_SUCCESS;
1970 Irp->IoStatus.Information = 0;
1971 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1972
1973 return(STATUS_SUCCESS);
1974 }
1975
1976
1977 static NTSTATUS STDCALL
1978 ScsiClassReadWrite(IN PDEVICE_OBJECT DeviceObject,
1979 IN PIRP Irp)
1980 {
1981 PDEVICE_EXTENSION DeviceExtension;
1982 PIO_STACK_LOCATION IrpStack;
1983 ULONG MaximumTransferLength;
1984 ULONG CurrentTransferLength;
1985 ULONG MaximumTransferPages;
1986 ULONG CurrentTransferPages;
1987 NTSTATUS Status;
1988
1989 DPRINT("ScsiClassReadWrite() called\n");
1990
1991 DeviceExtension = DeviceObject->DeviceExtension;
1992 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1993
1994 DPRINT("Relative Offset: %I64u Length: %lu\n",
1995 IrpStack->Parameters.Read.ByteOffset.QuadPart,
1996 IrpStack->Parameters.Read.Length);
1997
1998 MaximumTransferLength = DeviceExtension->PortCapabilities->MaximumTransferLength;
1999 MaximumTransferPages = DeviceExtension->PortCapabilities->MaximumPhysicalPages;
2000
2001 CurrentTransferLength = IrpStack->Parameters.Read.Length;
2002
2003 if ((DeviceObject->Flags & DO_VERIFY_VOLUME) &&
2004 !(IrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME))
2005 {
2006 IoSetHardErrorOrVerifyDevice(Irp,
2007 DeviceObject);
2008
2009 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
2010 Irp->IoStatus.Information = 0;
2011
2012 IoCompleteRequest(Irp,
2013 IO_NO_INCREMENT);
2014 return(STATUS_VERIFY_REQUIRED);
2015 }
2016
2017 /* Class driver verifies the IRP */
2018 Status = DeviceExtension->ClassReadWriteVerification(DeviceObject,
2019 Irp);
2020 if (!NT_SUCCESS(Status))
2021 {
2022 IoCompleteRequest(Irp,
2023 IO_NO_INCREMENT);
2024 return(Status);
2025 }
2026 else if (Status == STATUS_PENDING)
2027 {
2028 IoMarkIrpPending(Irp);
2029 return(STATUS_PENDING);
2030 }
2031
2032 /* Finish a zero-byte transfer */
2033 if (CurrentTransferLength == 0)
2034 {
2035 Irp->IoStatus.Status = STATUS_SUCCESS;
2036 Irp->IoStatus.Information = 0;
2037 IoCompleteRequest(Irp,
2038 IO_NO_INCREMENT);
2039 return(STATUS_SUCCESS);
2040 }
2041
2042 if (DeviceExtension->ClassStartIo != NULL)
2043 {
2044 DPRINT("ScsiClassReadWrite() starting packet\n");
2045
2046 IoMarkIrpPending(Irp);
2047 IoStartPacket(DeviceObject,
2048 Irp,
2049 NULL,
2050 NULL);
2051
2052 return(STATUS_PENDING);
2053 }
2054
2055 /* Adjust partition-relative starting offset to absolute offset */
2056 IrpStack->Parameters.Read.ByteOffset.QuadPart +=
2057 (DeviceExtension->StartingOffset.QuadPart + DeviceExtension->DMByteSkew);
2058
2059 /* Calculate number of pages in this transfer */
2060 CurrentTransferPages =
2061 ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
2062 IrpStack->Parameters.Read.Length);
2063
2064 if (CurrentTransferLength > MaximumTransferLength ||
2065 CurrentTransferPages > MaximumTransferPages)
2066 {
2067 DPRINT("Split current request: MaximumTransferLength %lu CurrentTransferLength %lu\n",
2068 MaximumTransferLength, CurrentTransferLength);
2069
2070 /* Adjust the maximum transfer length */
2071 CurrentTransferPages = DeviceExtension->PortCapabilities->MaximumPhysicalPages;
2072
2073 if (MaximumTransferLength > CurrentTransferPages * PAGE_SIZE)
2074 MaximumTransferLength = CurrentTransferPages * PAGE_SIZE;
2075
2076 if (MaximumTransferLength == 0)
2077 MaximumTransferLength = PAGE_SIZE;
2078
2079 IoMarkIrpPending(Irp);
2080
2081 /* Split current request */
2082 ScsiClassSplitRequest(DeviceObject,
2083 Irp,
2084 MaximumTransferLength);
2085
2086 return(STATUS_PENDING);
2087 }
2088
2089 ScsiClassBuildRequest(DeviceObject,
2090 Irp);
2091
2092 DPRINT("ScsiClassReadWrite() done\n");
2093
2094 /* Call the port driver */
2095 return(IoCallDriver(DeviceExtension->PortDeviceObject,
2096 Irp));
2097 }
2098
2099
2100 static NTSTATUS STDCALL
2101 ScsiClassDeviceDispatch(IN PDEVICE_OBJECT DeviceObject,
2102 IN PIRP Irp)
2103 {
2104 PDEVICE_EXTENSION DeviceExtension;
2105
2106 DPRINT("ScsiClassDeviceDispatch() called\n");
2107
2108 DeviceExtension = DeviceObject->DeviceExtension;
2109 if (DeviceExtension->ClassDeviceControl)
2110 {
2111 return(DeviceExtension->ClassDeviceControl(DeviceObject, Irp));
2112 }
2113
2114 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
2115 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2116
2117 return(STATUS_INVALID_DEVICE_REQUEST);
2118 }
2119
2120
2121 static NTSTATUS STDCALL
2122 ScsiClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
2123 IN PIRP Irp)
2124 {
2125 PDEVICE_EXTENSION DeviceExtension;
2126
2127 DPRINT("ScsiClassShutdownFlush() called\n");
2128
2129 DeviceExtension = DeviceObject->DeviceExtension;
2130 if (DeviceExtension->ClassShutdownFlush)
2131 {
2132 return(DeviceExtension->ClassShutdownFlush(DeviceObject, Irp));
2133 }
2134
2135 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
2136 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2137
2138 return(STATUS_INVALID_DEVICE_REQUEST);
2139 }
2140
2141
2142 static VOID
2143 ScsiClassRetryRequest(PDEVICE_OBJECT DeviceObject,
2144 PIRP Irp,
2145 PSCSI_REQUEST_BLOCK Srb,
2146 BOOLEAN Associated)
2147 {
2148 PDEVICE_EXTENSION DeviceExtension;
2149 PIO_STACK_LOCATION CurrentIrpStack;
2150 PIO_STACK_LOCATION NextIrpStack;
2151
2152 ULONG TransferLength;
2153
2154 DPRINT("ScsiPortRetryRequest() called\n");
2155
2156 DeviceExtension = DeviceObject->DeviceExtension;
2157 CurrentIrpStack = IoGetCurrentIrpStackLocation(Irp);
2158 NextIrpStack = IoGetNextIrpStackLocation(Irp);
2159
2160 if (CurrentIrpStack->MajorFunction != IRP_MJ_READ &&
2161 CurrentIrpStack->MajorFunction != IRP_MJ_WRITE)
2162 {
2163 /* We shouldn't setup the buffer pointer and transfer length on read/write requests. */
2164 if (Irp->MdlAddress != NULL)
2165 {
2166 TransferLength = Irp->MdlAddress->ByteCount;
2167 }
2168 else
2169 {
2170 TransferLength = 0;
2171 }
2172
2173 Srb->DataBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
2174 Srb->DataTransferLength = TransferLength;
2175 }
2176
2177 Srb->SrbStatus = 0;
2178 Srb->ScsiStatus = 0;
2179
2180 /* Don't modify the flags */
2181 // Srb->Flags =
2182 // Srb->QueueTag = SP_UNTAGGED;
2183
2184 NextIrpStack->MajorFunction = IRP_MJ_SCSI;
2185 NextIrpStack->Parameters.Scsi.Srb = Srb;
2186
2187 if (Associated == FALSE)
2188 {
2189 IoSetCompletionRoutine(Irp,
2190 ScsiClassIoComplete,
2191 Srb,
2192 TRUE,
2193 TRUE,
2194 TRUE);
2195 }
2196 else
2197 {
2198 IoSetCompletionRoutine(Irp,
2199 ScsiClassIoCompleteAssociated,
2200 Srb,
2201 TRUE,
2202 TRUE,
2203 TRUE);
2204 }
2205
2206 IoCallDriver(DeviceExtension->PortDeviceObject,
2207 Irp);
2208
2209 DPRINT("ScsiPortRetryRequest() done\n");
2210 }
2211
2212 /* EOF */