update for HEAD-2003091401
[reactos.git] / 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$
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 */