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