[MTHCA] (trial fix) reset Tavor without using HAL functions. for WHQL tests.
[mirror/winof/.git] / hw / mthca / kernel / mt_reset_tavor.c
1 #include <initguid.h>
2 #include <wdmguid.h>
3 #include "hca_driver.h"
4 #include "mthca.h"
5 #include "hca_debug.h"
6 #include "Mt_l2w.h"
7 #if defined(EVENT_TRACING)
8 #ifdef offsetof
9 #undef offsetof
10 #endif
11 #include "mt_reset_tavor.tmh"
12 #endif
13
14
15 #pragma warning(disable : 4996)
16
17 /* limitations */
18 #define N_BUSES                         16              /* max number of PCI buses */
19 #define N_DEVICES                       32              /* max number of devices on one bus */
20 #define N_FUNCTIONS             8                       /* max number of functions on one device */
21 #define N_CARDS                         8                       /* max number of HCA cards */
22
23 /*----------------------------------------------------------------*/
24
25 PWCHAR 
26 WcharFindChar(
27         IN      PWCHAR          pi_BufStart,
28         IN      PWCHAR          pi_BufEnd,
29         IN      WCHAR           pi_FromPattern,
30         IN      WCHAR           pi_ToPattern
31         )
32 /*++
33
34 Routine Description:
35     Converts wide-character string into ASCII
36
37 Arguments:
38
39         pi_BufStart.......... start of the source string
40         pi_BufEnd............ end of the source string
41         pi_FromPattern....... start of pattern range to find
42         pi_ToPattern......... end of pattern range to find
43
44 Return Value:
45
46         pointer to the first pattern found or NULL (when reached the end)
47
48 --*/
49 { /* WcharFindChar */
50
51         PWCHAR  l_pResult       = pi_BufStart;
52
53         while (l_pResult < pi_BufEnd )
54         {
55                 if (*l_pResult >= pi_FromPattern && *l_pResult <= pi_ToPattern)
56                         return l_pResult;
57                 l_pResult++;
58         }
59
60         return NULL;
61
62 } /* WcharFindChar */
63
64
65 /*----------------------------------------------------------------*/
66
67 /*
68  * Function: MdGetDevLocation
69  *
70  * Parameters:
71  *              IN              pi_pPdo                 - PDO of a device in question
72  *              OUT     po_pBus                 - pointer to the bus number of the device in question
73  *              OUT     po_pDevFunc     - pointer to dev/func of the device, if found
74  * 
75  * Returns:
76  *              not STATUS_SUCCESS      - the device location was not found
77  *      STATUS_SUCCESS          - the device location was found and returned in OUT parameters
78  *
79  * Description:
80  *              The function uses IoGetDeviceProperty to get the location of a device with given PDO
81  *                      
82  */
83 static NTSTATUS 
84 MdGetDevLocation(
85         IN      PDEVICE_OBJECT  pi_pPdo,
86         OUT     ULONG *                 po_pBus,
87         OUT ULONG        *                      po_pDevFunc 
88         )
89 {
90         ULONG   l_BusNumber, l_DevNumber, l_Function, l_ResultLength = 0;
91         WCHAR   l_Buffer[40], *l_pEnd, *l_pBuf = l_Buffer, *l_pBufEnd = l_Buffer + sizeof(l_Buffer);
92         NTSTATUS        l_Status;
93         UNICODE_STRING  l_UnicodeNumber;
94
95         /* prepare */
96         l_ResultLength = 0;
97         RtlZeroMemory( l_Buffer, sizeof(l_Buffer) );
98
99         /* Get the device number  */
100         l_Status = IoGetDeviceProperty(pi_pPdo,
101                 DevicePropertyLocationInformation, sizeof(l_Buffer), l_Buffer, &l_ResultLength);
102
103         /* Verify if the function was successful */
104         if ( !NT_SUCCESS(l_Status) || !l_ResultLength ) {
105                 HCA_PRINT( TRACE_LEVEL_ERROR  ,HCA_DBG_SHIM  ,("(MdGetDevLocation) Unable to get device number: Status 0x%x, ResultSize %d \n", 
106                         l_Status, l_ResultLength  ));
107                 goto exit;      
108         }
109
110         // ALL THE BELOW CRAP WE DO INSTEAD OF 
111         // sscanf(l_Buffer, "PCI bus %d, device %d, function %d", &l_BusNumber, &l_DevNumber, &l_Function );
112
113         /* take bus number */
114         l_pBuf  = WcharFindChar( l_pBuf, l_pBufEnd, L'0', L'9' );
115         if (l_pBuf == NULL) goto err;
116         l_pEnd  = WcharFindChar( l_pBuf, l_pBufEnd, L',', L',' );
117         if (l_pEnd == NULL) goto err;
118         l_UnicodeNumber.Length = l_UnicodeNumber.MaximumLength = (USHORT)((PCHAR)l_pEnd - (PCHAR)l_pBuf);
119         l_UnicodeNumber.Buffer = l_pBuf; l_pBuf = l_pEnd;
120         RtlUnicodeStringToInteger( &l_UnicodeNumber, 10, &l_BusNumber);
121
122         /* take slot number */
123         l_pBuf  = WcharFindChar( l_pBuf, l_pBufEnd, L'0', L'9' );
124         if (l_pBuf == NULL) goto err;
125         l_pEnd  = WcharFindChar( l_pBuf, l_pBufEnd, L',', L',' );
126         if (l_pEnd == NULL) goto err;
127         l_UnicodeNumber.Length = l_UnicodeNumber.MaximumLength = (USHORT)((PCHAR)l_pEnd - (PCHAR)l_pBuf);
128         l_UnicodeNumber.Buffer = l_pBuf; l_pBuf = l_pEnd;
129         RtlUnicodeStringToInteger( &l_UnicodeNumber, 10, &l_DevNumber);
130
131         /* take function number */
132         *(l_Buffer + (l_ResultLength>>1)) = 0;  /* set end of string */
133         l_pBuf  = WcharFindChar( l_pBuf, l_pBufEnd, L'0', L'9' );
134         if (l_pBuf == NULL) goto err;
135         l_pEnd  = WcharFindChar( l_pBuf, l_pBufEnd, 0, 0 );
136         if (l_pEnd == NULL) goto err;
137         l_UnicodeNumber.Length = l_UnicodeNumber.MaximumLength = (USHORT)((PCHAR)l_pEnd - (PCHAR)l_pBuf);
138         l_UnicodeNumber.Buffer = l_pBuf; l_pBuf = l_pEnd;
139         RtlUnicodeStringToInteger( &l_UnicodeNumber, 10, &l_Function);
140
141         /* return the results */
142         *po_pBus                = l_BusNumber;
143         *po_pDevFunc = (l_DevNumber & 0x01f) | ((l_Function & 7) << 5);
144
145         goto exit;
146
147 err:
148         l_Status = STATUS_UNSUCCESSFUL;
149 exit:
150         return l_Status;
151 }
152
153 #ifdef USE_HAL
154 /*----------------------------------------------------------------*/
155
156 /*
157  * Function: PciFindDeviceByBusAndId
158  *
159  * Parameters:
160  *              IN                      pi_Bus                          - a bus, to start the scan
161  *              IN                      pi_DevId                        - Device Id to search
162  *              INOUT   po_pDevFunc     - pointer to dev/func, from which to start the search
163  * 
164  * Returns:
165  *              FALSE   - device not found
166  *      TRUE    - a device was found;  *po_pDevFunc contains its location
167  *
168  * Description:
169  *      The function is intended for iterative search on one bus.
170  *              It looks for the device of pi_DevId id, starting from device with  
171  *              *po_pDevFunc location. When it finds the next device of that id, it updates  
172  *              *po_pDevFunc with the found device' location
173  *
174  */
175 BOOLEAN PciFindDeviceByBusAndId( 
176         IN      ULONG           pi_Bus, 
177         IN      ULONG           pi_DevId, 
178         IN OUT PULONG   po_pDevFunc )
179 {
180         ULONG   l_DevId;
181         ULONG   l_Bytes;
182         ULONG   l_Device;
183         ULONG l_Function; 
184
185         // calculate, where to start the search
186         l_Device = *po_pDevFunc & 0x01f;
187         l_Function = (*po_pDevFunc >> 5) & 7;
188         for (; l_Device < N_DEVICES; l_Device++, l_Function = 0 ) {
189                 for (; l_Function < N_FUNCTIONS; l_Function++ ) {
190                 l_Bytes = HalGetBusDataByOffset(
191                         PCIConfiguration,
192                         pi_Bus,
193                                 l_Device |(l_Function<<5),
194                         (PVOID)&l_DevId,
195                         0,
196                         sizeof(ULONG)
197                         );
198                 if (l_Bytes != sizeof(ULONG)) 
199                                 continue;       /* as if - "not found" */
200                         if (l_DevId == pi_DevId)
201                                 goto ExitFound;
202                 }
203         }
204         return FALSE;
205         
206 ExitFound:              
207         *po_pDevFunc = l_Device |(l_Function<<5);
208         return TRUE;
209 }
210
211 /*----------------------------------------------------------------*/
212
213 /*
214  * Function: PciFindDeviceById
215  *
216  * Parameters:
217  *              IN                      pi_DevId                        - Device Id to search
218  *              INOUT   po_pBus                 - pointer to bus number, from which to start the search
219  *              INOUT   po_pDevFunc     - pointer to dev/func, from which to start the search
220  * 
221  * Returns:
222  *              FALSE   - device was not found
223  *      TRUE    - a device was found;  *po_pBus/*po_pDevFunc contain its location
224  *
225  * Description:
226  *      The function is intended for an iterative search.
227  *              It looks for the device of pi_DevId id, starting from device with *po_pBus and 
228  *              *po_pDevFunc location. When it finds the next device of that id, updates *po_pBus 
229  *              and *po_pDevFunc with the found device' location
230  *
231  */
232 static 
233 BOOLEAN PciFindDeviceById( 
234         IN      ULONG           pi_DevId, 
235         IN OUT PULONG           po_pBus, 
236         IN OUT PULONG           po_pDevFunc )
237 {
238         ULONG l_Bus;
239         ULONG l_DevFunc = *po_pDevFunc;
240         
241         for (l_Bus= *po_pBus; l_Bus < N_BUSES; l_Bus++, l_DevFunc=0) {
242                 if (PciFindDeviceByBusAndId(l_Bus, pi_DevId, &l_DevFunc))
243                         break;
244         }
245         if (l_Bus >= N_BUSES)
246                 return FALSE;
247         
248         // found
249         *po_pBus = l_Bus;
250         *po_pDevFunc = l_DevFunc;
251         return TRUE;
252 }
253
254 /*----------------------------------------------------------------*/
255
256 /*
257  * Function: PciFindBridgeByBus
258  *
259  * Parameters:
260  *              IN              pi_SecBus               - bus number of an HCA in question
261  *              OUT     po_pBus                 - pointer to bus number of the bridge of the HCA, if found
262  *              OUT     po_pDevFunc     - pointer to dev/func of the bridge of the HCA, if found
263  * 
264  * Returns:
265  *              FALSE   - the bridge not found
266  *      TRUE    - a device was found;  *po_pBus/*po_pDevFunc contain its location
267  *
268  * Description:
269  *              The function scans all the buses to find the Bridge of an HCA device, found on bus pi_SecBus. 
270  *              The appropiate bridge must have its PrimaryBus field in PCI cfg header equal to pi_SecBus.
271  *                      
272  */
273 static BOOLEAN PciFindBridgeByBus( 
274         IN ULONG                pi_SecBus, 
275         OUT PULONG              po_pBus, 
276         OUT PULONG              po_pDevFunc )
277 {
278         ULONG   l_DevFunc=0, l_Bus=0;
279         ULONG l_DevId = ((int)(23110) << 16) | PCI_VENDOR_ID_MELLANOX;  
280         ULONG l_SecBus, l_tmp, l_Bytes;
281         ULONG   l_Device;
282         ULONG l_Function; 
283         int searching =1;
284
285         while (searching) {
286                 /* look for a bridge */
287                 if (!PciFindDeviceById(l_DevId, &l_Bus, &l_DevFunc)) 
288                         return FALSE;   /* bridge not found */
289                 
290                 /* found a bridge  -check, whether it is ours */
291        l_Bytes = HalGetBusDataByOffset(
292                 PCIConfiguration,
293                 l_Bus,
294                 l_DevFunc,
295                 (PVOID)&l_tmp,
296                 24,     /* 24 - PrimaryBus, 25 - SecondaryBus, 26 - SubordinateBus */
297                 sizeof(ULONG)
298                 );
299        if (l_Bytes != sizeof(ULONG)) 
300                         goto NextDevice;        /* as if - "not found" */
301                          
302                 l_SecBus = (l_tmp >> 16) & 255;
303                 if ( l_SecBus == pi_SecBus )
304                         break; /* found !!! */
305                 
306 NextDevice:             
307                 // calculate, where to continue the search
308                 l_Device = l_DevFunc & 0x01f;
309                 l_Function = (l_DevFunc >> 5) & 7;
310                 l_Function++;
311                 if (l_Function >= N_FUNCTIONS) {
312                         l_Function = 0;
313                         l_Device++;
314                         if (l_Device >= N_DEVICES) {
315                                 l_Device = 0;
316                                 l_Bus++;
317                         }
318                         if (l_Bus >= N_BUSES)
319                                 return FALSE;
320                 }
321                 l_DevFunc = l_Device |(l_Function<<5);;
322         }
323         
324         *po_pBus = l_Bus;
325         *po_pDevFunc = l_DevFunc;
326         return TRUE;
327 }
328
329
330 /*------------------------------------------------------------------------------------------------------*/
331
332 /*
333  * Function: PciFindPdoByPdoAndLocation
334  *
335  * Parameters:
336  *              IN              pi_pPdo                 - PDO of HCA's bus device
337  *              IN      pi_Bus, pi_DevFunc      - bridge location
338  *              OUT     po_pPdo                 - pointer to PDO of the bridge, when found
339  * 
340  * Returns:
341  *              FALSE   - the bridge was not found
342  *      TRUE    - a device was found;  *po_pPdo contains its PDO
343  *
344  * Description:
345  *              The function finds PDO of a Tavor bridge device by scanning through all the 
346  *              devices of the PCI.SYS driver   
347  *
348  *      Note:
349  *              It is a "hack" algorithm. It uses some fields of system structures and some
350  *              optimistic assumptions - see more below
351  */
352 static BOOLEAN PciFindPdoByPdoAndLocation(
353         IN PDEVICE_OBJECT pi_pPdo,
354         IN ULONG                pi_Bus, 
355         IN ULONG                pi_DevFunc,
356         OUT PDEVICE_OBJECT * po_pPdo )
357 {
358         PDRIVER_OBJECT l_pDrv;
359         PDEVICE_OBJECT l_pPdo;
360         NTSTATUS l_Status;
361         ULONG   l_Bus, l_DevFunc;
362         // suppose that there is no more than N_PCI_DEVICES, belonging to PCI.SYS
363         #define N_PCI_DEVICES   256
364         // suppose that the PDO objects, once created, never get moved
365         PDEVICE_OBJECT *pdo;
366         int i, n_pdos = 0;
367         KIRQL irql;
368         int l_all_pdos = 0;
369
370         
371         pdo = (PDEVICE_OBJECT *)ExAllocatePoolWithTag(
372                 NonPagedPool,
373                 N_PCI_DEVICES * sizeof(PDEVICE_OBJECT),
374                 MT_TAG_KERNEL );
375         if (!pdo)
376                 return FALSE;
377         
378         // suppose, that PDOs are added only at PASSIVE_LEVEL
379         irql = KeRaiseIrqlToDpcLevel();
380                 
381         // get to the PCI.SYS driver
382         l_pDrv = pi_pPdo->DriverObject;
383
384         // find and store all bus PDO   s (because the bridge is a bus enumerated device)
385         for ( l_pPdo = l_pDrv->DeviceObject; l_pPdo; l_pPdo = l_pPdo->NextDevice ) {
386                 l_all_pdos++;
387                 if ( l_pPdo->Flags & DO_BUS_ENUMERATED_DEVICE ) {
388                         pdo[n_pdos] = l_pPdo;
389                         if (++n_pdos >= N_PCI_DEVICES)
390                                 break;
391                 }
392         }
393
394         // return to previous level
395         KeLowerIrql(irql);
396         //TBD: change TRACE_LEVEL_ERROR to TRACE_LEVEL_INFORMATION      
397         HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SHIM ,("Found %d PCI.SYS's PDOs (from %d)\n", n_pdos, l_all_pdos ));
398         
399         //  loop over all the PCI driver devices
400         l_pPdo = NULL;  /* mark, that we didn't find PDO */
401         for ( i = 0; i < n_pdos; ++i ) {
402                 // get the location of the device of that PDO
403                 l_Status = MdGetDevLocation( pdo[i], &l_Bus, &l_DevFunc );
404                 if (l_Status != STATUS_SUCCESS)
405                         continue;
406                 // check, whether it's our device
407                 if (l_Bus == pi_Bus && l_DevFunc == pi_DevFunc) {
408                         l_pPdo = pdo[i];
409                         break;
410                 }
411         }
412
413         *po_pPdo = l_pPdo;
414         ExFreePool(pdo);
415         return (BOOLEAN)!!*po_pPdo;     
416 }
417
418
419 /*------------------------------------------------------------------------------------------------------*/
420
421 /*
422  * Function: FindBridgeIf
423  *
424  * Parameters:
425  *              IN              pi_ext                          - device extension
426  *              OUT     pi_pInterface   - bus interface to work with the bridge
427  * 
428  * Returns:
429  *              FALSE   - the bridge was not found
430  *      TRUE    - a device was found;  *po_pPdo contains its PDO
431  *
432  * Description:
433  *              The function finds PDO of the bridge by HCA's bus number
434  *                      
435  */
436 int
437 FindBridgeIf_old(
438         IN hca_dev_ext_t                *pi_ext,
439         IN      PBUS_INTERFACE_STANDARD pi_pInterface
440         )
441 {
442         NTSTATUS rc;
443         IO_STACK_LOCATION l_Iosl;
444         PDEVICE_RELATIONS l_pDr;
445         PDEVICE_OBJECT                  l_pPdo;
446         ULONG l_DevFunc, l_Bus;
447         // parameter buffer for the request
448         IO_STACK_LOCATION l_Stack;
449
450         // find bridge location
451         if (!PciFindBridgeByBus( pi_ext->bus_number,  &l_Bus, &l_DevFunc ))
452                 return FALSE;
453         
454         // find PDO of our bus driver (bypassing possible low filter drivers)
455         RtlZeroMemory( &l_Iosl, sizeof(l_Iosl) );
456         l_Iosl.Parameters.QueryDeviceRelations.Type = TargetDeviceRelation;
457         rc = SendAwaitIrp(
458                 pi_ext->cl_ext.p_self_do,
459                 pi_ext->cl_ext.p_next_do,
460                 IRP_MJ_PNP,
461                 IRP_MN_QUERY_DEVICE_RELATIONS,
462                 &l_Iosl.Parameters,
463                 sizeof(l_Iosl.Parameters.QueryDeviceRelations),
464                 &l_pDr
465                  );
466         
467         if (!NT_SUCCESS (rc)) {
468                 HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_SHIM ,("IRP_MN_QUERY_DEVICE_RELATIONS failed (%#x);: Fdo %p, Ldo %p \n",
469                         rc, pi_ext->cl_ext.p_self_do, pi_ext->cl_ext.p_next_do ));
470                 return FALSE;
471         }
472                 
473         //TBD: change TRACE_LEVEL_ERROR to TRACE_LEVEL_INFORMATION      
474         HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SHIM ,("IRP_MN_QUERY_DEVICE_RELATIONS for Fdo %p, Ldo %p: num_of_PDOs %d, PDO %p \n",
475                 pi_ext->cl_ext.p_self_do, pi_ext->cl_ext.p_next_do, l_pDr->Count, l_pDr->Objects[0] ));
476         
477         /* get the PDO of Bridge */
478         if (!PciFindPdoByPdoAndLocation( l_pDr->Objects[0], 
479                 l_Bus, l_DevFunc, &l_pPdo )) {
480                 HCA_PRINT( TRACE_LEVEL_ERROR  ,HCA_DBG_SHIM  ,("Not found bridge's (bus %d, dev/func %x. pdo %p) PDO - can't restore the PCI header \n",
481                                 l_Bus, l_DevFunc, l_pDr->Objects[0] ));
482                 return FALSE;
483         } 
484         //TBD: change TRACE_LEVEL_ERROR to TRACE_LEVEL_INFORMATION      
485         HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_SHIM ,("Found bridge's PDO %p (bus %d, dev/func %x. HcaPdo %p) \n",
486                 l_pPdo, l_Bus, l_DevFunc, l_pDr->Objects[0] ));
487                 
488         // clean interface data
489         RtlZeroMemory( (PCHAR)pi_pInterface, sizeof(BUS_INTERFACE_STANDARD) );
490         
491         // fill request parameters
492         l_Stack.Parameters.QueryInterface.InterfaceType                 = (LPGUID) &GUID_BUS_INTERFACE_STANDARD;
493         l_Stack.Parameters.QueryInterface.Size                                  = sizeof(BUS_INTERFACE_STANDARD);
494         l_Stack.Parameters.QueryInterface.Version                               = 1;
495         l_Stack.Parameters.QueryInterface.Interface                     = (PINTERFACE)pi_pInterface;
496         l_Stack.Parameters.QueryInterface.InterfaceSpecificData = NULL;
497         
498         rc =SendAwaitIrp( pi_ext->cl_ext.p_self_do, l_pPdo, IRP_MJ_PNP, 
499                 IRP_MN_QUERY_INTERFACE, &l_Stack.Parameters, sizeof(l_Stack.Parameters), NULL);
500         if (!NT_SUCCESS (rc)) 
501                 return FALSE;
502
503         return TRUE;
504 }
505
506 #endif
507
508 /*----------------------------------------------------------------*/
509
510 /* Function: SendAwaitIrpCompletion
511  *              
512  *  Parameters:
513  *
514  *  Description:
515  *              IRP completion routine 
516  *
517  *  Returns:
518  *              pointer to the entry on SUCCESS
519  *              NULL - otherwise
520  *
521 */ 
522 static
523 NTSTATUS
524 SendAwaitIrpCompletion (
525     IN PDEVICE_OBJECT   DeviceObject,
526     IN PIRP             Irp,
527     IN PVOID            Context
528     )
529 {
530     UNREFERENCED_PARAMETER (DeviceObject);    
531     UNREFERENCED_PARAMETER (Irp);    
532     KeSetEvent ((PKEVENT) Context, IO_NO_INCREMENT, FALSE);
533     return STATUS_MORE_PROCESSING_REQUIRED; // Keep this IRP
534 }
535
536 /*------------------------------------------------------------------------------------------------------*/
537
538 /*
539  *  Function: SendAwaitIrp
540  *
541  *  Description:
542  *              Create and send IRP stack down the stack and wait for the response (Blocking Mode)
543  *
544  *  Parameters:
545  *              pi_pDeviceExt.......... ointer to USB device extension
546  *              pi_MajorCode........... IRP major code
547  *              pi_MinorCode........... IRP minor code
548  *              pi_pBuffer............. parameter buffer
549  *              pi_nSize............... size of the buffer
550  *    po_pInfo.............. returned field Information from IoStatus block
551  *
552  *  Returns:
553  *              pointer to the entry on SUCCESS
554  *              NULL - otherwise
555  *
556 */
557 static 
558 NTSTATUS 
559 SendAwaitIrp(
560         IN  PDEVICE_OBJECT              pi_pFdo,
561         IN  PDEVICE_OBJECT              pi_pLdo,
562         IN  ULONG                               pi_MajorCode,
563         IN  ULONG                               pi_MinorCode,
564         IN      PVOID                           pi_pBuffer,
565         IN      int                                     pi_nSize,
566         OUT     PVOID           *               po_pInfo
567    )
568 /*++
569
570  Routine Description: 
571
572         Create and send IRP stack down the stack and wait for the response (
573 Blocking Mode)
574
575  Arguments: 
576  
577         pi_pFdo................ our device
578         pi_pLdo................ lower device
579         pi_MajorCode........... IRP major code
580         pi_MinorCode........... IRP minor code
581         pi_pBuffer............. parameter buffer
582         pi_nSize............... size of the buffer
583
584  Returns: 
585  
586         standard NTSTATUS return codes.
587
588  Notes:
589
590 --*/
591 { /* SendAwaitIrp */
592         // Event
593         KEVENT                          l_hEvent;
594         // Pointer to IRP
595         PIRP                            l_pIrp;
596         // Stack location
597         PIO_STACK_LOCATION      l_pStackLocation;
598         // Returned status
599         NTSTATUS                        l_Status;
600         // when to invoke
601         BOOLEAN InvokeAlways = TRUE;
602
603         // call validation
604         if(KeGetCurrentIrql() != PASSIVE_LEVEL)
605                 return STATUS_SUCCESS;
606
607         // create event
608         KeInitializeEvent(&l_hEvent, NotificationEvent, FALSE);
609
610         // build IRP request to USBD driver
611         l_pIrp = IoAllocateIrp( pi_pFdo->StackSize, FALSE );
612
613         // validate request
614         if (!l_pIrp)
615         {
616             //MdKdPrint( DBGLVL_MAXIMUM, ("(SendAwaitIrp) Unable to allocate IRP !\n"));
617                 return STATUS_INSUFFICIENT_RESOURCES;
618         }
619
620         // fill IRP
621         l_pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
622
623         // set completion routine
624     IoSetCompletionRoutine(l_pIrp,SendAwaitIrpCompletion, &l_hEvent, InvokeAlways, InvokeAlways, InvokeAlways);
625
626         // fill stack location
627     l_pStackLocation = IoGetNextIrpStackLocation(l_pIrp);
628     l_pStackLocation->MajorFunction= (UCHAR)pi_MajorCode;
629     l_pStackLocation->MinorFunction= (UCHAR)pi_MinorCode;
630         RtlCopyMemory( &l_pStackLocation->Parameters, pi_pBuffer, pi_nSize );
631
632         // Call lower driver perform request
633         l_Status = IoCallDriver( pi_pLdo, l_pIrp ); 
634
635         // if the request not performed --> wait
636         if (l_Status == STATUS_PENDING)
637         {
638                 // Wait until the IRP  will be complete
639                 KeWaitForSingleObject(
640                         &l_hEvent,                                                              // event to wait for
641                         Executive,                                                              // thread type (to wait into its context)
642                         KernelMode,                                                     // mode of work
643                         FALSE,                                                                  // alertable
644                         NULL                                                                    // timeout
645                 );
646                 l_Status = l_pIrp->IoStatus.Status;
647         }
648
649         if (po_pInfo)
650                 *po_pInfo = (PVOID)l_pIrp->IoStatus.Information;
651
652     IoFreeIrp(l_pIrp);
653         return l_Status;
654
655 } /* SendAwaitIrp */
656
657
658 /*------------------------------------------------------------------------------------------------------*/
659
660 /*
661  * Function: FindBridgeIf_new
662  *
663  * Parameters:
664  *              IN              pi_pPdo                 - PDO of HCA's bus device
665  *              IN      pi_Bus, pi_DevFunc      - bridge location
666  *              OUT     po_pPdo                 - pointer to PDO of the bridge, when found
667  * 
668  * Returns:
669  *              FALSE   - the bridge was not found
670  *      TRUE    - a device was found;  *po_pPdo contains its PDO
671  *
672  * Description:
673  *              The function finds and opens the bus interface for Tavor HCA
674  *
675  * Algorithm:
676  *      1. find all PDOs of PCI.SYS driver and save it into an array;
677  *      2. For each PDO open its bus i/f and check whether it is our bridge;
678  *
679  *      Note:
680  *              1. It is a "hack" algorithm. It uses some fields of system structures and some
681  *              optimistic assumptions - see more below
682  *              2. We dangerously assume, that during part to of the algoritm no PDO will removed or added !
683  */
684 int
685 FindBridgeIf_new(
686         IN hca_dev_ext_t                *pi_ext,
687         OUT PBUS_INTERFACE_STANDARD     pi_pInterface
688         )
689 {
690         NTSTATUS l_Status;
691         int rc = FALSE; /* result - "not found" by default */
692         int n_pdos = 0;                 /* number of PCI.SYS's PDOs */
693         PDEVICE_OBJECT *pdo;    /* an array of PCI.SYS's PDOs */
694         PDEVICE_OBJECT l_pHcaPdo;
695
696         { // get HCA's bus PDO
697                 IO_STACK_LOCATION l_Iosl;
698                 PDEVICE_RELATIONS l_pDr;
699
700                 // find PDO of our bus driver (bypassing possible low filter drivers)
701                 RtlZeroMemory( &l_Iosl, sizeof(l_Iosl) );
702                 l_Iosl.Parameters.QueryDeviceRelations.Type = TargetDeviceRelation;
703                 l_Status = SendAwaitIrp(
704                         pi_ext->cl_ext.p_self_do,
705                         pi_ext->cl_ext.p_next_do,
706                         IRP_MJ_PNP,
707                         IRP_MN_QUERY_DEVICE_RELATIONS,
708                         &l_Iosl.Parameters,
709                         sizeof(l_Iosl.Parameters.QueryDeviceRelations),
710                         &l_pDr
711                          );
712                 
713                 if (!NT_SUCCESS (l_Status)) {
714                         HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_SHIM ,("IRP_MN_QUERY_DEVICE_RELATIONS for TargetDeviceRelation failed (%#x);: Fdo %p, Ldo %p \n",
715                                 l_Status, pi_ext->cl_ext.p_self_do, pi_ext->cl_ext.p_next_do ));
716                         goto exit;
717                 }
718
719                 //TBD: change TRACE_LEVEL_ERROR to TRACE_LEVEL_INFORMATION      
720                 HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SHIM ,("IRP_MN_QUERY_DEVICE_RELATIONS for TargetDeviceRelation for Fdo %p, Ldo %p: num_of_PDOs %d, PDO %p \n",
721                         pi_ext->cl_ext.p_self_do, pi_ext->cl_ext.p_next_do, l_pDr->Count, l_pDr->Objects[0] ));
722                 l_pHcaPdo = l_pDr->Objects[0];
723         }
724
725         { // allocate and fill an array with all PCI.SYS PDO devices
726                 // suppose that there is no more than N_PCI_DEVICES, belonging to PCI.SYS
727                 #define N_PCI_DEVICES   256
728                 KIRQL irql;
729                 PDRIVER_OBJECT l_pDrv;
730                 PDEVICE_OBJECT l_pPdo;
731                 int l_all_pdos = 0;
732         
733                 pdo = (PDEVICE_OBJECT *)ExAllocatePoolWithTag(
734                         NonPagedPool,
735                         N_PCI_DEVICES * sizeof(PDEVICE_OBJECT),
736                         MT_TAG_KERNEL );
737                 if (!pdo)
738                         goto exit;
739                 
740                 // suppose, that PDOs are added only at PASSIVE_LEVEL
741                 irql = KeRaiseIrqlToDpcLevel();
742                         
743                 // get to the PCI.SYS driver
744                 l_pDrv = l_pHcaPdo->DriverObject;
745
746                 // find and store all bus PDO   s (because the bridge is a bus enumerated device)
747                 for ( l_pPdo = l_pDrv->DeviceObject; l_pPdo; l_pPdo = l_pPdo->NextDevice ) {
748                         l_all_pdos++;
749                         if ( l_pPdo->Flags & DO_BUS_ENUMERATED_DEVICE ) {
750                                 pdo[n_pdos] = l_pPdo;
751                                 if (++n_pdos >= N_PCI_DEVICES) {
752                                         HCA_PRINT( TRACE_LEVEL_ERROR ,HCA_DBG_SHIM ,
753                                                 ("There are more than %d children of PCI.SYS. Skipping the rest \n", N_PCI_DEVICES ));
754                                         break;
755                                 }
756                         }
757                 }
758
759                 // return to previous level
760                 KeLowerIrql(irql);
761                 //TBD: change TRACE_LEVEL_ERROR to TRACE_LEVEL_INFORMATION      
762                 HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_SHIM ,("Found %d PCI.SYS's PDOs (from %d) \n", n_pdos, l_all_pdos ));
763         }
764
765         { // Find PDO of the Bridge of our HCA and return open bus interface to it
766                 int i;
767                 ULONG data, l_SecBus;
768                 IO_STACK_LOCATION l_Stack; // parameter buffer for the request
769                 ULONG l_DevId = ((int)(23110) << 16) | PCI_VENDOR_ID_MELLANOX;  
770
771                 //  loop over all the PCI driver devices
772                 for ( i = 0; i < n_pdos; ++i ) {
773
774                         // clean interface data
775                         RtlZeroMemory( (PCHAR)pi_pInterface, sizeof(BUS_INTERFACE_STANDARD) );
776                         
777                         // get Bus Interface for the current PDO
778                         l_Stack.Parameters.QueryInterface.InterfaceType                 = (LPGUID) &GUID_BUS_INTERFACE_STANDARD;
779                         l_Stack.Parameters.QueryInterface.Size                                  = sizeof(BUS_INTERFACE_STANDARD);
780                         l_Stack.Parameters.QueryInterface.Version                               = 1;
781                         l_Stack.Parameters.QueryInterface.Interface                     = (PINTERFACE)pi_pInterface;
782                         l_Stack.Parameters.QueryInterface.InterfaceSpecificData = NULL;
783                         
784                         l_Status =SendAwaitIrp( pi_ext->cl_ext.p_self_do, pdo[i], IRP_MJ_PNP, 
785                                 IRP_MN_QUERY_INTERFACE, &l_Stack.Parameters, sizeof(l_Stack.Parameters), NULL);
786                         if (!NT_SUCCESS (l_Status)) {
787                                 //TBD: change TRACE_LEVEL_ERROR to TRACE_LEVEL_WARNING  
788                                 HCA_PRINT( TRACE_LEVEL_ERROR  ,HCA_DBG_SHIM  ,
789                                         ("Failed to get bus interface for pdo[%d] %p, error %#x \n", i, pdo[i], l_Status ));
790                                 continue;
791                         }
792
793                         // Read DevID
794                         data = 0;
795                         if (4 != pi_pInterface->GetBusData( pi_pInterface->Context,
796                                 PCI_WHICHSPACE_CONFIG, &data, 0, 4)) {
797                                 //TBD: change TRACE_LEVEL_ERROR to TRACE_LEVEL_WARNING  
798                                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, 
799                                         ("Failed to read DevID for pdo[%d] %p, data %#x \n", i, pdo[i], data ));
800                                 goto next_loop;
801                         }
802
803                         if (data != l_DevId) {
804                                 //TBD: change TRACE_LEVEL_ERROR to TRACE_LEVEL_INFORMATION      
805                                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, 
806                                         ("Not Tavor bridge: pdo[%d] %p, data %#x \n", i, pdo[i], data ));
807                                 goto next_loop;
808                         }
809
810                         // Found Tavor Bridge - read its SecondaryBus
811                         data = 0;
812                         if (4 != pi_pInterface->GetBusData( pi_pInterface->Context,
813                                 PCI_WHICHSPACE_CONFIG, &data, 24, 4)) { /* 24 - PrimaryBus, 25 - SecondaryBus, 26 - SubordinateBus */
814                                 //TBD: change TRACE_LEVEL_ERROR to TRACE_LEVEL_WARNING  
815                                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, 
816                                         ("Failed to read SecondaryBus for pdo[%d] %p, data %#x \n", i, pdo[i], data ));
817                                 goto next_loop;
818                         }
819
820                         l_SecBus = (data >> 16) & 255;
821                         if (l_SecBus != pi_ext->bus_number) {
822                                 //TBD: change TRACE_LEVEL_ERROR to TRACE_LEVEL_INFORMATION      
823                                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, 
824                                         ("Wrong bridge for our HCA: pdo[%d] %p, SecBus %d, HcaBus %d \n", i, pdo[i], l_SecBus, pi_ext->bus_number ));
825                                 goto next_loop;
826                         }
827                         else {
828                                 ULONG l_DevFunc, l_Bus;
829                                 l_Status = MdGetDevLocation( pdo[i], &l_Bus, &l_DevFunc );
830                                 //TBD: change TRACE_LEVEL_ERROR to TRACE_LEVEL_WARNING  
831                                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, 
832                                         ("Found bridge for our HCA: pdo[%d] %p (bus %d, dev/func %d, HcaPdo %p), SecBus %d, HcaBus %d \n", 
833                                         i, pdo[i], l_Bus, l_DevFunc, l_pHcaPdo, l_SecBus, pi_ext->bus_number ));
834                                 rc = TRUE;
835                                 break;
836                         }
837                 next_loop:      
838                         pi_pInterface->InterfaceDereference( pi_pInterface->Context );
839                 }
840         }
841
842         ExFreePool(pdo);
843 exit:   
844         return rc;      
845 }
846
847 /*----------------------------------------------------------------*/
848
849 int
850 FindBridgeIf(
851         IN hca_dev_ext_t                *pi_ext,
852         IN      PBUS_INTERFACE_STANDARD pi_pInterface
853         )
854 {
855         int rc;
856
857 #ifdef USE_HAL
858
859         rc = FindBridgeIf_old(pi_ext,pi_pInterface);
860         if (rc) {
861                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, ("Old way works !\n"));
862         }
863         else {
864                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, ("Old way fails !\n"));
865         }
866
867 #else
868
869         rc = FindBridgeIf_new(pi_ext,pi_pInterface);
870         if (rc) {
871                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, ("New way works !\n"));
872         }
873         else {
874                 HCA_PRINT( TRACE_LEVEL_ERROR, HCA_DBG_PNP, ("New way fails !\n"));
875         }
876
877 #endif  
878
879         return rc;
880 }