Leaked source code of windows server 2003
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.

857 lines
22 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 "clusvmsg.h"
  13. #include "diskarbp.h"
  14. #include <strsafe.h> // Should be included last.
  15. #if !defined(WMI_TRACING)
  16. #define CDLOG0(Dummy)
  17. #define CDLOG(Dummy1,Dummy2)
  18. #define CDLOGFLG(Dummy0,Dummy1,Dummy2)
  19. #define LOGENABLED(Dummy) FALSE
  20. #else
  21. #include "ezwrite.tmh"
  22. #endif // !defined(WMI_TRACING)
  23. #define ARBITRATION_BUFFER_SIZE PAGE_SIZE
  24. PARBITRATION_ID gArbitrationBuffer = 0;
  25. NTSTATUS
  26. ArbitrationInitialize(
  27. VOID
  28. )
  29. {
  30. gArbitrationBuffer = ExAllocatePool(NonPagedPool, ARBITRATION_BUFFER_SIZE);
  31. if( gArbitrationBuffer == NULL ) {
  32. return STATUS_INSUFFICIENT_RESOURCES;
  33. }
  34. RtlZeroMemory(gArbitrationBuffer, ARBITRATION_BUFFER_SIZE);
  35. KeQuerySystemTime( &gArbitrationBuffer->SystemTime );
  36. gArbitrationBuffer->SeqNo.QuadPart = 2; // UserMode arbitration uses 0 and 1 //
  37. return STATUS_SUCCESS;
  38. }
  39. VOID
  40. ArbitrationDone(
  41. VOID
  42. )
  43. {
  44. if(gArbitrationBuffer != 0) {
  45. ExFreePool(gArbitrationBuffer);
  46. gArbitrationBuffer = 0;
  47. }
  48. }
  49. VOID
  50. ArbitrationTick(
  51. VOID
  52. )
  53. {
  54. // InterlockedIncrement(&gArbitrationBuffer->SeqNo.LowPart);
  55. ++gArbitrationBuffer->SeqNo.QuadPart;
  56. }
  57. BOOLEAN
  58. ValidSectorSize(
  59. IN ULONG SectorSize)
  60. {
  61. // too big //
  62. if (SectorSize > ARBITRATION_BUFFER_SIZE) {
  63. return FALSE;
  64. }
  65. // too small //
  66. if (SectorSize < sizeof(ARBITRATION_ID)) {
  67. return FALSE;
  68. }
  69. // not a power of two //
  70. if (SectorSize & (SectorSize - 1) ) {
  71. return FALSE;
  72. }
  73. return TRUE;
  74. }
  75. NTSTATUS
  76. VerifyArbitrationArgumentsIfAny(
  77. IN PULONG InputData,
  78. IN LONG InputSize
  79. )
  80. /*++
  81. Routine Description:
  82. Process Parameters Passed to IOCTL_DISK_CLUSTER_START_RESERVE.
  83. Arguments:
  84. DeviceExtension - The target device extension
  85. InputData - InputData array from Irp
  86. InputSize - its size
  87. Return Value:
  88. NTSTATUS
  89. Notes:
  90. --*/
  91. {
  92. PSTART_RESERVE_DATA params = (PSTART_RESERVE_DATA)InputData;
  93. // Old style StartReserve //
  94. if( InputSize == sizeof(ULONG) ) {
  95. return STATUS_SUCCESS;
  96. }
  97. // We have less arguments than we need //
  98. if( InputSize < sizeof(START_RESERVE_DATA) ) {
  99. return STATUS_INVALID_PARAMETER;
  100. }
  101. // Wrong Version //
  102. if(params->Version != START_RESERVE_DATA_V1_SIG) {
  103. return STATUS_INVALID_PARAMETER;
  104. }
  105. // Signature size is invalid //
  106. if (params->NodeSignatureSize > sizeof(params->NodeSignature)) {
  107. return STATUS_INVALID_PARAMETER;
  108. }
  109. if( !ValidSectorSize(params->SectorSize) ) {
  110. return STATUS_INVALID_PARAMETER;
  111. }
  112. return STATUS_SUCCESS;
  113. }
  114. VOID
  115. ProcessArbitrationArgumentsIfAny(
  116. IN PCLUS_DEVICE_EXTENSION DeviceExtension,
  117. IN PULONG InputData,
  118. IN LONG InputSize
  119. )
  120. /*++
  121. Routine Description:
  122. Process Parameters Passed to IOCTL_DISK_CLUSTER_START_RESERVE.
  123. Arguments:
  124. DeviceExtension - The target device extension
  125. InputData - InputData array from Irp
  126. InputSize - its size
  127. Return Value:
  128. NTSTATUS
  129. Notes:
  130. Assumes that parameters are valid.
  131. Use VerifyArbitrationArgumentsIfAny to verify parameters
  132. --*/
  133. {
  134. PSTART_RESERVE_DATA params = (PSTART_RESERVE_DATA)InputData;
  135. DeviceExtension->SectorSize = 0; // Invalidate Sector Size //
  136. // old style StartReserve //
  137. if( InputSize == sizeof(ULONG) ) {
  138. return;
  139. }
  140. RtlCopyMemory(gArbitrationBuffer->NodeSignature,
  141. params->NodeSignature, params->NodeSignatureSize);
  142. DeviceExtension->ArbitrationSector = params->ArbitrationSector;
  143. DeviceExtension->SectorSize = params->SectorSize;
  144. }
  145. NTSTATUS
  146. DoUncheckedReadWrite(
  147. IN PCLUS_DEVICE_EXTENSION DeviceExtension,
  148. IN PARBITRATION_READ_WRITE_PARAMS params
  149. )
  150. /*++
  151. Routine Description:
  152. Prepares read/write IRP and executes it synchronously
  153. Arguments:
  154. DeviceExtension - The target device extension
  155. params - Describes offset, operation, buffer, etc
  156. This structure is defined in cluster\inc\diskarbp.h
  157. Return Value:
  158. NTSTATUS
  159. --*/
  160. {
  161. PIRP irp;
  162. NTSTATUS status;
  163. PKEVENT event;
  164. IO_STATUS_BLOCK ioStatusBlock;
  165. LARGE_INTEGER offset;
  166. ULONG function = (params->Operation == AE_READ)?IRP_MJ_READ:IRP_MJ_WRITE;
  167. ULONG retryCount = 1;
  168. event = ExAllocatePool( NonPagedPool,
  169. sizeof(KEVENT) );
  170. if ( !event ) {
  171. return(STATUS_INSUFFICIENT_RESOURCES);
  172. }
  173. retry:
  174. KeInitializeEvent(event,
  175. NotificationEvent,
  176. FALSE);
  177. offset.QuadPart = (ULONGLONG) (params->SectorSize * params->SectorNo);
  178. irp = IoBuildSynchronousFsdRequest(function,
  179. DeviceExtension->TargetDeviceObject,
  180. params->Buffer,
  181. params->SectorSize,
  182. &offset,
  183. event,
  184. &ioStatusBlock);
  185. if ( irp == NULL ) {
  186. ExFreePool( event );
  187. return(STATUS_INSUFFICIENT_RESOURCES);
  188. }
  189. status = IoCallDriver(DeviceExtension->TargetDeviceObject,
  190. irp);
  191. if (status == STATUS_PENDING) {
  192. KeWaitForSingleObject(event,
  193. Suspended,
  194. KernelMode,
  195. FALSE,
  196. NULL);
  197. status = ioStatusBlock.Status;
  198. }
  199. if ( !NT_SUCCESS(status) ) {
  200. if ( retryCount-- &&
  201. (status == STATUS_IO_DEVICE_ERROR) ) {
  202. goto retry;
  203. }
  204. ClusDiskPrint((
  205. 1,
  206. "[ClusDisk] Failed read/write for Signature %08X, status %lx.\n",
  207. DeviceExtension->Signature,
  208. status
  209. ));
  210. }
  211. ExFreePool(event);
  212. return(status);
  213. } // DoUncheckedReadWrite //
  214. NTSTATUS
  215. WriteToArbitrationSector(
  216. IN PCLUS_DEVICE_EXTENSION DeviceExtension,
  217. IN PARB_RESERVE_COMPLETION Context
  218. )
  219. /*++
  220. Routine Description:
  221. Writes to an Arbitration Sector asynchronously.
  222. Arguments:
  223. DeviceExtension - The device extension for the physical device to reserve.
  224. Return Value:
  225. NTSTATUS
  226. --*/
  227. {
  228. LARGE_INTEGER offset;
  229. PIRP irp = NULL;
  230. PIO_STACK_LOCATION irpStack;
  231. PARB_RESERVE_COMPLETION arbContext;
  232. NTSTATUS status = STATUS_UNSUCCESSFUL;
  233. if (0 == gArbitrationBuffer || 0 == DeviceExtension->SectorSize) {
  234. status = STATUS_SUCCESS;
  235. goto FnExit;
  236. }
  237. //
  238. // Acquire remove lock for this device. If the IRP is sent, it will be
  239. // released in the completion routine.
  240. //
  241. status = AcquireRemoveLock( &DeviceExtension->RemoveLock, WriteToArbitrationSector );
  242. if ( !NT_SUCCESS(status) ) {
  243. goto FnExit;
  244. }
  245. //
  246. // If context is non-null, then we are retrying this I/O. If null,
  247. // we need to allocate a context structure for the write.
  248. //
  249. if ( Context ) {
  250. arbContext = Context;
  251. arbContext->IoEndTime.QuadPart = (ULONGLONG) 0;
  252. } else {
  253. arbContext = ExAllocatePool( NonPagedPool, sizeof(ARB_RESERVE_COMPLETION) );
  254. if ( !arbContext ) {
  255. status = STATUS_INSUFFICIENT_RESOURCES;
  256. ReleaseRemoveLock( &DeviceExtension->RemoveLock, WriteToArbitrationSector );
  257. goto FnExit;
  258. }
  259. RtlZeroMemory( arbContext, sizeof(ARB_RESERVE_COMPLETION) );
  260. //
  261. // Fill in context structure. Note we do not specify the optional
  262. // routines as the write failure is not critical.
  263. //
  264. arbContext->RetriesLeft = 1;
  265. arbContext->LockTag = WriteToArbitrationSector;
  266. arbContext->DeviceObject = DeviceExtension->DeviceObject;
  267. arbContext->DeviceExtension = DeviceExtension;
  268. arbContext->Type = ArbIoWrite;
  269. }
  270. KeQuerySystemTime( &arbContext->IoStartTime );
  271. offset.QuadPart = (ULONGLONG) (DeviceExtension->SectorSize * DeviceExtension->ArbitrationSector);
  272. irp = IoBuildAsynchronousFsdRequest( IRP_MJ_WRITE,
  273. DeviceExtension->TargetDeviceObject,
  274. gArbitrationBuffer,
  275. DeviceExtension->SectorSize,
  276. &offset,
  277. NULL );
  278. if ( NULL == irp ) {
  279. status = STATUS_INSUFFICIENT_RESOURCES;
  280. ExFreePool( arbContext );
  281. ReleaseRemoveLock( &DeviceExtension->RemoveLock, WriteToArbitrationSector );
  282. goto FnExit;
  283. }
  284. InterlockedIncrement( &DeviceExtension->ArbWriteCount );
  285. IoSetCompletionRoutine( irp,
  286. ArbReserveCompletion,
  287. arbContext,
  288. TRUE,
  289. TRUE,
  290. TRUE );
  291. ClusDiskPrint(( 4,
  292. "[ClusDisk] ArbWrite IRP %p for DO %p DiskNo %u Sig %08X \n",
  293. irp,
  294. DeviceExtension->DeviceObject,
  295. DeviceExtension->DiskNumber,
  296. DeviceExtension->Signature ));
  297. status = IoCallDriver( DeviceExtension->TargetDeviceObject,
  298. irp );
  299. FnExit:
  300. return status;
  301. } // WriteToArbitrationSector
  302. NTSTATUS
  303. ArbReserveCompletion(
  304. IN PDEVICE_OBJECT DeviceObject,
  305. IN PIRP Irp,
  306. IN PVOID Context
  307. )
  308. /*++
  309. Routine Description:
  310. Completion routine for the asynchronous arbitration write.
  311. Arguments:
  312. DeviceObject
  313. Irp - Asynchoronous arbitration write.
  314. Context - Pointer to ARB_RESERVE_COMPLETION structure.
  315. Return Value:
  316. STATUS_MORE_PROCESSING_REQUIRED - must be returned or system will fail!
  317. --*/
  318. {
  319. PARB_RESERVE_COMPLETION arbContext = Context;
  320. PCLUS_DEVICE_EXTENSION deviceExtension;
  321. PIO_WORKITEM workItem = NULL;
  322. PVOID lockTag;
  323. if ( NULL == DeviceObject ) {
  324. DeviceObject = arbContext->DeviceObject;
  325. }
  326. deviceExtension = arbContext->DeviceExtension;
  327. arbContext->FinalStatus = Irp->IoStatus.Status;
  328. //
  329. // Save lock tag here because the context may be freed by the time
  330. // we need to release remove lock.
  331. //
  332. lockTag = arbContext->LockTag;
  333. KeQuerySystemTime( &arbContext->IoEndTime );
  334. //
  335. // Decrement the correct counter based on this I/O type.
  336. //
  337. if ( ArbIoReserve == arbContext->Type ) {
  338. InterlockedDecrement( &deviceExtension->ReserveCount );
  339. } else if ( ArbIoWrite == arbContext->Type ) {
  340. InterlockedDecrement( &deviceExtension->ArbWriteCount );
  341. }
  342. ClusDiskPrint(( 4,
  343. "[ClusDisk] %s IRP %p for DO %p DiskNo %u Sig %08X status %08X \n",
  344. ArbIoReserve == arbContext->Type ? "Reserve " : "ArbWrite",
  345. Irp,
  346. deviceExtension->DeviceObject,
  347. deviceExtension->DiskNumber,
  348. deviceExtension->Signature,
  349. arbContext->FinalStatus ));
  350. //
  351. // Retry this request (at least once) for specific failures.
  352. //
  353. if ( arbContext->RetriesLeft-- &&
  354. STATUS_IO_DEVICE_ERROR == arbContext->FinalStatus &&
  355. arbContext->RetryRoutine ) {
  356. ClusDiskPrint(( 1,
  357. "[ClusDisk] Retrying %s for DO %p DiskNo %u Sig %08X \n",
  358. ArbIoReserve == arbContext->Type ? "Reserve " : "ArbWrite",
  359. deviceExtension->DeviceObject,
  360. deviceExtension->DiskNumber,
  361. deviceExtension->Signature ));
  362. //
  363. // Since we are running in an I/O completion routine, this routine
  364. // could be running at any IRQL up to DISPATCH_LEVEL. It would be
  365. // bad to call back into the driver stack at this level, so queue
  366. // a work item to retry the I/O.
  367. //
  368. // Queue the workitem. IoQueueWorkItem will insure that the device object
  369. // referenced while the work-item progresses.
  370. //
  371. workItem = IoAllocateWorkItem( DeviceObject );
  372. if ( workItem ) {
  373. arbContext->WorkItem = workItem;
  374. IoQueueWorkItem( workItem,
  375. RequeueArbReserveIo,
  376. DelayedWorkQueue,
  377. Context );
  378. }
  379. } else if ( !NT_SUCCESS(arbContext->FinalStatus) ) {
  380. //
  381. // If not successful, call the optional failure routine.
  382. //
  383. if ( arbContext->FailureRoutine ) {
  384. (arbContext->FailureRoutine)( arbContext->DeviceExtension,
  385. arbContext );
  386. }
  387. } else {
  388. //
  389. // On success, call the optional post completion routine.
  390. //
  391. if ( arbContext->PostCompletionRoutine ) {
  392. (arbContext->PostCompletionRoutine)( arbContext->DeviceExtension,
  393. arbContext );
  394. }
  395. }
  396. ReleaseRemoveLock( &deviceExtension->RemoveLock, lockTag );
  397. //
  398. // If we did not allocate a work item, the I/O was not retried and we
  399. // have to free the context.
  400. //
  401. if ( !workItem ) {
  402. ExFreePool( Context );
  403. }
  404. //
  405. // Unlock and free the MDL. Then free the IRP.
  406. //
  407. if (Irp->MdlAddress != NULL) {
  408. MmUnlockPages( Irp->MdlAddress );
  409. IoFreeMdl( Irp->MdlAddress );
  410. Irp->MdlAddress = NULL;
  411. }
  412. IoFreeIrp( Irp );
  413. return STATUS_MORE_PROCESSING_REQUIRED;
  414. } // ArbReserveCompletion
  415. RequeueArbReserveIo(
  416. IN PDEVICE_OBJECT DeviceObject,
  417. IN PVOID Context
  418. )
  419. /*++
  420. Routine Description:
  421. This routine runs in a system worker thread. It will call
  422. the specified retry routine to requeue a new I/O.
  423. Arguments:
  424. DeviceObject
  425. Context - Pointer to ARB_RESERVE_COMPLETION structure.
  426. Return Value:
  427. None
  428. --*/
  429. {
  430. PARB_RESERVE_COMPLETION arbContext = Context;
  431. BOOLEAN freeArbContext = FALSE;
  432. //
  433. // Call the real routines to rebuild and re-issue the I/O request.
  434. //
  435. if ( arbContext->RetryRoutine ) {
  436. (arbContext->RetryRoutine)( DeviceObject->DeviceExtension,
  437. Context );
  438. } else {
  439. freeArbContext = TRUE;
  440. }
  441. IoFreeWorkItem( arbContext->WorkItem );
  442. if ( freeArbContext ) {
  443. ExFreePool( Context );
  444. }
  445. } // RequeueArbReserveIo
  446. VOID
  447. ArbitrationWrite(
  448. IN PCLUS_DEVICE_EXTENSION DeviceExtension
  449. )
  450. {
  451. NTSTATUS status;
  452. status = WriteToArbitrationSector( DeviceExtension, NULL );
  453. if ( !NT_SUCCESS(status) ) {
  454. CDLOGF(RESERVE,"ArbitrationWrite(%p) => %!status!",
  455. DeviceExtension->DeviceObject,
  456. status );
  457. ClusDiskPrint((
  458. 1,
  459. "[ClusDisk] Failed to write to arb sector on DiskNo %d Sig %08X status %08X \n",
  460. DeviceExtension->DiskNumber,
  461. DeviceExtension->Signature,
  462. status ));
  463. }
  464. }
  465. NTSTATUS
  466. SimpleDeviceIoControl(
  467. IN PDEVICE_OBJECT DeviceObject,
  468. IN ULONG Ioctl,
  469. IN PVOID InBuffer,
  470. IN ULONG InBufferSize,
  471. IN PVOID OutBuffer,
  472. IN ULONG OutBufferSize)
  473. {
  474. NTSTATUS status;
  475. IO_STATUS_BLOCK ioStatusBlock;
  476. PKEVENT event = 0;
  477. PIRP irp = 0;
  478. CDLOG( "SimpleDeviceIoControl(%p): Entry Ioctl %x", DeviceObject, Ioctl );
  479. event = ExAllocatePool( NonPagedPool, sizeof(KEVENT) );
  480. if ( event == NULL ) {
  481. status = STATUS_INSUFFICIENT_RESOURCES;
  482. ClusDiskPrint((
  483. 1,
  484. "[ClusDisk] SimpleDeviceIoControl: Failed to allocate event\n" ));
  485. goto exit_gracefully;
  486. }
  487. irp = IoBuildDeviceIoControlRequest(
  488. Ioctl,
  489. DeviceObject,
  490. InBuffer, InBufferSize,
  491. OutBuffer, OutBufferSize,
  492. FALSE,
  493. event,
  494. &ioStatusBlock);
  495. if ( !irp ) {
  496. status = STATUS_INSUFFICIENT_RESOURCES;
  497. ClusDiskPrint((
  498. 1,
  499. "[ClusDisk] SimpleDeviceIoControl. Failed to build IRP %x.\n",
  500. Ioctl
  501. ));
  502. goto exit_gracefully;
  503. }
  504. //
  505. // Set the event object to the unsignaled state.
  506. // It will be used to signal request completion.
  507. //
  508. KeInitializeEvent(event, NotificationEvent, FALSE);
  509. status = IoCallDriver(DeviceObject, irp);
  510. if (status == STATUS_PENDING) {
  511. KeWaitForSingleObject(event,
  512. Suspended,
  513. KernelMode,
  514. FALSE,
  515. NULL);
  516. status = ioStatusBlock.Status;
  517. }
  518. exit_gracefully:
  519. if ( event ) {
  520. ExFreePool( event );
  521. }
  522. CDLOG( "SimpleDeviceIoControl(%p): Exit Ioctl %x => %x",
  523. DeviceObject, Ioctl, status );
  524. return status;
  525. } // SimpleDeviceIoControl
  526. /*++
  527. Routine Description:
  528. Arbitration support routine. Currently provides ability to read/write
  529. physical sectors on the disk while the device is offline
  530. Arguments:
  531. SectorSize: requred sector size
  532. (Assumes that the SectorSize is a power of two)
  533. Return Value:
  534. STATUS_INVALID_PARAMETER
  535. STATUS_SUCCESS
  536. Notes:
  537. --*/
  538. NTSTATUS
  539. ProcessArbitrationEscape(
  540. IN PCLUS_DEVICE_EXTENSION DeviceExtension,
  541. IN PULONG InputData,
  542. IN LONG InputSize,
  543. IN PULONG OutputSize
  544. )
  545. {
  546. NTSTATUS status = STATUS_INVALID_PARAMETER;
  547. PARBITRATION_READ_WRITE_PARAMS params;
  548. if( InputData[0] != AE_SECTORSIZE ) {
  549. *OutputSize = 0;
  550. }
  551. switch(InputData[0]) {
  552. // Users can query whether ARBITRATION_ESCAPE is present by calling //
  553. // AE_TEST subfunction //
  554. case AE_TEST:
  555. status = STATUS_SUCCESS;
  556. break;
  557. case AE_WRITE:
  558. case AE_READ:
  559. if(InputSize < ARBITRATION_READ_WRITE_PARAMS_SIZE) {
  560. break;
  561. }
  562. params = (PARBITRATION_READ_WRITE_PARAMS)InputData;
  563. if ( !ValidSectorSize(params->SectorSize) ) {
  564. break;
  565. }
  566. //
  567. // This IOCTL is method buffered and the user data buffer is a pointer within
  568. // this buffered structure. The user buffer is checked now for read/write
  569. // access, and will be probed and locked in IoBuildSynchronousFsdRequest.
  570. //
  571. try {
  572. ProbeForWrite( params->Buffer, params->SectorSize, sizeof( UCHAR ) );
  573. ProbeForRead ( params->Buffer, params->SectorSize, sizeof( UCHAR ) );
  574. status = DoUncheckedReadWrite(DeviceExtension, params);
  575. } except (EXCEPTION_EXECUTE_HANDLER) {
  576. return GetExceptionCode();
  577. }
  578. break;
  579. case AE_POKE:
  580. {
  581. PARTITION_INFORMATION partInfo;
  582. status = SimpleDeviceIoControl(
  583. DeviceExtension->TargetDeviceObject,
  584. IOCTL_DISK_GET_PARTITION_INFO,
  585. NULL, 0,
  586. &partInfo, sizeof(PARTITION_INFORMATION) );
  587. break;
  588. }
  589. case AE_RESET:
  590. {
  591. ClusDiskLogError( DeviceExtension->DriverObject, // OK - DevObj is cluster DevObj
  592. DeviceExtension->DeviceObject,
  593. DeviceExtension->ScsiAddress.PathId, // Sequence number
  594. IRP_MJ_DEVICE_CONTROL, // Major function code
  595. 0, // Retry count
  596. ID_CLUSTER_ARB_RESET, // Unique error
  597. STATUS_SUCCESS,
  598. CLUSDISK_RESET_BUS_REQUESTED,
  599. 0,
  600. NULL );
  601. status = ResetScsiDevice( NULL, &DeviceExtension->ScsiAddress );
  602. break;
  603. }
  604. case AE_RESERVE:
  605. {
  606. status = SimpleDeviceIoControl(
  607. DeviceExtension->TargetDeviceObject,
  608. IOCTL_STORAGE_RESERVE,
  609. NULL, 0, NULL, 0 );
  610. break;
  611. }
  612. case AE_RELEASE:
  613. {
  614. status = SimpleDeviceIoControl(
  615. DeviceExtension->TargetDeviceObject,
  616. IOCTL_STORAGE_RELEASE,
  617. NULL, 0, NULL, 0 );
  618. break;
  619. }
  620. case AE_SECTORSIZE:
  621. {
  622. DISK_GEOMETRY diskGeometry;
  623. if (*OutputSize < sizeof(ULONG)) {
  624. status = STATUS_BUFFER_TOO_SMALL;
  625. *OutputSize = 0;
  626. break;
  627. }
  628. status = SimpleDeviceIoControl(
  629. DeviceExtension->TargetDeviceObject,
  630. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  631. NULL, 0,
  632. &diskGeometry, sizeof(diskGeometry) );
  633. if ( NT_SUCCESS(status) ) {
  634. *InputData = diskGeometry.BytesPerSector;
  635. *OutputSize = sizeof(ULONG);
  636. } else {
  637. *OutputSize = 0;
  638. }
  639. break;
  640. }
  641. }
  642. return(status);
  643. } // ProcessArbitrationEscape //