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