fixed a few warnings
[reactos.git] / reactos / drivers / storage / diskdump / diskdump.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2001, 2002, 2003 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: diskdump.c,v 1.2 2003/10/18 18:49:08 weiden Exp $
20 *
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)
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include <ddk/ntddk.h>
31 #include <ddk/scsi.h>
32 #include <ddk/class2.h>
33 #include <ddk/ntddscsi.h>
34 #include <napi/core.h>
35 #include "../scsiport/scsiport_int.h"
36
37 #define NDEBUG
38 #include <debug.h>
39
40 #define VERSION "0.0.1"
41
42 /* PROTOTYPES ***************************************************************/
43
44 NTSTATUS STDCALL
45 DiskDumpPrepare(PDEVICE_OBJECT DeviceObject, PDUMP_POINTERS DumpPointers);
46 VOID
47 DiskDumpScsiInvalid(VOID);
48 VOID
49 _DiskDumpScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,
50 IN PVOID HwDeviceExtension,
51 ...);
52 NTSTATUS STDCALL
53 DiskDumpInit(VOID);
54 NTSTATUS STDCALL
55 DiskDumpFinish(VOID);
56 NTSTATUS STDCALL
57 DiskDumpWrite(LARGE_INTEGER StartAddress, PMDL Mdl);
58
59 typedef VOID (*SCSIPORTNOTIFICATION)(IN SCSI_NOTIFICATION_TYPE NotificationType,
60 IN PVOID HwDeviceExtension,
61 ...);
62
63 /* GLOBALS ******************************************************************/
64
65 MM_CORE_DUMP_FUNCTIONS DiskDumpFunctions =
66 {
67 DiskDumpPrepare,
68 DiskDumpInit,
69 DiskDumpWrite,
70 DiskDumpFinish,
71 };
72
73 typedef struct
74 {
75 PCH Name;
76 ULONG Ordinal;
77 PVOID OldFunction;
78 PVOID NewFunction;
79 } SUBSTITUTE_EXPORT;
80
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[] =
93 {
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},
110 };
111
112 /* FUNCTIONS ****************************************************************/
113
114
115
116 VOID
117 DiskDumpScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,
118 IN PVOID HwDeviceExtension,
119 ...)
120 {
121 if (NotificationType == RequestComplete)
122 {
123 IrqComplete = TRUE;
124 }
125 if (NotificationType == NextRequest)
126 {
127 IrqNextRequest = TRUE;
128 }
129 }
130
131 VOID
132 DiskDumpScsiInvalid(VOID)
133 {
134 DbgPrint("DISKDUMP: Error: Miniport called a function not supported at dump time.\n");
135 KeBugCheck(0);
136 }
137
138 VOID STDCALL
139 DiskDumpBuildRequest(LARGE_INTEGER StartingOffset, PMDL Mdl)
140 {
141 LARGE_INTEGER StartingBlock;
142 PSCSI_REQUEST_BLOCK Srb;
143 PCDB Cdb;
144 ULONG LogicalBlockAddress;
145 USHORT TransferBlocks;
146
147 /* Calculate logical block address */
148 StartingBlock.QuadPart = StartingOffset.QuadPart >> CoreDumpClass2DeviceExtension->SectorShift;
149 LogicalBlockAddress = (ULONG)StartingBlock.u.LowPart;
150
151 DPRINT("Logical block address: %lu\n", LogicalBlockAddress);
152
153 /* Allocate and initialize an SRB */
154 Srb = &CoreDumpSrb;
155
156 Srb->SrbFlags = 0;
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;
167
168 Srb->SenseInfoBuffer = DiskDumpSenseData;
169 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
170
171 Srb->TimeOutValue =
172 ((Srb->DataTransferLength + 0xFFFF) >> 16) * CoreDumpClass2DeviceExtension->TimeOutValue;
173
174 Srb->SrbStatus = SRB_STATUS_SUCCESS;
175 Srb->ScsiStatus = 0;
176 Srb->NextSrb = 0;
177
178 Srb->CdbLength = 10;
179 Cdb = (PCDB)Srb->Cdb;
180
181 /* Initialize ATAPI packet (12 bytes) */
182 RtlZeroMemory(Cdb, MAXIMUM_CDB_SIZE);
183
184 Cdb->CDB10.LogicalUnitNumber = CoreDumpClass2DeviceExtension->Lun;
185 TransferBlocks = (USHORT)(PAGE_SIZE >>
186 CoreDumpClass2DeviceExtension->SectorShift);
187
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;
193
194 Cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&TransferBlocks)->Byte1;
195 Cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&TransferBlocks)->Byte0;
196
197
198 /* Write Command. */
199 Srb->SrbFlags |= SRB_FLAGS_DATA_OUT;
200 Cdb->CDB10.OperationCode = SCSIOP_WRITE;
201
202 /* Leave caching disabled. */
203 }
204
205 BOOLEAN STDCALL
206 DiskDumpIsr(PKINTERRUPT Interrupt, PVOID ServiceContext)
207 {
208 if (!CoreDumpPortDeviceExtension->HwInterrupt(&CoreDumpPortDeviceExtension->MiniPortDeviceExtension))
209 {
210 return(FALSE);
211 }
212 return(TRUE);
213 }
214
215 NTSTATUS STDCALL
216 DiskDumpInit(VOID)
217 {
218 KIRQL CurrentIrql = KeGetCurrentIrql();
219 IsDumping = TRUE;
220 if (CurrentIrql >= CoreDumpPortDeviceExtension->Interrupt->SynchLevel)
221 {
222 DbgPrint("DISKDUMP: Error: Crash inside high priority interrupt routine.\n");
223 return(STATUS_UNSUCCESSFUL);
224 }
225 CoreDumpPortDeviceExtension->Interrupt->ServiceRoutine = DiskDumpIsr;
226
227 return(STATUS_SUCCESS);
228 }
229
230 NTSTATUS STDCALL
231 DiskDumpFinish(VOID)
232 {
233 return(STATUS_SUCCESS);
234 }
235
236 NTSTATUS STDCALL
237 DiskDumpWrite(LARGE_INTEGER Address, PMDL Mdl)
238 {
239 KIRQL OldIrql, OldIrql2;
240 KIRQL CurrentIrql = KeGetCurrentIrql();
241
242 if (CurrentIrql < (CoreDumpPortDeviceExtension->Interrupt->SynchLevel - 1))
243 {
244 KeRaiseIrql(CoreDumpPortDeviceExtension->Interrupt->SynchLevel - 1, &OldIrql);
245 }
246
247 /* Adjust the address for the start of the partition. */
248 Address.QuadPart +=
249 (CoreDumpClass2DeviceExtension->StartingOffset.QuadPart + CoreDumpClass2DeviceExtension->DMByteSkew);
250
251 /* Assume the device is always able to transfer a page so no need to split up the transfer. */
252
253 /* Build an SRB to describe the write. */
254 DiskDumpBuildRequest(Address, Mdl);
255
256 /* Start i/o on the HBA. */
257 IrqComplete = IrqNextRequest = FALSE;
258 KeRaiseIrql(CoreDumpPortDeviceExtension->Interrupt->SynchLevel, &OldIrql2);
259 if (!CoreDumpPortDeviceExtension->HwStartIo(&CoreDumpPortDeviceExtension->MiniPortDeviceExtension,
260 &CoreDumpSrb))
261 {
262 KeLowerIrql(OldIrql);
263 DbgPrint("DISKDUMP: Error: Miniport HwStartIo failed.\n");
264 return(STATUS_UNSUCCESSFUL);
265 }
266 KeLowerIrql(OldIrql2);
267
268 /* Wait for the miniport to finish. */
269 __asm__ ("sti\n\t");
270 while (!IrqComplete || !IrqNextRequest)
271 {
272 __asm__ ("hlt\n\t");
273 }
274 if (CurrentIrql < (CoreDumpPortDeviceExtension->Interrupt->SynchLevel - 1))
275 {
276 KeLowerIrql(OldIrql);
277 }
278 __asm__("cli\n\t");
279
280 /* Check the result. */
281 if (SRB_STATUS(CoreDumpSrb.SrbStatus) != SRB_STATUS_SUCCESS)
282 {
283 DbgPrint("DISKDUMP: Error: SRB failed.\n");
284 return(STATUS_UNSUCCESSFUL);
285 }
286 return(STATUS_SUCCESS);
287 }
288
289 NTSTATUS STDCALL
290 DiskDumpPrepare(PDEVICE_OBJECT DeviceObject, PDUMP_POINTERS DumpPointers)
291 {
292 PIMAGE_NT_HEADERS NtHeader;
293 PVOID ImportDirectory;
294 ULONG ImportDirectorySize;
295 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
296 PVOID DriverBase;
297 PCH Name;
298 ULONG i;
299 ULONG Hint;
300 PVOID* ImportAddressList;
301 PULONG FunctionNameList;
302
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;
309
310 /* Replace all the miniport driver's imports with our functions. */
311 DriverBase = CoreDumpPortDevice->DriverObject->DriverStart;
312 NtHeader = RtlImageNtHeader(DriverBase);
313 ImportDirectory = RtlImageDirectoryEntryToData(DriverBase,
314 TRUE,
315 IMAGE_DIRECTORY_ENTRY_IMPORT,
316 &ImportDirectorySize);
317 if (ImportDirectory == NULL || ImportDirectorySize == 0)
318 {
319 DbgPrint("DISKDUMP: Error: Miniport has no imports?\n");
320 return(STATUS_UNSUCCESSFUL);
321 }
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)
326 {
327 /* Check to make sure that import lib is kernel */
328 Name = (PCHAR) DriverBase + ImportModuleDirectory->dwRVAModuleName;
329
330 if (strcmp(Name, "scsiport.sys") != 0)
331 {
332 DbgPrint("DISKDUMP: Warning: Miniport has illegal imports.\n");
333 ImportModuleDirectory++;
334 continue;
335 }
336
337 /* Get the import address list */
338 ImportAddressList = (PVOID *) ((PUCHAR)DriverBase +
339 ImportModuleDirectory->dwRVAFunctionAddressList);
340
341 /* Get the list of functions to import */
342 if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
343 {
344 FunctionNameList = (PULONG) ((PUCHAR)DriverBase +
345 ImportModuleDirectory->dwRVAFunctionNameList);
346 }
347 else
348 {
349 FunctionNameList = (PULONG) ((PUCHAR)DriverBase +
350 ImportModuleDirectory->dwRVAFunctionAddressList);
351 }
352 /* Walk through function list and fixup addresses */
353 while (*FunctionNameList != 0L)
354 {
355 if ((*FunctionNameList) & 0x80000000) // hint
356 {
357 Name = NULL;
358
359 Hint = (*FunctionNameList) & 0xffff;
360 }
361 else // hint-name
362 {
363 Name = (PCHAR)((DWORD)DriverBase +
364 *FunctionNameList + 2);
365 Hint = *(PWORD)((DWORD)DriverBase + *FunctionNameList);
366 }
367 DPRINT(" Hint:%04x Name:%s\n", Hint, pName);
368
369 for (i = 0; i < (sizeof(DiskDumpExports) / sizeof(DiskDumpExports[0])); i++)
370 {
371 if (DiskDumpExports[i].Ordinal == Hint ||
372 (Name != NULL && strcmp(DiskDumpExports[i].Name, Name) == 0))
373 {
374 break;
375 }
376 }
377 if (i == (sizeof(DiskDumpExports) / sizeof(DiskDumpExports[0])))
378 {
379 DbgPrint("DISKDUMP: Error: Miniport imports unknown symbol %s.\n", Name);
380 return(STATUS_UNSUCCESSFUL);
381 }
382 if (strcmp(Name, "ScsiPortNotification") == 0)
383 {
384 OldScsiPortNotification = *ImportAddressList;
385 }
386 DiskDumpExports[i].OldFunction = *ImportAddressList;
387 if (DiskDumpExports[i].NewFunction != NULL)
388 {
389 *ImportAddressList = DiskDumpExports[i].NewFunction;
390 }
391
392 ImportAddressList++;
393 FunctionNameList++;
394 }
395 ImportModuleDirectory++;
396 }
397 return(STATUS_SUCCESS);
398 }
399
400 /**********************************************************************
401 * NAME EXPORTED
402 * DriverEntry
403 *
404 * DESCRIPTION
405 * This function initializes the driver, locates and claims
406 * hardware resources, and creates various NT objects needed
407 * to process I/O requests.
408 *
409 * RUN LEVEL
410 * PASSIVE_LEVEL
411 *
412 * ARGUMENTS
413 * DriverObject
414 * System allocated Driver Object for this driver
415 *
416 * RegistryPath
417 * Name of registry driver service key
418 *
419 * RETURN VALUE
420 * Status
421 */
422
423 NTSTATUS STDCALL
424 DriverEntry(IN PDRIVER_OBJECT DriverObject,
425 IN PUNICODE_STRING RegistryPath)
426 {
427 DiskDumpDriver = DriverObject;
428 return(STATUS_SUCCESS);
429 }
430
431
432 /* EOF */