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.

2137 lines
51 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1997 - 2001
  3. Module Name:
  4. util.c
  5. Abstract:
  6. Utility functions for the SBP-2 port driver
  7. Author:
  8. George Chrysanthakopoulos January-1997
  9. Environment:
  10. Kernel mode
  11. Revision History :
  12. --*/
  13. #include "sbp2port.h"
  14. VOID
  15. AllocateIrpAndIrb(
  16. IN PDEVICE_EXTENSION DeviceExtension,
  17. IN PIRBIRP *Packet
  18. )
  19. {
  20. PIRBIRP pkt;
  21. if (DeviceExtension->Type == SBP2_PDO) {
  22. *Packet = (PIRBIRP) ExInterlockedPopEntrySList (&DeviceExtension->BusRequestIrpIrbListHead,
  23. &DeviceExtension->BusRequestLock);
  24. } else {
  25. *Packet = NULL;
  26. }
  27. if (*Packet == NULL) {
  28. //
  29. // run out , allocate a new one
  30. //
  31. pkt = ExAllocatePoolWithTag(NonPagedPool,sizeof(IRBIRP),'2pbs');
  32. if (pkt) {
  33. pkt->Irb = NULL;
  34. pkt->Irb = ExAllocatePoolWithTag(NonPagedPool,sizeof(IRB),'2pbs');
  35. if (!pkt->Irb) {
  36. ExFreePool(pkt);
  37. return;
  38. }
  39. pkt->Irp = NULL;
  40. pkt->Irp = IoAllocateIrp(DeviceExtension->LowerDeviceObject->StackSize,FALSE);
  41. if (!pkt->Irp) {
  42. ExFreePool(pkt->Irb);
  43. ExFreePool(pkt);
  44. return;
  45. }
  46. DEBUGPRINT3((
  47. "Sbp2Port: AllocPkt: %sdo, new irp=x%p, irb=x%p\n",
  48. (DeviceExtension->Type == SBP2_PDO ? "p" : "f"),
  49. pkt->Irp,
  50. pkt->Irb
  51. ));
  52. } else {
  53. return;
  54. }
  55. *Packet = pkt;
  56. }
  57. pkt = *Packet;
  58. }
  59. VOID
  60. DeAllocateIrpAndIrb(
  61. IN PDEVICE_EXTENSION DeviceExtension,
  62. IN PIRBIRP Packet
  63. )
  64. {
  65. if (DeviceExtension->Type == SBP2_PDO) {
  66. ExInterlockedPushEntrySList (&DeviceExtension->BusRequestIrpIrbListHead,
  67. &Packet->ListPointer,
  68. &DeviceExtension->BusRequestLock);
  69. } else {
  70. IoFreeIrp(Packet->Irp);
  71. ExFreePool(Packet->Irb);
  72. ExFreePool(Packet);
  73. }
  74. }
  75. NTSTATUS
  76. AllocateSingle1394Address(
  77. IN PDEVICE_OBJECT DeviceObject,
  78. IN PVOID Buffer,
  79. IN ULONG Length,
  80. IN ULONG AccessType,
  81. IN OUT PADDRESS_CONTEXT Context
  82. )
  83. /*++
  84. Routine Description:
  85. A wrapper to the bus driver AllocateAddressRange call, for Async Requests
  86. or ORB's that dont use callbacks.
  87. Arguments:
  88. DeviceObject - Sbp2 device object
  89. Buffer - Data buffer to mapped to 1394 address space
  90. Length - Size of buffer in bytes
  91. AccessType - 1394 bus access to allocated range
  92. Address - Returned Address, from 1394 address space
  93. AddressHanle - Handle associated with the 1394 address
  94. RequestMedl - Mdl associated with this range
  95. Return Value:
  96. NTSTATUS
  97. --*/
  98. {
  99. ULONG finalTransferMode;
  100. PIRBIRP packet;
  101. NTSTATUS status;
  102. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  103. AllocateIrpAndIrb (deviceExtension, &packet);
  104. if (!packet) {
  105. return STATUS_INSUFFICIENT_RESOURCES;
  106. }
  107. packet->Irb->FunctionNumber = REQUEST_ALLOCATE_ADDRESS_RANGE;
  108. packet->Irb->Flags = 0;
  109. packet->Irb->u.AllocateAddressRange.MaxSegmentSize = 0;
  110. packet->Irb->u.AllocateAddressRange.nLength = Length;
  111. packet->Irb->u.AllocateAddressRange.fulAccessType = AccessType;
  112. packet->Irb->u.AllocateAddressRange.fulNotificationOptions = NOTIFY_FLAGS_NEVER;
  113. packet->Irb->u.AllocateAddressRange.Callback = NULL;
  114. packet->Irb->u.AllocateAddressRange.Context = NULL;
  115. packet->Irb->u.AllocateAddressRange.FifoSListHead = NULL;
  116. packet->Irb->u.AllocateAddressRange.FifoSpinLock = NULL;
  117. packet->Irb->u.AllocateAddressRange.Required1394Offset.Off_High = 0;
  118. packet->Irb->u.AllocateAddressRange.Required1394Offset.Off_Low = 0;
  119. packet->Irb->u.AllocateAddressRange.AddressesReturned = 0;
  120. packet->Irb->u.AllocateAddressRange.DeviceExtension = deviceExtension;
  121. packet->Irb->u.AllocateAddressRange.p1394AddressRange = (PADDRESS_RANGE) &Context->Address;
  122. if (Buffer) {
  123. packet->Irb->u.AllocateAddressRange.fulFlags = 0;
  124. Context->RequestMdl = IoAllocateMdl (Buffer, Length, FALSE, FALSE, NULL);
  125. if (!Context->RequestMdl) {
  126. DeAllocateIrpAndIrb (deviceExtension,packet);
  127. return STATUS_INSUFFICIENT_RESOURCES;
  128. }
  129. MmBuildMdlForNonPagedPool (Context->RequestMdl);
  130. packet->Irb->u.AllocateAddressRange.Mdl = Context->RequestMdl;
  131. } else {
  132. packet->Irb->u.AllocateAddressRange.fulFlags =
  133. ALLOCATE_ADDRESS_FLAGS_USE_COMMON_BUFFER;
  134. packet->Irb->u.AllocateAddressRange.Mdl = NULL;
  135. }
  136. status = Sbp2SendRequest (deviceExtension, packet, SYNC_1394_REQUEST);
  137. if (NT_SUCCESS(status)) {
  138. Context->AddressHandle =
  139. packet->Irb->u.AllocateAddressRange.hAddressRange;
  140. Context->Address.BusAddress.NodeId =
  141. deviceExtension->InitiatorAddressId;
  142. if (!Buffer) {
  143. //
  144. // For common buffers we get an mdl *back* from the
  145. // bus/port driver, & need to retrieve a corresponding VA
  146. //
  147. Context->RequestMdl = packet->Irb->u.AllocateAddressRange.Mdl;
  148. Context->Reserved = MmGetMdlVirtualAddress (Context->RequestMdl);
  149. }
  150. }
  151. DeAllocateIrpAndIrb (deviceExtension, packet);
  152. return status;
  153. }
  154. NTSTATUS
  155. AllocateAddressForStatus(
  156. IN PDEVICE_OBJECT DeviceObject,
  157. IN PADDRESS_CONTEXT Context,
  158. IN UCHAR StatusType
  159. )
  160. /*++
  161. Routine Description:
  162. A wrapper to 1394 bus IOCTL AllocateAddressRange for status blocks that
  163. need a Callback notification when the device access the 1394 range...
  164. Arguments:
  165. DeviceObject - Device Object for the sbp2 driver
  166. ADDRESS_CONTEXT - Mini Context for an individual 1394 request
  167. Return Value:
  168. NTSTATUS
  169. --*/
  170. {
  171. NTSTATUS status;
  172. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  173. OCTLET address[2];
  174. PIRBIRP packet = NULL;
  175. AllocateIrpAndIrb (deviceExtension,&packet);
  176. if (!packet) {
  177. return STATUS_INSUFFICIENT_RESOURCES;
  178. }
  179. packet->Irb->FunctionNumber = REQUEST_ALLOCATE_ADDRESS_RANGE;
  180. packet->Irb->Flags = 0;
  181. packet->Irb->u.AllocateAddressRange.nLength = sizeof(STATUS_FIFO_BLOCK);
  182. packet->Irb->u.AllocateAddressRange.fulAccessType = ACCESS_FLAGS_TYPE_WRITE;
  183. packet->Irb->u.AllocateAddressRange.fulNotificationOptions = NOTIFY_FLAGS_AFTER_WRITE;
  184. packet->Irb->u.AllocateAddressRange.FifoSListHead = NULL;
  185. packet->Irb->u.AllocateAddressRange.FifoSpinLock = NULL;
  186. packet->Irb->u.AllocateAddressRange.fulFlags = 0;
  187. packet->Irb->u.AllocateAddressRange.Required1394Offset.Off_High = 0;
  188. packet->Irb->u.AllocateAddressRange.Required1394Offset.Off_Low = 0;
  189. packet->Irb->u.AllocateAddressRange.AddressesReturned = 0;
  190. packet->Irb->u.AllocateAddressRange.MaxSegmentSize = 0;
  191. packet->Irb->u.AllocateAddressRange.DeviceExtension = deviceExtension;
  192. switch (StatusType) {
  193. case TASK_STATUS_BLOCK:
  194. packet->Irb->u.AllocateAddressRange.Callback = Sbp2TaskOrbStatusCallback;
  195. Context->RequestMdl = IoAllocateMdl(&deviceExtension->TaskOrbStatusBlock, sizeof (STATUS_FIFO_BLOCK),FALSE,FALSE,NULL);
  196. if (!Context->RequestMdl) {
  197. status = STATUS_INSUFFICIENT_RESOURCES;
  198. goto exitAllocateAddress;
  199. }
  200. break;
  201. case MANAGEMENT_STATUS_BLOCK:
  202. packet->Irb->u.AllocateAddressRange.Callback = Sbp2ManagementOrbStatusCallback;
  203. Context->RequestMdl = IoAllocateMdl(&deviceExtension->ManagementOrbStatusBlock, sizeof (STATUS_FIFO_BLOCK),FALSE,FALSE,NULL);
  204. if (!Context->RequestMdl) {
  205. status = STATUS_INSUFFICIENT_RESOURCES;
  206. goto exitAllocateAddress;
  207. }
  208. break;
  209. case CMD_ORB_STATUS_BLOCK:
  210. //
  211. // setup the FIFO list that will receive the status blocks
  212. //
  213. packet->Irb->u.AllocateAddressRange.Callback = Sbp2GlobalStatusCallback;
  214. Context->RequestMdl = packet->Irb->u.AllocateAddressRange.Mdl = NULL;
  215. packet->Irb->u.AllocateAddressRange.FifoSListHead = &deviceExtension->StatusFifoListHead;
  216. packet->Irb->u.AllocateAddressRange.FifoSpinLock = &deviceExtension->StatusFifoLock;
  217. break;
  218. #if PASSWORD_SUPPORT
  219. case PASSWORD_STATUS_BLOCK:
  220. packet->Irb->u.AllocateAddressRange.Callback =
  221. Sbp2SetPasswordOrbStatusCallback;
  222. Context->RequestMdl = IoAllocateMdl(
  223. &deviceExtension->PasswordOrbStatusBlock,
  224. sizeof(STATUS_FIFO_BLOCK),
  225. FALSE,
  226. FALSE,
  227. NULL
  228. );
  229. if (!Context->RequestMdl) {
  230. status = STATUS_INSUFFICIENT_RESOURCES;
  231. goto exitAllocateAddress;
  232. }
  233. break;
  234. #endif
  235. }
  236. if (Context->RequestMdl) {
  237. MmBuildMdlForNonPagedPool(Context->RequestMdl);
  238. }
  239. packet->Irb->u.AllocateAddressRange.Mdl = Context->RequestMdl;
  240. packet->Irb->u.AllocateAddressRange.Context = Context;
  241. packet->Irb->u.AllocateAddressRange.p1394AddressRange = (PADDRESS_RANGE) &address;
  242. status = Sbp2SendRequest (deviceExtension, packet, SYNC_1394_REQUEST);
  243. if (NT_SUCCESS(status)) {
  244. //
  245. // Setup the address context for the status block
  246. //
  247. Context->Address = address[0];
  248. Context->AddressHandle = packet->Irb->u.AllocateAddressRange.hAddressRange;
  249. Context->DeviceObject = DeviceObject;
  250. Context->Address.BusAddress.NodeId = deviceExtension->InitiatorAddressId;
  251. }
  252. exitAllocateAddress:
  253. DeAllocateIrpAndIrb (deviceExtension, packet);
  254. return status;
  255. }
  256. VOID
  257. CleanupOrbList(
  258. PDEVICE_EXTENSION DeviceExtension,
  259. NTSTATUS CompletionStatus
  260. )
  261. /*++
  262. Routine Description:
  263. This routine will free a linked list of RequestContexts
  264. and will also free the 1394 addresses associated with the
  265. buffers in the context. If the DEVICE_FLAG_RECONNECT i set
  266. instead of completing pending irps, it will requeue them...
  267. Arguments:
  268. DeviceExtension - Device Extension of the sbp2 device
  269. CompletionSTATUS - If one of the linked requests is not completed,
  270. complete it with this status
  271. Return Value:
  272. None
  273. --*/
  274. {
  275. PIRP requestIrp;
  276. PASYNC_REQUEST_CONTEXT currentListItem;
  277. PASYNC_REQUEST_CONTEXT lastItem,nextItem;
  278. KIRQL oldIrql;
  279. //
  280. // Go through the linked list, complete its original Irp and
  281. // free all the associated memory and 1394 resources...
  282. // Since this function is called when we get a REMOVE irp,
  283. // all irps will be terminated with error status
  284. //
  285. KeAcquireSpinLock(&DeviceExtension->OrbListSpinLock,&oldIrql);
  286. if (DeviceExtension->NextContextToFree) {
  287. FreeAsyncRequestContext(DeviceExtension,DeviceExtension->NextContextToFree);
  288. DeviceExtension->NextContextToFree = NULL;
  289. }
  290. if (IsListEmpty (&DeviceExtension->PendingOrbList)) {
  291. //
  292. // nothing to do
  293. //
  294. KeReleaseSpinLock (&DeviceExtension->OrbListSpinLock,oldIrql);
  295. return;
  296. } else {
  297. nextItem = RETRIEVE_CONTEXT(DeviceExtension->PendingOrbList.Flink,OrbList);
  298. lastItem = RETRIEVE_CONTEXT(DeviceExtension->PendingOrbList.Blink,OrbList);
  299. InitializeListHead(&DeviceExtension->PendingOrbList);
  300. KeReleaseSpinLock(&DeviceExtension->OrbListSpinLock,oldIrql);
  301. }
  302. //
  303. // Qe have essentially detached this pending context list from
  304. // the main list so we can now free it without holding the lock
  305. // and allowing other requests to be processed.
  306. //
  307. do {
  308. currentListItem = nextItem;
  309. nextItem = (PASYNC_REQUEST_CONTEXT) currentListItem->OrbList.Flink;
  310. if (!TEST_FLAG(currentListItem->Flags,ASYNC_CONTEXT_FLAG_COMPLETED)) {
  311. SET_FLAG(currentListItem->Flags,ASYNC_CONTEXT_FLAG_COMPLETED);
  312. CLEAR_FLAG(currentListItem->Flags, ASYNC_CONTEXT_FLAG_TIMER_STARTED);
  313. Sbp2_SCSI_RBC_Conversion (currentListItem); // unwind MODE_SENSE hacks
  314. KeCancelTimer(&currentListItem->Timer);
  315. requestIrp =(PIRP)currentListItem->Srb->OriginalRequest;
  316. requestIrp->IoStatus.Status = CompletionStatus;
  317. switch (CompletionStatus) {
  318. case STATUS_DEVICE_DOES_NOT_EXIST:
  319. currentListItem->Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
  320. break;
  321. case STATUS_REQUEST_ABORTED:
  322. currentListItem->Srb->SrbStatus = SRB_STATUS_REQUEST_FLUSHED;
  323. break;
  324. case STATUS_IO_TIMEOUT:
  325. currentListItem->Srb->SrbStatus = SRB_STATUS_TIMEOUT;
  326. break;
  327. default:
  328. currentListItem->Srb->SrbStatus = SRB_STATUS_ERROR;
  329. break;
  330. }
  331. if (requestIrp->Type == IO_TYPE_IRP) {
  332. if (TEST_FLAG(DeviceExtension->DeviceFlags, DEVICE_FLAG_RECONNECT)) {
  333. Sbp2StartPacket(
  334. DeviceExtension->DeviceObject,
  335. requestIrp,
  336. &currentListItem->Srb->QueueSortKey
  337. );
  338. //
  339. // free everything related to this request
  340. //
  341. currentListItem->Srb = NULL;
  342. FreeAsyncRequestContext (DeviceExtension, currentListItem);
  343. } else {
  344. //
  345. // free everything related to this request
  346. //
  347. currentListItem->Srb = NULL;
  348. FreeAsyncRequestContext (DeviceExtension, currentListItem);
  349. DEBUGPRINT2(("Sbp2Port: CleanupOrbList: aborted irp x%p compl\n", requestIrp));
  350. IoReleaseRemoveLock (&DeviceExtension->RemoveLock, NULL);
  351. IoCompleteRequest (requestIrp, IO_NO_INCREMENT);
  352. }
  353. }
  354. } else {
  355. //
  356. // free everything related to this request
  357. //
  358. FreeAsyncRequestContext (DeviceExtension, currentListItem);
  359. }
  360. } while (lastItem != currentListItem); // while loop
  361. return;
  362. }
  363. VOID
  364. FreeAddressRange(
  365. IN PDEVICE_EXTENSION DeviceExtension,
  366. IN PADDRESS_CONTEXT Context
  367. )
  368. /*++
  369. Routine Description:
  370. 1394 BUS IOCTL call for freeing an address range.
  371. Arguments:
  372. DeviceExtension - Pointer to sbp2 deviceExtension.
  373. context - address context
  374. Return Value:
  375. NTSTATUS
  376. --*/
  377. {
  378. PIRBIRP packet ;
  379. if (Context->AddressHandle == NULL) {
  380. return;
  381. }
  382. AllocateIrpAndIrb (DeviceExtension, &packet);
  383. if (!packet) {
  384. return;
  385. }
  386. //
  387. // FreeAddressRange is synchronous call
  388. //
  389. packet->Irb->FunctionNumber = REQUEST_FREE_ADDRESS_RANGE;
  390. packet->Irb->Flags = 0;
  391. //
  392. // We always free one address handle even it refers to multiple
  393. // 1394 addresses. The mdl associated with the original Allocate
  394. // is freed by the port driver.
  395. //
  396. packet->Irb->u.FreeAddressRange.nAddressesToFree = 1;
  397. packet->Irb->u.FreeAddressRange.p1394AddressRange = (PADDRESS_RANGE) &Context->Address;
  398. packet->Irb->u.FreeAddressRange.pAddressRange = &Context->AddressHandle;
  399. if (Context->RequestMdl) {
  400. if (Context == &DeviceExtension->CommonBufferContext) {
  401. Context->RequestMdl = NULL; // common buffer, we didn't alloc mdl
  402. } else {
  403. packet->Irb->u.FreeAddressRange.p1394AddressRange->AR_Length =
  404. (USHORT) MmGetMdlByteCount(Context->RequestMdl);
  405. }
  406. } else if (Context == (PADDRESS_CONTEXT) &DeviceExtension->GlobalStatusContext) {
  407. packet->Irb->u.FreeAddressRange.p1394AddressRange->AR_Length = sizeof(STATUS_FIFO_BLOCK);
  408. }
  409. packet->Irb->u.FreeAddressRange.DeviceExtension = DeviceExtension;
  410. if ((KeGetCurrentIrql() >= DISPATCH_LEVEL) && !Context->Address.BusAddress.Off_High) {
  411. PPORT_PHYS_ADDR_ROUTINE routine = DeviceExtension->HostRoutineAPI.PhysAddrMappingRoutine;
  412. (*routine) (DeviceExtension->HostRoutineAPI.Context,packet->Irb);
  413. } else {
  414. //
  415. // dont care about the status of this op
  416. //
  417. Sbp2SendRequest (DeviceExtension, packet, SYNC_1394_REQUEST);
  418. }
  419. Context->AddressHandle = NULL;
  420. if (Context->RequestMdl) {
  421. IoFreeMdl (Context->RequestMdl);
  422. Context->RequestMdl = NULL;
  423. }
  424. DeAllocateIrpAndIrb (DeviceExtension, packet);
  425. }
  426. VOID
  427. Free1394DataMapping(
  428. PDEVICE_EXTENSION DeviceExtension,
  429. PASYNC_REQUEST_CONTEXT Context
  430. )
  431. {
  432. PIRBIRP packet ;
  433. if (Context->DataMappingHandle == NULL) {
  434. return;
  435. }
  436. AllocateIrpAndIrb (DeviceExtension, &packet);
  437. if (!packet) {
  438. return;
  439. }
  440. //
  441. // Free the data buffer's 1394 address range
  442. //
  443. packet->Irb->FunctionNumber = REQUEST_FREE_ADDRESS_RANGE;
  444. packet->Irb->Flags = 0;
  445. packet->Irb->u.FreeAddressRange.nAddressesToFree = 1;
  446. packet->Irb->u.FreeAddressRange.p1394AddressRange = (PADDRESS_RANGE) NULL;
  447. packet->Irb->u.FreeAddressRange.pAddressRange = &Context->DataMappingHandle;
  448. packet->Irb->u.FreeAddressRange.DeviceExtension = DeviceExtension;
  449. if (KeGetCurrentIrql() >= DISPATCH_LEVEL) {
  450. PPORT_PHYS_ADDR_ROUTINE routine = DeviceExtension->HostRoutineAPI.PhysAddrMappingRoutine;
  451. (*routine) (DeviceExtension->HostRoutineAPI.Context, packet->Irb);
  452. } else {
  453. //
  454. // dont care about the status of this op
  455. //
  456. Sbp2SendRequest (DeviceExtension, packet, SYNC_1394_REQUEST);
  457. }
  458. if (Context->PartialMdl) {
  459. IoFreeMdl (Context->PartialMdl);
  460. Context->PartialMdl = NULL;
  461. }
  462. Context->DataMappingHandle = NULL;
  463. DeAllocateIrpAndIrb (DeviceExtension, packet);
  464. }
  465. ULONG
  466. FreeAsyncRequestContext(
  467. PDEVICE_EXTENSION DeviceExtension,
  468. PASYNC_REQUEST_CONTEXT Context
  469. )
  470. /*++
  471. Routine Description:
  472. This routine will free a single RequestContext and will cleanup all
  473. its buffers and 1394 ranges, ONLY of the device is marked as STOPPED.
  474. Otherwise it will add the context to the FreeList, so it can be reused
  475. later one by another request. This way we are drastically speeding up
  476. each request.
  477. Arguments:
  478. DeviceExtension - Device Extension of the sbp2 device
  479. Context - Context to freed or returned to FreeList
  480. Return Value:
  481. None - The result of the decrement of DeviceExtension->OrbListDepth
  482. --*/
  483. {
  484. //
  485. // This ORB can now be freed along with its data descriptor,
  486. // page tables and context
  487. //
  488. if (!Context || (Context->Tag != SBP2_ASYNC_CONTEXT_TAG)) {
  489. DEBUGPRINT2((
  490. "Sbp2Port: FreeAsyncReqCtx: attempt to push freed ctx=x%p\n",
  491. Context
  492. ));
  493. ASSERT(FALSE);
  494. return 0;
  495. }
  496. ASSERT(Context->Srb == NULL);
  497. if (Context->DataMappingHandle) {
  498. Free1394DataMapping(DeviceExtension,Context);
  499. ASSERT(Context->DataMappingHandle==NULL);
  500. }
  501. //
  502. // Re-initiliaze this context so it can be reused
  503. // This context is still part on our FreeAsyncContextPool
  504. // All we have to do is initialize some flags, so next time
  505. // we try to retrieve it, we think its empty
  506. //
  507. Context->Flags |= ASYNC_CONTEXT_FLAG_COMPLETED;
  508. Context->Tag = 0;
  509. if (Context->OriginalSrb) {
  510. ExFreePool(Context->OriginalSrb);
  511. Context->OriginalSrb = NULL;
  512. }
  513. DEBUGPRINT3(("Sbp2Port: FreeAsyncReqCtx: push ctx=x%p on free list\n",Context));
  514. ExInterlockedPushEntrySList(&DeviceExtension->FreeContextListHead,
  515. &Context->LookasideList,
  516. &DeviceExtension->FreeContextLock);
  517. return InterlockedDecrement (&DeviceExtension->OrbListDepth);
  518. }
  519. NTSTATUS
  520. Sbp2SendRequest(
  521. PDEVICE_EXTENSION DeviceExtension,
  522. PIRBIRP RequestPacket,
  523. ULONG TransferMode
  524. )
  525. /*++
  526. Routine Description:
  527. Function used to send requests to the 1394 bus driver. It attaches
  528. a completion routine to each request it sends down, and it also wraps
  529. them in a small context, so we can track their completion
  530. Arguments:
  531. DeviceExtension - Sbp2 device extension
  532. Irp - Irp to send to the bus driver
  533. Irb - Bus driver packet, in the Irp
  534. TransferMode - Indicates if we want ot send this request synchronously
  535. or asynchronously
  536. FinalTransferMode - Indicates whether the request was sent synchronously
  537. or asynchronously
  538. Return Value:
  539. NTSTATUS
  540. --*/
  541. {
  542. ULONG originalTransferMode = TransferMode;
  543. NTSTATUS status;
  544. PDEVICE_OBJECT deviceObject = DeviceExtension->DeviceObject;
  545. PREQUEST_CONTEXT requestContext = NULL;
  546. PIO_STACK_LOCATION nextIrpStack;
  547. if (DeviceExtension->Type == SBP2_PDO) {
  548. //
  549. // if device is removed, dont send any requests down
  550. //
  551. if (TEST_FLAG(DeviceExtension->DeviceFlags,DEVICE_FLAG_REMOVED) &&
  552. (RequestPacket->Irb->FunctionNumber != REQUEST_FREE_ADDRESS_RANGE)) {
  553. return STATUS_UNSUCCESSFUL;
  554. }
  555. //
  556. // get a context for this request, from our pool
  557. //
  558. requestContext = (PREQUEST_CONTEXT) \
  559. ExInterlockedPopEntrySList(&DeviceExtension->BusRequestContextListHead,&DeviceExtension->BusRequestLock);
  560. } else {
  561. requestContext = ExAllocatePool (NonPagedPool,sizeof(REQUEST_CONTEXT));
  562. }
  563. if (!requestContext) {
  564. DEBUGPRINT2((
  565. "Sbp2Port: SendReq: ERROR, couldn't allocate bus req ctx\n"
  566. ));
  567. return STATUS_INSUFFICIENT_RESOURCES;
  568. }
  569. if (TransferMode == SYNC_1394_REQUEST) {
  570. if (KeGetCurrentIrql() >= DISPATCH_LEVEL) {
  571. //
  572. // Since we can't block at this level, we will have to do the
  573. // synch request asynchronously
  574. //
  575. TransferMode = ASYNC_SYNC_1394_REQUEST;
  576. requestContext->Complete = 0;
  577. } else {
  578. KeInitializeEvent(
  579. &requestContext->Event,
  580. NotificationEvent,
  581. FALSE
  582. );
  583. }
  584. }
  585. requestContext->DeviceExtension = DeviceExtension;
  586. requestContext->RequestType = TransferMode;
  587. if (TransferMode == SYNC_1394_REQUEST){
  588. requestContext->Packet = NULL;
  589. } else {
  590. requestContext->Packet = RequestPacket;
  591. }
  592. nextIrpStack = IoGetNextIrpStackLocation (RequestPacket->Irp);
  593. nextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  594. nextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_1394_CLASS;
  595. nextIrpStack->Parameters.Others.Argument1 = RequestPacket->Irb;
  596. IoSetCompletionRoutine(RequestPacket->Irp,
  597. Sbp2RequestCompletionRoutine,
  598. requestContext,
  599. TRUE,
  600. TRUE,
  601. TRUE
  602. );
  603. status = IoCallDriver(
  604. DeviceExtension->LowerDeviceObject,
  605. RequestPacket->Irp
  606. );
  607. if (status == STATUS_INVALID_GENERATION) {
  608. DEBUGPRINT1(("Sbp2Port: SendReq: Bus drv ret'd invalid generation\n"));
  609. RequestPacket->Irp->IoStatus.Status = STATUS_REQUEST_ABORTED;
  610. }
  611. if (originalTransferMode == SYNC_1394_REQUEST ) {
  612. if (TransferMode == SYNC_1394_REQUEST) {
  613. if (status == STATUS_PENDING) {
  614. //
  615. // < DISPATCH_LEVEL so wait on an event
  616. //
  617. KeWaitForSingleObject(
  618. &requestContext->Event,
  619. Executive,
  620. KernelMode,
  621. FALSE,
  622. NULL
  623. );
  624. }
  625. } else { // ASYNC_SYNC_1394_REQUEST
  626. //
  627. // >= DISPATCH_LEVEL so we can't wait, do the nasty...
  628. //
  629. volatile ULONG *pComplete = &requestContext->Complete;
  630. while (*pComplete == 0);
  631. status = RequestPacket->Irp->IoStatus.Status;
  632. }
  633. //
  634. // Free the context (the Irp.Irb will be returnd by the caller)
  635. //
  636. if (DeviceExtension->Type == SBP2_PDO) {
  637. ExInterlockedPushEntrySList(
  638. &DeviceExtension->BusRequestContextListHead,
  639. &requestContext->ListPointer,
  640. &DeviceExtension->BusRequestLock
  641. );
  642. } else {
  643. ExFreePool (requestContext);
  644. }
  645. return RequestPacket->Irp->IoStatus.Status;
  646. }
  647. return status;
  648. }
  649. NTSTATUS
  650. Sbp2RequestCompletionRoutine(
  651. IN PDEVICE_OBJECT DeviceObject,
  652. IN PIRP Irp,
  653. IN PREQUEST_CONTEXT Context
  654. )
  655. /*++
  656. Routine Description:
  657. Completion routine used for all requests to 1394 bus driver
  658. Arguments:
  659. DriverObject - Pointer to driver object created by system.
  660. Irp - Irp that just completed
  661. Event - Event we'll signal to say Irp is done
  662. Return Value:
  663. None.
  664. --*/
  665. {
  666. ASSERT(Context!=NULL);
  667. ASSERT(Context->DeviceExtension);
  668. if (Context->RequestType == SYNC_1394_REQUEST) {
  669. //
  670. // Synch request completion (either synch, or synch at DPC)
  671. //
  672. KeSetEvent (&Context->Event, IO_NO_INCREMENT, FALSE);
  673. } else if (Context->RequestType == ASYNC_1394_REQUEST) {
  674. //
  675. // Asynchronous request completion, so do any necessary
  676. // post-processing & return the context and the Irp/Irb
  677. // to the free lists.
  678. //
  679. if (Context->Packet) {
  680. switch (Context->Packet->Irb->FunctionNumber) {
  681. case REQUEST_ASYNC_READ:
  682. case REQUEST_ASYNC_WRITE:
  683. if (Context->Packet->Irb->u.AsyncWrite.nNumberOfBytesToWrite ==
  684. sizeof(OCTLET)) {
  685. IoFreeMdl (Context->Packet->Irb->u.AsyncRead.Mdl);
  686. Context->Packet->Irb->u.AsyncRead.Mdl = NULL;
  687. }
  688. break;
  689. }
  690. DeAllocateIrpAndIrb (Context->DeviceExtension, Context->Packet);
  691. }
  692. if (Context->DeviceExtension->Type == SBP2_PDO) {
  693. ExInterlockedPushEntrySList(
  694. &Context->DeviceExtension->BusRequestContextListHead,
  695. &Context->ListPointer,
  696. &Context->DeviceExtension->BusRequestLock
  697. );
  698. } else {
  699. ExFreePool (Context);
  700. }
  701. } else { // ASYNC_SYNC_1394_REQUEST
  702. //
  703. // Just set the Complete flag to unblock Sbp2SendRequest
  704. //
  705. Context->Complete = 1;
  706. }
  707. return STATUS_MORE_PROCESSING_REQUIRED;
  708. }
  709. VOID
  710. Sbp2CreateRequestErrorLog(
  711. IN PDEVICE_OBJECT DeviceObject,
  712. IN PASYNC_REQUEST_CONTEXT Context,
  713. IN NTSTATUS Status
  714. )
  715. {
  716. PIO_ERROR_LOG_PACKET errorLogEntry;
  717. errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
  718. DeviceObject,
  719. sizeof(IO_ERROR_LOG_PACKET) + sizeof(ORB_NORMAL_CMD)
  720. );
  721. if (errorLogEntry) {
  722. switch (Status) {
  723. case STATUS_DEVICE_POWER_FAILURE:
  724. errorLogEntry->ErrorCode = IO_ERR_NOT_READY;
  725. break;
  726. case STATUS_INSUFFICIENT_RESOURCES:
  727. errorLogEntry->ErrorCode = IO_ERR_INSUFFICIENT_RESOURCES;
  728. break;
  729. case STATUS_TIMEOUT:
  730. errorLogEntry->ErrorCode = IO_ERR_TIMEOUT;
  731. break;
  732. case STATUS_DEVICE_PROTOCOL_ERROR:
  733. errorLogEntry->ErrorCode = IO_ERR_BAD_FIRMWARE;
  734. break;
  735. case STATUS_INVALID_PARAMETER:
  736. case STATUS_INVALID_DEVICE_REQUEST:
  737. errorLogEntry->ErrorCode = IO_ERR_INVALID_REQUEST;
  738. break;
  739. case STATUS_REQUEST_ABORTED:
  740. errorLogEntry->ErrorCode = IO_ERR_RESET;
  741. break;
  742. default:
  743. errorLogEntry->ErrorCode = IO_ERR_BAD_FIRMWARE;
  744. break;
  745. }
  746. errorLogEntry->SequenceNumber = 0;
  747. errorLogEntry->MajorFunctionCode = IRP_MJ_SCSI;
  748. errorLogEntry->RetryCount = 0;
  749. errorLogEntry->UniqueErrorValue = 0;
  750. errorLogEntry->FinalStatus = Status;
  751. if (Context) {
  752. errorLogEntry->DumpDataSize = sizeof(ORB_NORMAL_CMD);
  753. RtlCopyMemory(&(errorLogEntry->DumpData[0]),Context->CmdOrb,sizeof(ORB_NORMAL_CMD));
  754. } else {
  755. errorLogEntry->DumpDataSize = 0;
  756. }
  757. IoWriteErrorLogEntry(errorLogEntry);
  758. DEBUGPRINT2((
  759. "Sbp2Port: ErrorLog: dev=x%p, status=x%x, ctx=x%p\n",
  760. DeviceObject,
  761. Status,
  762. Context
  763. ));
  764. } else {
  765. DEBUGPRINT2 (("Sbp2Port: ErrorLog: failed to allocate log entry\n"));
  766. }
  767. }
  768. NTSTATUS
  769. CheckStatusResponseValue(
  770. IN PSTATUS_FIFO_BLOCK StatusBlock
  771. )
  772. /*++
  773. Routine Description:
  774. It checks the status block result bits and maps the errors to
  775. NT status errors
  776. Arguments:
  777. DeviceExtension - Sbp2 device extension
  778. ManagementStatus - If true then we check the management orb status
  779. Return Value:
  780. NTSTATUS
  781. ++*/
  782. {
  783. NTSTATUS status;
  784. UCHAR resp;
  785. USHORT statusFlags = StatusBlock->AddressAndStatus.u.HighQuad.u.HighPart;
  786. if (statusFlags & STATUS_BLOCK_UNSOLICITED_BIT_MASK) {
  787. //
  788. // The unsolicited bit is set, which means this status is
  789. // not related to anything...
  790. //
  791. status = STATUS_NOT_FOUND;
  792. } else {
  793. resp = statusFlags & STATUS_BLOCK_RESP_MASK;
  794. if (resp == 0x01) {
  795. resp = (statusFlags & STATUS_BLOCK_RESP_MASK) & 0x0F;
  796. //
  797. // This a protocol/transport error. Check the redefined sbp-status field for serial-bus erros
  798. //
  799. switch (resp) {
  800. case 0x02: //time out
  801. case 0x0D: // data error
  802. case 0x0C: // conflict error
  803. status = STATUS_DEVICE_PROTOCOL_ERROR;
  804. break;
  805. case 0x04: // busy retry limit exceeded
  806. status = STATUS_DEVICE_BUSY;
  807. break;
  808. case 0x09: // rejected
  809. status = STATUS_INVALID_DEVICE_REQUEST;
  810. break;
  811. case 0x0F: // address error
  812. status = STATUS_INVALID_ADDRESS;
  813. break;
  814. case 0x0E: // type error
  815. status = STATUS_INVALID_PARAMETER;
  816. break;
  817. default:
  818. status = STATUS_UNSUCCESSFUL;
  819. break;
  820. }
  821. return status;
  822. }
  823. if (resp == 0x02) {
  824. return STATUS_ILLEGAL_FUNCTION;
  825. }
  826. //
  827. // REQUEST_COMPLETE. Check sbp_status field for more info
  828. //
  829. if (resp == 0x00) {
  830. switch ((statusFlags & STATUS_BLOCK_SBP_STATUS_MASK)) {
  831. case 0x11: //dummy orb completed
  832. case 0x00: // no additional status to report
  833. status = STATUS_SUCCESS;
  834. break;
  835. case 0x01: // request type not supported
  836. case 0x02: // speed not supported
  837. case 0x03: // page size not supported
  838. status = STATUS_NOT_SUPPORTED;
  839. break;
  840. case 0x10: // login id not recognized
  841. status = STATUS_TRANSACTION_INVALID_ID;
  842. break;
  843. case 0xFF: // unspecifed error
  844. status = STATUS_UNSUCCESSFUL;
  845. break;
  846. case 0x09: // function rejected
  847. status = STATUS_ILLEGAL_FUNCTION;
  848. break;
  849. case 0x04: // access denied
  850. case 0x05: //LUN not supported
  851. status = STATUS_ACCESS_DENIED;
  852. break;
  853. case 0x07:
  854. case 0x08:
  855. status = STATUS_INSUFFICIENT_RESOURCES;
  856. break;
  857. default:
  858. status = STATUS_UNSUCCESSFUL;
  859. break;
  860. }
  861. }
  862. }
  863. return status;
  864. }
  865. NTSTATUS
  866. GetRegistryParameters(
  867. IN PDEVICE_OBJECT PhysicalDeviceObject,
  868. IN OUT PULONG DiagnosticFlags,
  869. IN OUT PULONG MaxTransferSize
  870. )
  871. /*++
  872. Routine Description:
  873. This function gets some values out of the registry for initialization
  874. Arguments:
  875. PhysicalDeviceObject - The Port driver's parent device object
  876. DiagnosticFlags - Used for debugging
  877. ReceiveWorkers - Max number of receive worker structures
  878. TransmitWorkers - Max number of xmit worker structures
  879. bAllowPhyConfigPackets - do we allow phy config packets to be sent
  880. Return Value:
  881. Status is returned from Irp
  882. --*/
  883. {
  884. NTSTATUS status;
  885. HANDLE handle;
  886. WCHAR diagnosticModeKey[] = L"DiagnosticFlags";
  887. WCHAR maxTransferSizeKey[] = L"MaxTransferSize";
  888. status = IoOpenDeviceRegistryKey(
  889. PhysicalDeviceObject,
  890. PLUGPLAY_REGKEY_DEVICE,
  891. STANDARD_RIGHTS_ALL,
  892. &handle
  893. );
  894. if (NT_SUCCESS(status)) {
  895. GetRegistryKeyValue(
  896. handle,
  897. diagnosticModeKey,
  898. sizeof(diagnosticModeKey),
  899. DiagnosticFlags,
  900. sizeof(*DiagnosticFlags)
  901. );
  902. GetRegistryKeyValue(
  903. handle,
  904. maxTransferSizeKey,
  905. sizeof(maxTransferSizeKey),
  906. MaxTransferSize,
  907. sizeof(*MaxTransferSize)
  908. );
  909. ZwClose(handle);
  910. }
  911. DEBUGPRINT3((
  912. "Sbp2Port: GetRegParams: status=x%x, diag=x%x, maxXfer=x%x\n",
  913. status,
  914. *DiagnosticFlags,
  915. *MaxTransferSize
  916. ));
  917. return (status);
  918. }
  919. NTSTATUS
  920. GetRegistryKeyValue (
  921. IN HANDLE Handle,
  922. IN PWCHAR KeyNameString,
  923. IN ULONG KeyNameStringLength,
  924. IN PVOID Data,
  925. IN ULONG DataLength
  926. )
  927. /*++
  928. Routine Description:
  929. This routine gets the specified value out of the registry
  930. Arguments:
  931. Handle - Handle to location in registry
  932. KeyNameString - registry key we're looking for
  933. KeyNameStringLength - length of registry key we're looking for
  934. Data - where to return the data
  935. DataLength - how big the data is
  936. Return Value:
  937. status is returned from ZwQueryValueKey
  938. --*/
  939. {
  940. NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
  941. UNICODE_STRING keyName;
  942. ULONG length;
  943. PKEY_VALUE_FULL_INFORMATION fullInfo;
  944. RtlInitUnicodeString(&keyName, KeyNameString);
  945. length = sizeof(KEY_VALUE_FULL_INFORMATION) +
  946. KeyNameStringLength + DataLength;
  947. fullInfo = ExAllocatePoolWithTag(PagedPool, length,'2pbs');
  948. if (fullInfo) {
  949. status = ZwQueryValueKey(
  950. Handle,
  951. &keyName,
  952. KeyValueFullInformation,
  953. fullInfo,
  954. length,
  955. &length
  956. );
  957. if (NT_SUCCESS(status)){
  958. if (DataLength == fullInfo->DataLength) {
  959. RtlCopyMemory(
  960. Data,
  961. ((PUCHAR) fullInfo) + fullInfo->DataOffset,
  962. DataLength
  963. );
  964. } else {
  965. DEBUGPRINT1((
  966. "Sbp2Port: GetRegKeyVal: keyLen!=exp, dataLen=x%x " \
  967. "fullInfoLen=x%x\n",
  968. DataLength,
  969. fullInfo->DataLength
  970. ));
  971. }
  972. }
  973. ExFreePool(fullInfo);
  974. }
  975. return (status);
  976. }
  977. VOID
  978. ValidateTextLeaf(
  979. IN PTEXTUAL_LEAF Leaf
  980. )
  981. {
  982. PUCHAR buff;
  983. PWCHAR wBuff;
  984. ULONG byteSwappedData;
  985. //
  986. // check the lengths. insert null terminators if they are
  987. // too long...
  988. //
  989. byteSwappedData = bswap(*((PULONG)Leaf+1));
  990. wBuff = (PWCHAR) &Leaf->TL_Data;
  991. buff = &Leaf->TL_Data;
  992. if (Leaf->TL_Length > SBP2_MAX_TEXT_LEAF_LENGTH) {
  993. ASSERT(Leaf->TL_Length <= SBP2_MAX_TEXT_LEAF_LENGTH);
  994. buff[SBP2_MAX_TEXT_LEAF_LENGTH-1] = 0;
  995. buff[SBP2_MAX_TEXT_LEAF_LENGTH-2] = 0;
  996. }
  997. //
  998. // check for invalid characters and replace them with _
  999. //
  1000. if (byteSwappedData & 0x80000000) {
  1001. //
  1002. // unicode
  1003. //
  1004. for (wBuff = (PWCHAR) &Leaf->TL_Data; *wBuff; wBuff++) {
  1005. if ((*wBuff < L' ') || (*wBuff > (WCHAR)0x7F) || (*wBuff == L',')) {
  1006. *wBuff = L'_';
  1007. }
  1008. }
  1009. } else {
  1010. //
  1011. // ascii
  1012. //
  1013. for (buff = &Leaf->TL_Data; *buff; buff++) {
  1014. if ((*buff < L' ') || (*buff > (CHAR)0x7F) || (*buff == L',')) {
  1015. *buff = L'_';
  1016. }
  1017. }
  1018. }
  1019. }
  1020. VOID
  1021. Sbp2StartNextPacketByKey(
  1022. IN PDEVICE_OBJECT DeviceObject,
  1023. IN ULONG Key
  1024. )
  1025. /*++
  1026. Routine Description:
  1027. This routine was lifted from the Io sources
  1028. (IopStartNextPacketByKey), and duplicated/modifed here for
  1029. two reasons: 1) we got tired of hitting the queue-not-busy assert
  1030. in KeRemoveXxx, and 2) we needed a way to prevent stack-blowing
  1031. recursion, for example, arising from a bunch of requests sent to
  1032. a stopped device (all failed in StartIo, which calls this func).
  1033. These routines were originally designed with the idea that there
  1034. would only be one outstanding request at a time, but this driver
  1035. can have multiple outstanding requests, and it frequently ends up
  1036. making redundant calls to XxStartNextPacket(ByKey), which result
  1037. in the aforementioned assert.
  1038. Rolling our own version of this also allows us to get rid the
  1039. the cancel overhead, since we do not (currently) support cancels.
  1040. Arguments:
  1041. DeviceObject - Pointer to device object itself
  1042. Key - Specifics the Key used to remove the entry from the queue
  1043. Return Value:
  1044. None
  1045. --*/
  1046. {
  1047. PIRP irp;
  1048. PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION)
  1049. DeviceObject->DeviceExtension;
  1050. PKDEVICE_QUEUE_ENTRY packet;
  1051. //
  1052. // Increment the StartNextPacketCount, and if result is != 1
  1053. // then just return because we don't want to worry about
  1054. // recursion & blowing the stack. The instance of this
  1055. // function that caused the SNPCount 0 to 1 transition
  1056. // will eventually make another pass through the loop below
  1057. // on this instance's behalf.
  1058. //
  1059. if (InterlockedIncrement (&deviceExtension->StartNextPacketCount) != 1) {
  1060. return;
  1061. }
  1062. do {
  1063. //
  1064. // Attempt to remove the indicated packet according to the key
  1065. // from the device queue. If one is found, then process it.
  1066. //
  1067. packet = Sbp2RemoveByKeyDeviceQueueIfBusy(
  1068. &DeviceObject->DeviceQueue,
  1069. Key
  1070. );
  1071. if (packet) {
  1072. irp = CONTAINING_RECORD (packet,IRP,Tail.Overlay.DeviceQueueEntry);
  1073. Sbp2StartIo (DeviceObject, irp);
  1074. }
  1075. } while (InterlockedDecrement (&deviceExtension->StartNextPacketCount));
  1076. }
  1077. VOID
  1078. Sbp2StartPacket(
  1079. IN PDEVICE_OBJECT DeviceObject,
  1080. IN PIRP Irp,
  1081. IN PULONG Key OPTIONAL
  1082. )
  1083. /*++
  1084. Routine Description:
  1085. (See routine description for Sbp2StartNextPacketByKey)
  1086. Arguments:
  1087. DeviceObject - Pointer to device object itself
  1088. Irp - I/O Request Packet which should be started on the device
  1089. Return Value:
  1090. None
  1091. --*/
  1092. {
  1093. KIRQL oldIrql;
  1094. BOOLEAN inserted;
  1095. PLIST_ENTRY nextEntry;
  1096. PKDEVICE_QUEUE queue = &DeviceObject->DeviceQueue;
  1097. PKDEVICE_QUEUE_ENTRY queueEntry = &Irp->Tail.Overlay.DeviceQueueEntry,
  1098. queueEntry2;
  1099. //
  1100. // Raise the IRQL of the processor to dispatch level for synchronization
  1101. //
  1102. KeRaiseIrql (DISPATCH_LEVEL, &oldIrql);
  1103. KeAcquireSpinLockAtDpcLevel (&queue->Lock);
  1104. if (Key) {
  1105. //
  1106. // Insert the specified device queue entry in the device queue at the
  1107. // position specified by the sort key if the device queue is busy.
  1108. // Otherwise set the device queue busy an don't insert the device
  1109. // queue entry.
  1110. //
  1111. queueEntry->SortKey = *Key;
  1112. if (queue->Busy == TRUE) {
  1113. inserted = TRUE;
  1114. nextEntry = queue->DeviceListHead.Flink;
  1115. while (nextEntry != &queue->DeviceListHead) {
  1116. queueEntry2 = CONTAINING_RECORD(
  1117. nextEntry,
  1118. KDEVICE_QUEUE_ENTRY,
  1119. DeviceListEntry
  1120. );
  1121. if (*Key < queueEntry2->SortKey) {
  1122. break;
  1123. }
  1124. nextEntry = nextEntry->Flink;
  1125. }
  1126. nextEntry = nextEntry->Blink;
  1127. InsertHeadList (nextEntry, &queueEntry->DeviceListEntry);
  1128. } else {
  1129. queue->Busy = TRUE;
  1130. inserted = FALSE;
  1131. }
  1132. } else {
  1133. //
  1134. // Insert the specified device queue entry at the end of the device
  1135. // queue if the device queue is busy. Otherwise set the device queue
  1136. // busy and don't insert the device queue entry.
  1137. //
  1138. if (queue->Busy == TRUE) {
  1139. inserted = TRUE;
  1140. InsertTailList(
  1141. &queue->DeviceListHead,
  1142. &queueEntry->DeviceListEntry
  1143. );
  1144. } else {
  1145. queue->Busy = TRUE;
  1146. inserted = FALSE;
  1147. }
  1148. }
  1149. queueEntry->Inserted = inserted;
  1150. KeReleaseSpinLockFromDpcLevel (&queue->Lock);
  1151. //
  1152. // If the packet was not inserted into the queue, then this request is
  1153. // now the current packet for this device. Indicate so by storing its
  1154. // address in the current IRP field, and begin processing the request.
  1155. //
  1156. if (!inserted) {
  1157. //
  1158. // Invoke the driver's start I/O routine to get the request going
  1159. // on the device
  1160. //
  1161. Sbp2StartIo (DeviceObject, Irp);
  1162. }
  1163. //
  1164. // Restore the IRQL back to its value upon entry to this function before
  1165. // returning to the caller
  1166. //
  1167. KeLowerIrql (oldIrql);
  1168. }
  1169. PKDEVICE_QUEUE_ENTRY
  1170. Sbp2RemoveByKeyDeviceQueueIfBusy(
  1171. IN PKDEVICE_QUEUE DeviceQueue,
  1172. IN ULONG SortKey
  1173. )
  1174. /*++
  1175. Routine Description:
  1176. This routine was lifted directly from Ke sources
  1177. (KeRemoveByKeyDeviceQueueIfBusy) to allow this driver to maintain
  1178. WDM compatibility, since the Ke API does not exist on Win9x or Win2k.
  1179. N.B. This function can only be called from DISPATCH_LEVEL.
  1180. Arguments:
  1181. DeviceQueue - Supplies a pointer to a control object of type device queue.
  1182. SortKey - Supplies the sort key by which the position to remove the device
  1183. queue entry is to be determined.
  1184. Return Value:
  1185. A NULL pointer is returned if the device queue is empty. Otherwise a
  1186. pointer to a device queue entry is returned.
  1187. --*/
  1188. {
  1189. PLIST_ENTRY nextEntry;
  1190. PKDEVICE_QUEUE_ENTRY queueEntry;
  1191. ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
  1192. //
  1193. // Lock specified device queue.
  1194. //
  1195. KeAcquireSpinLockAtDpcLevel (&DeviceQueue->Lock);
  1196. //
  1197. // If the device queue is busy, then attempt to remove an entry from
  1198. // the queue using the sort key. Otherwise, set the device queue not
  1199. // busy.
  1200. //
  1201. if (DeviceQueue->Busy != FALSE) {
  1202. if (IsListEmpty (&DeviceQueue->DeviceListHead) != FALSE) {
  1203. DeviceQueue->Busy = FALSE;
  1204. queueEntry = NULL;
  1205. } else {
  1206. nextEntry = DeviceQueue->DeviceListHead.Flink;
  1207. while (nextEntry != &DeviceQueue->DeviceListHead) {
  1208. queueEntry = CONTAINING_RECORD(
  1209. nextEntry,
  1210. KDEVICE_QUEUE_ENTRY,
  1211. DeviceListEntry
  1212. );
  1213. if (SortKey <= queueEntry->SortKey) {
  1214. break;
  1215. }
  1216. nextEntry = nextEntry->Flink;
  1217. }
  1218. if (nextEntry != &DeviceQueue->DeviceListHead) {
  1219. RemoveEntryList (&queueEntry->DeviceListEntry);
  1220. } else {
  1221. nextEntry = RemoveHeadList (&DeviceQueue->DeviceListHead);
  1222. queueEntry = CONTAINING_RECORD(
  1223. nextEntry,
  1224. KDEVICE_QUEUE_ENTRY,
  1225. DeviceListEntry
  1226. );
  1227. }
  1228. queueEntry->Inserted = FALSE;
  1229. }
  1230. } else {
  1231. queueEntry = NULL;
  1232. }
  1233. //
  1234. // Unlock specified device queue and return address of device queue
  1235. // entry.
  1236. //
  1237. KeReleaseSpinLockFromDpcLevel (&DeviceQueue->Lock);
  1238. return queueEntry;
  1239. }
  1240. BOOLEAN
  1241. Sbp2InsertByKeyDeviceQueue(
  1242. PKDEVICE_QUEUE DeviceQueue,
  1243. PKDEVICE_QUEUE_ENTRY DeviceQueueEntry,
  1244. ULONG SortKey
  1245. )
  1246. /*++
  1247. Routine Description:
  1248. (Again, stolen from Ke src to maintain consistent use of spinlocks.)
  1249. This function inserts a device queue entry into the specified device
  1250. queue according to a sort key. If the device is not busy, then it is
  1251. set busy and the entry is not placed in the device queue. Otherwise
  1252. the specified entry is placed in the device queue at a position such
  1253. that the specified sort key is greater than or equal to its predecessor
  1254. and less than its successor.
  1255. N.B. This function can only be called from DISPATCH_LEVEL.
  1256. Arguments:
  1257. DeviceQueue - Supplies a pointer to a control object of type device queue.
  1258. DeviceQueueEntry - Supplies a pointer to a device queue entry.
  1259. SortKey - Supplies the sort key by which the position to insert the device
  1260. queue entry is to be determined.
  1261. Return Value:
  1262. If the device is not busy, then a value of FALSE is returned. Otherwise a
  1263. value of TRUE is returned.
  1264. --*/
  1265. {
  1266. BOOLEAN inserted;
  1267. PLIST_ENTRY nextEntry;
  1268. PKDEVICE_QUEUE queue = DeviceQueue;
  1269. PKDEVICE_QUEUE_ENTRY queueEntry = DeviceQueueEntry,
  1270. queueEntry2;
  1271. KeAcquireSpinLockAtDpcLevel (&queue->Lock);
  1272. //
  1273. // Insert the specified device queue entry in the device queue at the
  1274. // position specified by the sort key if the device queue is busy.
  1275. // Otherwise set the device queue busy an don't insert the device
  1276. // queue entry.
  1277. //
  1278. queueEntry->SortKey = SortKey;
  1279. if (queue->Busy == TRUE) {
  1280. inserted = TRUE;
  1281. nextEntry = queue->DeviceListHead.Flink;
  1282. while (nextEntry != &queue->DeviceListHead) {
  1283. queueEntry2 = CONTAINING_RECORD(
  1284. nextEntry,
  1285. KDEVICE_QUEUE_ENTRY,
  1286. DeviceListEntry
  1287. );
  1288. if (SortKey < queueEntry2->SortKey) {
  1289. break;
  1290. }
  1291. nextEntry = nextEntry->Flink;
  1292. }
  1293. nextEntry = nextEntry->Blink;
  1294. InsertHeadList (nextEntry, &queueEntry->DeviceListEntry);
  1295. } else {
  1296. queue->Busy = TRUE;
  1297. inserted = FALSE;
  1298. }
  1299. KeReleaseSpinLockFromDpcLevel (&queue->Lock);
  1300. return inserted;
  1301. }
  1302. #if PASSWORD_SUPPORT
  1303. NTSTATUS
  1304. Sbp2GetExclusiveValue(
  1305. IN PDEVICE_OBJECT PhysicalDeviceObject,
  1306. OUT PULONG Exclusive
  1307. )
  1308. {
  1309. NTSTATUS ntStatus = STATUS_SUCCESS;
  1310. HANDLE RootHandle = NULL;
  1311. UNICODE_STRING uniTempName;
  1312. // set default value...
  1313. *Exclusive = EXCLUSIVE_FLAG_CLEAR;
  1314. uniTempName.Buffer = NULL;
  1315. ntStatus = IoOpenDeviceRegistryKey( PhysicalDeviceObject,
  1316. PLUGPLAY_REGKEY_DEVICE,
  1317. KEY_ALL_ACCESS,
  1318. &RootHandle
  1319. );
  1320. if (!NT_SUCCESS(ntStatus)) {
  1321. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1322. goto Exit_Sbp2GetExclusiveValue;
  1323. }
  1324. uniTempName.Length = 0;
  1325. uniTempName.MaximumLength = 128;
  1326. uniTempName.Buffer = ExAllocatePool(
  1327. NonPagedPool,
  1328. uniTempName.MaximumLength
  1329. );
  1330. if (!uniTempName.Buffer) {
  1331. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1332. goto Exit_Sbp2GetExclusiveValue;
  1333. }
  1334. {
  1335. PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
  1336. ULONG KeyLength;
  1337. ULONG ResultLength;
  1338. KeyLength = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + sizeof (ULONG);
  1339. KeyInfo = ExAllocatePool (NonPagedPool, KeyLength);
  1340. if (KeyInfo == NULL) {
  1341. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1342. goto Exit_Sbp2GetExclusiveValue;
  1343. }
  1344. RtlZeroMemory(uniTempName.Buffer, uniTempName.MaximumLength);
  1345. uniTempName.Length = 0;
  1346. RtlAppendUnicodeToString(&uniTempName, L"Exclusive");
  1347. ntStatus = ZwQueryValueKey( RootHandle,
  1348. &uniTempName,
  1349. KeyValuePartialInformation,
  1350. KeyInfo,
  1351. KeyLength,
  1352. &ResultLength
  1353. );
  1354. if (NT_SUCCESS(ntStatus)) {
  1355. *Exclusive = *((PULONG) &KeyInfo->Data);
  1356. DEBUGPRINT1 (("Sbp2Port: GetExclVal: excl=x%x\n", *Exclusive));
  1357. } else {
  1358. DEBUGPRINT1((
  1359. "Sbp2Port: GetExclVal: QueryValueKey err=x%x\n",
  1360. ntStatus
  1361. ));
  1362. }
  1363. ExFreePool (KeyInfo);
  1364. }
  1365. Exit_Sbp2GetExclusiveValue:
  1366. if (RootHandle) {
  1367. ZwClose (RootHandle);
  1368. }
  1369. if (uniTempName.Buffer) {
  1370. ExFreePool (uniTempName.Buffer);
  1371. }
  1372. return ntStatus;
  1373. }
  1374. NTSTATUS
  1375. Sbp2SetExclusiveValue(
  1376. IN PDEVICE_OBJECT PhysicalDeviceObject,
  1377. IN PULONG Exclusive
  1378. )
  1379. {
  1380. NTSTATUS ntStatus = STATUS_SUCCESS;
  1381. HANDLE RootHandle = NULL;
  1382. UNICODE_STRING uniTempName;
  1383. uniTempName.Buffer = NULL;
  1384. ntStatus = IoOpenDeviceRegistryKey( PhysicalDeviceObject,
  1385. PLUGPLAY_REGKEY_DEVICE,
  1386. KEY_ALL_ACCESS,
  1387. &RootHandle
  1388. );
  1389. if (!NT_SUCCESS(ntStatus)) {
  1390. goto Exit_Sbp2SetExclusiveValue;
  1391. }
  1392. uniTempName.Length = 0;
  1393. uniTempName.MaximumLength = 128;
  1394. uniTempName.Buffer = ExAllocatePool(
  1395. NonPagedPool,
  1396. uniTempName.MaximumLength
  1397. );
  1398. if (!uniTempName.Buffer) {
  1399. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1400. goto Exit_Sbp2SetExclusiveValue;
  1401. }
  1402. RtlZeroMemory (uniTempName.Buffer, uniTempName.MaximumLength);
  1403. uniTempName.Length = 0;
  1404. RtlAppendUnicodeToString(&uniTempName, L"Exclusive");
  1405. ntStatus = ZwSetValueKey( RootHandle,
  1406. &uniTempName,
  1407. 0,
  1408. REG_DWORD,
  1409. Exclusive,
  1410. sizeof(ULONG)
  1411. );
  1412. if (!NT_SUCCESS(ntStatus)) {
  1413. DEBUGPRINT1(("Sbp2Port: SetExclVal: SetValueKey err=x%x\n", ntStatus));
  1414. *Exclusive = 0;
  1415. }
  1416. else {
  1417. DEBUGPRINT1(("Sbp2Port: SetExclVal: excl=x%x\n", *Exclusive));
  1418. }
  1419. Exit_Sbp2SetExclusiveValue:
  1420. if (RootHandle) {
  1421. ZwClose(RootHandle);
  1422. }
  1423. if (uniTempName.Buffer) {
  1424. ExFreePool(uniTempName.Buffer);
  1425. }
  1426. return ntStatus;
  1427. }
  1428. #endif