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 #define VERSION "0.0.1"
42 /* PROTOTYPES ***************************************************************/
45 DiskDumpPrepare(PDEVICE_OBJECT StorageDevice, 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 StorageDevice, 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 = StorageDevice;
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);