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