62e87f5ef1e450a4780200fe689c978f844b2fef
[mirror/winof/.git] / core / iou / kernel / iou_ioc_mgr.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  * Portions Copyright (c) 2008 Microsoft Corporation.  All rights reserved.\r
4  *\r
5  * This software is available to you under the OpenIB.org BSD license\r
6  * below:\r
7  *\r
8  *     Redistribution and use in source and binary forms, with or\r
9  *     without modification, are permitted provided that the following\r
10  *     conditions are met:\r
11  *\r
12  *      - Redistributions of source code must retain the above\r
13  *        copyright notice, this list of conditions and the following\r
14  *        disclaimer.\r
15  *\r
16  *      - Redistributions in binary form must reproduce the above\r
17  *        copyright notice, this list of conditions and the following\r
18  *        disclaimer in the documentation and/or other materials\r
19  *        provided with the distribution.\r
20  *\r
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
22  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
24  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
25  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
26  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
27  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
28  * SOFTWARE.\r
29  *\r
30  * $Id$\r
31  */\r
32 \r
33 \r
34 \r
35 #include <iba/ib_types.h>\r
36 #include <complib/cl_async_proc.h>\r
37 #include <complib/cl_bus_ifc.h>\r
38 #include "iou_driver.h"\r
39 #if defined(EVENT_TRACING)\r
40 #ifdef offsetof\r
41 #undef offsetof\r
42 #endif\r
43 #include "iou_ioc_mgr.tmh"\r
44 #endif\r
45 #include "iou_pnp.h"\r
46 #include "iou_ioc_mgr.h"\r
47 #include <initguid.h>\r
48 #include <wdmguid.h>\r
49 #include "iba/ioc_ifc.h"\r
50 \r
51 \r
52 /* {5A9649F4-0101-4a7c-8337-796C48082DA2} */\r
53 DEFINE_GUID(GUID_BUS_TYPE_IBA,\r
54 0x5a9649f4, 0x101, 0x4a7c, 0x83, 0x37, 0x79, 0x6c, 0x48, 0x8, 0x2d, 0xa2);\r
55 \r
56 \r
57 /*\r
58  * Size of device descriptions, as defined in\r
59  *      A1.2.3.1.1 - Creating Compatibility Strings for an I/O Controller\r
60  */\r
61 #define IOC_DEV_ID_SIZE         \\r
62         sizeof(L"IBA\\VxxxxxxPxxxxxxxxSxxxxxxsxxxxxxxxvxxxx")\r
63 #define IOC_HW_ID_SIZE          \\r
64         sizeof(L"IBA\\VxxxxxxPxxxxxxxxSxxxxxxsxxxxxxxxvxxxx") + \\r
65         sizeof(L"IBA\\VxxxxxxPxxxxxxxxSxxxxxxsxxxxxxxx") + \\r
66         sizeof(L"IBA\\VxxxxxxPxxxxxxxxvxxxx") + \\r
67         sizeof(L"IBA\\VxxxxxxPxxxxxxxx\0\0")\r
68 #define IOC_COMPAT_ID_SIZE      \\r
69         sizeof(L"IBA\\Cxxxxcxxxxpxxxxrxxxx") + \\r
70         sizeof(L"IBA\\Cxxxxcxxxxpxxxx\0\0")\r
71 #define IOC_LOCATION_SIZE       \\r
72         sizeof(L"Chassis 0xxxxxxxxxxxxxxxxx, Slot xx, IOC xx")\r
73 \r
74 /*\r
75  * Device extension for IOU PDOs.\r
76  */\r
77 typedef struct _ioc_ext\r
78 {\r
79         iou_pdo_ext_t                   pdo;\r
80 \r
81         ib_ioc_info_t                   info;\r
82         ib_svc_entry_t                  svc_entries[1];\r
83 \r
84 }       ioc_ext_t;\r
85 \r
86 \r
87 /*\r
88  * Function prototypes.\r
89  */\r
90 void\r
91 destroying_ioc_mgr(\r
92         IN                              cl_obj_t*                                       p_obj );\r
93 \r
94 void\r
95 free_ioc_mgr(\r
96         IN                              cl_obj_t*                                       p_obj );\r
97 \r
98 ib_api_status_t\r
99 ioc_mgr_pnp_cb(\r
100         IN                              ib_pnp_rec_t*                           p_pnp_rec );\r
101 \r
102 ib_api_status_t\r
103 ioc_mgr_ioc_add(\r
104         IN                              ib_pnp_ioc_rec_t*                       p_pnp_rec );\r
105 \r
106 void\r
107 ioc_mgr_ioc_remove(\r
108         IN                              ib_pnp_ioc_rec_t*                       p_pnp_rec );\r
109 \r
110 static NTSTATUS\r
111 ioc_start(\r
112         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
113         IN                              IRP* const                                      p_irp,\r
114                 OUT                     cl_irp_action_t* const          p_action );\r
115 \r
116 static void\r
117 ioc_release_resources(\r
118         IN                              DEVICE_OBJECT* const            p_dev_obj );\r
119 \r
120 static NTSTATUS\r
121 ioc_remove(\r
122         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
123         IN                              IRP* const                                      p_irp,\r
124                 OUT                     cl_irp_action_t* const          p_action );\r
125 \r
126 static NTSTATUS\r
127 ioc_surprise_remove(\r
128         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
129         IN                              IRP* const                                      p_irp,\r
130                 OUT                     cl_irp_action_t* const          p_action );\r
131 \r
132 static NTSTATUS\r
133 ioc_query_capabilities(\r
134         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
135         IN                              IRP* const                                      p_irp,\r
136                 OUT                     cl_irp_action_t* const          p_action );\r
137 \r
138 static NTSTATUS\r
139 ioc_query_target_relations(\r
140         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
141         IN                              IRP* const                                      p_irp,\r
142                 OUT                     cl_irp_action_t* const          p_action );\r
143 \r
144 static NTSTATUS\r
145 ioc_query_device_id(\r
146         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
147         IN                              IRP* const                                      p_irp );\r
148 \r
149 static NTSTATUS\r
150 ioc_query_hardware_ids(\r
151         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
152         IN                              IRP* const                                      p_irp );\r
153 \r
154 static NTSTATUS\r
155 ioc_query_compatible_ids(\r
156         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
157         IN                              IRP* const                                      p_irp );\r
158 \r
159 static NTSTATUS\r
160 ioc_query_unique_id(\r
161         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
162         IN                              IRP* const                                      p_irp );\r
163 \r
164 static NTSTATUS\r
165 ioc_query_description(\r
166         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
167         IN                              IRP* const                                      p_irp );\r
168 \r
169 static NTSTATUS\r
170 ioc_query_location(\r
171         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
172         IN                              IRP* const                                      p_irp );\r
173 \r
174 static NTSTATUS\r
175 ioc_query_bus_info(\r
176         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
177         IN                              IRP* const                                      p_irp,\r
178                 OUT                     cl_irp_action_t* const          p_action );\r
179 \r
180 static NTSTATUS\r
181 ioc_query_interface(\r
182         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
183         IN                              IRP* const                                      p_irp,\r
184                 OUT                     cl_irp_action_t* const          p_action );\r
185 \r
186 static NTSTATUS\r
187 ioc_set_power(\r
188         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
189         IN                              IRP* const                                      p_irp,\r
190                 OUT                     cl_irp_action_t* const          p_action );\r
191 \r
192 \r
193 \r
194 /*\r
195  * Global virtual function pointer tables shared between all\r
196  * instances of Port PDOs.\r
197  */\r
198 static const cl_vfptr_pnp_po_t          vfptr_ioc_pnp = {\r
199         "IB IOC",\r
200         ioc_start,\r
201         cl_irp_succeed,\r
202         cl_irp_succeed,\r
203         cl_irp_succeed,\r
204         cl_irp_succeed,\r
205         ioc_release_resources,\r
206         ioc_remove,\r
207         cl_irp_succeed,\r
208         ioc_surprise_remove,\r
209         ioc_query_capabilities,\r
210         cl_irp_complete,\r
211         cl_irp_complete,\r
212         cl_irp_succeed,\r
213         cl_irp_complete,\r
214         cl_irp_complete,\r
215         cl_irp_complete,\r
216         ioc_query_target_relations,\r
217         cl_irp_complete,\r
218         cl_irp_complete,\r
219         cl_irp_complete,\r
220         ioc_query_bus_info,\r
221         ioc_query_interface,\r
222         cl_irp_complete,\r
223         cl_irp_complete,\r
224         cl_irp_complete,\r
225         cl_irp_complete,\r
226         cl_irp_succeed,                         // QueryPower\r
227         ioc_set_power,                          // SetPower\r
228         cl_irp_unsupported,                     // PowerSequence\r
229         cl_irp_unsupported                      // WaitWake\r
230 };\r
231 \r
232 \r
233 static const cl_vfptr_query_txt_t               vfptr_iou_query_txt = {\r
234         ioc_query_device_id,\r
235         ioc_query_hardware_ids,\r
236         ioc_query_compatible_ids,\r
237         ioc_query_unique_id,\r
238         ioc_query_description,\r
239         ioc_query_location\r
240 };\r
241 \r
242 \r
243 void\r
244 ioc_mgr_construct(\r
245         IN      OUT                     ioc_mgr_t* const                        p_ioc_mgr )\r
246 {\r
247         IOU_ENTER( IOU_DBG_PNP );\r
248 \r
249         /* Construct the IOC manager service. */\r
250         cl_obj_construct( &p_ioc_mgr->obj, 0 );\r
251         cl_mutex_construct( &p_ioc_mgr->pdo_mutex );\r
252         cl_qlist_init( &p_ioc_mgr->ioc_list );\r
253 \r
254         IOU_EXIT( IOU_DBG_PNP );\r
255 }\r
256 \r
257 \r
258 ib_api_status_t\r
259 ioc_mgr_init(\r
260         IN      OUT                     ioc_mgr_t* const                        p_ioc_mgr )\r
261 {\r
262         ib_pnp_req_t            pnp_req;\r
263         ib_api_status_t         status;\r
264         cl_status_t                     cl_status;\r
265 \r
266         IOU_ENTER( IOU_DBG_PNP );\r
267 \r
268         cl_status = cl_mutex_init( &p_ioc_mgr->pdo_mutex );\r
269         if( cl_status != CL_SUCCESS )\r
270         {\r
271                 free_ioc_mgr( &p_ioc_mgr->obj );\r
272                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
273                         ("cl_mutex_init returned %#x.\n", cl_status) );\r
274                 return IB_ERROR;\r
275         }\r
276 \r
277         /* Initialize the load service object. */\r
278         cl_status = cl_obj_init( &p_ioc_mgr->obj, CL_DESTROY_SYNC,\r
279                 destroying_ioc_mgr, NULL, free_ioc_mgr );\r
280         if( cl_status != CL_SUCCESS )\r
281         {\r
282                 free_ioc_mgr( &p_ioc_mgr->obj );\r
283                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
284                         ("cl_obj_init returned %#x.\n", cl_status) );\r
285                 return IB_ERROR;\r
286         }\r
287 \r
288         status = p_ioc_mgr->ifc.open_al( &p_ioc_mgr->h_al );\r
289         if( status != IB_SUCCESS )\r
290         {\r
291                 cl_obj_destroy( &p_ioc_mgr->obj );\r
292                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
293                         ("open_al returned %s.\n",\r
294                         p_ioc_mgr->ifc.get_err_str(status)) );\r
295                 return status;\r
296         }\r
297 \r
298         /* Register for IOC PnP events. */\r
299         cl_memclr( &pnp_req, sizeof( ib_pnp_req_t ) );\r
300         pnp_req.pnp_class       = IB_PNP_IOC;\r
301         pnp_req.pnp_context = p_ioc_mgr;\r
302         pnp_req.pfn_pnp_cb      = ioc_mgr_pnp_cb;\r
303 \r
304         status = p_ioc_mgr->ifc.reg_pnp(\r
305                 p_ioc_mgr->h_al, &pnp_req, &p_ioc_mgr->h_pnp );\r
306         if( status != IB_SUCCESS )\r
307         {\r
308                 cl_obj_destroy( &p_ioc_mgr->obj );\r
309                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
310                         ("ib_reg_pnp returned %s.\n",\r
311                         p_ioc_mgr->ifc.get_err_str(status)) );\r
312                 return status;\r
313         }\r
314 \r
315         /* Reference the load service on behalf of the ib_reg_pnp call. */\r
316         cl_obj_ref( &p_ioc_mgr->obj );\r
317 \r
318         IOU_EXIT( IOU_DBG_PNP );\r
319         return IB_SUCCESS;\r
320 }\r
321 \r
322 \r
323 /*\r
324  * Pre-destroy the load service.\r
325  */\r
326 void\r
327 destroying_ioc_mgr(\r
328         IN                              cl_obj_t*                                       p_obj )\r
329 {\r
330         ioc_mgr_t                               *p_ioc_mgr;\r
331         ib_api_status_t                 status;\r
332 \r
333         IOU_ENTER( IOU_DBG_PNP );\r
334 \r
335         CL_ASSERT( p_obj );\r
336 \r
337         p_ioc_mgr = PARENT_STRUCT( p_obj, ioc_mgr_t, obj );\r
338 \r
339         /* Deregister for port PnP events. */\r
340         if( p_ioc_mgr->h_pnp )\r
341         {\r
342                 status = p_ioc_mgr->ifc.dereg_pnp(\r
343                         p_ioc_mgr->h_pnp, (ib_pfn_destroy_cb_t)cl_obj_deref );\r
344                 CL_ASSERT( status == IB_SUCCESS );\r
345         }\r
346         IOU_EXIT( IOU_DBG_PNP );\r
347 }\r
348 \r
349 \r
350 /*\r
351  * Free the load service.\r
352  */\r
353 void\r
354 free_ioc_mgr(\r
355         IN                              cl_obj_t*                                       p_obj )\r
356 {\r
357         ioc_mgr_t               *p_ioc_mgr;\r
358         ioc_ext_t               *p_iou_ext;\r
359         cl_list_item_t  *p_list_item;\r
360 \r
361         IOU_ENTER( IOU_DBG_PNP );\r
362 \r
363         CL_ASSERT( p_obj );\r
364         p_ioc_mgr = PARENT_STRUCT( p_obj, ioc_mgr_t, obj );\r
365 \r
366         /*\r
367          * Mark all IOCs as no longer present.  This will cause them\r
368          * to be removed when they process the IRP_MN_REMOVE_DEVICE.\r
369          */\r
370         p_list_item = cl_qlist_remove_head( &p_ioc_mgr->ioc_list );\r
371         while( p_list_item != cl_qlist_end( &p_ioc_mgr->ioc_list ) )\r
372         {\r
373                 p_iou_ext = PARENT_STRUCT(\r
374                         PARENT_STRUCT( p_list_item, iou_pdo_ext_t, list_item ),\r
375                         ioc_ext_t, pdo );\r
376                 p_list_item = cl_qlist_remove_head( &p_ioc_mgr->ioc_list );\r
377                 if( p_iou_ext->pdo.cl_ext.pnp_state == SurpriseRemoved )\r
378                 {\r
379                         CL_ASSERT( !p_iou_ext->pdo.b_present );\r
380                         p_iou_ext->pdo.b_reported_missing = TRUE;\r
381                         continue;\r
382                 }\r
383                 IoDeleteDevice( p_iou_ext->pdo.cl_ext.p_self_do );\r
384         }\r
385 \r
386         cl_mutex_destroy( &p_ioc_mgr->pdo_mutex );\r
387         cl_obj_deinit( p_obj );\r
388         IOU_EXIT( IOU_DBG_PNP );\r
389 }\r
390 \r
391 \r
392 /*\r
393  * Load service PnP event callback.\r
394  */\r
395 ib_api_status_t\r
396 ioc_mgr_pnp_cb(\r
397         IN                              ib_pnp_rec_t*                           p_pnp_rec )\r
398 {\r
399         ib_api_status_t         status;\r
400         ioc_mgr_t                       *p_ioc_mgr;\r
401 \r
402         IOU_ENTER( IOU_DBG_PNP );\r
403 \r
404         CL_ASSERT( p_pnp_rec );\r
405         p_ioc_mgr = (ioc_mgr_t*)p_pnp_rec->pnp_context;\r
406 \r
407         switch( p_pnp_rec->pnp_event )\r
408         {\r
409         case IB_PNP_IOC_ADD:\r
410                 status = ioc_mgr_ioc_add( (ib_pnp_ioc_rec_t*)p_pnp_rec );\r
411                 break;\r
412 \r
413         case IB_PNP_IOC_REMOVE:\r
414                 ioc_mgr_ioc_remove( (ib_pnp_ioc_rec_t*)p_pnp_rec );\r
415 \r
416         default:\r
417                 status = IB_SUCCESS;\r
418                 break;\r
419         }\r
420         IOU_EXIT( IOU_DBG_PNP );\r
421         return status;\r
422 }\r
423 \r
424 \r
425 /*\r
426  * Called to get child relations for the bus root.\r
427  */\r
428 NTSTATUS\r
429 ioc_mgr_get_iou_relations(\r
430         IN                              ioc_mgr_t* const                        p_ioc_mgr,\r
431         IN                              IRP* const                                      p_irp )\r
432 {\r
433         NTSTATUS                        status;\r
434         size_t                          n_devs;\r
435         DEVICE_RELATIONS        *p_rel;\r
436 \r
437         IOU_ENTER( IOU_DBG_PNP );\r
438 \r
439         /* If there are already relations, copy them. */\r
440         cl_mutex_acquire( &p_ioc_mgr->pdo_mutex );\r
441         n_devs = cl_qlist_count( &p_ioc_mgr->ioc_list );\r
442         if( !n_devs )\r
443         {\r
444                 cl_mutex_release( &p_ioc_mgr->pdo_mutex );\r
445                 IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_PNP,\r
446                         ("No child PDOs.\n") );\r
447                 return STATUS_NO_SUCH_DEVICE;\r
448         }\r
449 \r
450         /* Add space for our child IOUs. */\r
451         status = cl_alloc_relations( p_irp, n_devs );\r
452         if( !NT_SUCCESS( status ) )\r
453         {\r
454                 cl_mutex_release( &p_ioc_mgr->pdo_mutex );\r
455                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
456                         ("cl_alloc_relations returned %08x.\n", status) );\r
457                 return status;\r
458         }\r
459 \r
460         p_rel = (DEVICE_RELATIONS*)p_irp->IoStatus.Information;\r
461         update_relations( &p_ioc_mgr->ioc_list, p_rel );\r
462         cl_mutex_release( &p_ioc_mgr->pdo_mutex );\r
463         IOU_EXIT( IOU_DBG_PNP );\r
464         return STATUS_SUCCESS;\r
465 }\r
466 \r
467 \r
468 ib_api_status_t\r
469 ioc_mgr_ioc_add(\r
470         IN                              ib_pnp_ioc_rec_t*                       p_pnp_rec )\r
471 {\r
472         NTSTATUS                status;\r
473         DEVICE_OBJECT   *p_pdo;\r
474         iou_fdo_ext_t   *p_ext;\r
475         ioc_mgr_t               *p_ioc_mgr;\r
476         ioc_ext_t               *p_ioc_ext;\r
477         uint32_t                ext_size;\r
478 \r
479         IOU_ENTER( IOU_DBG_PNP );\r
480 \r
481         p_ioc_mgr = PARENT_STRUCT( p_pnp_rec->pnp_rec.pnp_context, ioc_mgr_t, obj );\r
482         p_ext = PARENT_STRUCT( p_ioc_mgr, iou_fdo_ext_t, ioc_mgr );\r
483 \r
484         if( p_pnp_rec->ca_guid != p_ioc_mgr->info.ca_guid ||\r
485                 p_pnp_rec->info.chassis_guid != p_ioc_mgr->info.chassis_guid ||\r
486                 p_pnp_rec->info.chassis_slot != p_ioc_mgr->info.slot||\r
487                 p_pnp_rec->info.iou_guid != p_ioc_mgr->info.guid )\r
488         {\r
489                 IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_PNP,\r
490                         ("IOC not in this IOU.\n") );\r
491                 return IB_NOT_DONE;\r
492         }\r
493 \r
494         ext_size = sizeof(ioc_ext_t) +\r
495                 (sizeof(ib_svc_entry_t) * p_pnp_rec->info.profile.num_svc_entries);\r
496 \r
497         /* Create the PDO for the new port device. */\r
498         status = IoCreateDevice( iou_globals.p_driver_obj, ext_size,\r
499                 NULL, FILE_DEVICE_CONTROLLER,\r
500                 FILE_DEVICE_SECURE_OPEN | FILE_AUTOGENERATED_DEVICE_NAME,\r
501                 FALSE, &p_pdo );\r
502         if( !NT_SUCCESS( status ) )\r
503         {\r
504                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
505                         ("IoCreateDevice returned %08x.\n", status) );\r
506                 return IB_ERROR;\r
507         }\r
508 \r
509         /* Initialize the device extension. */\r
510         cl_init_pnp_po_ext( p_pdo, NULL, p_pdo, g_iou_dbg_flags,\r
511                 &vfptr_ioc_pnp, &vfptr_iou_query_txt );\r
512 \r
513         /* Set the DO_BUS_ENUMERATED_DEVICE flag to mark it as a PDO. */\r
514         p_pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;\r
515 \r
516         p_ioc_ext = p_pdo->DeviceExtension;\r
517         p_ioc_ext->pdo.dev_po_state.DeviceState = PowerDeviceD0;\r
518         p_ioc_ext->pdo.p_parent_ext = p_ext;\r
519         p_ioc_ext->pdo.b_present = TRUE;\r
520         p_ioc_ext->pdo.b_reported_missing = FALSE;\r
521         p_ioc_ext->pdo.ca_guid = p_pnp_rec->ca_guid;\r
522                 \r
523         /* Copy the IOC profile and service entries. */\r
524         p_ioc_ext->info = p_pnp_rec->info;\r
525         cl_memcpy( p_ioc_ext->svc_entries, p_pnp_rec->svc_entry_array,\r
526                 p_pnp_rec->info.profile.num_svc_entries );\r
527         /* Make sure the IOC string is null terminated. */\r
528         p_ioc_ext->info.profile.id_string[CTRL_ID_STRING_LEN-1] = '\0';\r
529 \r
530         /* Store the device extension in the PDO list for future queries. */\r
531         cl_mutex_acquire( &p_ioc_mgr->pdo_mutex );\r
532         cl_qlist_insert_tail( &p_ioc_mgr->ioc_list,\r
533                 &p_ioc_ext->pdo.list_item );\r
534         cl_mutex_release( &p_ioc_mgr->pdo_mutex );\r
535 \r
536         /*\r
537          * Set the context of the PNP event.  The context is passed in for future\r
538          * events on the same port.\r
539          */\r
540         p_pnp_rec->pnp_rec.context = p_ioc_ext;\r
541 \r
542         /* Tell the PnP Manager to rescan for bus relations. */\r
543         IoInvalidateDeviceRelations( p_ext->cl_ext.p_pdo, BusRelations );\r
544 \r
545         IOU_EXIT( IOU_DBG_PNP );\r
546         return IB_SUCCESS;\r
547 }\r
548 \r
549 \r
550 void\r
551 ioc_mgr_ioc_remove(\r
552         IN                              ib_pnp_ioc_rec_t*                       p_pnp_rec )\r
553 {\r
554         ioc_mgr_t       *p_ioc_mgr;\r
555         ioc_ext_t       *p_ioc_ext;\r
556 \r
557         IOU_ENTER( IOU_DBG_PNP );\r
558 \r
559         /* The PNP record's context is the IOC's device extension. */\r
560         p_ioc_ext = p_pnp_rec->pnp_rec.context;\r
561         CL_ASSERT( p_ioc_ext );\r
562 \r
563         p_ioc_mgr = &p_ioc_ext->pdo.p_parent_ext->ioc_mgr;\r
564         /*\r
565          * Flag the port IOC as no longer being present.  We have to wait until\r
566          * the PnP manager removes it to clean up.\r
567          */\r
568         cl_mutex_acquire( &p_ioc_mgr->pdo_mutex );\r
569         p_ioc_ext->pdo.b_present = FALSE;\r
570 \r
571         /* Invalidate bus relations for the bus root. */\r
572         IoInvalidateDeviceRelations(\r
573                 p_ioc_ext->pdo.p_parent_ext->cl_ext.p_pdo, BusRelations );\r
574 \r
575         cl_mutex_release( &p_ioc_mgr->pdo_mutex );\r
576 \r
577         IOU_EXIT( IOU_DBG_PNP );\r
578 }\r
579 \r
580 \r
581 static NTSTATUS\r
582 ioc_start(\r
583         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
584         IN                                      IRP* const                              p_irp,\r
585                 OUT                             cl_irp_action_t* const  p_action )\r
586 {\r
587         iou_pdo_ext_t   *p_ext;\r
588 \r
589         IOU_ENTER( IOU_DBG_PNP );\r
590 \r
591         UNUSED_PARAM( p_irp );\r
592 \r
593         p_ext = p_dev_obj->DeviceExtension;\r
594 \r
595         /* Notify the Power Manager that the device is started. */\r
596         PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state );\r
597 \r
598         *p_action = IrpComplete;\r
599         IOU_EXIT( IOU_DBG_PNP );\r
600         return STATUS_SUCCESS;\r
601 }\r
602 \r
603 \r
604 static void\r
605 ioc_release_resources(\r
606         IN                                      DEVICE_OBJECT* const    p_dev_obj )\r
607 {\r
608         ioc_mgr_t               *p_ioc_mgr;\r
609         ioc_ext_t               *p_ext;\r
610         POWER_STATE             po_state;\r
611 \r
612         IOU_ENTER( IOU_DBG_PNP );\r
613 \r
614         p_ext = p_dev_obj->DeviceExtension;\r
615         p_ioc_mgr = &p_ext->pdo.p_parent_ext->ioc_mgr;\r
616 \r
617         /* Remove this PDO from its list. */\r
618         cl_mutex_acquire( &p_ioc_mgr->pdo_mutex );\r
619         IOU_PRINT( TRACE_LEVEL_INFORMATION, IOU_DBG_PNP,\r
620                 ("Removing IOC from list.\n") );\r
621         cl_qlist_remove_item( &p_ioc_mgr->ioc_list, &p_ext->pdo.list_item );\r
622         cl_mutex_release( &p_ioc_mgr->pdo_mutex );\r
623         po_state.DeviceState = PowerDeviceD3;\r
624         PoSetPowerState( p_ext->pdo.cl_ext.p_pdo, DevicePowerState, po_state );\r
625 \r
626         IOU_EXIT( IOU_DBG_PNP );\r
627 }\r
628 \r
629 \r
630 static NTSTATUS\r
631 ioc_remove(\r
632         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
633         IN                                      IRP* const                              p_irp,\r
634                 OUT                             cl_irp_action_t* const  p_action )\r
635 {\r
636         ioc_ext_t       *p_ext;\r
637 \r
638         IOU_ENTER( IOU_DBG_PNP );\r
639 \r
640         p_ext = p_dev_obj->DeviceExtension;\r
641 \r
642         if( p_ext->pdo.b_present )\r
643         {\r
644                 CL_ASSERT( p_ext->pdo.cl_ext.pnp_state != NotStarted );\r
645                 CL_ASSERT( !p_ext->pdo.b_reported_missing );\r
646                 /* Reset the state to NotStarted.  CompLib set it to Deleted. */\r
647                 cl_set_pnp_state( &p_ext->pdo.cl_ext, NotStarted );\r
648                 /* Don't delete the device.  It may simply be disabled. */\r
649                 *p_action = IrpComplete;\r
650                 IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_PNP,\r
651                         ("Device still present.\n") );\r
652                 return STATUS_SUCCESS;\r
653         }\r
654 \r
655         if( !p_ext->pdo.b_reported_missing )\r
656         {\r
657                 /* Reset the state to RemovePending.  Complib set it to Deleted. */\r
658                 cl_rollback_pnp_state( &p_ext->pdo.cl_ext );\r
659                 *p_action = IrpComplete;\r
660                 IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_PNP,\r
661                         ("Device not reported missing yet.\n") );\r
662                 return STATUS_SUCCESS;\r
663         }\r
664 \r
665         /* Wait for all I/O operations to complete. */\r
666         IoReleaseRemoveLockAndWait( &p_ext->pdo.cl_ext.remove_lock, p_irp );\r
667 \r
668         /* Release resources if it was not done yet. */\r
669         if( p_ext->pdo.cl_ext.last_pnp_state != SurpriseRemoved )\r
670                 p_ext->pdo.cl_ext.vfptr_pnp_po->pfn_release_resources( p_dev_obj );\r
671 \r
672         p_irp->IoStatus.Status = STATUS_SUCCESS;\r
673         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
674 \r
675         IoDeleteDevice( p_dev_obj );\r
676 \r
677         *p_action = IrpDoNothing;\r
678         IOU_EXIT( IOU_DBG_PNP );\r
679         return STATUS_SUCCESS;\r
680 }\r
681 \r
682 \r
683 static NTSTATUS\r
684 ioc_surprise_remove(\r
685         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
686         IN                              IRP* const                                      p_irp,\r
687                 OUT                     cl_irp_action_t* const          p_action )\r
688 {\r
689         ioc_ext_t       *p_ext;\r
690 \r
691         IOU_ENTER( IOU_DBG_PNP );\r
692 \r
693         UNUSED_PARAM( p_irp );\r
694 \r
695         p_ext = p_dev_obj->DeviceExtension;\r
696         p_ext->pdo.b_present = FALSE;\r
697         p_ext->pdo.b_reported_missing = TRUE;\r
698 \r
699         *p_action = IrpComplete;\r
700 \r
701         IOU_EXIT( IOU_DBG_PNP );\r
702         return STATUS_SUCCESS;\r
703 }\r
704 \r
705 \r
706 static NTSTATUS\r
707 ioc_query_capabilities(\r
708         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
709         IN                                      IRP* const                              p_irp,\r
710                 OUT                             cl_irp_action_t* const  p_action )\r
711 {\r
712         DEVICE_CAPABILITIES             *p_caps;\r
713         IO_STACK_LOCATION               *p_io_stack;\r
714 \r
715         IOU_ENTER( IOU_DBG_PNP );\r
716 \r
717         UNUSED_PARAM( p_dev_obj );\r
718 \r
719         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
720         p_caps = p_io_stack->Parameters.DeviceCapabilities.Capabilities;\r
721 \r
722         p_caps->DeviceD1 = FALSE;\r
723         p_caps->DeviceD2 = FALSE;\r
724         p_caps->LockSupported = FALSE;\r
725         p_caps->EjectSupported = FALSE;\r
726         p_caps->Removable = TRUE;\r
727         p_caps->DockDevice = FALSE;\r
728         p_caps->UniqueID = TRUE;\r
729         p_caps->SilentInstall = TRUE;\r
730         p_caps->RawDeviceOK = FALSE;\r
731         p_caps->SurpriseRemovalOK = FALSE;\r
732         p_caps->WakeFromD0 = FALSE;\r
733         p_caps->WakeFromD1 = FALSE;\r
734         p_caps->WakeFromD2 = FALSE;\r
735         p_caps->WakeFromD3 = FALSE;\r
736         p_caps->HardwareDisabled = FALSE;\r
737         p_caps->DeviceState[PowerSystemWorking] = PowerDeviceD0;\r
738         p_caps->DeviceState[PowerSystemSleeping1] = PowerDeviceD3;\r
739         p_caps->DeviceState[PowerSystemSleeping2] = PowerDeviceD3;\r
740         p_caps->DeviceState[PowerSystemSleeping3] = PowerDeviceD3;\r
741         p_caps->DeviceState[PowerSystemHibernate] = PowerDeviceD3;\r
742         p_caps->DeviceState[PowerSystemShutdown] = PowerDeviceD3;\r
743         p_caps->SystemWake = PowerSystemUnspecified;\r
744         p_caps->DeviceWake = PowerDeviceUnspecified;\r
745         p_caps->D1Latency = 0;\r
746         p_caps->D2Latency = 0;\r
747         p_caps->D3Latency = 0;\r
748 \r
749         *p_action = IrpComplete;\r
750         IOU_EXIT( IOU_DBG_PNP );\r
751         return STATUS_SUCCESS;\r
752 }\r
753 \r
754 \r
755 static NTSTATUS\r
756 ioc_query_target_relations(\r
757         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
758         IN                                      IRP* const                              p_irp,\r
759                 OUT                             cl_irp_action_t* const  p_action )\r
760 {\r
761         NTSTATUS                        status;\r
762         DEVICE_RELATIONS        *p_rel;\r
763 \r
764         IOU_ENTER( IOU_DBG_PNP );\r
765 \r
766         *p_action = IrpComplete;\r
767 \r
768         status = cl_alloc_relations( p_irp, 1 );\r
769         if( !NT_SUCCESS( status ) )\r
770         {\r
771                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
772                         ("cl_alloc_relations returned 0x%08x.\n", status) );\r
773                 return status;\r
774         }\r
775 \r
776         p_rel = (DEVICE_RELATIONS*)p_irp->IoStatus.Information;\r
777         p_rel->Count = 1;\r
778         p_rel->Objects[0] = p_dev_obj;\r
779 \r
780         ObReferenceObject( p_dev_obj );\r
781 \r
782         IOU_EXIT( IOU_DBG_PNP );\r
783         return status;\r
784 }\r
785 \r
786 \r
787 static NTSTATUS\r
788 ioc_query_device_id(\r
789         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
790                 OUT                             IRP* const                              p_irp )\r
791 {\r
792         NTSTATUS                        status;\r
793         ioc_ext_t                       *p_ext;\r
794         WCHAR                           *p_string;\r
795 \r
796         IOU_ENTER( IOU_DBG_PNP );\r
797 \r
798         p_ext = (ioc_ext_t*)p_dev_obj->DeviceExtension;\r
799         if( !p_ext->pdo.b_present )\r
800         {\r
801                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
802                         ("Device not present.\n") );\r
803                 return STATUS_NO_SUCH_DEVICE;\r
804         }\r
805 \r
806         p_string = ExAllocatePoolWithTag( PagedPool, IOC_DEV_ID_SIZE, 'didq' );\r
807         if( !p_string )\r
808         {\r
809                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
810                         ("Failed to allocate device ID buffer (%d bytes).\n",\r
811                         IOC_DEV_ID_SIZE) );\r
812                 return STATUS_INSUFFICIENT_RESOURCES;\r
813         }\r
814 \r
815         status = RtlStringCbPrintfW( p_string, IOC_DEV_ID_SIZE,\r
816                 L"IBA\\V%06xP%08xS%06xs%08xv%04x",\r
817                 ib_ioc_profile_get_vend_id( &p_ext->info.profile ),\r
818                 cl_ntoh32( p_ext->info.profile.dev_id ),\r
819                 ib_ioc_profile_get_subsys_vend_id( &p_ext->info.profile ),\r
820                 cl_ntoh32( p_ext->info.profile.subsys_id ),\r
821                 cl_ntoh16( p_ext->info.profile.dev_ver ) );\r
822         if( !NT_SUCCESS( status ) )\r
823         {\r
824                 ExFreePool( p_string );\r
825                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
826                         ("Failed to format device ID string.\n") );\r
827                 return status;\r
828         }\r
829         p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
830 \r
831         IOU_EXIT( IOU_DBG_PNP );\r
832         return STATUS_SUCCESS;\r
833 }\r
834 \r
835 \r
836 static NTSTATUS\r
837 ioc_query_hardware_ids(\r
838         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
839                 OUT                             IRP* const                              p_irp )\r
840 {\r
841         NTSTATUS                        status;\r
842         ioc_ext_t                       *p_ext;\r
843         WCHAR                           *p_string, *p_start;\r
844         size_t                          size;\r
845         uint32_t                        V,P,S,s;\r
846         uint16_t                        v;\r
847 \r
848         IOU_ENTER( IOU_DBG_PNP );\r
849 \r
850         p_ext = (ioc_ext_t*)p_dev_obj->DeviceExtension;\r
851         if( !p_ext->pdo.b_present )\r
852         {\r
853                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
854                         ("Device not present.\n") );\r
855                 return STATUS_NO_SUCH_DEVICE;\r
856         }\r
857 \r
858         p_string = ExAllocatePoolWithTag( PagedPool, IOC_HW_ID_SIZE, 'ihqi' );\r
859         if( !p_string )\r
860         {\r
861                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
862                         ("Failed to allocate hardware ID buffer (%d bytes).\n",\r
863                         IOC_HW_ID_SIZE) );\r
864                 return STATUS_INSUFFICIENT_RESOURCES;\r
865         }\r
866 \r
867         V = ib_ioc_profile_get_vend_id( &p_ext->info.profile );\r
868         P = cl_ntoh32( p_ext->info.profile.dev_id );\r
869         S = ib_ioc_profile_get_subsys_vend_id( &p_ext->info.profile );\r
870         s = cl_ntoh32( p_ext->info.profile.subsys_id );\r
871         v = cl_ntoh16( p_ext->info.profile.dev_ver );\r
872 \r
873         /* Fill in the first hardware ID. */\r
874         p_start = p_string;\r
875         size = IOC_HW_ID_SIZE;\r
876         status = RtlStringCbPrintfExW( p_start, size, &p_start, &size,\r
877                 STRSAFE_FILL_BEHIND_NULL, L"IBA\\V%06xP%08xS%06xs%08xv%04x",\r
878                 V, P, S, s, v );\r
879         if( !NT_SUCCESS( status ) )\r
880         {\r
881                 ExFreePool( p_string );\r
882                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
883                         ("Failed to format hardware ID string.\n") );\r
884                 return status;\r
885         }\r
886         /* Fill in the second hardware ID. */\r
887         p_start++;\r
888         size -= sizeof(WCHAR);\r
889         status = RtlStringCbPrintfExW( p_start, size, &p_start, &size,\r
890                 STRSAFE_FILL_BEHIND_NULL, L"IBA\\V%06xP%08xS%06xs%08x", V, P, S, s );\r
891         if( !NT_SUCCESS( status ) )\r
892         {\r
893                 ExFreePool( p_string );\r
894                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
895                         ("Failed to format hardware ID string.\n") );\r
896                 return status;\r
897         }\r
898         /* Fill in the third hardware ID. */\r
899         p_start++;\r
900         size -= sizeof(WCHAR);\r
901         status = RtlStringCbPrintfExW( p_start, size, &p_start, &size,\r
902                 STRSAFE_FILL_BEHIND_NULL, L"IBA\\V%06xP%08xv%04x", V, P, v );\r
903         if( !NT_SUCCESS( status ) )\r
904         {\r
905                 ExFreePool( p_string );\r
906                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
907                         ("Failed to format hardware ID string.\n") );\r
908                 return status;\r
909         }\r
910         /* Fill in the fourth hardware ID. */\r
911         p_start++;\r
912         size -= sizeof(WCHAR);\r
913         status = RtlStringCbPrintfExW( p_start, size, &p_start, &size,\r
914                 STRSAFE_FILL_BEHIND_NULL, L"IBA\\V%06xP%08x", V, P );\r
915         if( !NT_SUCCESS( status ) )\r
916         {\r
917                 ExFreePool( p_string );\r
918                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
919                         ("Failed to format hardware ID string.\n") );\r
920                 return status;\r
921         }\r
922         p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
923 \r
924         IOU_EXIT( IOU_DBG_PNP );\r
925         return STATUS_SUCCESS;\r
926 }\r
927 \r
928 \r
929 static NTSTATUS\r
930 ioc_query_compatible_ids(\r
931         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
932                 OUT                             IRP* const                              p_irp )\r
933 {\r
934         NTSTATUS                        status;\r
935         ioc_ext_t                       *p_ext;\r
936         WCHAR                           *p_string, *p_start;\r
937         size_t                          size;\r
938         uint16_t                        C, c, p, r;\r
939 \r
940         IOU_ENTER( IOU_DBG_PNP );\r
941 \r
942         p_ext = (ioc_ext_t*)p_dev_obj->DeviceExtension;\r
943         if( !p_ext->pdo.b_present )\r
944         {\r
945                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
946                         ("Device not present.\n") );\r
947                 return STATUS_NO_SUCH_DEVICE;\r
948         }\r
949 \r
950         p_string = ExAllocatePoolWithTag( PagedPool, IOC_COMPAT_ID_SIZE, 'icqi' );\r
951         if( !p_string )\r
952         {\r
953                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
954                         ("Failed to allocate compatible ID buffer (%d bytes).\n",\r
955                         IOC_HW_ID_SIZE) );\r
956                 return STATUS_INSUFFICIENT_RESOURCES;\r
957         }\r
958 \r
959         C = cl_ntoh16( p_ext->info.profile.io_class );\r
960         c = cl_ntoh16( p_ext->info.profile.io_subclass );\r
961         p = cl_ntoh16( p_ext->info.profile.protocol );\r
962         r = cl_ntoh16( p_ext->info.profile.protocol_ver );\r
963 \r
964         p_start = p_string;\r
965         size = IOC_COMPAT_ID_SIZE;\r
966         /* Fill in the first compatible ID. */\r
967         status = RtlStringCbPrintfExW( p_start, size, &p_start, &size,\r
968                 STRSAFE_FILL_BEHIND_NULL, L"IBA\\C%04xc%04xp%04xr%04x", C, c, p, r );\r
969         if( !NT_SUCCESS( status ) )\r
970         {\r
971                 ExFreePool( p_string );\r
972                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
973                         ("Failed to format device ID string.\n") );\r
974                 return status;\r
975         }\r
976         /* Fill in the second compatible ID. */\r
977         p_start++;\r
978         size -= sizeof(WCHAR);\r
979         status = RtlStringCbPrintfExW( p_start, size, NULL, NULL,\r
980                 STRSAFE_FILL_BEHIND_NULL, L"IBA\\C%04xc%04xp%04x", C, c, p );\r
981         if( !NT_SUCCESS( status ) )\r
982         {\r
983                 ExFreePool( p_string );\r
984                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
985                         ("Failed to format device ID string.\n") );\r
986                 return status;\r
987         }\r
988         p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
989 \r
990         IOU_EXIT( IOU_DBG_PNP );\r
991         return STATUS_SUCCESS;\r
992 }\r
993 \r
994 \r
995 static NTSTATUS\r
996 ioc_query_unique_id(\r
997         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
998                 OUT                             IRP* const                              p_irp )\r
999 {\r
1000         NTSTATUS                        status;\r
1001         WCHAR                           *p_string;\r
1002         ioc_ext_t                       *p_ext;\r
1003 \r
1004         IOU_ENTER( IOU_DBG_PNP );\r
1005 \r
1006         p_ext = p_dev_obj->DeviceExtension;\r
1007         if( !p_ext->pdo.b_present )\r
1008         {\r
1009                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
1010                         ("Device not present.\n") );\r
1011                 return STATUS_NO_SUCH_DEVICE;\r
1012         }\r
1013 \r
1014         /* The instance ID is the port GUID. */\r
1015         p_string = ExAllocatePoolWithTag( PagedPool, sizeof(WCHAR) * 33, 'iuqi' );\r
1016         if( !p_string )\r
1017         {\r
1018                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
1019                         ("Failed to allocate instance ID buffer (%d bytes).\n",\r
1020                         sizeof(WCHAR) * 17) );\r
1021                 return STATUS_NO_MEMORY;\r
1022         }\r
1023 \r
1024         status = RtlStringCchPrintfW(p_string, 33, L"%016I64x%016I64x",\r
1025                  p_ext->info.profile.ioc_guid,p_ext->pdo.ca_guid);\r
1026         if( !NT_SUCCESS( status ) )\r
1027         {\r
1028                 CL_ASSERT( NT_SUCCESS( status ) );\r
1029                 ExFreePool( p_string );\r
1030                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
1031                         ("RtlStringCchPrintfW returned %08x.\n", status) );\r
1032                 return status;\r
1033         }\r
1034 \r
1035         p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
1036 \r
1037         IOU_EXIT( IOU_DBG_PNP );\r
1038         return STATUS_SUCCESS;\r
1039 }\r
1040 \r
1041 \r
1042 static NTSTATUS\r
1043 ioc_query_description(\r
1044         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1045                 OUT                             IRP* const                              p_irp )\r
1046 {\r
1047         NTSTATUS                        status;\r
1048         WCHAR                           *p_string;\r
1049         ioc_ext_t                       *p_ext;\r
1050 \r
1051         IOU_ENTER( IOU_DBG_PNP );\r
1052 \r
1053         p_ext = p_dev_obj->DeviceExtension;\r
1054         if( !p_ext->pdo.b_present )\r
1055         {\r
1056                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
1057                         ("Device not present.\n") );\r
1058                 return STATUS_NO_SUCH_DEVICE;\r
1059         }\r
1060 \r
1061         p_string = ExAllocatePoolWithTag( PagedPool,\r
1062                                                                           sizeof(WCHAR) * sizeof(p_ext->info.profile.id_string),\r
1063                                                                           'edqi');\r
1064         if( !p_string )\r
1065         {\r
1066                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
1067                         ("Failed to allocate device description buffer (%d bytes).\n",\r
1068                         sizeof(WCHAR) * sizeof(p_ext->info.profile.id_string)) );\r
1069                 return STATUS_INSUFFICIENT_RESOURCES;\r
1070         }\r
1071 \r
1072         if( ib_ioc_profile_get_vend_id( &p_ext->info.profile ) == 0x00066a &&\r
1073                 p_ext->info.profile.dev_id == CL_HTON32(0x00000030) )\r
1074         {\r
1075                 status = RtlStringCchPrintfW(\r
1076                         p_string, sizeof(p_ext->info.profile.id_string),\r
1077                         L"SilverStorm Technologies VEx I/O Controller" );\r
1078         }\r
1079         else if( ib_ioc_profile_get_vend_id( &p_ext->info.profile ) == 0x00066a &&\r
1080                 p_ext->info.profile.dev_id == CL_HTON32(0x00000038) )\r
1081         {\r
1082                 status = RtlStringCchPrintfW(\r
1083                         p_string, sizeof(p_ext->info.profile.id_string),\r
1084                         L"SilverStorm Technologies VFx I/O Controller" );\r
1085         }\r
1086         else\r
1087         {\r
1088                 status = RtlStringCchPrintfW(\r
1089                         p_string, sizeof(p_ext->info.profile.id_string),\r
1090                         L"%S", p_ext->info.profile.id_string );\r
1091         }\r
1092         if( !NT_SUCCESS( status ) )\r
1093         {\r
1094                 CL_ASSERT( NT_SUCCESS( status ) );\r
1095                 ExFreePool( p_string );\r
1096                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
1097                         ("RtlStringCchPrintfW returned %08x.\n", status) );\r
1098                 return status;\r
1099         }\r
1100         p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
1101 \r
1102         IOU_EXIT( IOU_DBG_PNP );\r
1103         return STATUS_SUCCESS;\r
1104 }\r
1105 \r
1106 \r
1107 static NTSTATUS\r
1108 ioc_query_location(\r
1109         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1110                 OUT                             IRP* const                              p_irp )\r
1111 {\r
1112         NTSTATUS                        status;\r
1113         ioc_ext_t                       *p_ext;\r
1114         WCHAR                           *p_string;\r
1115 \r
1116         IOU_ENTER( IOU_DBG_PNP );\r
1117 \r
1118         p_ext = (ioc_ext_t*)p_dev_obj->DeviceExtension;\r
1119         if( !p_ext->pdo.b_present )\r
1120         {\r
1121                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
1122                         ("Device not present.\n") );\r
1123                 return STATUS_NO_SUCH_DEVICE;\r
1124         }\r
1125 \r
1126         p_string = ExAllocatePoolWithTag( PagedPool, \r
1127                                                                           max( IOC_LOCATION_SIZE, sizeof( WCHAR ) *\r
1128                                                                                ( sizeof( p_ext->info.profile.id_string ) + 1 )),\r
1129                                                                           'olqi');\r
1130         if( !p_string )\r
1131         {\r
1132                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
1133                         ("Failed to allocate location buffer (%d bytes).\n",\r
1134                         IOC_LOCATION_SIZE) );\r
1135                 return STATUS_INSUFFICIENT_RESOURCES;\r
1136         }\r
1137 \r
1138         if( ib_ioc_profile_get_vend_id( &p_ext->info.profile ) == 0x00066a )\r
1139         {\r
1140                 status = RtlStringCchPrintfW(\r
1141                         p_string, sizeof(p_ext->info.profile.id_string),\r
1142                         L"%S", p_ext->info.profile.id_string );\r
1143         }\r
1144         else\r
1145         {\r
1146                 status = RtlStringCbPrintfW( p_string, IOC_LOCATION_SIZE,\r
1147                         L"Chassis 0x%016I64x, Slot %d, IOC %d",\r
1148                         cl_ntoh64( p_ext->info.chassis_guid ),\r
1149                         p_ext->info.chassis_slot, p_ext->info.iou_slot );\r
1150         }\r
1151         if( !NT_SUCCESS( status ) )\r
1152         {\r
1153                 ExFreePool( p_string );\r
1154                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
1155                         ("Failed to format device ID string.\n") );\r
1156                 return status;\r
1157         }\r
1158         p_irp->IoStatus.Information = (ULONG_PTR)p_string;\r
1159 \r
1160         IOU_EXIT( IOU_DBG_PNP );\r
1161         return STATUS_SUCCESS;\r
1162 }\r
1163 \r
1164 \r
1165 static NTSTATUS\r
1166 ioc_query_bus_info(\r
1167         IN                                      DEVICE_OBJECT* const    p_dev_obj,\r
1168         IN                                      IRP* const                              p_irp,\r
1169                 OUT                             cl_irp_action_t* const  p_action )\r
1170 {\r
1171         ioc_ext_t                       *p_ext;\r
1172         PNP_BUS_INFORMATION     *p_iou_info;\r
1173 \r
1174         IOU_ENTER( IOU_DBG_PNP );\r
1175 \r
1176         p_ext = (ioc_ext_t*)p_dev_obj->DeviceExtension;\r
1177         if( !p_ext->pdo.b_present )\r
1178         {\r
1179                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
1180                         ("Device not present.\n") );\r
1181                 return STATUS_NO_SUCH_DEVICE;\r
1182         }\r
1183 \r
1184         *p_action = IrpComplete;\r
1185 \r
1186         p_iou_info = ExAllocatePoolWithTag( PagedPool, sizeof(PNP_BUS_INFORMATION), 'ibqi' );\r
1187         if( !p_iou_info )\r
1188         {\r
1189                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
1190                         ("Failed to allocate PNP_BUS_INFORMATION (%d bytes).\n",\r
1191                         sizeof(PNP_BUS_INFORMATION)) );\r
1192                 return STATUS_INSUFFICIENT_RESOURCES;\r
1193         }\r
1194 \r
1195 \r
1196         p_iou_info->BusTypeGuid = GUID_BUS_TYPE_IBA;\r
1197         //TODO: Memory from Intel - storage miniport would not stay loaded unless\r
1198         //TODO: bus type was PCI.  Look here if SRP is having problems staying\r
1199         //TODO: loaded.\r
1200         p_iou_info->LegacyBusType = PNPBus;\r
1201         p_iou_info->BusNumber = p_ext->info.iou_slot;\r
1202 \r
1203         p_irp->IoStatus.Information = (ULONG_PTR)p_iou_info;\r
1204         IOU_EXIT( IOU_DBG_PNP );\r
1205         return STATUS_SUCCESS;\r
1206 }\r
1207 \r
1208 \r
1209 static __ref_ioc_ifc(\r
1210         IN                              ioc_ext_t*                                              p_ext )\r
1211 {\r
1212         IOU_ENTER( IOU_DBG_PNP );\r
1213 \r
1214         cl_atomic_inc( &p_ext->pdo.p_parent_ext->cl_ext.n_ifc_ref );\r
1215         ObReferenceObject( p_ext->pdo.p_parent_ext->cl_ext.p_self_do );\r
1216 \r
1217         IOU_EXIT( IOU_DBG_PNP );\r
1218 }\r
1219 \r
1220 \r
1221 static void\r
1222 __deref_ioc_ifc(\r
1223         IN                              ioc_ext_t*                                              p_ext )\r
1224 {\r
1225         IOU_ENTER( IOU_DBG_PNP );\r
1226 \r
1227         cl_atomic_dec( &p_ext->pdo.p_parent_ext->cl_ext.n_ifc_ref );\r
1228         ObDereferenceObject( p_ext->pdo.p_parent_ext->cl_ext.p_self_do );\r
1229 \r
1230         IOU_EXIT( IOU_DBG_PNP );\r
1231 }\r
1232 \r
1233 \r
1234 \r
1235 \r
1236 static NTSTATUS\r
1237 ioc_query_interface(\r
1238         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1239         IN                              IRP* const                                      p_irp,\r
1240                 OUT                     cl_irp_action_t* const          p_action )\r
1241 {\r
1242         NTSTATUS                                status;\r
1243         IO_STACK_LOCATION               *p_io_stack;\r
1244         ib_al_ifc_t                             *p_ifc;\r
1245         ib_al_ifc_data_t                *p_ifc_data;\r
1246         ioc_ifc_data_t                  *p_ioc_data;\r
1247         ioc_ext_t                               *p_ext;\r
1248         const GUID                              *p_guid;\r
1249 \r
1250         IOU_ENTER( IOU_DBG_PNP );\r
1251 \r
1252         CL_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );\r
1253 \r
1254         p_ext = p_dev_obj->DeviceExtension;\r
1255         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1256         p_guid = p_io_stack->Parameters.QueryInterface.InterfaceType;\r
1257         /* Bottom of the stack - IRP must be completed. */\r
1258         *p_action = IrpComplete;\r
1259 \r
1260         /* Compare requested GUID with our supported interface GUIDs. */\r
1261         if( IsEqualGUID( p_guid, &GUID_BUS_INTERFACE_STANDARD ) )\r
1262         {\r
1263                 IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_PNP,\r
1264                         ("BUS_INTERFACE_STANDARD\n") );\r
1265                 return cl_fwd_query_ifc(\r
1266                         p_ext->pdo.p_parent_ext->cl_ext.p_self_do, p_io_stack );\r
1267         }\r
1268 \r
1269         if( !IsEqualGUID( p_guid, &GUID_IB_AL_INTERFACE ) )\r
1270         {\r
1271                 IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_PNP,\r
1272                         ("Unsupported interface: \n\t"\r
1273                         "0x%08x, 0x%04x, 0x%04x, 0x%02x, 0x%02x, 0x%02x,"\r
1274                         "0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x.\n",\r
1275                         p_guid->Data1, p_guid->Data2, p_guid->Data3,\r
1276                         p_guid->Data4[0], p_guid->Data4[1], p_guid->Data4[2],\r
1277                         p_guid->Data4[3], p_guid->Data4[4], p_guid->Data4[5],\r
1278                         p_guid->Data4[6], p_guid->Data4[7]) );\r
1279                 return p_irp->IoStatus.Status;\r
1280         }\r
1281 \r
1282         /* Get the interface. */\r
1283         status = cl_fwd_query_ifc(\r
1284                 p_ext->pdo.p_parent_ext->cl_ext.p_self_do, p_io_stack );\r
1285         if( !NT_SUCCESS( status ) )\r
1286         {\r
1287                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
1288                         ("Failed to forward interface query: %08X\n", status) );\r
1289                 return status;\r
1290         }\r
1291 \r
1292         if( !p_io_stack->Parameters.QueryInterface.InterfaceSpecificData )\r
1293         {\r
1294                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
1295                         ("No interface specific data!\n") );\r
1296                 return status;\r
1297         }\r
1298 \r
1299         p_ifc = (ib_al_ifc_t*)p_io_stack->Parameters.QueryInterface.Interface;\r
1300 \r
1301         p_ifc_data = (ib_al_ifc_data_t*)\r
1302                 p_io_stack->Parameters.QueryInterface.InterfaceSpecificData;\r
1303         p_guid = p_ifc_data->type;\r
1304         if( !IsEqualGUID( p_guid, &GUID_IOC_INTERFACE_DATA ) ||\r
1305                 p_ifc_data->version != IOC_INTERFACE_DATA_VERSION )\r
1306         {\r
1307                 p_ifc->wdm.InterfaceDereference( p_ifc->wdm.Context );\r
1308                 IOU_PRINT_EXIT( TRACE_LEVEL_ERROR, IOU_DBG_ERROR,\r
1309                         ("Unsupported interface data: \n\t"\r
1310                         "0x%08x, 0x%04x, 0x%04x, 0x%02x, 0x%02x, 0x%02x,"\r
1311                         "0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x.\n",\r
1312                         p_guid->Data1, p_guid->Data2, p_guid->Data3,\r
1313                         p_guid->Data4[0], p_guid->Data4[1], p_guid->Data4[2],\r
1314                         p_guid->Data4[3], p_guid->Data4[4], p_guid->Data4[5],\r
1315                         p_guid->Data4[6], p_guid->Data4[7]) );\r
1316                 return STATUS_INVALID_PARAMETER;\r
1317         }\r
1318 \r
1319         ASSERT( p_ifc_data->p_data );\r
1320 \r
1321         if( p_ifc_data->size != sizeof(ioc_ifc_data_t) )\r
1322         {\r
1323                 p_ifc->wdm.InterfaceDereference( p_ifc->wdm.Context );\r
1324                 IOU_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IOU_DBG_PNP,\r
1325                         ("Buffer too small (%d given, %d required).\n",\r
1326                         p_ifc_data->size,\r
1327                         sizeof(ioc_ifc_data_t)) );\r
1328                 return STATUS_BUFFER_TOO_SMALL;\r
1329         }\r
1330 \r
1331         /* Set the interface data. */\r
1332         p_ioc_data = (ioc_ifc_data_t*)p_ifc_data->p_data;\r
1333 \r
1334         p_ioc_data->ca_guid = p_ext->pdo.p_parent_ext->ioc_mgr.info.ca_guid;\r
1335         p_ioc_data->guid = p_ext->info.profile.ioc_guid;\r
1336 \r
1337         IOU_EXIT( IOU_DBG_PNP );\r
1338         return STATUS_SUCCESS;\r
1339 }\r
1340 \r
1341 \r
1342 /*\r
1343  * The PDOs created by the IB Bus driver are software devices.  As such,\r
1344  * all power states are supported.  It is left to the HCA power policy\r
1345  * owner to handle which states can be supported by the HCA.\r
1346  */\r
1347 static NTSTATUS\r
1348 ioc_set_power(\r
1349         IN                              DEVICE_OBJECT* const            p_dev_obj,\r
1350         IN                              IRP* const                                      p_irp,\r
1351                 OUT                     cl_irp_action_t* const          p_action )\r
1352 {\r
1353         IO_STACK_LOCATION       *p_io_stack;\r
1354         iou_pdo_ext_t           *p_ext;\r
1355 \r
1356         IOU_ENTER( IOU_DBG_POWER );\r
1357 \r
1358         p_ext = p_dev_obj->DeviceExtension;\r
1359         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
1360 \r
1361         if( p_io_stack->Parameters.Power.Type == DevicePowerState )\r
1362         {\r
1363                 /* Notify the power manager. */\r
1364                 p_ext->dev_po_state = p_io_stack->Parameters.Power.State;\r
1365                 PoSetPowerState( p_dev_obj, DevicePowerState, p_ext->dev_po_state );\r
1366         }\r
1367 \r
1368         *p_action = IrpComplete;\r
1369         IOU_EXIT( IOU_DBG_POWER );\r
1370         return STATUS_SUCCESS;\r
1371 }\r