[NTOS]
[reactos.git] / reactos / drivers / storage / port / diskdump / diskdump.c
1 /* $Id: diskdump.c 29690 2007-10-19 23:21:45Z dreimer $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS Kernel
5 * FILE: services/storage/diskdump/diskdump.c
6 * PURPOSE: Dumping crash data to the pagefile
7 * PROGRAMMER:
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntddk.h>
13 #include <scsi.h>
14 #include <ntdddisk.h>
15 #include <ntddscsi.h>
16 #include <../class/include/class2.h>
17 #include <diskdump/diskdump.h>
18 #include <ndk/rtlfuncs.h>
19
20 #include "../scsiport/scsiport_int.h"
21
22 #define NDEBUG
23 #include <debug.h>
24
25 /* It's already defined in scsiport_int.h */
26 #undef VERSION
27 #define VERSION "0.0.1"
28
29 #undef KeGetCurrentIrql
30 /* PROTOTYPES ***************************************************************/
31
32 NTSTATUS NTAPI
33 DiskDumpPrepare(PDEVICE_OBJECT DeviceObject, PDUMP_POINTERS DumpPointers);
34 VOID
35 DiskDumpScsiInvalid(VOID);
36 VOID
37 _DiskDumpScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,
38 IN PVOID HwDeviceExtension,
39 ...);
40 NTSTATUS NTAPI
41 DiskDumpInit(VOID);
42 NTSTATUS NTAPI
43 DiskDumpFinish(VOID);
44 NTSTATUS NTAPI
45 DiskDumpWrite(LARGE_INTEGER StartAddress, PMDL Mdl);
46
47 typedef VOID (*SCSIPORTNOTIFICATION)(IN SCSI_NOTIFICATION_TYPE NotificationType,
48 IN PVOID HwDeviceExtension,
49 ...);
50
51 /* GLOBALS ******************************************************************/
52
53 MM_CORE_DUMP_FUNCTIONS DiskDumpFunctions =
54 {
55 (PVOID)DiskDumpPrepare,
56 (PVOID)DiskDumpInit,
57 (PVOID)DiskDumpWrite,
58 (PVOID)DiskDumpFinish,
59 };
60
61 typedef struct
62 {
63 PCH Name;
64 ULONG Ordinal;
65 PVOID OldFunction;
66 PVOID NewFunction;
67 } SUBSTITUTE_EXPORT;
68
69 static SCSI_REQUEST_BLOCK CoreDumpSrb;
70 static DUMP_POINTERS CoreDumpPointers;
71 static PDEVICE_OBJECT CoreDumpClassDevice;
72 static PDEVICE_EXTENSION CoreDumpClass2DeviceExtension;
73 static PDEVICE_OBJECT CoreDumpPortDevice;
74 static SCSI_PORT_DEVICE_EXTENSION* CoreDumpPortDeviceExtension;
75 BOOLEAN IsDumping = FALSE;
76 static PDRIVER_OBJECT DiskDumpDriver;
77 static UCHAR DiskDumpSenseData[SENSE_BUFFER_SIZE];
78 static BOOLEAN IrqComplete, IrqNextRequest;
79 PVOID OldScsiPortNotification;
80 static SUBSTITUTE_EXPORT DiskDumpExports[] =
81 {
82 {"ScsiPortConvertPhysicalAddressToUlong", 2, NULL, NULL},
83 {"ScsiPortConvertUlongToPhysicalAddress", 3, NULL, NULL},
84 {"ScsiPortFreeDeviceBase", 5, NULL, DiskDumpScsiInvalid},
85 {"ScsiPortGetBusData", 6, NULL, DiskDumpScsiInvalid},
86 {"ScsiPortGetDeviceBase", 7, NULL, DiskDumpScsiInvalid},
87 {"ScsiPortInitialize", 13, NULL, DiskDumpScsiInvalid},
88 {"ScsiPortNotification", 17, NULL, _DiskDumpScsiPortNotification},
89 {"ScsiPortReadPortBufferUlong", 19, NULL, NULL},
90 {"ScsiPortReadPortBufferUshort", 20, NULL, NULL},
91 {"ScsiPortReadPortUchar", 21, NULL, NULL},
92 {"ScsiPortReadPortUshort", 23, NULL, NULL},
93 {"ScsiPortStallExecution", 31, NULL, NULL},
94 {"ScsiPortWritePortBufferUlong", 34, NULL, NULL},
95 {"ScsiPortWritePortBufferUshort", 35, NULL, NULL},
96 {"ScsiPortWritePortUchar", 36, NULL, NULL},
97 {"ScsiDebugPrint", 0, NULL, NULL},
98 };
99
100 /* FUNCTIONS ****************************************************************/
101
102
103
104 VOID
105 DiskDumpScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,
106 IN PVOID HwDeviceExtension,
107 ...)
108 {
109 if (NotificationType == RequestComplete)
110 {
111 IrqComplete = TRUE;
112 }
113 if (NotificationType == NextRequest)
114 {
115 IrqNextRequest = TRUE;
116 }
117 }
118
119 VOID
120 DiskDumpScsiInvalid(VOID)
121 {
122 DbgPrint("DISKDUMP: Error: Miniport called a function not supported at dump time.\n");
123 KeBugCheck(0);
124 }
125
126 VOID NTAPI
127 DiskDumpBuildRequest(LARGE_INTEGER StartingOffset, PMDL Mdl)
128 {
129 LARGE_INTEGER StartingBlock;
130 PSCSI_REQUEST_BLOCK Srb;
131 PCDB Cdb;
132 ULONG LogicalBlockAddress;
133 USHORT TransferBlocks;
134
135 /* Calculate logical block address */
136 StartingBlock.QuadPart = StartingOffset.QuadPart >> CoreDumpClass2DeviceExtension->SectorShift;
137 LogicalBlockAddress = (ULONG)StartingBlock.u.LowPart;
138
139 DPRINT("Logical block address: %lu\n", LogicalBlockAddress);
140
141 /* Allocate and initialize an SRB */
142 Srb = &CoreDumpSrb;
143
144 Srb->SrbFlags = 0;
145 Srb->Length = sizeof(SCSI_REQUEST_BLOCK); //SCSI_REQUEST_BLOCK_SIZE;
146 Srb->OriginalRequest = NULL;
147 Srb->PathId = CoreDumpClass2DeviceExtension->PathId;
148 Srb->TargetId = CoreDumpClass2DeviceExtension->TargetId;
149 Srb->Lun = CoreDumpClass2DeviceExtension->Lun;
150 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
151 Srb->DataBuffer = Mdl->MappedSystemVa;
152 Srb->DataTransferLength = PAGE_SIZE;
153 Srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
154 Srb->QueueSortKey = LogicalBlockAddress;
155
156 Srb->SenseInfoBuffer = DiskDumpSenseData;
157 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
158
159 Srb->TimeOutValue =
160 ((Srb->DataTransferLength + 0xFFFF) >> 16) * CoreDumpClass2DeviceExtension->TimeOutValue;
161
162 Srb->SrbStatus = SRB_STATUS_SUCCESS;
163 Srb->ScsiStatus = 0;
164 Srb->NextSrb = 0;
165
166 Srb->CdbLength = 10;
167 Cdb = (PCDB)Srb->Cdb;
168
169 /* Initialize ATAPI packet (12 bytes) */
170 RtlZeroMemory(Cdb, MAXIMUM_CDB_SIZE);
171
172 Cdb->CDB10.LogicalUnitNumber = CoreDumpClass2DeviceExtension->Lun;
173 TransferBlocks = (USHORT)(PAGE_SIZE >>
174 CoreDumpClass2DeviceExtension->SectorShift);
175
176 /* Copy little endian values into CDB in big endian format */
177 Cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte3;
178 Cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte2;
179 Cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte1;
180 Cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte0;
181
182 Cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&TransferBlocks)->Byte1;
183 Cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&TransferBlocks)->Byte0;
184
185
186 /* Write Command. */
187 Srb->SrbFlags |= SRB_FLAGS_DATA_OUT;
188 Cdb->CDB10.OperationCode = SCSIOP_WRITE;
189
190 /* Leave caching disabled. */
191 }
192
193 BOOLEAN NTAPI
194 DiskDumpIsr(PKINTERRUPT Interrupt, PVOID ServiceContext)
195 {
196 if (!CoreDumpPortDeviceExtension->HwInterrupt(&CoreDumpPortDeviceExtension->MiniPortDeviceExtension))
197 {
198 return(FALSE);
199 }
200 return(TRUE);
201 }
202
203 NTSTATUS NTAPI
204 DiskDumpInit(VOID)
205 {
206 KIRQL CurrentIrql = KeGetCurrentIrql();
207 IsDumping = TRUE;
208 if (CurrentIrql >= CoreDumpPortDeviceExtension->Interrupt->SynchronizeIrql)
209 {
210 DbgPrint("DISKDUMP: Error: Crash inside high priority interrupt routine.\n");
211 return(STATUS_UNSUCCESSFUL);
212 }
213 CoreDumpPortDeviceExtension->Interrupt->ServiceRoutine = DiskDumpIsr;
214
215 return(STATUS_SUCCESS);
216 }
217
218 NTSTATUS NTAPI
219 DiskDumpFinish(VOID)
220 {
221 return(STATUS_SUCCESS);
222 }
223
224 NTSTATUS NTAPI
225 DiskDumpWrite(LARGE_INTEGER Address, PMDL Mdl)
226 {
227 KIRQL OldIrql = 0, OldIrql2 = 0;
228 KIRQL CurrentIrql = KeGetCurrentIrql();
229
230 if (CurrentIrql < (CoreDumpPortDeviceExtension->Interrupt->SynchronizeIrql - 1))
231 {
232 KeRaiseIrql(CoreDumpPortDeviceExtension->Interrupt->SynchronizeIrql - 1, &OldIrql);
233 }
234
235 /* Adjust the address for the start of the partition. */
236 Address.QuadPart +=
237 (CoreDumpClass2DeviceExtension->StartingOffset.QuadPart + CoreDumpClass2DeviceExtension->DMByteSkew);
238
239 /* Assume the device is always able to transfer a page so no need to split up the transfer. */
240
241 /* Build an SRB to describe the write. */
242 DiskDumpBuildRequest(Address, Mdl);
243
244 /* Start i/o on the HBA. */
245 IrqComplete = IrqNextRequest = FALSE;
246 KeRaiseIrql(CoreDumpPortDeviceExtension->Interrupt->SynchronizeIrql, &OldIrql2);
247 if (!CoreDumpPortDeviceExtension->HwStartIo(&CoreDumpPortDeviceExtension->MiniPortDeviceExtension,
248 &CoreDumpSrb))
249 {
250 KeLowerIrql(OldIrql);
251 DbgPrint("DISKDUMP: Error: Miniport HwStartIo failed.\n");
252 return(STATUS_UNSUCCESSFUL);
253 }
254 KeLowerIrql(OldIrql2);
255
256 /* Wait for the miniport to finish. */
257 __asm__ ("sti\n\t");
258 while (!IrqComplete || !IrqNextRequest)
259 {
260 __asm__ ("hlt\n\t");
261 }
262 if (CurrentIrql < (CoreDumpPortDeviceExtension->Interrupt->SynchronizeIrql - 1))
263 {
264 KeLowerIrql(OldIrql);
265 }
266 __asm__("cli\n\t");
267
268 /* Check the result. */
269 if (SRB_STATUS(CoreDumpSrb.SrbStatus) != SRB_STATUS_SUCCESS)
270 {
271 DbgPrint("DISKDUMP: Error: SRB failed.\n");
272 return(STATUS_UNSUCCESSFUL);
273 }
274 return(STATUS_SUCCESS);
275 }
276
277 NTSTATUS NTAPI
278 DiskDumpPrepare(PDEVICE_OBJECT DeviceObject, PDUMP_POINTERS DumpPointers)
279 {
280 PIMAGE_NT_HEADERS NtHeader;
281 PVOID ImportDirectory;
282 ULONG ImportDirectorySize;
283 PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
284 PVOID DriverBase;
285 PCH Name;
286 ULONG i;
287 ULONG Hint;
288 PVOID* ImportAddressList;
289 PULONG FunctionNameList;
290
291 /* Save the information from the kernel. */
292 CoreDumpClassDevice = DeviceObject;
293 CoreDumpPointers = *DumpPointers;
294 CoreDumpClass2DeviceExtension = (PDEVICE_EXTENSION)CoreDumpClassDevice->DeviceExtension;
295 CoreDumpPortDevice = DumpPointers->DeviceObject;
296 CoreDumpPortDeviceExtension = CoreDumpPortDevice->DeviceExtension;
297
298 /* Replace all the miniport driver's imports with our functions. */
299 DriverBase = CoreDumpPortDevice->DriverObject->DriverStart;
300 NtHeader = RtlImageNtHeader(DriverBase);
301 ImportDirectory = RtlImageDirectoryEntryToData(DriverBase,
302 TRUE,
303 IMAGE_DIRECTORY_ENTRY_IMPORT,
304 &ImportDirectorySize);
305 if (ImportDirectory == NULL || ImportDirectorySize == 0)
306 {
307 DbgPrint("DISKDUMP: Error: Miniport has no imports?\n");
308 return(STATUS_UNSUCCESSFUL);
309 }
310 /* Process each import module */
311 ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)ImportDirectory;
312 DPRINT("Processeing import directory at %p\n", ImportModuleDirectory);
313 while (ImportModuleDirectory->Name)
314 {
315 /* Check to make sure that import lib is kernel */
316 Name = (PCHAR) DriverBase + ImportModuleDirectory->Name;
317
318 if (strcmp(Name, "scsiport.sys") != 0)
319 {
320 DbgPrint("DISKDUMP: Warning: Miniport has illegal imports.\n");
321 ImportModuleDirectory++;
322 continue;
323 }
324
325 /* Get the import address list */
326 ImportAddressList = (PVOID *) ((PUCHAR)DriverBase +
327 (ULONG_PTR)ImportModuleDirectory->FirstThunk);
328
329 /* Get the list of functions to import */
330 if (ImportModuleDirectory->OriginalFirstThunk != 0)
331 {
332 FunctionNameList = (PULONG) ((PUCHAR)DriverBase +
333 (ULONG_PTR)ImportModuleDirectory->OriginalFirstThunk);
334 }
335 else
336 {
337 FunctionNameList = (PULONG) ((PUCHAR)DriverBase +
338 (ULONG_PTR)ImportModuleDirectory->FirstThunk);
339 }
340 /* Walk through function list and fixup addresses */
341 while (*FunctionNameList != 0L)
342 {
343 if ((*FunctionNameList) & 0x80000000) // hint
344 {
345 Name = NULL;
346
347 Hint = (*FunctionNameList) & 0xffff;
348 }
349 else // hint-name
350 {
351 Name = (PCHAR)((ULONG_PTR)DriverBase +
352 (ULONG_PTR)*FunctionNameList + 2);
353 Hint = *(PUSHORT)((ULONG_PTR)DriverBase + (ULONG_PTR)*FunctionNameList);
354 }
355 #if 0
356 DPRINT(" Hint:%04x Name:%s\n", Hint, pName);
357 #endif
358
359 for (i = 0; i < (sizeof(DiskDumpExports) / sizeof(DiskDumpExports[0])); i++)
360 {
361 if (DiskDumpExports[i].Ordinal == Hint ||
362 (Name != NULL && strcmp(DiskDumpExports[i].Name, Name) == 0))
363 {
364 break;
365 }
366 }
367 if (i == (sizeof(DiskDumpExports) / sizeof(DiskDumpExports[0])))
368 {
369 DbgPrint("DISKDUMP: Error: Miniport imports unknown symbol %s.\n", Name);
370 return(STATUS_UNSUCCESSFUL);
371 }
372 if (strcmp(Name, "ScsiPortNotification") == 0)
373 {
374 OldScsiPortNotification = *ImportAddressList;
375 }
376 DiskDumpExports[i].OldFunction = *ImportAddressList;
377 if (DiskDumpExports[i].NewFunction != NULL)
378 {
379 *ImportAddressList = DiskDumpExports[i].NewFunction;
380 }
381
382 ImportAddressList++;
383 FunctionNameList++;
384 }
385 ImportModuleDirectory++;
386 }
387 return(STATUS_SUCCESS);
388 }
389
390 /**********************************************************************
391 * NAME EXPORTED
392 * DriverEntry
393 *
394 * DESCRIPTION
395 * This function initializes the driver, locates and claims
396 * hardware resources, and creates various NT objects needed
397 * to process I/O requests.
398 *
399 * RUN LEVEL
400 * PASSIVE_LEVEL
401 *
402 * ARGUMENTS
403 * DriverObject
404 * System allocated Driver Object for this driver
405 *
406 * RegistryPath
407 * Name of registry driver service key
408 *
409 * RETURN VALUE
410 * Status
411 */
412
413 NTSTATUS NTAPI
414 DriverEntry(IN PDRIVER_OBJECT DriverObject,
415 IN PUNICODE_STRING RegistryPath)
416 {
417 DiskDumpDriver = DriverObject;
418 return(STATUS_SUCCESS);
419 }
420
421
422 /* EOF */