3 * Copyright (C) 2001, 2002, 2003 ReactOS Team
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.
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.
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.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: services/storage/diskdump/diskdump.c
24 * PURPOSE: Dumping crash data to the pagefile
25 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
28 /* INCLUDES *****************************************************************/
30 #include <ddk/ntddk.h>
32 #include <ddk/class2.h>
33 #include <ddk/ntddscsi.h>
34 #include <napi/core.h>
35 #include "../scsiport/scsiport_int.h"
40 /* It's already defined in scsiport_int.h */
42 #define VERSION "0.0.1"
44 /* PROTOTYPES ***************************************************************/
47 DiskDumpPrepare(PDEVICE_OBJECT DeviceObject
, PDUMP_POINTERS DumpPointers
);
49 DiskDumpScsiInvalid(VOID
);
51 _DiskDumpScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType
,
52 IN PVOID HwDeviceExtension
,
59 DiskDumpWrite(LARGE_INTEGER StartAddress
, PMDL Mdl
);
61 typedef VOID (*SCSIPORTNOTIFICATION
)(IN SCSI_NOTIFICATION_TYPE NotificationType
,
62 IN PVOID HwDeviceExtension
,
65 /* GLOBALS ******************************************************************/
67 MM_CORE_DUMP_FUNCTIONS DiskDumpFunctions
=
69 (PVOID
)DiskDumpPrepare
,
72 (PVOID
)DiskDumpFinish
,
83 static SCSI_REQUEST_BLOCK CoreDumpSrb
;
84 static DUMP_POINTERS CoreDumpPointers
;
85 static PDEVICE_OBJECT CoreDumpClassDevice
;
86 static PDEVICE_EXTENSION CoreDumpClass2DeviceExtension
;
87 static PDEVICE_OBJECT CoreDumpPortDevice
;
88 static SCSI_PORT_DEVICE_EXTENSION
* CoreDumpPortDeviceExtension
;
89 BOOLEAN IsDumping
= FALSE
;
90 static PDRIVER_OBJECT DiskDumpDriver
;
91 static UCHAR DiskDumpSenseData
[SENSE_BUFFER_SIZE
];
92 static BOOLEAN IrqComplete
, IrqNextRequest
;
93 PVOID OldScsiPortNotification
;
94 static SUBSTITUTE_EXPORT DiskDumpExports
[] =
96 {"ScsiPortConvertPhysicalAddressToUlong", 2, NULL
, NULL
},
97 {"ScsiPortConvertUlongToPhysicalAddress", 3, NULL
, NULL
},
98 {"ScsiPortFreeDeviceBase", 5, NULL
, DiskDumpScsiInvalid
},
99 {"ScsiPortGetBusData", 6, NULL
, DiskDumpScsiInvalid
},
100 {"ScsiPortGetDeviceBase", 7, DiskDumpScsiInvalid
},
101 {"ScsiPortInitialize", 13, NULL
, DiskDumpScsiInvalid
},
102 {"ScsiPortNotification", 17, NULL
, _DiskDumpScsiPortNotification
},
103 {"ScsiPortReadPortBufferUlong", 19, NULL
},
104 {"ScsiPortReadPortBufferUshort", 20, NULL
},
105 {"ScsiPortReadPortUchar", 21, NULL
, NULL
},
106 {"ScsiPortReadPortUshort", 23, NULL
, NULL
},
107 {"ScsiPortStallExecution", 31, NULL
, NULL
},
108 {"ScsiPortWritePortBufferUlong", 34, NULL
},
109 {"ScsiPortWritePortBufferUshort", 35, NULL
},
110 {"ScsiPortWritePortUchar", 36, NULL
, NULL
},
111 {"ScsiDebugPrint", 0, NULL
, NULL
},
114 /* FUNCTIONS ****************************************************************/
119 DiskDumpScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType
,
120 IN PVOID HwDeviceExtension
,
123 if (NotificationType
== RequestComplete
)
127 if (NotificationType
== NextRequest
)
129 IrqNextRequest
= TRUE
;
134 DiskDumpScsiInvalid(VOID
)
136 DbgPrint("DISKDUMP: Error: Miniport called a function not supported at dump time.\n");
141 DiskDumpBuildRequest(LARGE_INTEGER StartingOffset
, PMDL Mdl
)
143 LARGE_INTEGER StartingBlock
;
144 PSCSI_REQUEST_BLOCK Srb
;
146 ULONG LogicalBlockAddress
;
147 USHORT TransferBlocks
;
149 /* Calculate logical block address */
150 StartingBlock
.QuadPart
= StartingOffset
.QuadPart
>> CoreDumpClass2DeviceExtension
->SectorShift
;
151 LogicalBlockAddress
= (ULONG
)StartingBlock
.u
.LowPart
;
153 DPRINT("Logical block address: %lu\n", LogicalBlockAddress
);
155 /* Allocate and initialize an SRB */
159 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
); //SCSI_REQUEST_BLOCK_SIZE;
160 Srb
->OriginalRequest
= NULL
;
161 Srb
->PathId
= CoreDumpClass2DeviceExtension
->PathId
;
162 Srb
->TargetId
= CoreDumpClass2DeviceExtension
->TargetId
;
163 Srb
->Lun
= CoreDumpClass2DeviceExtension
->Lun
;
164 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
165 Srb
->DataBuffer
= Mdl
->MappedSystemVa
;
166 Srb
->DataTransferLength
= PAGE_SIZE
;
167 Srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
168 Srb
->QueueSortKey
= LogicalBlockAddress
;
170 Srb
->SenseInfoBuffer
= DiskDumpSenseData
;
171 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
174 ((Srb
->DataTransferLength
+ 0xFFFF) >> 16) * CoreDumpClass2DeviceExtension
->TimeOutValue
;
176 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
181 Cdb
= (PCDB
)Srb
->Cdb
;
183 /* Initialize ATAPI packet (12 bytes) */
184 RtlZeroMemory(Cdb
, MAXIMUM_CDB_SIZE
);
186 Cdb
->CDB10
.LogicalUnitNumber
= CoreDumpClass2DeviceExtension
->Lun
;
187 TransferBlocks
= (USHORT
)(PAGE_SIZE
>>
188 CoreDumpClass2DeviceExtension
->SectorShift
);
190 /* Copy little endian values into CDB in big endian format */
191 Cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte3
;
192 Cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte2
;
193 Cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte1
;
194 Cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte0
;
196 Cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)&TransferBlocks
)->Byte1
;
197 Cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)&TransferBlocks
)->Byte0
;
201 Srb
->SrbFlags
|= SRB_FLAGS_DATA_OUT
;
202 Cdb
->CDB10
.OperationCode
= SCSIOP_WRITE
;
204 /* Leave caching disabled. */
208 DiskDumpIsr(PKINTERRUPT Interrupt
, PVOID ServiceContext
)
210 if (!CoreDumpPortDeviceExtension
->HwInterrupt(&CoreDumpPortDeviceExtension
->MiniPortDeviceExtension
))
220 KIRQL CurrentIrql
= KeGetCurrentIrql();
222 if (CurrentIrql
>= CoreDumpPortDeviceExtension
->Interrupt
->SynchLevel
)
224 DbgPrint("DISKDUMP: Error: Crash inside high priority interrupt routine.\n");
225 return(STATUS_UNSUCCESSFUL
);
227 CoreDumpPortDeviceExtension
->Interrupt
->ServiceRoutine
= DiskDumpIsr
;
229 return(STATUS_SUCCESS
);
235 return(STATUS_SUCCESS
);
239 DiskDumpWrite(LARGE_INTEGER Address
, PMDL Mdl
)
241 KIRQL OldIrql
, OldIrql2
;
242 KIRQL CurrentIrql
= KeGetCurrentIrql();
244 if (CurrentIrql
< (CoreDumpPortDeviceExtension
->Interrupt
->SynchLevel
- 1))
246 KeRaiseIrql(CoreDumpPortDeviceExtension
->Interrupt
->SynchLevel
- 1, &OldIrql
);
249 /* Adjust the address for the start of the partition. */
251 (CoreDumpClass2DeviceExtension
->StartingOffset
.QuadPart
+ CoreDumpClass2DeviceExtension
->DMByteSkew
);
253 /* Assume the device is always able to transfer a page so no need to split up the transfer. */
255 /* Build an SRB to describe the write. */
256 DiskDumpBuildRequest(Address
, Mdl
);
258 /* Start i/o on the HBA. */
259 IrqComplete
= IrqNextRequest
= FALSE
;
260 KeRaiseIrql(CoreDumpPortDeviceExtension
->Interrupt
->SynchLevel
, &OldIrql2
);
261 if (!CoreDumpPortDeviceExtension
->HwStartIo(&CoreDumpPortDeviceExtension
->MiniPortDeviceExtension
,
264 KeLowerIrql(OldIrql
);
265 DbgPrint("DISKDUMP: Error: Miniport HwStartIo failed.\n");
266 return(STATUS_UNSUCCESSFUL
);
268 KeLowerIrql(OldIrql2
);
270 /* Wait for the miniport to finish. */
272 while (!IrqComplete
|| !IrqNextRequest
)
276 if (CurrentIrql
< (CoreDumpPortDeviceExtension
->Interrupt
->SynchLevel
- 1))
278 KeLowerIrql(OldIrql
);
282 /* Check the result. */
283 if (SRB_STATUS(CoreDumpSrb
.SrbStatus
) != SRB_STATUS_SUCCESS
)
285 DbgPrint("DISKDUMP: Error: SRB failed.\n");
286 return(STATUS_UNSUCCESSFUL
);
288 return(STATUS_SUCCESS
);
292 DiskDumpPrepare(PDEVICE_OBJECT DeviceObject
, PDUMP_POINTERS DumpPointers
)
294 PIMAGE_NT_HEADERS NtHeader
;
295 PVOID ImportDirectory
;
296 ULONG ImportDirectorySize
;
297 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
302 PVOID
* ImportAddressList
;
303 PULONG FunctionNameList
;
305 /* Save the information from the kernel. */
306 CoreDumpClassDevice
= DeviceObject
;
307 CoreDumpPointers
= *DumpPointers
;
308 CoreDumpClass2DeviceExtension
= (PDEVICE_EXTENSION
)CoreDumpClassDevice
->DeviceExtension
;
309 CoreDumpPortDevice
= DumpPointers
->DeviceObject
;
310 CoreDumpPortDeviceExtension
= CoreDumpPortDevice
->DeviceExtension
;
312 /* Replace all the miniport driver's imports with our functions. */
313 DriverBase
= CoreDumpPortDevice
->DriverObject
->DriverStart
;
314 NtHeader
= RtlImageNtHeader(DriverBase
);
315 ImportDirectory
= RtlImageDirectoryEntryToData(DriverBase
,
317 IMAGE_DIRECTORY_ENTRY_IMPORT
,
318 &ImportDirectorySize
);
319 if (ImportDirectory
== NULL
|| ImportDirectorySize
== 0)
321 DbgPrint("DISKDUMP: Error: Miniport has no imports?\n");
322 return(STATUS_UNSUCCESSFUL
);
324 /* Process each import module */
325 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)ImportDirectory
;
326 DPRINT("Processeing import directory at %p\n", ImportModuleDirectory
);
327 while (ImportModuleDirectory
->dwRVAModuleName
)
329 /* Check to make sure that import lib is kernel */
330 Name
= (PCHAR
) DriverBase
+ ImportModuleDirectory
->dwRVAModuleName
;
332 if (strcmp(Name
, "scsiport.sys") != 0)
334 DbgPrint("DISKDUMP: Warning: Miniport has illegal imports.\n");
335 ImportModuleDirectory
++;
339 /* Get the import address list */
340 ImportAddressList
= (PVOID
*) ((PUCHAR
)DriverBase
+
341 ImportModuleDirectory
->dwRVAFunctionAddressList
);
343 /* Get the list of functions to import */
344 if (ImportModuleDirectory
->dwRVAFunctionNameList
!= 0)
346 FunctionNameList
= (PULONG
) ((PUCHAR
)DriverBase
+
347 ImportModuleDirectory
->dwRVAFunctionNameList
);
351 FunctionNameList
= (PULONG
) ((PUCHAR
)DriverBase
+
352 ImportModuleDirectory
->dwRVAFunctionAddressList
);
354 /* Walk through function list and fixup addresses */
355 while (*FunctionNameList
!= 0L)
357 if ((*FunctionNameList
) & 0x80000000) // hint
361 Hint
= (*FunctionNameList
) & 0xffff;
365 Name
= (PCHAR
)((DWORD
)DriverBase
+
366 *FunctionNameList
+ 2);
367 Hint
= *(PWORD
)((DWORD
)DriverBase
+ *FunctionNameList
);
369 DPRINT(" Hint:%04x Name:%s\n", Hint
, pName
);
371 for (i
= 0; i
< (sizeof(DiskDumpExports
) / sizeof(DiskDumpExports
[0])); i
++)
373 if (DiskDumpExports
[i
].Ordinal
== Hint
||
374 (Name
!= NULL
&& strcmp(DiskDumpExports
[i
].Name
, Name
) == 0))
379 if (i
== (sizeof(DiskDumpExports
) / sizeof(DiskDumpExports
[0])))
381 DbgPrint("DISKDUMP: Error: Miniport imports unknown symbol %s.\n", Name
);
382 return(STATUS_UNSUCCESSFUL
);
384 if (strcmp(Name
, "ScsiPortNotification") == 0)
386 OldScsiPortNotification
= *ImportAddressList
;
388 DiskDumpExports
[i
].OldFunction
= *ImportAddressList
;
389 if (DiskDumpExports
[i
].NewFunction
!= NULL
)
391 *ImportAddressList
= DiskDumpExports
[i
].NewFunction
;
397 ImportModuleDirectory
++;
399 return(STATUS_SUCCESS
);
402 /**********************************************************************
407 * This function initializes the driver, locates and claims
408 * hardware resources, and creates various NT objects needed
409 * to process I/O requests.
416 * System allocated Driver Object for this driver
419 * Name of registry driver service key
426 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
427 IN PUNICODE_STRING RegistryPath
)
429 DiskDumpDriver
= DriverObject
;
430 return(STATUS_SUCCESS
);