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.
19 /* $Id: diskdump.c,v 1.2 2003/10/18 18:49:08 weiden Exp $
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 #define VERSION "0.0.1"
42 /* PROTOTYPES ***************************************************************/
45 DiskDumpPrepare(PDEVICE_OBJECT DeviceObject
, PDUMP_POINTERS DumpPointers
);
47 DiskDumpScsiInvalid(VOID
);
49 _DiskDumpScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType
,
50 IN PVOID HwDeviceExtension
,
57 DiskDumpWrite(LARGE_INTEGER StartAddress
, PMDL Mdl
);
59 typedef VOID (*SCSIPORTNOTIFICATION
)(IN SCSI_NOTIFICATION_TYPE NotificationType
,
60 IN PVOID HwDeviceExtension
,
63 /* GLOBALS ******************************************************************/
65 MM_CORE_DUMP_FUNCTIONS DiskDumpFunctions
=
81 static SCSI_REQUEST_BLOCK CoreDumpSrb
;
82 static DUMP_POINTERS CoreDumpPointers
;
83 static PDEVICE_OBJECT CoreDumpClassDevice
;
84 static PDEVICE_EXTENSION CoreDumpClass2DeviceExtension
;
85 static PDEVICE_OBJECT CoreDumpPortDevice
;
86 static SCSI_PORT_DEVICE_EXTENSION
* CoreDumpPortDeviceExtension
;
87 BOOLEAN IsDumping
= FALSE
;
88 static PDRIVER_OBJECT DiskDumpDriver
;
89 static UCHAR DiskDumpSenseData
[SENSE_BUFFER_SIZE
];
90 static BOOLEAN IrqComplete
, IrqNextRequest
;
91 PVOID OldScsiPortNotification
;
92 static SUBSTITUTE_EXPORT DiskDumpExports
[] =
94 {"ScsiPortConvertPhysicalAddressToUlong", 2, NULL
, NULL
},
95 {"ScsiPortConvertUlongToPhysicalAddress", 3, NULL
, NULL
},
96 {"ScsiPortFreeDeviceBase", 5, NULL
, DiskDumpScsiInvalid
},
97 {"ScsiPortGetBusData", 6, NULL
, DiskDumpScsiInvalid
},
98 {"ScsiPortGetDeviceBase", 7, DiskDumpScsiInvalid
},
99 {"ScsiPortInitialize", 13, NULL
, DiskDumpScsiInvalid
},
100 {"ScsiPortNotification", 17, NULL
, _DiskDumpScsiPortNotification
},
101 {"ScsiPortReadPortBufferUlong", 19, NULL
},
102 {"ScsiPortReadPortBufferUshort", 20, NULL
},
103 {"ScsiPortReadPortUchar", 21, NULL
, NULL
},
104 {"ScsiPortReadPortUshort", 23, NULL
, NULL
},
105 {"ScsiPortStallExecution", 31, NULL
, NULL
},
106 {"ScsiPortWritePortBufferUlong", 34, NULL
},
107 {"ScsiPortWritePortBufferUshort", 35, NULL
},
108 {"ScsiPortWritePortUchar", 36, NULL
, NULL
},
109 {"ScsiDebugPrint", 0, NULL
, NULL
},
112 /* FUNCTIONS ****************************************************************/
117 DiskDumpScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType
,
118 IN PVOID HwDeviceExtension
,
121 if (NotificationType
== RequestComplete
)
125 if (NotificationType
== NextRequest
)
127 IrqNextRequest
= TRUE
;
132 DiskDumpScsiInvalid(VOID
)
134 DbgPrint("DISKDUMP: Error: Miniport called a function not supported at dump time.\n");
139 DiskDumpBuildRequest(LARGE_INTEGER StartingOffset
, PMDL Mdl
)
141 LARGE_INTEGER StartingBlock
;
142 PSCSI_REQUEST_BLOCK Srb
;
144 ULONG LogicalBlockAddress
;
145 USHORT TransferBlocks
;
147 /* Calculate logical block address */
148 StartingBlock
.QuadPart
= StartingOffset
.QuadPart
>> CoreDumpClass2DeviceExtension
->SectorShift
;
149 LogicalBlockAddress
= (ULONG
)StartingBlock
.u
.LowPart
;
151 DPRINT("Logical block address: %lu\n", LogicalBlockAddress
);
153 /* Allocate and initialize an SRB */
157 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
); //SCSI_REQUEST_BLOCK_SIZE;
158 Srb
->OriginalRequest
= NULL
;
159 Srb
->PathId
= CoreDumpClass2DeviceExtension
->PathId
;
160 Srb
->TargetId
= CoreDumpClass2DeviceExtension
->TargetId
;
161 Srb
->Lun
= CoreDumpClass2DeviceExtension
->Lun
;
162 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
163 Srb
->DataBuffer
= Mdl
->MappedSystemVa
;
164 Srb
->DataTransferLength
= PAGE_SIZE
;
165 Srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
166 Srb
->QueueSortKey
= LogicalBlockAddress
;
168 Srb
->SenseInfoBuffer
= DiskDumpSenseData
;
169 Srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
172 ((Srb
->DataTransferLength
+ 0xFFFF) >> 16) * CoreDumpClass2DeviceExtension
->TimeOutValue
;
174 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
179 Cdb
= (PCDB
)Srb
->Cdb
;
181 /* Initialize ATAPI packet (12 bytes) */
182 RtlZeroMemory(Cdb
, MAXIMUM_CDB_SIZE
);
184 Cdb
->CDB10
.LogicalUnitNumber
= CoreDumpClass2DeviceExtension
->Lun
;
185 TransferBlocks
= (USHORT
)(PAGE_SIZE
>>
186 CoreDumpClass2DeviceExtension
->SectorShift
);
188 /* Copy little endian values into CDB in big endian format */
189 Cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte3
;
190 Cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte2
;
191 Cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte1
;
192 Cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)&LogicalBlockAddress
)->Byte0
;
194 Cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)&TransferBlocks
)->Byte1
;
195 Cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)&TransferBlocks
)->Byte0
;
199 Srb
->SrbFlags
|= SRB_FLAGS_DATA_OUT
;
200 Cdb
->CDB10
.OperationCode
= SCSIOP_WRITE
;
202 /* Leave caching disabled. */
206 DiskDumpIsr(PKINTERRUPT Interrupt
, PVOID ServiceContext
)
208 if (!CoreDumpPortDeviceExtension
->HwInterrupt(&CoreDumpPortDeviceExtension
->MiniPortDeviceExtension
))
218 KIRQL CurrentIrql
= KeGetCurrentIrql();
220 if (CurrentIrql
>= CoreDumpPortDeviceExtension
->Interrupt
->SynchLevel
)
222 DbgPrint("DISKDUMP: Error: Crash inside high priority interrupt routine.\n");
223 return(STATUS_UNSUCCESSFUL
);
225 CoreDumpPortDeviceExtension
->Interrupt
->ServiceRoutine
= DiskDumpIsr
;
227 return(STATUS_SUCCESS
);
233 return(STATUS_SUCCESS
);
237 DiskDumpWrite(LARGE_INTEGER Address
, PMDL Mdl
)
239 KIRQL OldIrql
, OldIrql2
;
240 KIRQL CurrentIrql
= KeGetCurrentIrql();
242 if (CurrentIrql
< (CoreDumpPortDeviceExtension
->Interrupt
->SynchLevel
- 1))
244 KeRaiseIrql(CoreDumpPortDeviceExtension
->Interrupt
->SynchLevel
- 1, &OldIrql
);
247 /* Adjust the address for the start of the partition. */
249 (CoreDumpClass2DeviceExtension
->StartingOffset
.QuadPart
+ CoreDumpClass2DeviceExtension
->DMByteSkew
);
251 /* Assume the device is always able to transfer a page so no need to split up the transfer. */
253 /* Build an SRB to describe the write. */
254 DiskDumpBuildRequest(Address
, Mdl
);
256 /* Start i/o on the HBA. */
257 IrqComplete
= IrqNextRequest
= FALSE
;
258 KeRaiseIrql(CoreDumpPortDeviceExtension
->Interrupt
->SynchLevel
, &OldIrql2
);
259 if (!CoreDumpPortDeviceExtension
->HwStartIo(&CoreDumpPortDeviceExtension
->MiniPortDeviceExtension
,
262 KeLowerIrql(OldIrql
);
263 DbgPrint("DISKDUMP: Error: Miniport HwStartIo failed.\n");
264 return(STATUS_UNSUCCESSFUL
);
266 KeLowerIrql(OldIrql2
);
268 /* Wait for the miniport to finish. */
270 while (!IrqComplete
|| !IrqNextRequest
)
274 if (CurrentIrql
< (CoreDumpPortDeviceExtension
->Interrupt
->SynchLevel
- 1))
276 KeLowerIrql(OldIrql
);
280 /* Check the result. */
281 if (SRB_STATUS(CoreDumpSrb
.SrbStatus
) != SRB_STATUS_SUCCESS
)
283 DbgPrint("DISKDUMP: Error: SRB failed.\n");
284 return(STATUS_UNSUCCESSFUL
);
286 return(STATUS_SUCCESS
);
290 DiskDumpPrepare(PDEVICE_OBJECT DeviceObject
, PDUMP_POINTERS DumpPointers
)
292 PIMAGE_NT_HEADERS NtHeader
;
293 PVOID ImportDirectory
;
294 ULONG ImportDirectorySize
;
295 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory
;
300 PVOID
* ImportAddressList
;
301 PULONG FunctionNameList
;
303 /* Save the information from the kernel. */
304 CoreDumpClassDevice
= DeviceObject
;
305 CoreDumpPointers
= *DumpPointers
;
306 CoreDumpClass2DeviceExtension
= (PDEVICE_EXTENSION
)CoreDumpClassDevice
->DeviceExtension
;
307 CoreDumpPortDevice
= DumpPointers
->DeviceObject
;
308 CoreDumpPortDeviceExtension
= CoreDumpPortDevice
->DeviceExtension
;
310 /* Replace all the miniport driver's imports with our functions. */
311 DriverBase
= CoreDumpPortDevice
->DriverObject
->DriverStart
;
312 NtHeader
= RtlImageNtHeader(DriverBase
);
313 ImportDirectory
= RtlImageDirectoryEntryToData(DriverBase
,
315 IMAGE_DIRECTORY_ENTRY_IMPORT
,
316 &ImportDirectorySize
);
317 if (ImportDirectory
== NULL
|| ImportDirectorySize
== 0)
319 DbgPrint("DISKDUMP: Error: Miniport has no imports?\n");
320 return(STATUS_UNSUCCESSFUL
);
322 /* Process each import module */
323 ImportModuleDirectory
= (PIMAGE_IMPORT_MODULE_DIRECTORY
)ImportDirectory
;
324 DPRINT("Processeing import directory at %p\n", ImportModuleDirectory
);
325 while (ImportModuleDirectory
->dwRVAModuleName
)
327 /* Check to make sure that import lib is kernel */
328 Name
= (PCHAR
) DriverBase
+ ImportModuleDirectory
->dwRVAModuleName
;
330 if (strcmp(Name
, "scsiport.sys") != 0)
332 DbgPrint("DISKDUMP: Warning: Miniport has illegal imports.\n");
333 ImportModuleDirectory
++;
337 /* Get the import address list */
338 ImportAddressList
= (PVOID
*) ((PUCHAR
)DriverBase
+
339 ImportModuleDirectory
->dwRVAFunctionAddressList
);
341 /* Get the list of functions to import */
342 if (ImportModuleDirectory
->dwRVAFunctionNameList
!= 0)
344 FunctionNameList
= (PULONG
) ((PUCHAR
)DriverBase
+
345 ImportModuleDirectory
->dwRVAFunctionNameList
);
349 FunctionNameList
= (PULONG
) ((PUCHAR
)DriverBase
+
350 ImportModuleDirectory
->dwRVAFunctionAddressList
);
352 /* Walk through function list and fixup addresses */
353 while (*FunctionNameList
!= 0L)
355 if ((*FunctionNameList
) & 0x80000000) // hint
359 Hint
= (*FunctionNameList
) & 0xffff;
363 Name
= (PCHAR
)((DWORD
)DriverBase
+
364 *FunctionNameList
+ 2);
365 Hint
= *(PWORD
)((DWORD
)DriverBase
+ *FunctionNameList
);
367 DPRINT(" Hint:%04x Name:%s\n", Hint
, pName
);
369 for (i
= 0; i
< (sizeof(DiskDumpExports
) / sizeof(DiskDumpExports
[0])); i
++)
371 if (DiskDumpExports
[i
].Ordinal
== Hint
||
372 (Name
!= NULL
&& strcmp(DiskDumpExports
[i
].Name
, Name
) == 0))
377 if (i
== (sizeof(DiskDumpExports
) / sizeof(DiskDumpExports
[0])))
379 DbgPrint("DISKDUMP: Error: Miniport imports unknown symbol %s.\n", Name
);
380 return(STATUS_UNSUCCESSFUL
);
382 if (strcmp(Name
, "ScsiPortNotification") == 0)
384 OldScsiPortNotification
= *ImportAddressList
;
386 DiskDumpExports
[i
].OldFunction
= *ImportAddressList
;
387 if (DiskDumpExports
[i
].NewFunction
!= NULL
)
389 *ImportAddressList
= DiskDumpExports
[i
].NewFunction
;
395 ImportModuleDirectory
++;
397 return(STATUS_SUCCESS
);
400 /**********************************************************************
405 * This function initializes the driver, locates and claims
406 * hardware resources, and creates various NT objects needed
407 * to process I/O requests.
414 * System allocated Driver Object for this driver
417 * Name of registry driver service key
424 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
425 IN PUNICODE_STRING RegistryPath
)
427 DiskDumpDriver
= DriverObject
;
428 return(STATUS_SUCCESS
);