Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

552 lines
13 KiB

  1. /*++
  2. Copyright (c) 1995-1996 Microsoft Corporation
  3. Module Name:
  4. ezwrite.c
  5. Abstract:
  6. Arbitration Support routines for clusdisk.c
  7. Authors:
  8. Gor Nishanov 11-June-1998
  9. Revision History:
  10. --*/
  11. #include "clusdskp.h"
  12. #include "diskarbp.h"
  13. #if !defined(WMI_TRACING)
  14. #define CDLOG0(Dummy)
  15. #define CDLOG(Dummy1,Dummy2)
  16. #define CDLOGFLG(Dummy0,Dummy1,Dummy2)
  17. #define LOGENABLED(Dummy) FALSE
  18. #else
  19. #include "ezwrite.tmh"
  20. #endif // !defined(WMI_TRACING)
  21. #define ARBITRATION_BUFFER_SIZE PAGE_SIZE
  22. PARBITRATION_ID gArbitrationBuffer = 0;
  23. NTSTATUS
  24. ArbitrationInitialize(
  25. VOID
  26. )
  27. {
  28. gArbitrationBuffer = ExAllocatePool(NonPagedPool, ARBITRATION_BUFFER_SIZE);
  29. if( gArbitrationBuffer == NULL ) {
  30. return STATUS_INSUFFICIENT_RESOURCES;
  31. }
  32. RtlZeroMemory(gArbitrationBuffer, ARBITRATION_BUFFER_SIZE);
  33. KeQuerySystemTime( &gArbitrationBuffer->SystemTime );
  34. gArbitrationBuffer->SeqNo.QuadPart = 2; // UserMode arbitration uses 0 and 1 //
  35. return STATUS_SUCCESS;
  36. }
  37. VOID
  38. ArbitrationDone(
  39. VOID
  40. )
  41. {
  42. if(gArbitrationBuffer != 0) {
  43. ExFreePool(gArbitrationBuffer);
  44. gArbitrationBuffer = 0;
  45. }
  46. }
  47. VOID
  48. ArbitrationTick(
  49. VOID
  50. )
  51. {
  52. // InterlockedIncrement(&gArbitrationBuffer->SeqNo.LowPart);
  53. ++gArbitrationBuffer->SeqNo.QuadPart;
  54. }
  55. BOOLEAN
  56. ValidSectorSize(
  57. IN ULONG SectorSize)
  58. {
  59. // too big //
  60. if (SectorSize > ARBITRATION_BUFFER_SIZE) {
  61. return FALSE;
  62. }
  63. // too small //
  64. if (SectorSize < sizeof(ARBITRATION_ID)) {
  65. return FALSE;
  66. }
  67. // not a power of two //
  68. if (SectorSize & (SectorSize - 1) ) {
  69. return FALSE;
  70. }
  71. return TRUE;
  72. }
  73. NTSTATUS
  74. VerifyArbitrationArgumentsIfAny(
  75. IN PULONG InputData,
  76. IN LONG InputSize
  77. )
  78. /*++
  79. Routine Description:
  80. Process Parameters Passed to IOCTL_DISK_CLUSTER_START_RESERVE.
  81. Arguments:
  82. DeviceExtension - The target device extension
  83. InputData - InputData array from Irp
  84. InputSize - its size
  85. Return Value:
  86. NTSTATUS
  87. Notes:
  88. --*/
  89. {
  90. PSTART_RESERVE_DATA params = (PSTART_RESERVE_DATA)InputData;
  91. // Old style StartReserve //
  92. if( InputSize == sizeof(ULONG) ) {
  93. return STATUS_SUCCESS;
  94. }
  95. // We have less arguments than we need //
  96. if( InputSize < sizeof(START_RESERVE_DATA) ) {
  97. return STATUS_INVALID_PARAMETER;
  98. }
  99. // Wrong Version //
  100. if(params->Version != START_RESERVE_DATA_V1_SIG) {
  101. return STATUS_INVALID_PARAMETER;
  102. }
  103. // Signature size is invalid //
  104. if (params->NodeSignatureSize > sizeof(params->NodeSignature)) {
  105. return STATUS_INVALID_PARAMETER;
  106. }
  107. if( !ValidSectorSize(params->SectorSize) ) {
  108. return STATUS_INVALID_PARAMETER;
  109. }
  110. return STATUS_SUCCESS;
  111. }
  112. VOID
  113. ProcessArbitrationArgumentsIfAny(
  114. IN PCLUS_DEVICE_EXTENSION DeviceExtension,
  115. IN PULONG InputData,
  116. IN LONG InputSize
  117. )
  118. /*++
  119. Routine Description:
  120. Process Parameters Passed to IOCTL_DISK_CLUSTER_START_RESERVE.
  121. Arguments:
  122. DeviceExtension - The target device extension
  123. InputData - InputData array from Irp
  124. InputSize - its size
  125. Return Value:
  126. NTSTATUS
  127. Notes:
  128. Assumes that parameters are valid.
  129. Use VerifyArbitrationArgumentsIfAny to verify parameters
  130. --*/
  131. {
  132. PSTART_RESERVE_DATA params = (PSTART_RESERVE_DATA)InputData;
  133. DeviceExtension->SectorSize = 0; // Invalidate Sector Size //
  134. // old style StartReserve //
  135. if( InputSize == sizeof(ULONG) ) {
  136. return;
  137. }
  138. RtlCopyMemory(gArbitrationBuffer->NodeSignature,
  139. params->NodeSignature, params->NodeSignatureSize);
  140. DeviceExtension->ArbitrationSector = params->ArbitrationSector;
  141. DeviceExtension->SectorSize = params->SectorSize;
  142. }
  143. NTSTATUS
  144. DoUncheckedReadWrite(
  145. IN PCLUS_DEVICE_EXTENSION DeviceExtension,
  146. IN PARBITRATION_READ_WRITE_PARAMS params
  147. )
  148. /*++
  149. Routine Description:
  150. Prepares read/write IRP and execute its synchronously
  151. Arguments:
  152. DeviceExtension - The target device extension
  153. params - Describes offset, operation, buffer, etc
  154. This structure is defined in cluster\inc\diskarbp.h
  155. Return Value:
  156. NTSTATUS
  157. --*/
  158. {
  159. PIRP irp;
  160. NTSTATUS status;
  161. PKEVENT event;
  162. KIRQL irql;
  163. PCLUS_DEVICE_EXTENSION rootDeviceExtension;
  164. IO_STATUS_BLOCK ioStatusBlock;
  165. ULONG sectorSize = DeviceExtension->SectorSize;
  166. LARGE_INTEGER offset;
  167. ULONG function = (params->Operation == AE_READ)?IRP_MJ_READ:IRP_MJ_WRITE;
  168. ULONG retryCount = 1;
  169. event = ExAllocatePool( NonPagedPool,
  170. sizeof(KEVENT) );
  171. if ( !event ) {
  172. return(STATUS_INSUFFICIENT_RESOURCES);
  173. }
  174. retry:
  175. KeInitializeEvent(event,
  176. NotificationEvent,
  177. FALSE);
  178. offset.QuadPart = (ULONGLONG) (params->SectorSize * params->SectorNo);
  179. irp = IoBuildSynchronousFsdRequest(function,
  180. DeviceExtension->TargetDeviceObject,
  181. params->Buffer,
  182. params->SectorSize,
  183. &offset,
  184. event,
  185. &ioStatusBlock);
  186. if ( irp == NULL ) {
  187. ExFreePool( event );
  188. return(STATUS_INSUFFICIENT_RESOURCES);
  189. }
  190. status = IoCallDriver(DeviceExtension->TargetDeviceObject,
  191. irp);
  192. if (status == STATUS_PENDING) {
  193. KeWaitForSingleObject(event,
  194. Suspended,
  195. KernelMode,
  196. FALSE,
  197. NULL);
  198. status = ioStatusBlock.Status;
  199. }
  200. if ( !NT_SUCCESS(status) ) {
  201. if ( retryCount-- &&
  202. (status == STATUS_IO_DEVICE_ERROR) ) {
  203. goto retry;
  204. }
  205. ClusDiskPrint((
  206. 1,
  207. "[ClusDisk] Failed read/write for Signature %08X, status %lx.\n",
  208. DeviceExtension->Signature,
  209. status
  210. ));
  211. }
  212. ExFreePool(event);
  213. return(status);
  214. } // DoUncheckedReadWrite //
  215. NTSTATUS
  216. WriteToArbitrationSector(
  217. IN PCLUS_DEVICE_EXTENSION DeviceExtension
  218. )
  219. /*++
  220. Routine Description:
  221. Writes to an Arbitration Sector.
  222. Arguments:
  223. DeviceExtension - The device extension for the device to reserve.
  224. Return Value:
  225. NTSTATUS
  226. --*/
  227. {
  228. ARBITRATION_READ_WRITE_PARAMS params;
  229. ULONG sectorSize = DeviceExtension->SectorSize;
  230. if (0 == gArbitrationBuffer || 0 == DeviceExtension->SectorSize) {
  231. return STATUS_SUCCESS;
  232. }
  233. params.Operation = AE_WRITE;
  234. params.SectorSize = DeviceExtension->SectorSize;
  235. params.Buffer = gArbitrationBuffer;
  236. params.SectorNo = DeviceExtension->ArbitrationSector;
  237. return( DoUncheckedReadWrite(DeviceExtension, &params) );
  238. } // WriteToArbitrationSector //
  239. VOID
  240. ArbitrationReserve(
  241. IN PCLUS_DEVICE_EXTENSION DeviceExtension
  242. )
  243. {
  244. NTSTATUS status;
  245. status = WriteToArbitrationSector( DeviceExtension );
  246. if ( !NT_SUCCESS(status) ) {
  247. CDLOGF(RESERVE,"ArbitrationReserve(%p) => %!status!",
  248. DeviceExtension->DeviceObject,
  249. status );
  250. ClusDiskPrint((
  251. 1,
  252. "[ClusDisk] Failed to write to arbitration sector on Signature %08X\n",
  253. DeviceExtension->Signature));
  254. }
  255. }
  256. NTSTATUS
  257. SimpleDeviceIoControl(
  258. IN PDEVICE_OBJECT DeviceObject,
  259. IN ULONG Ioctl,
  260. IN PVOID InBuffer,
  261. IN ULONG InBufferSize,
  262. IN PVOID OutBuffer,
  263. IN ULONG OutBufferSize)
  264. {
  265. NTSTATUS status;
  266. IO_STATUS_BLOCK ioStatusBlock;
  267. PKEVENT event = 0;
  268. PIRP irp = 0;
  269. CDLOG( "SimpleDeviceIoControl(%p): Entry Ioctl %x", DeviceObject, Ioctl );
  270. event = ExAllocatePool( NonPagedPool, sizeof(KEVENT) );
  271. if ( event == NULL ) {
  272. status = STATUS_INSUFFICIENT_RESOURCES;
  273. ClusDiskPrint((
  274. 1,
  275. "[ClusDisk] SimpleDeviceIoControl: Failed to allocate event\n" ));
  276. goto exit_gracefully;
  277. }
  278. irp = IoBuildDeviceIoControlRequest(
  279. Ioctl,
  280. DeviceObject,
  281. InBuffer, InBufferSize,
  282. OutBuffer, OutBufferSize,
  283. FALSE,
  284. event,
  285. &ioStatusBlock);
  286. if ( !irp ) {
  287. status = STATUS_INSUFFICIENT_RESOURCES;
  288. ClusDiskPrint((
  289. 1,
  290. "[ClusDisk] SimpleDeviceIoControl. Failed to build IRP %x.\n",
  291. Ioctl
  292. ));
  293. goto exit_gracefully;
  294. }
  295. //
  296. // Set the event object to the unsignaled state.
  297. // It will be used to signal request completion.
  298. //
  299. KeInitializeEvent(event, NotificationEvent, FALSE);
  300. status = IoCallDriver(DeviceObject, irp);
  301. if (status == STATUS_PENDING) {
  302. KeWaitForSingleObject(event,
  303. Suspended,
  304. KernelMode,
  305. FALSE,
  306. NULL);
  307. status = ioStatusBlock.Status;
  308. }
  309. exit_gracefully:
  310. if ( event ) {
  311. ExFreePool( event );
  312. }
  313. CDLOG( "SimpleDeviceIoControl(%p): Exit Ioctl %x => %!status!",
  314. DeviceObject, Ioctl, status );
  315. return status;
  316. } // SimpleDeviceIoControl
  317. /*++
  318. Routine Description:
  319. Arbitration support routine. Currently provides ability to read/write
  320. physical sectors on the disk while the device is offline
  321. Arguments:
  322. SectorSize: requred sector size
  323. (Assumes that the SectorSize is a power of two)
  324. Return Value:
  325. STATUS_INVALID_PARAMETER
  326. STATUS_SUCCESS
  327. Notes:
  328. --*/
  329. NTSTATUS
  330. ProcessArbitrationEscape(
  331. IN PCLUS_DEVICE_EXTENSION DeviceExtension,
  332. IN PULONG InputData,
  333. IN LONG InputSize,
  334. IN PULONG OutputSize
  335. )
  336. {
  337. NTSTATUS status = STATUS_INVALID_PARAMETER;
  338. PARBITRATION_READ_WRITE_PARAMS params;
  339. if( InputData[0] != AE_SECTORSIZE ) {
  340. *OutputSize = 0;
  341. }
  342. switch(InputData[0]) {
  343. // Users can query whether ARBITRATION_ESCAPE is present by calling //
  344. // AE_TEST subfunction //
  345. case AE_TEST:
  346. status = STATUS_SUCCESS;
  347. break;
  348. case AE_WRITE:
  349. case AE_READ:
  350. if(InputSize < ARBITRATION_READ_WRITE_PARAMS_SIZE) {
  351. break;
  352. }
  353. params = (PARBITRATION_READ_WRITE_PARAMS)InputData;
  354. if ( !ValidSectorSize(params->SectorSize) ) {
  355. break;
  356. }
  357. try {
  358. ProbeForWrite( params->Buffer, params->SectorSize, sizeof( UCHAR ) );
  359. ProbeForRead ( params->Buffer, params->SectorSize, sizeof( UCHAR ) );
  360. status = DoUncheckedReadWrite(DeviceExtension, params);
  361. } except (EXCEPTION_EXECUTE_HANDLER) {
  362. return GetExceptionCode();
  363. }
  364. break;
  365. case AE_POKE:
  366. {
  367. PARTITION_INFORMATION partInfo;
  368. status = SimpleDeviceIoControl(
  369. DeviceExtension->TargetDeviceObject,
  370. IOCTL_DISK_GET_PARTITION_INFO,
  371. NULL, 0,
  372. &partInfo, sizeof(PARTITION_INFORMATION) );
  373. break;
  374. }
  375. case AE_RESET:
  376. {
  377. STORAGE_BUS_RESET_REQUEST storageReset;
  378. storageReset.PathId = DeviceExtension->ScsiAddress.PathId;
  379. status = SimpleDeviceIoControl(
  380. DeviceExtension->TargetDeviceObject,
  381. IOCTL_STORAGE_BREAK_RESERVATION,
  382. &storageReset, sizeof(storageReset),
  383. NULL, 0 );
  384. break;
  385. }
  386. case AE_RESERVE:
  387. {
  388. status = SimpleDeviceIoControl(
  389. DeviceExtension->TargetDeviceObject,
  390. IOCTL_STORAGE_RESERVE,
  391. NULL, 0, NULL, 0 );
  392. break;
  393. }
  394. case AE_RELEASE:
  395. {
  396. status = SimpleDeviceIoControl(
  397. DeviceExtension->TargetDeviceObject,
  398. IOCTL_STORAGE_RELEASE,
  399. NULL, 0, NULL, 0 );
  400. break;
  401. }
  402. case AE_SECTORSIZE:
  403. {
  404. DISK_GEOMETRY diskGeometry;
  405. if (*OutputSize < sizeof(ULONG)) {
  406. status = STATUS_BUFFER_TOO_SMALL;
  407. *OutputSize = 0;
  408. break;
  409. }
  410. status = SimpleDeviceIoControl(
  411. DeviceExtension->TargetDeviceObject,
  412. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  413. NULL, 0,
  414. &diskGeometry, sizeof(diskGeometry) );
  415. if ( NT_SUCCESS(status) ) {
  416. *InputData = diskGeometry.BytesPerSector;
  417. *OutputSize = sizeof(ULONG);
  418. } else {
  419. *OutputSize = 0;
  420. }
  421. break;
  422. }
  423. }
  424. return(status);
  425. } // ProcessArbitrationEscape //