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