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.

1441 lines
36 KiB

  1. // Copyright (c) 1998-1999, Microsoft Corporation, all rights reserved
  2. //
  3. // send.c
  4. //
  5. // IEEE1394 mini-port/call-manager driver
  6. //
  7. // Mini-port Send routines
  8. //
  9. // 05/15/1999 ADube Created,
  10. //
  11. #include <precomp.h>
  12. //-----------------------------------------------------------------------------
  13. // Local prototypes (alphabetically)
  14. //-----------------------------------------------------------------------------
  15. extern ULONG NdisBufferAllocated[NoMoreCodePaths];
  16. extern ULONG NdisBufferFreed[NoMoreCodePaths];
  17. NDIS_STATUS
  18. nicGetIsochDescriptors(
  19. IN UINT Num,
  20. OUT PPISOCH_DESCRIPTOR ppIsochDescriptor
  21. );
  22. NDIS_STATUS
  23. nicInitializeIsochDescriptor (
  24. IN PCHANNEL_VCCB pChannelVc,
  25. IN PMDL pMdl,
  26. IN PISOCH_DESCRIPTOR pIsochDesriptor
  27. );
  28. VOID
  29. nicIsochRxCallback (
  30. IN PVOID Context1,
  31. IN PVOID Context2
  32. );
  33. ULONG ReassemblyCompleted = 0;
  34. //-----------------------------------------------------------------------------
  35. // prototypes implementations (alphabetically)
  36. //-----------------------------------------------------------------------------
  37. NDIS_STATUS
  38. nicAllocateAndInitializeIsochDescriptors (
  39. IN PCHANNEL_VCCB pChannelVc,
  40. IN UINT NumDescriptors,
  41. IN UINT BufferLength,
  42. IN OUT PPISOCH_DESCRIPTOR ppIsochDescriptor
  43. )
  44. // Function Description:
  45. // This function allocate and initializes a
  46. // a numer of isoch descriptors all allocated
  47. // together.
  48. // This should allocate isoch desc,
  49. // get local memory, get mdls
  50. // initialize mdl, isoch _desc and then return
  51. //
  52. //
  53. // Arguments
  54. // ChannelVc- this contains all the other argumernts, size
  55. // num of descriptors,etc
  56. // ppIsochDescriptor- will contain the pointer to the allocated
  57. // array of IsochDescriptor
  58. //
  59. //
  60. // Return Value:
  61. // Success if all the memory allocations succeeded
  62. //
  63. //
  64. //
  65. {
  66. NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
  67. UINT Size;
  68. UINT index =0;
  69. PMDL pMdl = NULL;
  70. PVOID pLocalBuffer = NULL;
  71. TRACE( TL_T, TM_Recv, ( "==>nicAllocateAndInitializeIsochDescriptors Vc %.8x, Num %.8x",
  72. pChannelVc, NumDescriptors) );
  73. TRACE( TL_V, TM_Recv, ( "Max BuffferSize %.8x", pChannelVc, BufferLength) );
  74. do
  75. {
  76. NdisStatus = nicGetIsochDescriptors (NumDescriptors, ppIsochDescriptor);
  77. if (NdisStatus != NDIS_STATUS_SUCCESS)
  78. {
  79. BREAK ( TM_Recv, "nicGetIsochDescriptors FAILED" );
  80. }
  81. ASSERT (*ppIsochDescriptor != NULL);
  82. while (index < NumDescriptors)
  83. {
  84. //
  85. // Get a local that point to the isoch descriptor that needs to be initialized
  86. //
  87. PISOCH_DESCRIPTOR pIsochDescriptor = NULL;
  88. pIsochDescriptor = (PISOCH_DESCRIPTOR)((ULONG_PTR)(*ppIsochDescriptor)+ index*sizeof(ISOCH_DESCRIPTOR));
  89. //
  90. // Get Locally owned memory for the data
  91. //
  92. NdisStatus = nicGetLocalBuffer (BufferLength, &pLocalBuffer);
  93. if (NdisStatus != NDIS_STATUS_SUCCESS)
  94. {
  95. BREAK ( TM_Recv, ( "nicGetLocalBuffer FAILED " ) );
  96. }
  97. //
  98. // Get an MDL and initialze the MDL with the buffer
  99. //
  100. NdisStatus = nicGetMdl ( BufferLength,
  101. pLocalBuffer,
  102. &pMdl);
  103. if (NdisStatus != NDIS_STATUS_SUCCESS)
  104. {
  105. BREAK ( TM_Recv, ( "nicGetMdl FAILED " ) );
  106. }
  107. //
  108. // this reference will be removed when the MDL will be freed
  109. // in FreeSingleIsochDescriptor
  110. //
  111. nicReferenceCall ((PVCCB)pChannelVc, "nicAllocateAndInitializeIsochDescriptors " );
  112. NdisStatus = nicInitializeIsochDescriptor (pChannelVc,
  113. pMdl,
  114. pIsochDescriptor);
  115. if (NdisStatus != NDIS_STATUS_SUCCESS)
  116. {
  117. BREAK ( TM_Recv, ( "nicInitializeIsochDescriptor FAILED " ) );
  118. }
  119. index++;
  120. }
  121. } while (FALSE);
  122. TRACE( TL_T, TM_Recv, ( "==>nicAllocateAndInitializeIsochDescriptors Status %.8x", NdisStatus) );
  123. return NdisStatus;
  124. }
  125. NDIS_STATUS
  126. nicFreeIsochDescriptors(
  127. IN UINT Num,
  128. IN PISOCH_DESCRIPTOR pIsochDescriptor,
  129. IN PVCCB pVc
  130. )
  131. // Function Description:
  132. // Free Num number of IsochDescriptors
  133. //
  134. // Arguments
  135. // Num number of descriptors
  136. // Start of the allocated memory
  137. //
  138. //
  139. // Return Value:
  140. // Success if all the memory allocations succeeded
  141. //
  142. {
  143. NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
  144. PISOCH_DESCRIPTOR pCurrDesc = pIsochDescriptor;
  145. UINT i=0;
  146. TRACE( TL_T, TM_Recv, ( "==>nicFreeIsochDescriptors Num %.8x, pIsochDescriptor %x", Num, pIsochDescriptor ) );
  147. do
  148. {
  149. if (pIsochDescriptor == NULL)
  150. {
  151. break;
  152. }
  153. pCurrDesc = pIsochDescriptor;
  154. while (i < Num)
  155. {
  156. nicFreeSingleIsochDescriptor( pCurrDesc, pVc);
  157. pCurrDesc = (PISOCH_DESCRIPTOR)((PUCHAR)pCurrDesc + sizeof(ISOCH_DESCRIPTOR));
  158. i++;
  159. }
  160. FREE_NONPAGED (pIsochDescriptor);
  161. } while (FALSE);
  162. NdisStatus = NDIS_STATUS_SUCCESS;
  163. TRACE( TL_T, TM_Recv, ( "<==nicGetIsochDescriptors Status %.8x", NdisStatus ) );
  164. return NdisStatus;
  165. }
  166. NDIS_STATUS
  167. nicFreeSingleIsochDescriptor(
  168. IN PISOCH_DESCRIPTOR pIsochDescriptor,
  169. IN PVCCB pVc
  170. )
  171. // Function Description:
  172. // Free IsochDescriptor and its MDL
  173. //
  174. // Arguments
  175. // Start of the isochDesc
  176. //
  177. //
  178. // Return Value:
  179. // Success if all the memory allocations succeeded
  180. //
  181. {
  182. NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
  183. PCHANNEL_VCCB pChannelVc = pIsochDescriptor->Context1;
  184. ASSERT (pVc == (PVCCB)pChannelVc);
  185. TRACE( TL_T, TM_Recv, ( "==>nicFreeSingleIsochDescriptor pIsochDescriptor %x", pIsochDescriptor ) );
  186. //
  187. // Lets make sure we have a VC and Channel VC
  188. //
  189. ASSERT (pChannelVc->Hdr.ulTag == MTAG_VCCB );
  190. //
  191. // Just to protect ourselves against a bad isoch descriptor
  192. //
  193. if (pIsochDescriptor->Mdl != NULL)
  194. {
  195. PVOID pVa = MmGetMdlVirtualAddress(pIsochDescriptor->Mdl);
  196. ULONG Length = MmGetMdlByteCount(pIsochDescriptor->Mdl);
  197. nicDereferenceCall ((PVCCB)pChannelVc, "nicFreeSingleIsochDescriptors ");
  198. nicFreeMdl (pIsochDescriptor->Mdl);
  199. nicFreeLocalBuffer(Length, pVa);
  200. }
  201. else
  202. {
  203. ASSERT (pIsochDescriptor->Mdl != NULL);
  204. }
  205. NdisStatus = NDIS_STATUS_SUCCESS;
  206. TRACE( TL_T, TM_Recv, ( "<==nicFreeSingleIsochDescriptors Status %.8x", NdisStatus ) );
  207. return NdisStatus;
  208. }
  209. NDIS_STATUS
  210. nicGetIsochDescriptors(
  211. IN UINT Num,
  212. OUT PPISOCH_DESCRIPTOR ppIsochDescriptor
  213. )
  214. // Function Description:
  215. // The function returns a block of contigious memory of size
  216. // Num * sizeof (ISOCH_DESCRIPTOR)
  217. //
  218. //
  219. // Arguments
  220. // Num number of descriptors
  221. // Start of the allocated memory
  222. //
  223. //
  224. // Return Value:
  225. // Success if all the memory allocations succeeded
  226. //
  227. {
  228. NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
  229. PVOID pMemory = NULL;
  230. TRACE( TL_T, TM_Recv, ( "==>nicGetIsochDescriptors Num %.8x", Num) );
  231. pMemory = ALLOC_NONPAGED (Num*sizeof(ISOCH_DESCRIPTOR), MTAG_CBUF );
  232. if (pMemory != NULL)
  233. {
  234. NdisStatus = NDIS_STATUS_SUCCESS;
  235. *ppIsochDescriptor = (PISOCH_DESCRIPTOR)pMemory;
  236. }
  237. else
  238. {
  239. *ppIsochDescriptor = NULL;
  240. TRACE( TL_A, TM_Recv, ( "<==nicGetIsochDescriptors About to Fail") );
  241. ASSERT (*ppIsochDescriptor != NULL);
  242. }
  243. TRACE( TL_T, TM_Recv, ( "<==nicGetIsochDescriptors Status %.8x, StartAddress %.8x", NdisStatus , *ppIsochDescriptor) );
  244. return NdisStatus;
  245. }
  246. NDIS_STATUS
  247. nicInitializeIsochDescriptor (
  248. IN PCHANNEL_VCCB pChannelVc,
  249. IN PMDL pMdl,
  250. IN OUT PISOCH_DESCRIPTOR pIsochDescriptor
  251. )
  252. // Function Description:
  253. // Initializes the Isoch_desciptor using the fields in
  254. // the Channel Vc Block and the Mdl
  255. //
  256. // Arguments
  257. // ChannelVc- Pointer to the Channel Vc which will own
  258. // Descriptor, also contains information
  259. // pMdl- The IsochDescriptor will get a pointer to this Mdl
  260. // pIsochDescriptor - is the descriptor whose fields will get
  261. // initialized
  262. //
  263. // Return Value:
  264. // Success if all the memory allocations succeeded
  265. //
  266. {
  267. NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
  268. TRACE( TL_T, TM_Recv, ( "==>nicInitializeIsochDescriptor Vc %.8x, Mdl ", pChannelVc, pMdl) );
  269. pIsochDescriptor->fulFlags = DESCRIPTOR_SYNCH_ON_TAG;
  270. //
  271. // Mdl pointing to buffer
  272. //
  273. pIsochDescriptor->Mdl = pMdl;
  274. //
  275. // Length of combined buffer(s) as represented by the Mdl
  276. //
  277. pIsochDescriptor->ulLength = MmGetMdlByteCount(pMdl);
  278. //
  279. // Payload size of each Isoch packet to be used in this descriptor
  280. //
  281. pIsochDescriptor->nMaxBytesPerFrame = MmGetMdlByteCount(pMdl);
  282. //
  283. // Synchronization field; equivalent to Sy in the Isoch packet
  284. //
  285. pIsochDescriptor->ulSynch= 0;
  286. //
  287. // Synchronization field; equivalent to Tag in the Isoch packet.
  288. //
  289. pIsochDescriptor->ulTag = g_IsochTag;
  290. //
  291. // Cycle time field; returns time to be sent/received or when finished
  292. //
  293. // (ULONG)pIsochDescriptor->CycleTime=0;
  294. //
  295. // Callback routine (if any) to be called when this descriptor completes
  296. //
  297. pIsochDescriptor->Callback = nicIsochRxCallback;
  298. //
  299. // First context (if any) parameter to be passed when doing callbacks
  300. //
  301. pIsochDescriptor->Context1 = pChannelVc;
  302. //
  303. // Second context (if any) parameter to be passed when doing callbacks
  304. //
  305. pIsochDescriptor->Context2 = pIsochDescriptor;
  306. //
  307. // Holds the final status of this descriptor. Assign a bogus value
  308. //
  309. pIsochDescriptor->status = STATUS_INFO_LENGTH_MISMATCH;
  310. NdisStatus = NDIS_STATUS_SUCCESS;
  311. TRACE( TL_T, TM_Recv, ( "<==nicInitializeIsochDescriptors Status %.8x, IsochDesc %.8x", NdisStatus, pIsochDescriptor) );
  312. return NdisStatus;
  313. }
  314. VOID
  315. nicIsochRxCallback (
  316. PVOID Context1,
  317. PVOID Context2
  318. )
  319. /*++
  320. Routine Description:
  321. This is the callback routine passed to bus driver
  322. This function does some channel specific work and calls the common callback routine
  323. Arguments:
  324. Context1 - pChannel Vc
  325. Context2 - pIsochDescriptor2
  326. Return Value:
  327. --*/
  328. {
  329. PISOCH_DESCRIPTOR pIsochDescriptor = (PISOCH_DESCRIPTOR)Context2;
  330. PVCCB pVc = (PVCCB) Context1;
  331. MARK_ISOCH_DESCRIPTOR_INDICATED (pIsochDescriptor);
  332. STORE_CHANNELVC_IN_DESCRIPTOR (pIsochDescriptor, pVc );
  333. NdisInterlockedIncrement (&((PCHANNEL_VCCB)pVc)->NumIndicatedIsochDesc);
  334. CLEAR_DESCRIPTOR_NEXT (pIsochDescriptor);
  335. pIsochDescriptor->Mdl->Next = NULL;
  336. nicReceiveCommonCallback (pIsochDescriptor ,
  337. pVc,
  338. IsochReceive,
  339. pIsochDescriptor->Mdl);
  340. }
  341. VOID
  342. nicReceiveCommonCallback (
  343. IN PVOID pIndicatedStruct,
  344. IN PVCCB pVc,
  345. BUS_OPERATION RecvOp,
  346. PMDL pMdl
  347. )
  348. /*++
  349. Routine Description:
  350. This function is the common receive code for Isoch and Fifo Recv
  351. It allocate an NdisBuffer that points to the Ip1394 data
  352. If packet is complete (i.e reassembly is complete) , then it allocates an ndis packet
  353. and indicates it up to Ndis
  354. Arguments:
  355. pIndicatedStruct - Isoch Desc. or Address fifo,
  356. pVc - VC on which data was indicated,
  357. RecvOp - Isoch or Fifo,
  358. pMdl - Mdl associated with the Isoch Desc or Fifo.
  359. Passed in seperately for ease of use (debugging)
  360. Return Value:
  361. None
  362. --*/
  363. {
  364. NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
  365. PNDIS1394_REASSEMBLY_STRUCTURE pReassembly = NULL;
  366. NIC_RECV_DATA_INFO RcvInfo;
  367. ULONG DataLength = 0;
  368. BOOLEAN fVcActive = FALSE;
  369. ULONG ulValidDataLength = 0;
  370. PVOID pStartValidData = NULL;
  371. PNDIS_BUFFER pHeadNdisBuffer = NULL;
  372. PADAPTERCB pAdapter = NULL;
  373. BOOLEAN fPacketCompleted = FALSE;
  374. PNDIS_PACKET pMyPacket = NULL;
  375. ULONG PacketLength = 0;
  376. PPKT_CONTEXT pPktContext = NULL;
  377. NDIS_STATUS IndicatedStatus = NDIS_STATUS_FAILURE;
  378. PVOID pIndicatedChain = NULL;
  379. STORE_CURRENT_IRQL;
  380. ASSERT (pMdl != NULL);
  381. ASSERT (RecvOp == IsochReceive || RecvOp == AddressRange);
  382. TRACE( TL_T, TM_Recv, ( "==>nicReceiveCommonCallback pVc %x, IndicatedStruc %x, Mdl %x",
  383. pVc, pIndicatedStruct , pMdl ) );
  384. do
  385. {
  386. if (pVc->Hdr.ulTag != MTAG_VCCB)
  387. {
  388. ASSERT (pVc->Hdr.ulTag == MTAG_VCCB);
  389. NdisStatus = NDIS_STATUS_VC_NOT_ACTIVATED;
  390. break;
  391. }
  392. //
  393. // First, we need to check if we still have an active make call. VC will be present will bus driver
  394. // has buffers
  395. //
  396. fVcActive = VC_ACTIVE (pVc) ;
  397. if (fVcActive == TRUE)
  398. {
  399. pAdapter = pVc->Hdr.pAF->pAdapter;
  400. }
  401. if (fVcActive == FALSE )
  402. {
  403. TRACE( TL_N, TM_Recv, ( "We do not have a valid VC Block %x ",pVc) );
  404. NdisStatus = NDIS_STATUS_VC_NOT_ACTIVATED;
  405. break;
  406. }
  407. NdisStatus = nicValidateRecvData ( pMdl,
  408. RecvOp,
  409. pIndicatedStruct,
  410. pVc ,
  411. &RcvInfo);
  412. if (NdisStatus != NDIS_STATUS_SUCCESS)
  413. {
  414. TRACE (TL_A, TM_Recv, ("Invalid Data Received pMdl %x, RecvOp %x, pVc %x",
  415. pMdl, RecvOp, pVc) );
  416. break;
  417. }
  418. nicDumpMdl (pMdl, RcvInfo.Length1394, "Received Mdl\n");
  419. #ifdef PKT_LOG
  420. {
  421. if (RecvOp == IsochReceive)
  422. {
  423. PPACKET_FORMAT pPacketFormat = (PPACKET_FORMAT)RcvInfo.p1394Data;
  424. GASP_HEADER GaspHeader = pPacketFormat->IsochReceiveNonFragmented.GaspHeader;
  425. GaspHeader.FirstQuadlet.GaspHeaderHigh = SWAPBYTES_ULONG (GaspHeader.FirstQuadlet.GaspHeaderHigh);
  426. NIC1394_LOG_PKT(
  427. pVc->Hdr.pAF->pAdapter,
  428. NIC1394_LOGFLAGS_RECV_CHANNEL,
  429. GaspHeader.FirstQuadlet.u.GH_Source_ID, // SourceID
  430. ((PCHANNEL_VCCB)pVc)->Channel, // DestID
  431. RcvInfo.p1394Data,
  432. RcvInfo.DataLength );
  433. }
  434. else
  435. {
  436. PNOTIFICATION_INFO pNotificationInfo = (PNOTIFICATION_INFO)pIndicatedStruct;
  437. ULONG NodeNumber = ((PASYNC_PACKET)pNotificationInfo->RequestPacket)->AP_Source_ID.NA_Node_Number;
  438. NIC1394_LOG_PKT(
  439. pVc->Hdr.pAF->pAdapter,
  440. NIC1394_LOGFLAGS_RECV_FIFO ,
  441. NodeNumber , // SourceID
  442. pAdapter->BCRData.LocalNodeNumber,
  443. RcvInfo.p1394Data,
  444. RcvInfo.DataLength );
  445. }
  446. }
  447. #endif
  448. //
  449. // Sanity check
  450. //
  451. if (RcvInfo.fFragmented == FALSE)
  452. {
  453. //
  454. // Pack the mdl into an ndispacket and indicate it to Ndis.
  455. // SHOULD BE NDIS_BUFFERS
  456. //
  457. ulValidDataLength = RcvInfo.DataLength;
  458. pStartValidData = (PVOID)RcvInfo.pEncapHeader;
  459. {
  460. PNDIS1394_UNFRAGMENTED_HEADER pEncapHeader = (PNDIS1394_UNFRAGMENTED_HEADER)RcvInfo.pEncapHeader;
  461. if (0x777 == SWAPBYTES_USHORT(pEncapHeader->u1.EtherType))
  462. {
  463. TRACE (TL_N, TM_Recv, ("Received Bridge STA Packet %p\n", pEncapHeader));
  464. }
  465. }
  466. NdisStatus = nicGetNdisBuffer ( ulValidDataLength,
  467. pStartValidData,
  468. &pHeadNdisBuffer);
  469. if (NdisStatus != NDIS_STATUS_SUCCESS)
  470. {
  471. pHeadNdisBuffer = NULL;
  472. break;
  473. }
  474. nicIncRecvBuffer(pVc->Hdr.VcType == NIC1394_RecvFIFO);
  475. pIndicatedChain = RcvInfo.NdisPktContext.pCommon;
  476. fPacketCompleted = TRUE;
  477. }
  478. else // Recv Data is fragemented
  479. {
  480. PREMOTE_NODE pRemoteNode= NULL;
  481. USHORT SourceNodeAddress = 0xff;
  482. //
  483. // First extract all the useful information from the indicated structure, rem node, dgl, first frag, etc
  484. //
  485. nicInitRecvDataFragmented (pMdl, RecvOp, pIndicatedStruct, &RcvInfo);
  486. RcvInfo.pRemoteNode = nicGetRemoteNodeFromTable (RcvInfo.SourceID,pAdapter);
  487. TRACE( TL_T, TM_Recv, ( " pRemoteNode %x", RcvInfo.pRemoteNode) );
  488. //
  489. // If there is no remote node present , break out
  490. //
  491. if (RcvInfo.pRemoteNode == NULL)
  492. {
  493. NdisStatus = NDIS_STATUS_FAILURE;
  494. nicRecvNoRemoteNode (pAdapter);
  495. BREAK (TM_Recv, (" Rx - Did not find a remote Node for reassembly" ) );
  496. }
  497. //
  498. // Try and use the indicated data to reassemble
  499. //
  500. NdisStatus = nicDoReassembly (&RcvInfo, &pReassembly, &fPacketCompleted );
  501. if (NdisStatus != NDIS_STATUS_SUCCESS)
  502. {
  503. TRACE (TL_N, TM_Recv, ("Generic RX - Reassembly Failed") );
  504. break;
  505. }
  506. ASSERT (pReassembly != NULL);
  507. if (fPacketCompleted == TRUE &&
  508. REASSEMBLY_ACTIVE (pReassembly))
  509. {
  510. TRACE( TL_V, TM_Recv, ( " pReassembly->ReassemblyComplete %x ", pReassembly->fReassemblyComplete ) );
  511. pHeadNdisBuffer = pReassembly->pHeadNdisBuffer;
  512. pIndicatedChain = pReassembly->Head.pCommon;
  513. nicReassemblyCompleted(pAdapter);
  514. }
  515. else
  516. {
  517. //
  518. // Do not call the return packet as reassembly is in progress. Dereference the ref made
  519. // when the reaassembly was found in nicFindReassembly...
  520. //
  521. ASSERT (pHeadNdisBuffer == NULL);
  522. NdisStatus = NDIS_STATUS_SUCCESS;
  523. }
  524. ASSERT (NdisStatus == NDIS_STATUS_SUCCESS);
  525. //
  526. // Dereference the ref that was made nicFindReassembly. After this only one thread
  527. // should have the reassembly struct. And there should be one ref on it.
  528. //
  529. nicDereferenceReassembly (pReassembly, "nicIsochRxCallback Reassembly Incomplete");
  530. } // Completed the ifFragmented code
  531. if (RcvInfo.pRemoteNode != NULL)
  532. {
  533. //
  534. // Deref the ref made earlier in the if fragmented code path within this function
  535. //
  536. nicDereferenceRemoteNode(RcvInfo.pRemoteNode , "nicCommonRxCallback - nicGetRemoteNodeFromTable");
  537. RcvInfo.pRemoteNode = NULL;
  538. }
  539. if (fPacketCompleted == FALSE)
  540. {
  541. //
  542. // If the packet is not completely reassembled, then there is no
  543. // more work to be done
  544. //
  545. pReassembly = NULL;
  546. NdisStatus = NDIS_STATUS_SUCCESS;
  547. break;
  548. }
  549. if (pReassembly)
  550. {
  551. ASSERT (pReassembly->Ref == 1);
  552. }
  553. //
  554. // Now we package the data into an NdisPacket
  555. //
  556. nicAllocatePacket (&NdisStatus,
  557. &pMyPacket,
  558. RcvInfo.pPacketPool);
  559. if (NdisStatus != NDIS_STATUS_SUCCESS)
  560. {
  561. pMyPacket = NULL;
  562. ASSERT(NdisStatus == NDIS_STATUS_SUCCESS);
  563. break;
  564. }
  565. //
  566. // Set the NdisBuffer as Head and Tail of the Packet
  567. //
  568. NdisChainBufferAtFront (pMyPacket, pHeadNdisBuffer);
  569. NdisQueryPacket( pMyPacket,
  570. NULL,
  571. NULL,
  572. NULL,
  573. &PacketLength);
  574. TRACE( TL_V, TM_Recv, ( "Packet %x Length %x", pMyPacket, PacketLength ) );
  575. NDIS_SET_PACKET_STATUS (pMyPacket, NDIS_STATUS_SUCCESS);
  576. // Insert the node address if we are in bridge mode
  577. //
  578. if (ADAPTER_TEST_FLAG(pAdapter,fADAPTER_BridgeMode)== TRUE)
  579. {
  580. nicInsertNodeAddressAtHead (pMyPacket, &RcvInfo);
  581. }
  582. //
  583. // Set up the context in the ndis packet . Contains the Vc, and
  584. // the Buffer registered with the bus driver
  585. //
  586. pPktContext = (PPKT_CONTEXT)&pMyPacket->MiniportReserved;
  587. pPktContext->Receive.pVc = pVc;
  588. pPktContext->Receive.IndicatedStruct.pCommon = pIndicatedChain ;
  589. //
  590. // Its time to indicate the packet to NDIS
  591. //
  592. IndicatedStatus = NDIS_GET_PACKET_STATUS(pMyPacket);
  593. nicIndicateNdisPacketToNdis (pMyPacket,
  594. pVc,
  595. pVc->Hdr.pAF->pAdapter);
  596. //
  597. // Dereference the reassembly here . so that pReassembly is valid and it will catch all
  598. // failures prior this
  599. //
  600. if (pReassembly != NULL)
  601. {
  602. //
  603. // This should free the reassembly
  604. //
  605. nicFreeReassemblyStructure (pReassembly);
  606. pReassembly = NULL;
  607. }
  608. } while (FALSE);
  609. ASSERT (IndicatedStatus != NDIS_STATUS_RESOURCES);
  610. if (IndicatedStatus == NDIS_STATUS_RESOURCES)
  611. {
  612. #if QUEUED_PACKETS
  613. //
  614. // Do nothing the queue will complete the packet
  615. //
  616. #else
  617. //
  618. // The packet was completed with a status of resources.
  619. // It is gauranteed to be valid and we need to call the
  620. // return packet handler
  621. //
  622. nicInternalReturnPacket (pVc, pMyPacket);
  623. #endif
  624. }
  625. //
  626. // Failure code path
  627. //
  628. if (NdisStatus != NDIS_STATUS_SUCCESS)
  629. {
  630. //
  631. // if there was a valid reassembly structure and the failure occured after that
  632. // then we need to abort the reaasembly
  633. //
  634. if (pMyPacket)
  635. {
  636. nicFreePacket (pMyPacket, RcvInfo.pPacketPool);
  637. }
  638. //
  639. // There could still be NdisBuffers that are allocated.
  640. //
  641. if (pReassembly != NULL)
  642. {
  643. nicDereferenceReassembly (pReassembly, "Indication failure");
  644. nicAbortReassembly(pReassembly);
  645. }
  646. else
  647. {
  648. //
  649. // We need to return this descriptor or fifo back to the bus driver
  650. //
  651. if (pVc->Hdr.VcType == NIC1394_SendRecvChannel ||
  652. pVc->Hdr.VcType == NIC1394_RecvChannel )
  653. {
  654. nicReturnDescriptorChain ((PISOCH_DESCRIPTOR)pIndicatedStruct,
  655. (PCHANNEL_VCCB) pVc);
  656. }
  657. else
  658. {
  659. ASSERT (pVc->Hdr.VcType == NIC1394_RecvFIFO);
  660. ASSERT (((PNOTIFICATION_INFO)pIndicatedStruct)->Fifo != NULL);
  661. nicReturnFifoChain ( ((PNOTIFICATION_INFO)pIndicatedStruct)->Fifo,
  662. (PRECVFIFO_VCCB) pVc);
  663. }
  664. if (pHeadNdisBuffer != NULL)
  665. {
  666. nicReturnNdisBufferChain(pHeadNdisBuffer, pVc);
  667. }
  668. }
  669. }
  670. TRACE( TL_T, TM_Recv, ( "<==nicReceiveCommonCallback " ) );
  671. }
  672. VOID
  673. nicChannelReturnPacket (
  674. IN PVCCB pVc,
  675. IN PNDIS_PACKET pMyPacket
  676. )
  677. // Function Description:
  678. // Return Packets Handler -
  679. // For FIFO's will reinsert the buffer (MDL) into the Fifo SList
  680. // Check for the VC Active and then return it ot the SList . Free it otherwise
  681. //
  682. // Arguments
  683. // RecvFIFOVc - Vc of the packet
  684. // pPacket = Packet in question
  685. //
  686. // Return Value:
  687. //
  688. //
  689. //
  690. {
  691. PCHANNEL_VCCB pChannelVc = (PCHANNEL_VCCB)pVc;
  692. PNDIS_BUFFER pMyNdisBuffer;
  693. PPKT_CONTEXT pPktContext = (PPKT_CONTEXT)&pMyPacket->MiniportReserved;
  694. PISOCH_DESCRIPTOR pIsochDescriptor = NULL;
  695. TRACE( TL_T, TM_Recv, ( "==>nicChannelReturnPacket pVc %x, pPacket %x",
  696. pChannelVc, pMyPacket) );
  697. ASSERT (pMyPacket != NULL);
  698. NdisUnchainBufferAtFront (pMyPacket,
  699. &pMyNdisBuffer);
  700. while (pMyNdisBuffer != NULL)
  701. {
  702. NdisFreeBuffer(pMyNdisBuffer);
  703. nicDecChannelRecvBuffer();
  704. pMyNdisBuffer = NULL;
  705. NdisUnchainBufferAtFront (pMyPacket,
  706. &pMyNdisBuffer);
  707. }
  708. //
  709. // Return the Descriptors to the bus driver
  710. //
  711. pIsochDescriptor = pPktContext->IsochListen.pIsochDescriptor;
  712. //
  713. // temporary sanity check asserts
  714. //
  715. ASSERT (pIsochDescriptor != NULL);
  716. nicReturnDescriptorChain (pIsochDescriptor, pChannelVc);
  717. //
  718. // Free The packet
  719. //
  720. nicFreePacket(pMyPacket, &pChannelVc->PacketPool);
  721. //
  722. // Update Count
  723. //
  724. //NdisInterlockedDecrement (&pChannelVc->OutstandingPackets ) ;
  725. TRACE( TL_T, TM_Recv, ( "<==nicChannelReturnPacket " ) );
  726. }
  727. VOID
  728. nicReturnDescriptorChain (
  729. IN PISOCH_DESCRIPTOR pIsochDescriptor,
  730. IN PCHANNEL_VCCB pChannelVc
  731. )
  732. {
  733. //
  734. // Walk the list of isoch descriptors and mark them as returned
  735. //
  736. PISOCH_DESCRIPTOR pCurr = NULL;
  737. PVOID pNext = NULL;
  738. PMDL pMdl = NULL;
  739. PVOID pVa = NULL;
  740. ULONG Len = 0;
  741. TRACE( TL_T, TM_Recv, ( "==> nicReturnDescriptorChain pIsochDescriptor %x",pIsochDescriptor ) );
  742. pCurr = pIsochDescriptor ;
  743. while (pCurr != NULL)
  744. {
  745. //ASSERT (pChannelVc == (PCHANNEL_VCCB)GET_CHANNELVC_FROM_DESCRIPTOR(pCurr));
  746. if (pNext != NULL)
  747. {
  748. pCurr = CONTAINING_RECORD (pNext,
  749. ISOCH_DESCRIPTOR,
  750. DeviceReserved[IsochNext] );
  751. }
  752. pNext = (PVOID)NEXT_ISOCH_DESCRIPTOR(pCurr);
  753. TRACE (TL_V, TM_Recv ,(" Isoch Descriptors Curr %x, next %x" , pCurr, pNext) );
  754. CLEAR_DESCRIPTOR_OF_NDIS_TAG(pCurr);
  755. CLEAR_DESCRIPTOR_NEXT(pCurr);
  756. //
  757. // Zero out the data that is being returned to the bus driver
  758. //
  759. #if 0
  760. pMdl = pCurr->Mdl;
  761. pVa = NIC_GET_SYSTEM_ADDRESS_FOR_MDL (pMdl);
  762. if (pVa != NULL)
  763. {
  764. Len = NIC_GET_BYTE_COUNT_FOR_MDL(pMdl);
  765. NdisZeroMemory(pVa, Len);
  766. }
  767. #endif
  768. pCurr = pNext;
  769. //
  770. // Update the count, The close call will wait for this count to go to zero
  771. //
  772. NdisInterlockedDecrement (&pChannelVc->NumIndicatedIsochDesc);
  773. //
  774. // Clear the Variables
  775. //
  776. pMdl = NULL;
  777. pVa = NULL;
  778. Len = 0;
  779. }
  780. TRACE( TL_T, TM_Recv, ( "<== nicReturnDescriptorChain pIsochDescriptor %x",pIsochDescriptor ) );
  781. }
  782. VOID
  783. nicRecvNoRemoteNode(
  784. PADAPTERCB pAdapter
  785. )
  786. /*++
  787. Routine Description:
  788. Queues a work item to go and update the node addresses of all the remote node
  789. Arguments:
  790. Return Value:
  791. --*/
  792. {
  793. NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
  794. TRACE( TL_T, TM_Send, ( "==>nicRecvNoRemoteNode ") );
  795. ASSERT (pAdapter != NULL);
  796. do
  797. {
  798. PNDIS_WORK_ITEM pUpdateTableWorkItem = NULL;
  799. BOOLEAN fWorkItemAlreadyLaunched = FALSE;
  800. //
  801. // We need to update the generation count
  802. //
  803. pUpdateTableWorkItem = ALLOC_NONPAGED (sizeof(NDIS_WORK_ITEM), MTAG_WORKITEM);
  804. if (pUpdateTableWorkItem == NULL)
  805. {
  806. TRACE( TL_A, TM_Cm, ( "Local Alloc failed for WorkItem - GetGeneration FAILED" ) );
  807. break;
  808. }
  809. ADAPTER_ACQUIRE_LOCK (pAdapter);
  810. if (ADAPTER_TEST_FLAGS (pAdapter, fADAPTER_UpdateNodeTable))
  811. {
  812. fWorkItemAlreadyLaunched = TRUE;
  813. }
  814. else
  815. {
  816. ADAPTER_SET_FLAG (pAdapter, fADAPTER_UpdateNodeTable);
  817. //
  818. // Ref the adapter. Deref in workitem
  819. //
  820. nicReferenceAdapter (pAdapter, "nicRecvNoRemoteNode" );
  821. fWorkItemAlreadyLaunched = FALSE;
  822. }
  823. ADAPTER_RELEASE_LOCK (pAdapter);
  824. if (fWorkItemAlreadyLaunched == TRUE)
  825. {
  826. FREE_NONPAGED(pUpdateTableWorkItem);
  827. break;
  828. }
  829. //
  830. // Set the Workitem
  831. //
  832. NdisInitializeWorkItem ( pUpdateTableWorkItem,
  833. (NDIS_PROC)nicUpdateNodeTable,
  834. (PVOID)pAdapter );
  835. NdisInterlockedIncrement(&pAdapter->OutstandingWorkItems);
  836. NdisScheduleWorkItem (pUpdateTableWorkItem);
  837. NdisStatus = NDIS_STATUS_SUCCESS;
  838. } while (FALSE);
  839. TRACE( TL_T, TM_Send, ( "<==nicRecvNoRemoteNode %x", NdisStatus) );
  840. }
  841. VOID
  842. nicUpdateNodeTable(
  843. NDIS_WORK_ITEM* pUpdateTable,
  844. IN PVOID Context
  845. )
  846. /*++
  847. Routine Description:
  848. This is called when the reassembly cannot find
  849. a remote node for reassembly
  850. For simplicity's sake, we go through all 63 entries
  851. We find a remote node, get its address. now the address' entry
  852. in the Node Table may already have another node there, so we take that
  853. node out put the new remote Node in that location. Then we go
  854. and update the node address of that remote node
  855. This is the WorkItem version of nicUpdateRemoteNodeTable
  856. Arguments:
  857. pAdapter Local host
  858. Return Value:
  859. --*/
  860. {
  861. ULONG i = 0;
  862. ULONG NumNodes = 0;
  863. PREMOTE_NODE pRemoteNode = NULL;
  864. NODE_ADDRESS NodeAddress ;
  865. NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
  866. PADAPTERCB pAdapter = (PADAPTERCB)Context;
  867. NdisZeroMemory (&NodeAddress, sizeof(NODE_ADDRESS));
  868. do
  869. {
  870. ADAPTER_ACQUIRE_LOCK (pAdapter);
  871. //
  872. // Get a remote node
  873. //
  874. pRemoteNode = NULL;
  875. while (i<MAX_NUMBER_NODES)
  876. {
  877. pRemoteNode = pAdapter->NodeTable.RemoteNode[i];
  878. if (pRemoteNode != NULL)
  879. {
  880. break;
  881. }
  882. i++;
  883. }
  884. if (pRemoteNode != NULL)
  885. {
  886. nicReferenceRemoteNode (pRemoteNode, "nicVerifyRemoteNodeAddress ");
  887. }
  888. ADAPTER_RELEASE_LOCK (pAdapter);
  889. //
  890. // break out if we are the end of the loop
  891. //
  892. if (i>=MAX_NUMBER_NODES)
  893. {
  894. ASSERT (pRemoteNode == NULL)
  895. break;
  896. }
  897. if (pRemoteNode == NULL)
  898. {
  899. break;
  900. }
  901. i++;
  902. //
  903. // Now update the table. The new location of the Node in the
  904. // NodeTable may already have a Node, so we we will need to
  905. // update that remote node's address as well
  906. //
  907. do
  908. {
  909. PREMOTE_NODE pRemNodeOld = NULL;
  910. nicGet1394AddressOfRemoteNode (pRemoteNode,
  911. &NodeAddress,
  912. 0);
  913. if (NdisStatus != NDIS_STATUS_SUCCESS)
  914. {
  915. //
  916. // Just use the old node address, if it fails
  917. //
  918. NodeAddress = pRemoteNode->RemoteAddress;
  919. }
  920. ADAPTER_ACQUIRE_LOCK (pAdapter);
  921. //
  922. // Extract the occupant of the location
  923. //
  924. pRemNodeOld = pAdapter->NodeTable.RemoteNode[NodeAddress.NA_Node_Number];
  925. //
  926. // Update RemoteNode Address
  927. //
  928. pRemoteNode->RemoteAddress = NodeAddress ;
  929. if (pRemNodeOld == pRemoteNode)
  930. {
  931. //
  932. // The remote nodes are the same, so we do not
  933. // care about the old remote node
  934. //
  935. pRemNodeOld = NULL;
  936. }
  937. //
  938. // Only Reference And Update the Old remoteNode'address
  939. // if it is not our current remote node
  940. //
  941. if ( pRemNodeOld != NULL )
  942. {
  943. //
  944. // This location is already occupied.
  945. // Take it out, reference it and update its address
  946. //
  947. nicReferenceRemoteNode (pRemNodeOld, "nicVerifyRemoteNode");
  948. }
  949. //
  950. // Update the Master Node Table
  951. //
  952. pAdapter->NodeTable.RemoteNode[NodeAddress.NA_Node_Number] = pRemoteNode;
  953. //
  954. // This either derefs' the remote node or pRemNodeOld from a previous interation
  955. //
  956. nicDereferenceRemoteNode (pRemoteNode, "nicVerifyRemoteNode" );
  957. //
  958. // Update pRemoteNode so that it loops again
  959. // and we can update the node addres of this pRemNodeOld
  960. // else it will be null and we exit this loop
  961. //
  962. pRemoteNode = pRemNodeOld;
  963. ADAPTER_RELEASE_LOCK (pAdapter);
  964. } while (pRemoteNode != NULL);
  965. //
  966. // If we have not gone through all the nodes .
  967. // get the next remote node
  968. //
  969. }while (i<MAX_NUMBER_NODES);
  970. ADAPTER_ACQUIRE_LOCK (pAdapter);
  971. ADAPTER_CLEAR_FLAG (pAdapter, fADAPTER_UpdateNodeTable);
  972. ADAPTER_RELEASE_LOCK (pAdapter);
  973. FREE_NONPAGED (pUpdateTable);
  974. NdisInterlockedDecrement(&pAdapter->OutstandingWorkItems);
  975. nicDereferenceAdapter(pAdapter, "nicRecvNoRemoteNode Derefed in nicUpdateNodeTable" );
  976. }
  977. VOID
  978. nicInsertNodeAddressAtHead (
  979. IN PNDIS_PACKET pPacket,
  980. IN PNIC_RECV_DATA_INFO pRcvInfo
  981. )
  982. /*++
  983. Routine Description:
  984. Adds the Node Address to the first 16 bits in the packet.
  985. It fails quietly if it is not able to do so
  986. Arguments:
  987. pPacket pPacket in Question
  988. pRcvInfo -> With the correct Gasp Header
  989. Return Value:
  990. --*/
  991. {
  992. PNDIS1394_UNFRAGMENTED_HEADER pHeader = NULL;
  993. TRACE( TL_T, TM_Recv, ( "nicInsertNodeAddressAtHead , pPacket %x pRecvInfo %x",pPacket, pRcvInfo ) );
  994. do
  995. {
  996. pHeader = nicNdisBufferVirtualAddress (pPacket->Private.Head);
  997. if (pHeader == NULL)
  998. {
  999. break;
  1000. }
  1001. //
  1002. // Assert for now. Will not work if there are 1394 bridges with bus number = 0;
  1003. //
  1004. ASSERT (pRcvInfo->SourceID < 64);
  1005. pHeader->u1.SourceAddress= (UCHAR)(pRcvInfo->SourceID);
  1006. pHeader->u1.fHeaderHasSourceAddress = TRUE;
  1007. } while (FALSE);
  1008. TRACE( TL_T, TM_Recv, ( "nicInsertNodeAddressAtHead , pHeader %x = *pHeader %x", pHeader, pHeader->HeaderUlong ) );
  1009. }