6ddf2682fb3cfa219498f7ab1db15eefa2eb92a8
[mirror/winof/.git] / core / al / kernel / al_ioc_pnp.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 #include <iba/ib_al.h>\r
35 #include "al_pnp.h"\r
36 #include "al_ioc_pnp.h"\r
37 #include "al_debug.h"\r
38 #if defined(EVENT_TRACING)\r
39 #ifdef offsetof\r
40 #undef offsetof\r
41 #endif\r
42 #include "al_ioc_pnp.tmh"\r
43 #endif\r
44 #include "ib_common.h"\r
45 #include "al_mgr.h"\r
46 #include "al_ca.h"\r
47 #include <complib/cl_timer.h>\r
48 #include <complib/cl_qpool.h>\r
49 #include <complib/cl_qmap.h>\r
50 #include <complib/cl_fleximap.h>\r
51 #include <complib/cl_math.h>\r
52 \r
53 \r
54 /* Basic sweep operation flow:\r
55  *\r
56  * NOTE: Empty lines indicate asynchronous decoupling.\r
57  *      1. Timer expires\r
58  *      2. Issue SA query for all CA nodes\r
59  *      3. Issue SA query for all paths\r
60  *\r
61  *      4. Query callback for first query - store results.\r
62  *      5. Query callback for second query - process results.\r
63  *      6. Associate paths to nodes.\r
64  *      7. For each node, use the first path to send a IOU Info query.\r
65  *\r
66  *      8a. Recv callback (success) - record IOU info, decrement ref count.\r
67  *      8b. Recv callback (failure) - decrement ref count.\r
68  *      8c. Send failure - decrement ref count.\r
69  *      8d. Send timeout - pick next path and repeate IOU info query.\r
70  *      9. Queue results to async proc thread once ref count hits zero\r
71  *\r
72  *      10. Discard any nodes that failed IOU info query, or reported no IOCs.\r
73  *      11. For each node scanned that is already known, compare change ID\r
74  *      12a. Change ID identical - report any path changes.\r
75  *      12b. Change ID different - for each active IOC slot, query IOC profile.\r
76  *\r
77  *      13a. Recv callback (success) - associate IOC with IOU, decrement ref count.\r
78  *      13b. Recv callback (failure) - decrement ref count.\r
79  *      13c. Send failure - decrement ref count.\r
80  *      14. Queue results to async proc thread once ref count hits zero.\r
81  *\r
82  *      15. Discard any nodes that have no IOCs.\r
83  *      16. For each IOC of each node, query all service entries.\r
84  *\r
85  *      17a. Recv callback (success) - copy service entries, decrement ref count.\r
86  *      17b. Recv callback (failure) - Remove IOC from IOU, decrement ref count.\r
87  *      17c. Send failure - Remove IOC from IOU, decrement ref count.\r
88  *      18. Queue results to async proc thread once ref count hits zero.\r
89  *\r
90  *      19. Discard any nodes that have no IOCs.\r
91  *      20. Compare new node map to known nodes and report changes.\r
92  *      21. Compare IOCs for any duplicates and report changes.\r
93  *      22. Compare paths for any duplicates and report changes.\r
94  *      23. Reset sweep timer.\r
95  *\r
96  * Note: the sweep timer is reset at any point where there can be no further\r
97  * progress towards.\r
98  */\r
99 \r
100 \r
101 /* Number of entries in the various pools to grow by. */\r
102 #define IOC_PNP_POOL_GROW       (10)\r
103 \r
104 \r
105 /* IOC PnP Manager structure. */\r
106 typedef struct _ioc_pnp_mgr\r
107 {\r
108         al_obj_t                                obj;\r
109 \r
110         cl_qlist_t                              iou_reg_list;\r
111         cl_qlist_t                              ioc_reg_list;\r
112 \r
113         ib_pnp_handle_t                 h_pnp;\r
114 \r
115         cl_async_proc_item_t    async_item;\r
116         boolean_t                               async_item_is_busy;\r
117 \r
118         cl_spinlock_t                   iou_pool_lock;\r
119         cl_qpool_t                              iou_pool;\r
120         cl_spinlock_t                   ioc_pool_lock;\r
121         cl_qpool_t                              ioc_pool;\r
122         cl_spinlock_t                   path_pool_lock;\r
123         cl_qpool_t                              path_pool;\r
124 \r
125         cl_fmap_t                               iou_map;        /* Map of currently known IOUs */\r
126         cl_fmap_t                               sweep_map;      /* Map of IOUs from sweep results. */\r
127         cl_timer_t                              sweep_timer;/* Timer to trigger sweep. */\r
128         atomic32_t                              query_cnt;      /* Number of sweep results outstanding. */\r
129 \r
130 }       ioc_pnp_mgr_t;\r
131 \r
132 \r
133 /* Per-port IOC PnP agent. */\r
134 typedef struct _ioc_pnp_svc\r
135 {\r
136         al_obj_t                                obj;\r
137 \r
138         net64_t                                 ca_guid;\r
139         net64_t                                 port_guid;\r
140 \r
141         ib_qp_handle_t                  h_qp;\r
142         ib_pool_key_t                   pool_key;\r
143         ib_mad_svc_handle_t             h_mad_svc;\r
144 \r
145         atomic32_t                              query_cnt;\r
146         ib_query_handle_t               h_node_query;\r
147         ib_query_handle_t               h_path_query;\r
148         ib_mad_element_t                *p_node_element;\r
149         ib_mad_element_t                *p_path_element;\r
150         uint32_t                                num_nodes;\r
151         uint32_t                                num_paths;\r
152 \r
153 }       ioc_pnp_svc_t;\r
154 \r
155 \r
156 /****d* Access Layer:IOC PnP/iou_path_t\r
157 * NAME\r
158 *       iou_path_t\r
159 *\r
160 * DESCRIPTION\r
161 *       Describes a path to an IOU node.\r
162 *\r
163 * SYNOPSIS\r
164 */\r
165 typedef struct _iou_path\r
166 {\r
167         cl_fmap_item_t                  map_item;\r
168         net64_t                                 ca_guid;\r
169         net64_t                                 port_guid;\r
170         ib_path_rec_t                   rec;\r
171 \r
172 }       iou_path_t;\r
173 /*\r
174 * FIELDS\r
175 *       map_item\r
176 *               Map item for storing paths in a map.\r
177 *\r
178 *       path_rec\r
179 *               Path record.\r
180 *\r
181 * SEE ALSO\r
182 *       IOC PnP\r
183 *********/\r
184 \r
185 \r
186 /****d* Access Layer:IOC PnP/iou_node_t\r
187 * NAME\r
188 *       iou_node_t\r
189 *\r
190 * DESCRIPTION\r
191 *       Describes an IOU node on the fabric.\r
192 *\r
193 * SYNOPSIS\r
194 */\r
195 typedef struct _iou_node\r
196 {\r
197         cl_fmap_item_t                  map_item;\r
198         cl_fmap_t                               path_map;\r
199         cl_qmap_t                               ioc_map;\r
200         cl_spinlock_t                   lock;\r
201 \r
202         iou_path_t                              *p_config_path;\r
203 \r
204         net64_t                                 ca_guid;\r
205         net64_t                                 guid;\r
206         net64_t                                 chassis_guid;\r
207         uint8_t                                 slot;\r
208         net32_t                                 vend_id;\r
209         net16_t                                 dev_id;\r
210         net32_t                                 revision;\r
211         ib_iou_info_t                   info;\r
212 \r
213         char                                    desc[IB_NODE_DESCRIPTION_SIZE + 1];\r
214 \r
215 }       iou_node_t;\r
216 /*\r
217 * FIELDS\r
218 *       map_item\r
219 *               Map item for storing IOUs in a map.\r
220 *\r
221 *       path_map\r
222 *               Map of paths to the IOU.\r
223 *\r
224 *       ioc_map\r
225 *               Map of IOCs on the IOU.\r
226 *\r
227 *       p_config_path\r
228 *               Path used to get configuration information from the IOU.\r
229 *\r
230 *       ca_guid\r
231 *               CA GUID through which the IOU is accessible.\r
232 *\r
233 *       guid\r
234 *               Node GUID used as key when storing IOUs in the map.\r
235 *\r
236 *       chassis_guid\r
237 *               GUID of the chassis in which the IOU is installed.\r
238 *\r
239 *       slot\r
240 *               Slot number in the chassis in which the IOU is installed.\r
241 *\r
242 *       vend_id\r
243 *               Vendor ID of the IOU.\r
244 *\r
245 *       dev_id\r
246 *               Device ID of the IOU.\r
247 *\r
248 *       revision\r
249 *               Device revision of the IOU.\r
250 *\r
251 *       info\r
252 *               I/O unit info structure.\r
253 *\r
254 *       desc\r
255 *               Node description as provided in ib_node_record_t, along with space for\r
256 *               terminating NULL.\r
257 *\r
258 * NOTES\r
259 *       The guid member must follow the ca_guid member to allow both guids to\r
260 *       be compared in single call to cl_memcmp.\r
261 *\r
262 * SEE ALSO\r
263 *       IOC PnP\r
264 *********/\r
265 \r
266 \r
267 #pragma warning(disable:4324)\r
268 typedef struct _iou_ioc\r
269 {\r
270         cl_map_item_t                   map_item;\r
271         iou_node_t                              *p_iou;\r
272         uint8_t                                 slot;\r
273         ib_ioc_profile_t                profile;\r
274         uint8_t                                 num_valid_entries;\r
275         ib_svc_entry_t                  *p_svc_entries;\r
276         atomic32_t                              ref_cnt;\r
277 \r
278 }       iou_ioc_t;\r
279 #pragma warning(default:4324)\r
280 \r
281 \r
282 typedef enum _sweep_state\r
283 {\r
284         SWEEP_IOU_INFO,\r
285         SWEEP_IOC_PROFILE,\r
286         SWEEP_SVC_ENTRIES,\r
287         SWEEP_COMPLETE\r
288 \r
289 }       sweep_state_t;\r
290 \r
291 \r
292 typedef struct _ioc_sweep_results\r
293 {\r
294         cl_async_proc_item_t    async_item;\r
295         sweep_state_t                   state;\r
296         ioc_pnp_svc_t                   *p_svc;\r
297         atomic32_t                              query_cnt;\r
298         cl_fmap_t                               iou_map;\r
299 \r
300 }       ioc_sweep_results_t;\r
301 \r
302 \r
303 typedef struct _al_pnp_ioc_event\r
304 {\r
305         size_t                                  rec_size;\r
306         ib_pnp_rec_t                    *p_rec;\r
307         ib_pnp_rec_t                    *p_user_rec;\r
308 \r
309 }       al_pnp_ioc_event_t;\r
310 \r
311 \r
312 /* Global instance of the IOC PnP manager. */\r
313 ioc_pnp_mgr_t   *gp_ioc_pnp = NULL;\r
314 uint32_t                g_ioc_query_timeout = 250;\r
315 uint32_t                g_ioc_query_retries = 4;\r
316 uint32_t                g_ioc_poll_interval = 30000;\r
317 \r
318 \r
319 \r
320 /******************************************************************************\r
321 *\r
322 * IOC PnP Manager functions - global object.\r
323 *\r
324 ******************************************************************************/\r
325 static void\r
326 __construct_ioc_pnp(\r
327         IN                              ioc_pnp_mgr_t* const            p_ioc_mgr );\r
328 \r
329 static ib_api_status_t\r
330 __init_ioc_pnp(\r
331         IN                              ioc_pnp_mgr_t* const            p_ioc_mgr );\r
332 \r
333 static void\r
334 __destroying_ioc_pnp(\r
335         IN                              al_obj_t                                        *p_obj );\r
336 \r
337 static void\r
338 __free_ioc_pnp(\r
339         IN                              al_obj_t                                        *p_obj );\r
340 \r
341 static ib_api_status_t\r
342 __ioc_pnp_cb(\r
343         IN                              ib_pnp_rec_t                            *p_pnp_rec );\r
344 \r
345 static cl_status_t\r
346 __init_iou(\r
347         IN                              void* const                                     p_obj,\r
348         IN                              void*                                           context,\r
349                 OUT                     cl_pool_item_t** const          pp_pool_item );\r
350 \r
351 /******************************************************************************\r
352 *\r
353 * IOC PnP manager sweep-related functions.\r
354 *\r
355 ******************************************************************************/\r
356 static iou_node_t*\r
357 __get_iou(\r
358         IN                              ioc_pnp_mgr_t* const            p_ioc_mgr,\r
359         IN              const   net64_t                                         ca_guid,\r
360         IN              const   ib_node_record_t* const         p_node_rec );\r
361 \r
362 static void\r
363 __put_iou(\r
364         IN                              ioc_pnp_mgr_t* const            p_ioc_mgr,\r
365         IN                              iou_node_t* const                       p_iou );\r
366 \r
367 static void\r
368 __put_iou_map(\r
369         IN                              ioc_pnp_mgr_t* const            p_ioc_mgr,\r
370         IN                              cl_fmap_t* const                        p_iou_map );\r
371 \r
372 static iou_path_t*\r
373 __get_path(\r
374         IN                              ioc_pnp_mgr_t* const            p_ioc_mgr,\r
375         IN              const   net64_t                                         ca_guid,\r
376         IN              const   net64_t                                         port_guid,\r
377         IN              const   ib_path_rec_t* const            p_path_rec );\r
378 \r
379 static void\r
380 __put_path(\r
381         IN                              ioc_pnp_mgr_t* const            p_ioc_mgr,\r
382         IN                              iou_path_t* const                       p_path );\r
383 \r
384 static void\r
385 __put_path_map(\r
386         IN                              ioc_pnp_mgr_t* const            p_ioc_mgr,\r
387         IN                              cl_fmap_t* const                        p_path_map );\r
388 \r
389 static iou_ioc_t*\r
390 __get_ioc(\r
391         IN                              ioc_pnp_mgr_t* const            p_ioc_mgr,\r
392         IN              const   uint32_t                                        ioc_slot,\r
393         IN              const   ib_ioc_profile_t* const         p_profile );\r
394 \r
395 static void\r
396 __put_ioc(\r
397         IN                              ioc_pnp_mgr_t* const            p_ioc_mgr,\r
398         IN                              iou_ioc_t* const                        p_ioc );\r
399 \r
400 static void\r
401 __put_ioc_map(\r
402         IN                              ioc_pnp_mgr_t* const            p_ioc_mgr,\r
403         IN                              cl_qmap_t* const                        p_ioc_map );\r
404 \r
405 static intn_t\r
406 __iou_cmp(\r
407         IN              const   void* const                                     p_key1,\r
408         IN              const   void* const                                     p_key2 );\r
409 \r
410 static intn_t\r
411 __path_cmp(\r
412         IN              const   void* const                                     p_key1,\r
413         IN              const   void* const                                     p_key2 );\r
414 \r
415 static void\r
416 __ioc_pnp_timer_cb(\r
417         IN                              void                                            *context );\r
418 \r
419 static void\r
420 __ioc_async_cb(\r
421         IN                              cl_async_proc_item_t            *p_async_item );\r
422 \r
423 /******************************************************************************\r
424 *\r
425 * IOC PnP service - per local port child of IOC PnP manager.\r
426 *\r
427 ******************************************************************************/\r
428 static ib_api_status_t\r
429 __create_ioc_pnp_svc(\r
430         IN                              ib_pnp_rec_t                            *p_pnp_rec );\r
431 \r
432 static ib_api_status_t\r
433 __init_ioc_pnp_svc(\r
434         IN                              ioc_pnp_svc_t* const            p_ioc_pnp_svc,\r
435         IN              const   ib_pnp_rec_t* const                     p_pnp_rec );\r
436 \r
437 static void\r
438 __destroying_ioc_pnp_svc(\r
439         IN                              al_obj_t                                        *p_obj );\r
440 \r
441 static void\r
442 __free_ioc_pnp_svc(\r
443         IN                              al_obj_t                                        *p_obj );\r
444 \r
445 /******************************************************************************\r
446 *\r
447 * IOC PnP service sweep functions.\r
448 *\r
449 ******************************************************************************/\r
450 static void\r
451 __ioc_pnp_recv_cb(\r
452         IN              const   ib_mad_svc_handle_t                     h_mad_svc,\r
453         IN                              void                                            *mad_svc_context,\r
454         IN                              ib_mad_element_t                        *p_request_mad );\r
455 \r
456 static void\r
457 __ioc_pnp_send_cb(\r
458         IN              const   ib_mad_svc_handle_t                     h_mad_svc,\r
459         IN                              void                                            *mad_svc_context,\r
460         IN                              ib_mad_element_t                        *p_mad_response );\r
461 \r
462 static void\r
463 __node_rec_cb(\r
464         IN                              ib_query_rec_t                          *p_query_rec );\r
465 \r
466 static void\r
467 __path_rec_cb(\r
468         IN                              ib_query_rec_t                          *p_query_rec );\r
469 \r
470 static void\r
471 __process_sweep(\r
472         IN                              cl_async_proc_item_t            *p_async_item );\r
473 \r
474 static void\r
475 __process_query(\r
476         IN                              ioc_pnp_svc_t* const            p_svc );\r
477 \r
478 static void\r
479 __process_nodes(\r
480         IN                              ioc_pnp_svc_t* const            p_svc,\r
481         IN                              cl_qmap_t* const                        p_iou_map );\r
482 \r
483 static void\r
484 __process_paths(\r
485         IN                              ioc_pnp_svc_t* const            p_svc,\r
486         IN                              cl_qmap_t* const                        p_iou_map );\r
487 \r
488 static void\r
489 __build_iou_map(\r
490         IN                              cl_qmap_t* const                        p_port_map,\r
491         IN      OUT                     cl_fmap_t* const                        p_iou_map );\r
492 \r
493 static void\r
494 __format_dm_get(\r
495         IN              const   void* const                                     context1,\r
496         IN              const   void* const                                     context2,\r
497         IN              const   iou_path_t* const                       p_path,\r
498         IN              const   net16_t                                         attr_id,\r
499         IN              const   net32_t                                         attr_mod,\r
500         IN      OUT                     ib_mad_element_t* const         p_mad_element );\r
501 \r
502 static ib_api_status_t\r
503 __ioc_query_sa(\r
504         IN                              ioc_pnp_svc_t* const            p_svc );\r
505 \r
506 static ib_api_status_t\r
507 __query_ious(\r
508         IN                              ioc_sweep_results_t* const      p_results );\r
509 \r
510 static ib_api_status_t\r
511 __query_ioc_profiles(\r
512         IN                              ioc_sweep_results_t* const      p_results );\r
513 \r
514 static ib_api_status_t\r
515 __query_svc_entries(\r
516         IN                              ioc_sweep_results_t* const      p_results );\r
517 \r
518 static void\r
519 __update_results(\r
520         IN                              ioc_sweep_results_t* const      p_results );\r
521 \r
522 static void\r
523 __iou_info_resp(\r
524         IN      OUT                     iou_node_t* const                       p_iou,\r
525         IN              const   ib_dm_mad_t* const                      p_mad );\r
526 \r
527 static void\r
528 __ioc_profile_resp(\r
529         IN      OUT                     iou_node_t* const                       p_iou,\r
530         IN              const   ib_dm_mad_t* const                      p_mad );\r
531 \r
532 static void\r
533 __svc_entry_resp(\r
534         IN      OUT                     iou_ioc_t* const                        p_ioc,\r
535         IN              const   ib_dm_mad_t* const                      p_mad );\r
536 \r
537 /******************************************************************************\r
538 *\r
539 * Client registration and notification management\r
540 *\r
541 ******************************************************************************/\r
542 static void\r
543 __change_ious(\r
544         IN                              cl_fmap_t* const                        p_cur_ious,\r
545         IN                              cl_fmap_t* const                        p_dup_ious );\r
546 \r
547 static void\r
548 __add_ious(\r
549         IN                              cl_fmap_t* const                        p_cur_ious,\r
550         IN                              cl_fmap_t* const                        p_new_ious,\r
551         IN                              al_pnp_t* const                         p_reg OPTIONAL );\r
552 \r
553 static void\r
554 __remove_ious(\r
555         IN                              cl_fmap_t* const                        p_old_ious );\r
556 \r
557 static void\r
558 __add_iocs(\r
559         IN                              iou_node_t* const                       p_iou,\r
560         IN                              cl_qmap_t* const                        p_new_iocs,\r
561         IN                              al_pnp_t* const                         p_reg OPTIONAL );\r
562 \r
563 static void\r
564 __remove_iocs(\r
565         IN                              iou_node_t* const                       p_iou,\r
566         IN                              cl_qmap_t* const                        p_old_iocs );\r
567 \r
568 static void\r
569 __add_paths(\r
570         IN                              iou_node_t* const                       p_iou,\r
571         IN                              cl_qmap_t* const                        p_ioc_map,\r
572         IN                              cl_fmap_t* const                        p_new_paths,\r
573         IN                              al_pnp_t* const                         p_reg OPTIONAL );\r
574 \r
575 static void\r
576 __add_ioc_paths(\r
577         IN                              iou_ioc_t* const                        p_ioc,\r
578         IN                              cl_fmap_t* const                        p_new_paths,\r
579         IN                              al_pnp_t* const                         p_reg OPTIONAL );\r
580 \r
581 static void\r
582 __remove_paths(\r
583         IN                              cl_qmap_t* const                        p_ioc_map,\r
584         IN                              cl_fmap_t* const                        p_old_paths );\r
585 \r
586 static void\r
587 __report_iou_add(\r
588         IN                              iou_node_t* const                       p_iou,\r
589         IN                              al_pnp_t* const                         p_reg OPTIONAL );\r
590 \r
591 static void\r
592 __report_iou_remove(\r
593         IN                              iou_node_t* const                       p_iou );\r
594 \r
595 static void\r
596 __report_ioc_add(\r
597         IN                              iou_node_t* const                       p_iou,\r
598         IN                              iou_ioc_t* const                        p_ioc,\r
599         IN                              al_pnp_t* const                         p_reg OPTIONAL );\r
600 \r
601 static void\r
602 __report_ioc_remove(\r
603         IN                              iou_node_t* const                       p_iou,\r
604         IN                              iou_ioc_t* const                        p_ioc );\r
605 \r
606 static void\r
607 __report_path(\r
608         IN                              iou_ioc_t* const                        p_ioc,\r
609         IN                              iou_path_t* const                       p_path,\r
610         IN                              ib_pnp_event_t                          pnp_event,\r
611         IN                              al_pnp_t* const                         p_reg OPTIONAL );\r
612 \r
613 \r
614 /******************************************************************************\r
615 *\r
616 * Implementation\r
617 *\r
618 ******************************************************************************/\r
619 ib_api_status_t\r
620 create_ioc_pnp(\r
621         IN                              al_obj_t* const                         p_parent_obj )\r
622 {\r
623         ib_api_status_t         status;\r
624         ib_pnp_req_t            pnp_req;\r
625 \r
626         AL_ENTER( AL_DBG_PNP );\r
627 \r
628         CL_ASSERT( !gp_ioc_pnp );\r
629 \r
630         gp_ioc_pnp = (ioc_pnp_mgr_t*)cl_zalloc( sizeof(ioc_pnp_mgr_t) );\r
631         if( !gp_ioc_pnp )\r
632         {\r
633                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
634                         ("Failed to allocate IOC PnP manager.\n") );\r
635                 return IB_INSUFFICIENT_MEMORY;\r
636         }\r
637 \r
638         __construct_ioc_pnp( gp_ioc_pnp );\r
639 \r
640         status = __init_ioc_pnp( gp_ioc_pnp );\r
641         if( status != IB_SUCCESS )\r
642         {\r
643                 __free_ioc_pnp( &gp_ioc_pnp->obj );\r
644                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
645                         ("__construct_ioc_pnp returned %s\n", ib_get_err_str( status )) );\r
646                 return status;\r
647         }\r
648 \r
649         /* Attach to the parent object. */\r
650         status = attach_al_obj( p_parent_obj, &gp_ioc_pnp->obj );\r
651         if( status != IB_SUCCESS )\r
652         {\r
653                 gp_ioc_pnp->obj.pfn_destroy( &gp_ioc_pnp->obj, NULL );\r
654                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
655                         ("attach_al_obj returned %s.\n", ib_get_err_str(status)) );\r
656                 return status;\r
657         }\r
658 \r
659         /* Register for port PnP notifications. */\r
660         cl_memclr( &pnp_req, sizeof(pnp_req) );\r
661         pnp_req.pnp_class = IB_PNP_PORT;\r
662         pnp_req.pnp_context = gp_ioc_pnp;\r
663         pnp_req.pfn_pnp_cb = __ioc_pnp_cb;\r
664         status = ib_reg_pnp( gh_al, &pnp_req, &gp_ioc_pnp->h_pnp );\r
665         if( status != IB_SUCCESS )\r
666         {\r
667                 gp_ioc_pnp->obj.pfn_destroy( &gp_ioc_pnp->obj, NULL );\r
668                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
669                         ("ib_reg_pnp failed with status %s.\n",\r
670                         ib_get_err_str( status )) );\r
671                 return status;\r
672         }\r
673         /*\r
674          * We don't release the reference taken in init_al_obj\r
675          * since PnP deregistration is asynchronous.\r
676          */\r
677         \r
678         AL_EXIT( AL_DBG_PNP );\r
679         return IB_SUCCESS;\r
680 }\r
681 \r
682 \r
683 static void\r
684 __construct_ioc_pnp(\r
685         IN                              ioc_pnp_mgr_t* const            p_ioc_mgr )\r
686 {\r
687         AL_ENTER( AL_DBG_PNP );\r
688 \r
689         cl_qlist_init( &p_ioc_mgr->iou_reg_list );\r
690         cl_qlist_init( &p_ioc_mgr->ioc_reg_list );\r
691         cl_fmap_init( &p_ioc_mgr->iou_map, __iou_cmp );\r
692         construct_al_obj( &p_ioc_mgr->obj, AL_OBJ_TYPE_IOC_PNP_MGR );\r
693         cl_spinlock_construct( &p_ioc_mgr->iou_pool_lock );\r
694         cl_spinlock_construct( &p_ioc_mgr->path_pool_lock );\r
695         cl_spinlock_construct( &p_ioc_mgr->ioc_pool_lock );\r
696         cl_qpool_construct( &p_ioc_mgr->iou_pool );\r
697         cl_qpool_construct( &p_ioc_mgr->path_pool );\r
698         cl_qpool_construct( &p_ioc_mgr->ioc_pool );\r
699         cl_fmap_init( &p_ioc_mgr->sweep_map, __iou_cmp );\r
700         cl_timer_construct( &p_ioc_mgr->sweep_timer );\r
701         p_ioc_mgr->async_item.pfn_callback = __ioc_async_cb;\r
702 \r
703         AL_EXIT( AL_DBG_PNP );\r
704 }\r
705 \r
706 \r
707 static ib_api_status_t\r
708 __init_ioc_pnp(\r
709         IN                              ioc_pnp_mgr_t* const            p_ioc_mgr )\r
710 {\r
711         ib_api_status_t         status;\r
712         cl_status_t                     cl_status;\r
713 \r
714         AL_ENTER( AL_DBG_PNP );\r
715 \r
716         /* Initialize the pool locks. */\r
717         cl_status = cl_spinlock_init( &p_ioc_mgr->iou_pool_lock );\r
718         if( cl_status != CL_SUCCESS )\r
719         {\r
720                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
721                         ("cl_spinlock_init returned %#x\n", cl_status) );\r
722                 return ib_convert_cl_status( cl_status );\r
723         }\r
724 \r
725         cl_status = cl_spinlock_init( &p_ioc_mgr->path_pool_lock );\r
726         if( cl_status != CL_SUCCESS )\r
727         {\r
728                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
729                         ("cl_spinlock_init returned %#x\n", cl_status) );\r
730                 return ib_convert_cl_status( cl_status );\r
731         }\r
732 \r
733         cl_status = cl_spinlock_init( &p_ioc_mgr->ioc_pool_lock );\r
734         if( cl_status != CL_SUCCESS )\r
735         {\r
736                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
737                         ("cl_spinlock_init returned %#x\n", cl_status) );\r
738                 return ib_convert_cl_status( cl_status );\r
739         }\r
740 \r
741         /* Initialize the pools */\r
742         cl_status = cl_qpool_init( &p_ioc_mgr->iou_pool, 0, 0, IOC_PNP_POOL_GROW,\r
743                 sizeof(iou_node_t), __init_iou, NULL, p_ioc_mgr );\r
744         if( cl_status != CL_SUCCESS )\r
745         {\r
746                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
747                         ("cl_qpool_init returned %#x\n", cl_status) );\r
748                 return ib_convert_cl_status( cl_status );\r
749         }\r
750 \r
751         cl_status = cl_qpool_init( &p_ioc_mgr->path_pool, 0, 0, IOC_PNP_POOL_GROW,\r
752                 sizeof(iou_path_t), NULL, NULL, NULL );\r
753         if( cl_status != CL_SUCCESS )\r
754         {\r
755                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
756                         ("cl_qpool_init returned %#x\n", cl_status) );\r
757                 return ib_convert_cl_status( cl_status );\r
758         }\r
759 \r
760         cl_status = cl_qpool_init( &p_ioc_mgr->ioc_pool, 0, 0, IOC_PNP_POOL_GROW,\r
761                 sizeof(iou_ioc_t), NULL, NULL, NULL );\r
762         if( cl_status != CL_SUCCESS )\r
763         {\r
764                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
765                         ("cl_qpool_init returned %#x\n", cl_status) );\r
766                 return ib_convert_cl_status( cl_status );\r
767         }\r
768 \r
769         /* Initialize the sweep timer. */\r
770         cl_status = cl_timer_init( &p_ioc_mgr->sweep_timer,\r
771                 __ioc_pnp_timer_cb, p_ioc_mgr );\r
772         if( cl_status != CL_SUCCESS )\r
773         {\r
774                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
775                         ("cl_timer_init failed with %#x\n", cl_status) );\r
776                 return ib_convert_cl_status( cl_status );\r
777         }\r
778 \r
779         status = init_al_obj( &p_ioc_mgr->obj, p_ioc_mgr, TRUE,\r
780                 __destroying_ioc_pnp, NULL, __free_ioc_pnp );\r
781         if( status != IB_SUCCESS )\r
782         {\r
783                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
784                         ("init_al_obj returned %s\n", ib_get_err_str( status )) );\r
785                 return status;\r
786         }\r
787 \r
788         AL_EXIT( AL_DBG_PNP );\r
789         return IB_SUCCESS;\r
790 }\r
791 \r
792 \r
793 static void\r
794 __destroying_ioc_pnp(\r
795         IN                              al_obj_t                                        *p_obj )\r
796 {\r
797         ib_api_status_t         status;\r
798 \r
799         AL_ENTER( AL_DBG_PNP );\r
800 \r
801         UNUSED_PARAM( p_obj );\r
802         CL_ASSERT( &gp_ioc_pnp->obj == p_obj );\r
803 \r
804         /* Stop the timer. */\r
805         cl_timer_stop( &gp_ioc_pnp->sweep_timer );\r
806 \r
807         if( gp_ioc_pnp->h_pnp )\r
808         {\r
809                 status = ib_dereg_pnp( gp_ioc_pnp->h_pnp,\r
810                         (ib_pfn_destroy_cb_t)deref_al_obj );\r
811                 CL_ASSERT( status == IB_SUCCESS );\r
812         }\r
813 \r
814         AL_EXIT( AL_DBG_PNP );\r
815 }\r
816 \r
817 \r
818 static void\r
819 __free_ioc_pnp(\r
820         IN                              al_obj_t                                        *p_obj )\r
821 {\r
822         AL_ENTER( AL_DBG_PNP );\r
823 \r
824         CL_ASSERT( &gp_ioc_pnp->obj == p_obj );\r
825 \r
826         /*\r
827          * Return all items from the maps to their pools before\r
828          * destroying the pools\r
829          */\r
830         __put_iou_map( gp_ioc_pnp, &gp_ioc_pnp->iou_map );\r
831         cl_timer_destroy( &gp_ioc_pnp->sweep_timer );\r
832         cl_qpool_destroy( &gp_ioc_pnp->ioc_pool );\r
833         cl_qpool_destroy( &gp_ioc_pnp->path_pool );\r
834         cl_qpool_destroy( &gp_ioc_pnp->iou_pool );\r
835         cl_spinlock_destroy( &gp_ioc_pnp->ioc_pool_lock );\r
836         cl_spinlock_destroy( &gp_ioc_pnp->path_pool_lock );\r
837         cl_spinlock_destroy( &gp_ioc_pnp->iou_pool_lock );\r
838         destroy_al_obj( p_obj );\r
839         cl_free( gp_ioc_pnp );\r
840         gp_ioc_pnp = NULL;\r
841 \r
842         AL_EXIT( AL_DBG_PNP );\r
843 }\r
844 \r
845 \r
846 static cl_status_t\r
847 __init_iou(\r
848         IN                              void* const                                     p_obj,\r
849         IN                              void*                                           context,\r
850                 OUT                     cl_pool_item_t** const          pp_pool_item )\r
851 {\r
852         iou_node_t      *p_iou;\r
853 \r
854         UNUSED_PARAM( context );\r
855 \r
856         p_iou = (iou_node_t*)p_obj;\r
857         \r
858         cl_spinlock_construct( &p_iou->lock );\r
859         cl_qmap_init( &p_iou->ioc_map );\r
860         cl_fmap_init( &p_iou->path_map, __path_cmp );\r
861 \r
862         *pp_pool_item = &p_iou->map_item.pool_item;\r
863         return cl_spinlock_init( &p_iou->lock );\r
864 }\r
865 \r
866 \r
867 static iou_node_t*\r
868 __get_iou(\r
869         IN                              ioc_pnp_mgr_t* const            p_ioc_mgr,\r
870         IN              const   net64_t                                         ca_guid,\r
871         IN              const   ib_node_record_t* const         p_node_rec )\r
872 {\r
873         iou_node_t              *p_iou;\r
874         cl_pool_item_t  *p_item;\r
875 \r
876         cl_spinlock_acquire( &p_ioc_mgr->iou_pool_lock );\r
877         p_item = cl_qpool_get( &p_ioc_mgr->iou_pool );\r
878         cl_spinlock_release( &p_ioc_mgr->iou_pool_lock );\r
879         if( !p_item )\r
880                 return NULL;\r
881 \r
882         p_iou = PARENT_STRUCT( PARENT_STRUCT( p_item, cl_map_item_t, pool_item ),\r
883                 iou_node_t, map_item );\r
884 \r
885         p_iou->ca_guid = ca_guid;\r
886         p_iou->guid = p_node_rec->node_info.node_guid;\r
887         p_iou->chassis_guid = p_node_rec->node_info.sys_guid;\r
888         p_iou->vend_id = ib_node_info_get_vendor_id( &p_node_rec->node_info );\r
889         p_iou->dev_id = p_node_rec->node_info.device_id;\r
890         p_iou->revision = p_node_rec->node_info.revision;\r
891 \r
892         cl_memclr( &p_iou->info, sizeof(ib_iou_info_t) );\r
893 \r
894         cl_memcpy( p_iou->desc, p_node_rec->node_desc.description,\r
895                 IB_NODE_DESCRIPTION_SIZE );\r
896 \r
897         /* The terminating NULL should never get overwritten. */\r
898         CL_ASSERT( p_iou->desc[IB_NODE_DESCRIPTION_SIZE] == '\0' );\r
899 \r
900         return p_iou;\r
901 }\r
902 \r
903 \r
904 static void\r
905 __put_iou(\r
906         IN                              ioc_pnp_mgr_t* const            p_ioc_mgr,\r
907         IN                              iou_node_t* const                       p_iou )\r
908 {\r
909         __put_path_map( p_ioc_mgr, &p_iou->path_map );\r
910         __put_ioc_map( p_ioc_mgr, &p_iou->ioc_map );\r
911 \r
912         cl_spinlock_acquire( &p_ioc_mgr->iou_pool_lock );\r
913         cl_qpool_put( &p_ioc_mgr->iou_pool, &p_iou->map_item.pool_item );\r
914         cl_spinlock_release( &p_ioc_mgr->iou_pool_lock );\r
915 }\r
916 \r
917 \r
918 static void\r
919 __put_iou_map(\r
920         IN                              ioc_pnp_mgr_t* const            p_ioc_mgr,\r
921         IN                              cl_fmap_t* const                        p_iou_map )\r
922 {\r
923         cl_qlist_t              list;\r
924         cl_fmap_item_t  *p_item;\r
925         iou_node_t              *p_iou;\r
926 \r
927         cl_qlist_init( &list );\r
928 \r
929         p_item = cl_fmap_head( p_iou_map );\r
930         while( p_item != cl_fmap_end( p_iou_map ) )\r
931         {\r
932                 cl_fmap_remove_item( p_iou_map, p_item );\r
933 \r
934                 p_iou = PARENT_STRUCT(\r
935                         PARENT_STRUCT( p_item, cl_map_item_t, pool_item ),\r
936                         iou_node_t, map_item );\r
937 \r
938                 __put_path_map( p_ioc_mgr, &p_iou->path_map );\r
939                 __put_ioc_map( p_ioc_mgr, &p_iou->ioc_map );\r
940                 cl_qlist_insert_head( &list, &p_item->pool_item.list_item );\r
941                 p_item = cl_fmap_head( p_iou_map );\r
942         }\r
943         cl_spinlock_acquire( &p_ioc_mgr->iou_pool_lock );\r
944         cl_qpool_put_list( &p_ioc_mgr->iou_pool, &list );\r
945         cl_spinlock_release( &p_ioc_mgr->iou_pool_lock );\r
946 }\r
947 \r
948 \r
949 static iou_path_t*\r
950 __get_path(\r
951         IN                              ioc_pnp_mgr_t* const            p_ioc_mgr,\r
952         IN              const   net64_t                                         ca_guid,\r
953         IN              const   net64_t                                         port_guid,\r
954         IN              const   ib_path_rec_t* const            p_path_rec )\r
955 {\r
956         cl_pool_item_t  *p_item;\r
957         iou_path_t              *p_path;\r
958 \r
959         cl_spinlock_acquire( &p_ioc_mgr->path_pool_lock );\r
960         p_item = cl_qpool_get( &p_ioc_mgr->path_pool );\r
961         cl_spinlock_release( &p_ioc_mgr->path_pool_lock );\r
962         if( !p_item )\r
963                 return NULL;\r
964 \r
965         p_path = PARENT_STRUCT( PARENT_STRUCT( p_item, cl_fmap_item_t, pool_item ),\r
966                 iou_path_t, map_item );\r
967 \r
968         /*\r
969          * Store the local CA and port GUID for this path to let recipients\r
970          * of a PATH_ADD event avoid a CA lookup based on GID.\r
971          */\r
972         p_path->ca_guid = ca_guid;\r
973         p_path->port_guid = port_guid;\r
974 \r
975         p_path->rec = *p_path_rec;\r
976         /* Clear the num_path field since it is just "undefined". */\r
977         p_path->rec.num_path = 0;\r
978         /*\r
979          * Clear reserved fields in case they were set to prevent undue path\r
980          * thrashing.\r
981          */\r
982         p_path->rec.resv1 = 0;\r
983         p_path->rec.resv2 = 0;\r
984 \r
985         return p_path;\r
986 }\r
987 \r
988 \r
989 static void\r
990 __put_path(\r
991         IN                              ioc_pnp_mgr_t* const            p_ioc_mgr,\r
992         IN                              iou_path_t* const                       p_path )\r
993 {\r
994         cl_spinlock_acquire( &p_ioc_mgr->path_pool_lock );\r
995         cl_qpool_put( &p_ioc_mgr->path_pool, &p_path->map_item.pool_item );\r
996         cl_spinlock_release( &p_ioc_mgr->path_pool_lock );\r
997 }\r
998 \r
999 \r
1000 static void\r
1001 __put_path_map(\r
1002         IN                              ioc_pnp_mgr_t* const            p_ioc_mgr,\r
1003         IN                              cl_fmap_t* const                        p_path_map )\r
1004 {\r
1005         cl_qlist_t              list;\r
1006         cl_fmap_item_t  *p_item;\r
1007         iou_path_t              *p_path;\r
1008 \r
1009         cl_qlist_init( &list );\r
1010 \r
1011         p_item = cl_fmap_head( p_path_map );\r
1012         while( p_item != cl_fmap_end( p_path_map ) )\r
1013         {\r
1014                 cl_fmap_remove_item( p_path_map, p_item );\r
1015 \r
1016                 p_path = PARENT_STRUCT( PARENT_STRUCT( p_item, cl_fmap_item_t, pool_item ),\r
1017                         iou_path_t, map_item );\r
1018 \r
1019                 cl_qlist_insert_head( &list, &p_item->pool_item.list_item );\r
1020                 p_item = cl_fmap_head( p_path_map );\r
1021         }\r
1022         cl_spinlock_acquire( &p_ioc_mgr->path_pool_lock );\r
1023         cl_qpool_put_list( &p_ioc_mgr->path_pool, &list );\r
1024         cl_spinlock_release( &p_ioc_mgr->path_pool_lock );\r
1025 }\r
1026 \r
1027 \r
1028 static iou_ioc_t*\r
1029 __get_ioc(\r
1030         IN                              ioc_pnp_mgr_t* const            p_ioc_mgr,\r
1031         IN              const   uint32_t                                        ioc_slot,\r
1032         IN              const   ib_ioc_profile_t* const         p_profile )\r
1033 {\r
1034         cl_pool_item_t          *p_item;\r
1035         iou_ioc_t                       *p_ioc;\r
1036         ib_svc_entry_t          *p_svc_entries;\r
1037 \r
1038         if( !p_profile->num_svc_entries )\r
1039                 return NULL;\r
1040 \r
1041         p_svc_entries =\r
1042                 cl_zalloc( sizeof(ib_svc_entry_t) * p_profile->num_svc_entries );\r
1043         if( !p_svc_entries )\r
1044                 return NULL;\r
1045 \r
1046         cl_spinlock_acquire( &p_ioc_mgr->ioc_pool_lock );\r
1047         p_item = cl_qpool_get( &p_ioc_mgr->ioc_pool );\r
1048         cl_spinlock_release( &p_ioc_mgr->ioc_pool_lock );\r
1049         if( !p_item )\r
1050         {\r
1051                 cl_free( p_svc_entries );\r
1052                 return NULL;\r
1053         }\r
1054 \r
1055         p_ioc = PARENT_STRUCT( PARENT_STRUCT( p_item, cl_map_item_t, pool_item ),\r
1056                 iou_ioc_t, map_item );\r
1057         \r
1058         CL_ASSERT( !p_ioc->ref_cnt );\r
1059 \r
1060         CL_ASSERT( !(ioc_slot >> 8) );\r
1061         p_ioc->slot = (uint8_t)ioc_slot;\r
1062         p_ioc->profile = *p_profile;\r
1063         p_ioc->num_valid_entries = 0;\r
1064         p_ioc->p_svc_entries = p_svc_entries;\r
1065         cl_atomic_inc( &p_ioc->ref_cnt );\r
1066         return p_ioc;\r
1067 }\r
1068 \r
1069 \r
1070 static void\r
1071 __put_ioc(\r
1072         IN                              ioc_pnp_mgr_t* const            p_ioc_mgr,\r
1073         IN                              iou_ioc_t* const                        p_ioc )\r
1074 {\r
1075         if( cl_atomic_dec( &p_ioc->ref_cnt ) == 0 )\r
1076         {\r
1077                 cl_free( p_ioc->p_svc_entries );\r
1078 \r
1079                 cl_spinlock_acquire( &p_ioc_mgr->ioc_pool_lock );\r
1080                 cl_qpool_put( &p_ioc_mgr->ioc_pool, &p_ioc->map_item.pool_item );\r
1081                 cl_spinlock_release( &p_ioc_mgr->ioc_pool_lock );\r
1082         }\r
1083 }\r
1084 \r
1085 \r
1086 static void\r
1087 __put_ioc_map(\r
1088         IN                              ioc_pnp_mgr_t* const            p_ioc_mgr,\r
1089         IN                              cl_qmap_t* const                        p_ioc_map )\r
1090 {\r
1091         cl_qlist_t              list;\r
1092         cl_map_item_t   *p_item;\r
1093         iou_ioc_t               *p_ioc;\r
1094 \r
1095         cl_qlist_init( &list );\r
1096 \r
1097         p_item = cl_qmap_head( p_ioc_map );\r
1098         while( p_item != cl_qmap_end( p_ioc_map ) )\r
1099         {\r
1100                 cl_qmap_remove_item( p_ioc_map, p_item );\r
1101 \r
1102                 p_ioc = PARENT_STRUCT(\r
1103                         PARENT_STRUCT( p_item, cl_map_item_t, pool_item ),\r
1104                         iou_ioc_t, map_item );\r
1105                 \r
1106                 if( cl_atomic_dec( &p_ioc->ref_cnt ) == 0 )\r
1107                 {\r
1108                         cl_free( p_ioc->p_svc_entries );\r
1109                         cl_qlist_insert_head( &list, &p_item->pool_item.list_item );\r
1110                 }\r
1111                 p_item = cl_qmap_head( p_ioc_map );\r
1112         }\r
1113         cl_spinlock_acquire( &p_ioc_mgr->ioc_pool_lock );\r
1114         cl_qpool_put_list( &p_ioc_mgr->ioc_pool, &list );\r
1115         cl_spinlock_release( &p_ioc_mgr->ioc_pool_lock );\r
1116 }\r
1117 \r
1118 \r
1119 /*\r
1120  * Compares two IOUs for inserts/lookups in a flexi map.  Keys are the\r
1121  * address of the ca_guid, which is adjacent to the node GUID of the IOU.\r
1122  * This allows for a single call to cl_memcmp.\r
1123  */\r
1124 static intn_t\r
1125 __iou_cmp(\r
1126         IN              const   void* const                                     p_key1,\r
1127         IN              const   void* const                                     p_key2 )\r
1128 {\r
1129         return cl_memcmp( p_key1, p_key2, sizeof(uint64_t) * 2 );\r
1130 }\r
1131 \r
1132 \r
1133 /*\r
1134  * Compares two paths for inserts/lookups in a flexi map.\r
1135  */\r
1136 static intn_t\r
1137 __path_cmp(\r
1138         IN              const   void* const                                     p_key1,\r
1139         IN              const   void* const                                     p_key2 )\r
1140 {\r
1141         return cl_memcmp( p_key1, p_key2, sizeof(ib_path_rec_t) );\r
1142 }\r
1143 \r
1144 \r
1145 /*\r
1146  * Removes all paths and orphaned IOC/IOUs upon a port DOWN event.\r
1147  */\r
1148 static void\r
1149 __process_port_down(\r
1150         IN              const   net64_t                                         port_guid )\r
1151 {\r
1152         cl_fmap_item_t          *p_path_item;\r
1153         cl_fmap_item_t          *p_iou_item;\r
1154         iou_node_t                      *p_iou;\r
1155         iou_path_t                      *p_path;\r
1156         cl_fmap_t                       old_paths;\r
1157         cl_fmap_t                       old_ious;\r
1158 \r
1159         AL_ENTER( AL_DBG_PNP );\r
1160 \r
1161         cl_fmap_init( &old_paths, __path_cmp );\r
1162         cl_fmap_init( &old_ious, __iou_cmp );\r
1163 \r
1164         p_iou_item = cl_fmap_head( &gp_ioc_pnp->iou_map );\r
1165         while( p_iou_item != cl_fmap_end( &gp_ioc_pnp->iou_map ) )\r
1166         {\r
1167                 p_iou = PARENT_STRUCT( p_iou_item, iou_node_t, map_item );\r
1168                 /*\r
1169                  * Note that it is safe to move to the next item even if we remove\r
1170                  * the IOU from the map since the map effectively maintains an ordered\r
1171                  * list of its contents.\r
1172                  */\r
1173                 p_iou_item = cl_fmap_next( p_iou_item );\r
1174 \r
1175                 p_path_item = cl_fmap_head( &p_iou->path_map );\r
1176                 while( p_path_item != cl_fmap_end( &p_iou->path_map ) )\r
1177                 {\r
1178                         p_path = PARENT_STRUCT( p_path_item, iou_path_t, map_item );\r
1179                         p_path_item = cl_fmap_next( p_path_item );\r
1180                         if( p_path->rec.sgid.unicast.interface_id == port_guid )\r
1181                         {\r
1182                                 cl_fmap_remove_item( &p_iou->path_map, &p_path->map_item );\r
1183                                 cl_fmap_insert( &old_paths, &p_path->rec, &p_path->map_item );\r
1184                         }\r
1185                 }\r
1186 \r
1187                 if( !cl_fmap_count( &p_iou->path_map ) )\r
1188                 {\r
1189                         /* Move the paths back to the IOU so that they get freed. */\r
1190                         cl_fmap_merge( &p_iou->path_map, &old_paths );\r
1191                         cl_fmap_remove_item( &gp_ioc_pnp->iou_map, &p_iou->map_item );\r
1192                         cl_fmap_insert( &old_ious, &p_iou->ca_guid, &p_iou->map_item );\r
1193                 }\r
1194                 else\r
1195                 {\r
1196                         /* Report the removed paths. */\r
1197                         __remove_paths( &p_iou->ioc_map, &old_paths );\r
1198                 }\r
1199         }\r
1200 \r
1201         /* Report any removed IOUs. */\r
1202         __remove_ious( &old_ious );\r
1203 \r
1204         AL_EXIT( AL_DBG_PNP );\r
1205 }\r
1206 \r
1207 \r
1208 /*\r
1209  * PnP callback for port event notifications.\r
1210  */\r
1211 static ib_api_status_t\r
1212 __ioc_pnp_cb(\r
1213         IN                              ib_pnp_rec_t                            *p_pnp_rec )\r
1214 {\r
1215         ib_api_status_t status = IB_SUCCESS;\r
1216         cl_status_t             cl_status;\r
1217 \r
1218         AL_ENTER( AL_DBG_PNP );\r
1219 \r
1220         AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_PNP,\r
1221                 ("p_pnp_rec->pnp_event = 0x%x (%s)\n",\r
1222                 p_pnp_rec->pnp_event, ib_get_pnp_event_str( p_pnp_rec->pnp_event )) );\r
1223 \r
1224         switch( p_pnp_rec->pnp_event )\r
1225         {\r
1226         case IB_PNP_PORT_ADD:\r
1227                 /* Create the port service. */\r
1228                 CL_ASSERT( !p_pnp_rec->context );\r
1229                 status = __create_ioc_pnp_svc( p_pnp_rec );\r
1230                 break;\r
1231 \r
1232         case IB_PNP_SM_CHANGE:\r
1233         case IB_PNP_PORT_ACTIVE:\r
1234                 /* Initiate a sweep - delay a bit to allow the ports to come up. */\r
1235                 if( g_ioc_poll_interval && !gp_ioc_pnp->query_cnt)\r
1236                 {\r
1237                         cl_status = cl_timer_start( &gp_ioc_pnp->sweep_timer, 250 );\r
1238                         CL_ASSERT( cl_status == CL_SUCCESS );\r
1239                 }\r
1240                 break;\r
1241 \r
1242         case IB_PNP_PORT_DOWN:\r
1243         case IB_PNP_PORT_INIT:\r
1244         case IB_PNP_PORT_ARMED:\r
1245                 CL_ASSERT( p_pnp_rec->context );\r
1246 \r
1247                 /*\r
1248                  * Report IOC and IOU remove events for any IOU/IOCs that only have\r
1249                  * paths through this port.  Note, no need to synchronize with a\r
1250                  * sweep since synchronization is provided by the PnP thread.\r
1251                  */\r
1252                 __process_port_down( p_pnp_rec->guid );\r
1253                 break;\r
1254 \r
1255         case IB_PNP_PORT_REMOVE:\r
1256                 /* Destroy the port service. */\r
1257                 ref_al_obj( &((ioc_pnp_svc_t*)p_pnp_rec->context)->obj );\r
1258                 ((ioc_pnp_svc_t*)p_pnp_rec->context)->obj.pfn_destroy(\r
1259                         &((ioc_pnp_svc_t*)p_pnp_rec->context)->obj, NULL );\r
1260                 p_pnp_rec->context = NULL;\r
1261 \r
1262         default:\r
1263                 break;  /* Ignore other PNP events. */\r
1264         }\r
1265 \r
1266         AL_EXIT( AL_DBG_PNP );\r
1267         return status;\r
1268 }\r
1269 \r
1270 \r
1271 static ib_api_status_t\r
1272 __init_ioc_pnp_svc(\r
1273         IN                              ioc_pnp_svc_t* const            p_ioc_pnp_svc,\r
1274         IN              const   ib_pnp_rec_t* const                     p_pnp_rec )\r
1275 {\r
1276         ib_api_status_t         status;\r
1277         ib_ca_handle_t          h_ca;\r
1278         ib_qp_create_t          qp_create;\r
1279         ib_mad_svc_t            mad_svc;\r
1280         ib_pnp_port_rec_t       *p_pnp_port_rec;\r
1281 \r
1282         AL_ENTER( AL_DBG_PNP );\r
1283 \r
1284         p_pnp_port_rec = PARENT_STRUCT( p_pnp_rec, ib_pnp_port_rec_t, pnp_rec );\r
1285 \r
1286         /* Store the CA and port GUID so we can issue SA queries. */\r
1287         p_ioc_pnp_svc->ca_guid = p_pnp_port_rec->p_ca_attr->ca_guid;\r
1288         p_ioc_pnp_svc->port_guid = p_pnp_rec->guid;\r
1289 \r
1290         /* Acquire the correct CI CA for this port. */\r
1291         h_ca = acquire_ca( p_pnp_port_rec->p_ca_attr->ca_guid );\r
1292         if( !h_ca )\r
1293         {\r
1294                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("acquire_ca failed.\n") );\r
1295                 return IB_INVALID_GUID;\r
1296         }\r
1297         p_ioc_pnp_svc->obj.p_ci_ca = h_ca->obj.p_ci_ca;\r
1298 \r
1299         /* Create the MAD QP. */\r
1300         cl_memclr( &qp_create, sizeof( ib_qp_create_t ) );\r
1301         qp_create.qp_type = IB_QPT_QP1_ALIAS;\r
1302         qp_create.sq_depth = p_pnp_port_rec->p_ca_attr->max_wrs;\r
1303         qp_create.sq_sge = 1;\r
1304         qp_create.sq_signaled = TRUE;\r
1305         /*\r
1306          * We use the IOC PnP service's al_obj_t as the context to allow using\r
1307          * deref_al_obj as the destroy callback.\r
1308          */\r
1309         status = ib_get_spl_qp( h_ca->obj.p_ci_ca->h_pd_alias,\r
1310                 p_pnp_port_rec->p_port_attr->port_guid, &qp_create,\r
1311                 &p_ioc_pnp_svc->obj, NULL, &p_ioc_pnp_svc->pool_key,\r
1312                 &p_ioc_pnp_svc->h_qp );\r
1313 \r
1314         /*\r
1315          * Release the CI CA once we've allocated the QP.  The CI CA will not\r
1316          * go away while we hold the QP.\r
1317          */\r
1318         deref_al_obj( &h_ca->obj );\r
1319 \r
1320         /* Check for failure allocating the QP. */\r
1321         if( status != IB_SUCCESS )\r
1322         {\r
1323                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1324                         ("ib_get_spl_qp failed with status %s\n",\r
1325                         ib_get_err_str( status )) );\r
1326                 return status;\r
1327         }\r
1328         /* Reference the port object on behalf of the QP. */\r
1329         ref_al_obj( &p_ioc_pnp_svc->obj );\r
1330 \r
1331         /* Create the MAD service. */\r
1332         cl_memclr( &mad_svc, sizeof(ib_mad_svc_t) );\r
1333         mad_svc.mad_svc_context = p_ioc_pnp_svc;\r
1334         mad_svc.pfn_mad_recv_cb = __ioc_pnp_recv_cb;\r
1335         mad_svc.pfn_mad_send_cb = __ioc_pnp_send_cb;\r
1336         status =\r
1337                 ib_reg_mad_svc( p_ioc_pnp_svc->h_qp, &mad_svc,\r
1338                 &p_ioc_pnp_svc->h_mad_svc );\r
1339         if( status != IB_SUCCESS )\r
1340         {\r
1341                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1342                         ("ib_reg_mad_svc failed with status %s\n",\r
1343                         ib_get_err_str( status )) );\r
1344                 return status;\r
1345         }\r
1346 \r
1347         AL_EXIT( AL_DBG_PNP );\r
1348         return IB_SUCCESS;\r
1349 }\r
1350 \r
1351 \r
1352 /*\r
1353  * Create a port agent for a given port.\r
1354  */\r
1355 static ib_api_status_t\r
1356 __create_ioc_pnp_svc(\r
1357         IN                              ib_pnp_rec_t                            *p_pnp_rec )\r
1358 {\r
1359         ioc_pnp_svc_t           *p_ioc_pnp_svc;\r
1360         ib_api_status_t         status;\r
1361 \r
1362         AL_ENTER( AL_DBG_PNP );\r
1363 \r
1364         /* calculate size of port_cm struct */\r
1365         p_ioc_pnp_svc = (ioc_pnp_svc_t*)cl_zalloc( sizeof(ioc_pnp_svc_t) );\r
1366         if( !p_ioc_pnp_svc )\r
1367         {\r
1368                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1369                         ("Failed to cl_zalloc port CM agent.\n") );\r
1370                 return IB_INSUFFICIENT_MEMORY;\r
1371         }\r
1372 \r
1373         construct_al_obj( &p_ioc_pnp_svc->obj, AL_OBJ_TYPE_IOC_PNP_SVC );\r
1374 \r
1375         status = init_al_obj( &p_ioc_pnp_svc->obj, p_ioc_pnp_svc, TRUE,\r
1376                 __destroying_ioc_pnp_svc, NULL, __free_ioc_pnp_svc );\r
1377         if( status != IB_SUCCESS )\r
1378         {\r
1379                 __free_ioc_pnp_svc( &p_ioc_pnp_svc->obj );\r
1380                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1381                         ("init_al_obj failed with status %s.\n",\r
1382                         ib_get_err_str( status )) );\r
1383                 return status;\r
1384         }\r
1385 \r
1386         /* Attach to the global CM object. */\r
1387         status = attach_al_obj( &gp_ioc_pnp->obj, &p_ioc_pnp_svc->obj );\r
1388         if( status != IB_SUCCESS )\r
1389         {\r
1390                 p_ioc_pnp_svc->obj.pfn_destroy( &p_ioc_pnp_svc->obj, NULL );\r
1391                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1392                         ("attach_al_obj returned %s.\n", ib_get_err_str(status)) );\r
1393                 return status;\r
1394         }\r
1395 \r
1396         status = __init_ioc_pnp_svc( p_ioc_pnp_svc, p_pnp_rec );\r
1397         if( status != IB_SUCCESS )\r
1398         {\r
1399                 p_ioc_pnp_svc->obj.pfn_destroy( &p_ioc_pnp_svc->obj, NULL );\r
1400                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1401                         ("__init_data_svc failed with status %s.\n",\r
1402                         ib_get_err_str( status )) );\r
1403                 return status;\r
1404         }\r
1405 \r
1406         /* Set the PnP context to reference this service. */\r
1407         p_pnp_rec->context = p_ioc_pnp_svc;\r
1408 \r
1409         /* Release the reference taken in init_al_obj. */\r
1410         deref_al_obj( &p_ioc_pnp_svc->obj );\r
1411 \r
1412         AL_EXIT( AL_DBG_PNP );\r
1413         return status;\r
1414 }\r
1415 \r
1416 \r
1417 static void\r
1418 __destroying_ioc_pnp_svc(\r
1419         IN                              al_obj_t                                        *p_obj )\r
1420 {\r
1421         ib_api_status_t         status;\r
1422         ioc_pnp_svc_t           *p_svc;\r
1423 \r
1424         CL_ASSERT( p_obj );\r
1425         p_svc = PARENT_STRUCT( p_obj, ioc_pnp_svc_t, obj );\r
1426 \r
1427         if( p_svc->h_node_query )\r
1428                 ib_cancel_query( gh_al, p_svc->h_node_query );\r
1429 \r
1430         if( p_svc->h_path_query )\r
1431                 ib_cancel_query( gh_al, p_svc->h_path_query );\r
1432 \r
1433         /* Destroy the QP. */\r
1434         if( p_svc->h_qp )\r
1435         {\r
1436                 status =\r
1437                         ib_destroy_qp( p_svc->h_qp, (ib_pfn_destroy_cb_t)deref_al_obj );\r
1438                 CL_ASSERT( status == IB_SUCCESS );\r
1439         }\r
1440 }\r
1441 \r
1442 \r
1443 static void\r
1444 __free_ioc_pnp_svc(\r
1445         IN                              al_obj_t                                        *p_obj )\r
1446 {\r
1447         ioc_pnp_svc_t*          p_svc;\r
1448 \r
1449         CL_ASSERT( p_obj );\r
1450         p_svc = PARENT_STRUCT( p_obj, ioc_pnp_svc_t, obj );\r
1451 \r
1452         CL_ASSERT( !p_svc->query_cnt );\r
1453 \r
1454         destroy_al_obj( p_obj );\r
1455         cl_free( p_svc );\r
1456 }\r
1457 \r
1458 \r
1459 static void\r
1460 __ioc_pnp_timer_cb(\r
1461         IN                              void                                            *context )\r
1462 {\r
1463         ib_api_status_t         status;\r
1464         ioc_pnp_mgr_t           *p_mgr;\r
1465         cl_list_item_t          *p_item;\r
1466         ioc_pnp_svc_t           *p_svc;\r
1467 \r
1468         AL_ENTER( AL_DBG_PNP );\r
1469 \r
1470         p_mgr = (ioc_pnp_mgr_t*)context;\r
1471 \r
1472         cl_spinlock_acquire( &p_mgr->obj.lock );\r
1473         if( p_mgr->obj.state == CL_DESTROYING )\r
1474         {\r
1475                 AL_PRINT_EXIT( TRACE_LEVEL_INFORMATION, AL_DBG_PNP,\r
1476                         ("Destroying - not resetting timer.\n") );\r
1477                 cl_spinlock_release( &p_mgr->obj.lock );\r
1478                 return;\r
1479         }\r
1480 \r
1481         CL_ASSERT( !cl_fmap_count( &p_mgr->sweep_map ) );\r
1482 \r
1483         /* Pre-charge the ref count so that we don't toggle between 0 and 1. */\r
1484         cl_atomic_inc( &p_mgr->query_cnt );\r
1485         /* Take a reference on the object for the duration of the sweep process. */\r
1486         ref_al_obj( &p_mgr->obj );\r
1487         for( p_item = cl_qlist_head( &p_mgr->obj.obj_list );\r
1488                 p_item != cl_qlist_end( &p_mgr->obj.obj_list );\r
1489                 p_item = cl_qlist_next( p_item ) )\r
1490         {\r
1491                 p_svc = PARENT_STRUCT( PARENT_STRUCT( p_item, al_obj_t, pool_item ),\r
1492                         ioc_pnp_svc_t, obj );\r
1493                 cl_atomic_inc( &p_mgr->query_cnt );\r
1494                 status = __ioc_query_sa( p_svc );\r
1495                 if( status != IB_SUCCESS )\r
1496                         cl_atomic_dec( &p_mgr->query_cnt );\r
1497         }\r
1498         /* Release the reference we took and see if we're done sweeping. */\r
1499         if( !cl_atomic_dec( &p_mgr->query_cnt ) )\r
1500                 cl_async_proc_queue( gp_async_pnp_mgr, &p_mgr->async_item );\r
1501 \r
1502         cl_spinlock_release( &p_mgr->obj.lock );\r
1503 \r
1504         AL_EXIT( AL_DBG_PNP );\r
1505 }\r
1506 \r
1507 \r
1508 static ib_api_status_t\r
1509 __ioc_query_sa(\r
1510         IN                              ioc_pnp_svc_t* const            p_svc )\r
1511 {\r
1512         ib_api_status_t         status = IB_NOT_DONE;\r
1513         ib_query_req_t          query;\r
1514         ib_user_query_t         info;\r
1515         union _ioc_pnp_timer_cb_u\r
1516         {\r
1517                 ib_node_record_t        node_rec;\r
1518                 ib_path_rec_t           path_rec;\r
1519 \r
1520         }       u;\r
1521 \r
1522         AL_ENTER( AL_DBG_PNP );\r
1523 \r
1524         if( p_svc->h_node_query )\r
1525                 return IB_NOT_DONE;\r
1526         if( p_svc->h_path_query )\r
1527                 return IB_NOT_DONE;\r
1528 \r
1529         if( p_svc->obj.state == CL_DESTROYING )\r
1530         {\r
1531                 AL_PRINT_EXIT( TRACE_LEVEL_INFORMATION, AL_DBG_PNP,\r
1532                         ("Destroying - not resetting timer.\n") );\r
1533                 return IB_NOT_DONE;\r
1534         }\r
1535 \r
1536         info.method = IB_MAD_METHOD_GETTABLE;\r
1537         info.attr_id = IB_MAD_ATTR_NODE_RECORD;\r
1538         info.attr_size = sizeof(ib_node_record_t);\r
1539         info.comp_mask = IB_NR_COMPMASK_NODETYPE;\r
1540         info.p_attr = &u.node_rec;\r
1541 \r
1542         cl_memclr( &u.node_rec, sizeof(ib_node_record_t) );\r
1543         u.node_rec.node_info.node_type = IB_NODE_TYPE_CA;\r
1544 \r
1545         cl_memclr( &query, sizeof(ib_query_req_t) );\r
1546         query.query_type = IB_QUERY_USER_DEFINED;\r
1547         query.p_query_input = &info;\r
1548         query.port_guid = p_svc->port_guid;\r
1549         query.timeout_ms = g_ioc_query_timeout;\r
1550         query.retry_cnt = g_ioc_query_retries;\r
1551         query.query_context = p_svc;\r
1552         query.pfn_query_cb = __node_rec_cb;\r
1553 \r
1554         /* Reference the service for the node record query. */\r
1555         ref_al_obj( &p_svc->obj );\r
1556         cl_atomic_inc( &p_svc->query_cnt );\r
1557 \r
1558         status = ib_query( gh_al, &query, &p_svc->h_node_query );\r
1559         if( status != IB_SUCCESS )\r
1560         {\r
1561                 cl_atomic_dec( &p_svc->query_cnt );\r
1562                 deref_al_obj( &p_svc->obj );\r
1563                 AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_PNP,\r
1564                         ("ib_query returned %s\n", ib_get_err_str( status )) );\r
1565                 return status;\r
1566         }\r
1567 \r
1568         /* Setup the path query. */\r
1569         info.method = IB_MAD_METHOD_GETTABLE;\r
1570         info.attr_id = IB_MAD_ATTR_PATH_RECORD;\r
1571         info.attr_size = sizeof(ib_path_rec_t);\r
1572         info.comp_mask = IB_PR_COMPMASK_SGID | IB_PR_COMPMASK_NUMBPATH | \r
1573                 IB_PR_COMPMASK_PKEY;\r
1574         info.p_attr = &u.path_rec;\r
1575 \r
1576         cl_memclr( &u.path_rec, sizeof(ib_path_rec_t) );\r
1577         ib_gid_set_default( &u.path_rec.sgid, p_svc->port_guid );\r
1578         /* Request all the paths available, setting the reversible bit. */\r
1579         u.path_rec.num_path = 0xFF;\r
1580         /* Request only paths from the default partition */\r
1581         u.path_rec.pkey = cl_hton16(IB_DEFAULT_PKEY);\r
1582 \r
1583         query.pfn_query_cb = __path_rec_cb;\r
1584 \r
1585         /* Reference the service for the node record query. */\r
1586         ref_al_obj( &p_svc->obj );\r
1587         cl_atomic_inc( &p_svc->query_cnt );\r
1588 \r
1589         status = ib_query( gh_al, &query, &p_svc->h_path_query );\r
1590         if( status != IB_SUCCESS )\r
1591         {\r
1592                 cl_atomic_dec( &p_svc->query_cnt );\r
1593                 deref_al_obj( &p_svc->obj );\r
1594                 AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_PNP,\r
1595                         ("ib_query returned %s\n", ib_get_err_str( status )) );\r
1596         }\r
1597 \r
1598         AL_EXIT( AL_DBG_PNP );\r
1599         return IB_SUCCESS;\r
1600 }\r
1601 \r
1602 \r
1603 static void\r
1604 __node_rec_cb(\r
1605         IN                              ib_query_rec_t                          *p_query_rec )\r
1606 {\r
1607         ioc_pnp_svc_t           *p_svc;\r
1608 \r
1609         AL_ENTER( AL_DBG_PNP );\r
1610 \r
1611         p_svc = (ioc_pnp_svc_t*)p_query_rec->query_context;\r
1612 \r
1613         if( p_svc->obj.state != CL_DESTROYING &&\r
1614                 p_query_rec->status == IB_SUCCESS && p_query_rec->result_cnt )\r
1615         {\r
1616                 CL_ASSERT( p_query_rec->p_result_mad );\r
1617                 CL_ASSERT( !p_svc->p_node_element );\r
1618                 CL_ASSERT( p_query_rec->p_result_mad->p_next == NULL );\r
1619                 p_svc->p_node_element = p_query_rec->p_result_mad;\r
1620                 p_svc->num_nodes = p_query_rec->result_cnt;\r
1621         }\r
1622         else if( p_query_rec->p_result_mad )\r
1623         {\r
1624                 ib_put_mad( p_query_rec->p_result_mad );\r
1625         }\r
1626 \r
1627         p_svc->h_node_query = NULL;\r
1628         if( !cl_atomic_dec( &p_svc->query_cnt ) )\r
1629         {\r
1630                 /* The path query has already completed.  Process the results. */\r
1631                 __process_query( p_svc );\r
1632         }\r
1633 \r
1634         /* Release the reference taken for the query. */\r
1635         deref_al_obj( &p_svc->obj );\r
1636 \r
1637         AL_EXIT( AL_DBG_PNP );\r
1638 }\r
1639 \r
1640 \r
1641 static void\r
1642 __path_rec_cb(\r
1643         IN                              ib_query_rec_t                          *p_query_rec )\r
1644 {\r
1645         ioc_pnp_svc_t           *p_svc;\r
1646 \r
1647         AL_ENTER( AL_DBG_PNP );\r
1648 \r
1649         p_svc = (ioc_pnp_svc_t*)p_query_rec->query_context;\r
1650 \r
1651         if( p_svc->obj.state != CL_DESTROYING &&\r
1652                 p_query_rec->status == IB_SUCCESS && p_query_rec->result_cnt )\r
1653         {\r
1654                 CL_ASSERT( p_query_rec->p_result_mad );\r
1655                 CL_ASSERT( !p_svc->p_path_element );\r
1656                 CL_ASSERT( p_query_rec->p_result_mad->p_next == NULL );\r
1657                 p_svc->p_path_element = p_query_rec->p_result_mad;\r
1658                 p_svc->num_paths = p_query_rec->result_cnt;\r
1659         }\r
1660         else if( p_query_rec->p_result_mad )\r
1661         {\r
1662                 ib_put_mad( p_query_rec->p_result_mad );\r
1663         }\r
1664 \r
1665         p_svc->h_path_query = NULL;\r
1666         if( !cl_atomic_dec( &p_svc->query_cnt ) )\r
1667         {\r
1668                 /* The node query has already completed.  Process the results. */\r
1669                 __process_query( p_svc );\r
1670         }\r
1671 \r
1672         /* Release the reference taken for the query. */\r
1673         deref_al_obj( &p_svc->obj );\r
1674 \r
1675         AL_EXIT( AL_DBG_PNP );\r
1676 }\r
1677 \r
1678 static void\r
1679 __process_query(\r
1680         IN                              ioc_pnp_svc_t* const            p_svc )\r
1681 {\r
1682         ib_api_status_t                 status;\r
1683         ioc_sweep_results_t             *p_results;\r
1684         cl_qmap_t                               port_map;\r
1685 \r
1686         AL_ENTER( AL_DBG_PNP );\r
1687 \r
1688         cl_qmap_init( &port_map );\r
1689 \r
1690         if( !p_svc->p_node_element || !p_svc->p_path_element )\r
1691         {\r
1692                 /* One of the queries failed.  Release the MADs and reset the timer. */\r
1693                 if( p_svc->p_node_element )\r
1694                 {\r
1695                         ib_put_mad( p_svc->p_node_element );\r
1696                         p_svc->p_node_element = NULL;\r
1697                 }\r
1698 \r
1699                 if( p_svc->p_path_element )\r
1700                 {\r
1701                         ib_put_mad( p_svc->p_path_element );\r
1702                         p_svc->p_path_element = NULL;\r
1703                 }\r
1704 \r
1705                 /* Decrement the IOC PnP manager's query count. */\r
1706                 if( !cl_atomic_dec( &gp_ioc_pnp->query_cnt ) )\r
1707                         cl_async_proc_queue( gp_async_pnp_mgr, &gp_ioc_pnp->async_item );\r
1708                 AL_EXIT( AL_DBG_PNP );\r
1709                 return;\r
1710         }\r
1711 \r
1712         /*\r
1713          * Allocate the sweep results structure to allow processing\r
1714          * asynchronously.\r
1715          */\r
1716         p_results = cl_zalloc( sizeof(ioc_sweep_results_t) );\r
1717         if( p_results )\r
1718         {\r
1719                 p_results->async_item.pfn_callback = __process_sweep;\r
1720                 p_results->p_svc = p_svc;\r
1721                 cl_fmap_init( &p_results->iou_map, __iou_cmp );\r
1722 \r
1723                 /* Reference the service till the end of sweep processing */\r
1724                 ref_al_obj( &p_results->p_svc->obj );\r
1725                 cl_dbg_out ("~%d:[IBBUS] %s() : p_results %p, p_svc %p, ref_cnt %d", \r
1726                         KeGetCurrentProcessorNumber(), __FUNCTION__, p_results, p_svc, p_results->p_svc->obj.ref_cnt);\r
1727 \r
1728                 /* Build the map of nodes by port GUID. */\r
1729                 __process_nodes( p_svc, &port_map );\r
1730 \r
1731                 /* Build the map of paths for each node. */\r
1732                 __process_paths( p_svc, &port_map );\r
1733 \r
1734                 /* Collapse the map of nodes to be keyed by node GUID. */\r
1735                 __build_iou_map( &port_map, &p_results->iou_map );\r
1736 \r
1737                 /* Send the IOU Info queries to the nodes. */\r
1738                 status = __query_ious( p_results );\r
1739         }\r
1740         else\r
1741         {\r
1742                 status = IB_INSUFFICIENT_MEMORY;\r
1743         }\r
1744 \r
1745         /* Release the query result MADs now that we're done with them. */\r
1746         ib_put_mad( p_svc->p_node_element );\r
1747         ib_put_mad( p_svc->p_path_element );\r
1748         p_svc->p_node_element = NULL;\r
1749         p_svc->p_path_element = NULL;\r
1750 \r
1751         switch( status )\r
1752         {\r
1753         case IB_SUCCESS:\r
1754                 break;\r
1755         default:\r
1756                 CL_ASSERT( p_results );\r
1757                 /* Release the reference taken for the sweep. */\r
1758                 deref_al_obj( &p_results->p_svc->obj );\r
1759                 cl_dbg_out ("~%d:[IBBUS] %s() : p_results %p, p_svc %p, ref_cnt %d", \r
1760                         KeGetCurrentProcessorNumber(), __FUNCTION__, p_results, p_svc, p_results->p_svc->obj.ref_cnt);\r
1761                 cl_free( p_results );\r
1762                 /* Fall through */\r
1763         case IB_INSUFFICIENT_MEMORY:\r
1764                 /* Decrement the IOC PnP manager's query count. */\r
1765                 if( !cl_atomic_dec( &gp_ioc_pnp->query_cnt ) )\r
1766                         cl_async_proc_queue( gp_async_pnp_mgr, &gp_ioc_pnp->async_item );\r
1767         }\r
1768         AL_EXIT( AL_DBG_PNP );\r
1769 }\r
1770 \r
1771 \r
1772 static void\r
1773 __process_nodes(\r
1774         IN                              ioc_pnp_svc_t* const            p_svc,\r
1775         IN                              cl_qmap_t* const                        p_port_map )\r
1776 {\r
1777         iou_node_t                      *p_iou;\r
1778         ib_node_record_t        *p_node_rec;\r
1779         uint32_t                        i;\r
1780         void                            *p_item;\r
1781 \r
1782         AL_ENTER( AL_DBG_PNP );\r
1783 \r
1784         CL_ASSERT( p_svc );\r
1785         CL_ASSERT( p_svc->p_node_element );\r
1786         CL_ASSERT( p_port_map );\r
1787 \r
1788         for( i = 0; i < p_svc->num_nodes; i++ )\r
1789         {\r
1790                 p_node_rec = ib_get_query_node_rec( p_svc->p_node_element, i );\r
1791 \r
1792                 p_iou = __get_iou( gp_ioc_pnp, p_svc->ca_guid, p_node_rec );\r
1793                 if( !p_iou )\r
1794                         break;\r
1795 \r
1796                 /*\r
1797                  * We insert by port GUID, not node GUID so that we can match\r
1798                  * to paths using DGID.  Note that it is safe to cast between\r
1799                  * a flexi-map item and a map item since the pointer to the key\r
1800                  * in a flexi-map item is always a 64-bit pointer.\r
1801                  */\r
1802                 p_item = cl_qmap_insert(\r
1803                         p_port_map, p_node_rec->node_info.port_guid,\r
1804                         (cl_map_item_t*)&p_iou->map_item );\r
1805                 if( p_item != &p_iou->map_item )\r
1806                 {\r
1807                         /* Duplicate node - discard. */\r
1808                         __put_iou( gp_ioc_pnp, p_iou );\r
1809                 }\r
1810         }\r
1811 \r
1812         AL_EXIT( AL_DBG_PNP );\r
1813 }\r
1814 \r
1815 \r
1816 static void\r
1817 __process_paths(\r
1818         IN                              ioc_pnp_svc_t* const            p_svc,\r
1819         IN                              cl_qmap_t* const                        p_port_map )\r
1820 {\r
1821         iou_node_t                      *p_iou;\r
1822         iou_path_t                      *p_path;\r
1823         ib_path_rec_t           *p_path_rec;\r
1824         uint32_t                        i;\r
1825         cl_map_item_t           *p_iou_item;\r
1826         cl_fmap_item_t          *p_item;\r
1827 \r
1828         AL_ENTER( AL_DBG_PNP );\r
1829 \r
1830         CL_ASSERT( p_svc );\r
1831         CL_ASSERT( p_svc->p_node_element );\r
1832         CL_ASSERT( p_port_map );\r
1833 \r
1834         for( i = 0; i < p_svc->num_paths; i++ )\r
1835         {\r
1836                 p_path_rec = ib_get_query_path_rec( p_svc->p_path_element, i );\r
1837 \r
1838                 p_iou_item =\r
1839                         cl_qmap_get( p_port_map, p_path_rec->dgid.unicast.interface_id );\r
1840                 if( p_iou_item == cl_qmap_end( p_port_map ) )\r
1841                         continue;\r
1842 \r
1843                 p_iou = PARENT_STRUCT( p_iou_item, iou_node_t, map_item );\r
1844 \r
1845                 p_path = __get_path( gp_ioc_pnp, p_svc->ca_guid,\r
1846                         p_svc->port_guid, p_path_rec );\r
1847                 if( !p_path )\r
1848                         break;\r
1849 \r
1850                 p_item = cl_fmap_insert( &p_iou->path_map, &p_path->rec,\r
1851                         &p_path->map_item );\r
1852                 if( p_item != &p_path->map_item )\r
1853                 {\r
1854                         /* Duplicate path - discard. */\r
1855                         __put_path( gp_ioc_pnp, p_path );\r
1856                 }\r
1857         }\r
1858 \r
1859         AL_EXIT( AL_DBG_PNP );\r
1860 }\r
1861 \r
1862 \r
1863 static void\r
1864 __build_iou_map(\r
1865         IN                              cl_qmap_t* const                        p_port_map,\r
1866         IN      OUT                     cl_fmap_t* const                        p_iou_map )\r
1867 {\r
1868         cl_fmap_t               map1, map2;\r
1869         void                    *p_item;\r
1870         iou_node_t              *p_iou, *p_dup;\r
1871 \r
1872         AL_ENTER( AL_DBG_PNP );\r
1873 \r
1874         CL_ASSERT( !cl_fmap_count( p_iou_map ) );\r
1875 \r
1876         cl_fmap_init( &map1, __path_cmp );\r
1877         cl_fmap_init( &map2, __path_cmp );\r
1878 \r
1879         /*\r
1880          * Now collapse the map so that IOUs aren't repeated.\r
1881          * This is needed because the IOU map is keyed by port GUID, and thus\r
1882          * a multi-port IOU could be listed twice.\r
1883          */\r
1884         /* Merge the port map into a map of IOUs. */\r
1885         for( p_item = cl_qmap_head( p_port_map );\r
1886                 p_item != cl_qmap_end( p_port_map );\r
1887                 p_item = cl_qmap_head( p_port_map ) )\r
1888         {\r
1889                 cl_qmap_remove_item( p_port_map, (cl_map_item_t*)p_item );\r
1890                 p_iou = PARENT_STRUCT( p_item, iou_node_t, map_item );\r
1891 \r
1892                 p_item = cl_fmap_insert( p_iou_map, &p_iou->ca_guid, p_item );\r
1893                 if( p_item != &p_iou->map_item )\r
1894                 {\r
1895                         /* Duplicate IOU information - merge the paths. */\r
1896                         p_dup = PARENT_STRUCT( p_item, iou_node_t, map_item );\r
1897                         CL_ASSERT( p_dup != p_iou );\r
1898                         cl_fmap_delta( &p_dup->path_map, &p_iou->path_map, &map1, &map2 );\r
1899                         /*\r
1900                          * The path map in p_iou->path_map is duplicate paths.\r
1901                          * map1 contains paths unique to p_iou->path_map, map2 contains\r
1902                          * paths unique to p_dup->path_map.  Add the unique paths back to\r
1903                          * p_dup->path_map since that IOU is already in the IOU map.\r
1904                          * Note that we are keeping the p_dup IOU node.\r
1905                          */\r
1906                         cl_fmap_merge( &p_dup->path_map, &map1 );\r
1907                         cl_fmap_merge( &p_dup->path_map, &map2 );\r
1908                         /* All unique items should have merged without duplicates. */\r
1909                         CL_ASSERT( !cl_fmap_count( &map1 ) );\r
1910                         CL_ASSERT( !cl_fmap_count( &map2 ) );\r
1911 \r
1912                         __put_iou( gp_ioc_pnp, p_iou );\r
1913                 }\r
1914         }\r
1915 \r
1916         AL_EXIT( AL_DBG_PNP );\r
1917 }\r
1918 \r
1919 \r
1920 static void\r
1921 __format_dm_get(\r
1922         IN              const   void* const                                     context1,\r
1923         IN              const   void* const                                     context2,\r
1924         IN              const   iou_path_t* const                       p_path,\r
1925         IN              const   net16_t                                         attr_id,\r
1926         IN              const   net32_t                                         attr_mod,\r
1927         IN      OUT                     ib_mad_element_t* const         p_mad_element )\r
1928 {\r
1929         static uint64_t         tid = 0;\r
1930 \r
1931         AL_ENTER( AL_DBG_PNP );\r
1932 \r
1933         /*\r
1934          * Context information so that we can continue processing when\r
1935          * the query completes.\r
1936          */\r
1937         p_mad_element->context1 = context1;\r
1938         p_mad_element->context2 = context2;\r
1939 \r
1940         /*\r
1941          * Set the addressing bits necessary for the mad service to\r
1942          * create the address vector\r
1943          */\r
1944         p_mad_element->h_av = NULL;\r
1945         p_mad_element->remote_sl = ib_path_rec_sl( &p_path->rec );\r
1946         p_mad_element->remote_lid = p_path->rec.dlid;\r
1947         p_mad_element->grh_valid = FALSE;\r
1948         p_mad_element->path_bits = p_path->rec.num_path;\r
1949 \r
1950         /* Request response processing. */\r
1951         p_mad_element->resp_expected = TRUE;\r
1952         p_mad_element->retry_cnt = g_ioc_query_retries;\r
1953         p_mad_element->timeout_ms = g_ioc_query_timeout;\r
1954 \r
1955         /* Set the destination information for the send. */\r
1956         p_mad_element->remote_qp = IB_QP1;\r
1957         p_mad_element->remote_qkey = IB_QP1_WELL_KNOWN_Q_KEY;\r
1958 \r
1959         /* Format the MAD payload. */\r
1960         cl_memclr( p_mad_element->p_mad_buf, sizeof(ib_dm_mad_t) );\r
1961         ib_mad_init_new( p_mad_element->p_mad_buf, IB_MCLASS_DEV_MGMT, 1,\r
1962                 IB_MAD_METHOD_GET, cl_ntoh64( tid++ ), attr_id, attr_mod );\r
1963 \r
1964         AL_EXIT( AL_DBG_PNP );\r
1965 }\r
1966 \r
1967 \r
1968 static ib_api_status_t\r
1969 __query_ious(\r
1970         IN                              ioc_sweep_results_t* const      p_results )\r
1971 {\r
1972         ib_api_status_t         status;\r
1973         iou_node_t                      *p_iou;\r
1974         iou_path_t                      *p_path;\r
1975         cl_fmap_item_t          *p_iou_item;\r
1976         cl_fmap_item_t          *p_path_item;\r
1977         ib_mad_element_t        *p_mad, *p_mad_list = NULL;\r
1978 \r
1979         AL_ENTER( AL_DBG_PNP );\r
1980 \r
1981         p_results->state = SWEEP_IOU_INFO;\r
1982 \r
1983         /* Send a IOU Info query on the first path to every IOU. */\r
1984         p_iou_item = cl_fmap_head( &p_results->iou_map );\r
1985         while( p_iou_item != cl_fmap_end( &p_results->iou_map ) )\r
1986         {\r
1987                 p_iou = PARENT_STRUCT( p_iou_item, iou_node_t, map_item );\r
1988                 p_iou_item = cl_fmap_next( p_iou_item );\r
1989                 if( !cl_fmap_count( &p_iou->path_map ) )\r
1990                 {\r
1991                         /* No paths for this node.  Discard it. */\r
1992                         cl_fmap_remove_item( &p_results->iou_map, &p_iou->map_item );\r
1993                         __put_iou( gp_ioc_pnp, p_iou );\r
1994                         continue;\r
1995                 }\r
1996 \r
1997                 p_path_item = cl_fmap_head( &p_iou->path_map );\r
1998 \r
1999                 p_path = PARENT_STRUCT( p_path_item, iou_path_t, map_item );\r
2000 \r
2001                 status = ib_get_mad( p_results->p_svc->pool_key,\r
2002                         MAD_BLOCK_SIZE, &p_mad );\r
2003                 if( status != IB_SUCCESS )\r
2004                 {\r
2005                         AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
2006                                 ("ib_get_mad for IOU Info query returned %s.\n",\r
2007                                 ib_get_err_str( status )) );\r
2008                         break;\r
2009                 }\r
2010 \r
2011                 p_iou->p_config_path = p_path;\r
2012                 __format_dm_get( p_results, p_iou, p_path,\r
2013                         IB_MAD_ATTR_IO_UNIT_INFO, 0, p_mad );\r
2014 \r
2015                 /* Link the elements together. */\r
2016                 p_mad->p_next = p_mad_list;\r
2017                 p_mad_list = p_mad;\r
2018 \r
2019                 cl_atomic_inc( &p_results->p_svc->query_cnt );\r
2020         }\r
2021 \r
2022         if( !p_mad_list )\r
2023         {\r
2024                 AL_EXIT( AL_DBG_PNP );\r
2025                 return IB_ERROR;\r
2026         }\r
2027 \r
2028         status = ib_send_mad( p_results->p_svc->h_mad_svc, p_mad_list, &p_mad );\r
2029         if( status != IB_SUCCESS )\r
2030         {\r
2031                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
2032                         ("ib_send_mad returned %s\n", ib_get_err_str( status )) );\r
2033 \r
2034                 /* If some sends succeeded, change the status. */\r
2035                 if( p_mad_list != p_mad )\r
2036                         status = IB_SUCCESS;\r
2037 \r
2038                 while( p_mad )\r
2039                 {\r
2040                         p_mad_list = p_mad->p_next;\r
2041                         p_mad->p_next = NULL;\r
2042                         ib_put_mad( p_mad );\r
2043                         if( !cl_atomic_dec( &p_results->p_svc->query_cnt ) &&\r
2044                                 status == IB_SUCCESS )\r
2045                         {\r
2046                                 cl_async_proc_queue( gp_async_pnp_mgr,\r
2047                                         &p_results->async_item );\r
2048                         }\r
2049                         p_mad = p_mad_list;\r
2050                 }\r
2051         }\r
2052         AL_EXIT( AL_DBG_PNP );\r
2053         return status;\r
2054 }\r
2055 \r
2056 \r
2057 static void\r
2058 __ioc_pnp_recv_cb(\r
2059         IN              const   ib_mad_svc_handle_t                     h_mad_svc,\r
2060         IN                              void                                            *mad_svc_context,\r
2061         IN                              ib_mad_element_t                        *p_mad_response )\r
2062 {\r
2063         ioc_sweep_results_t     *p_results;\r
2064         iou_node_t                      *p_iou;\r
2065         iou_ioc_t                       *p_ioc;\r
2066 \r
2067         AL_ENTER( AL_DBG_PNP );\r
2068 \r
2069         UNUSED_PARAM( h_mad_svc );\r
2070         UNUSED_PARAM( mad_svc_context );\r
2071         CL_ASSERT( !p_mad_response->p_next );\r
2072 \r
2073         p_results = (ioc_sweep_results_t*)p_mad_response->send_context1;\r
2074         if( !p_mad_response->p_mad_buf->status )\r
2075         {\r
2076                 /* Query was successful */\r
2077                 switch( p_mad_response->p_mad_buf->attr_id )\r
2078                 {\r
2079                 case IB_MAD_ATTR_IO_UNIT_INFO:\r
2080                         p_iou = (iou_node_t*)p_mad_response->send_context2;\r
2081                         __iou_info_resp( p_iou,\r
2082                                 (ib_dm_mad_t*)p_mad_response->p_mad_buf );\r
2083                         break;\r
2084 \r
2085                 case IB_MAD_ATTR_IO_CONTROLLER_PROFILE:\r
2086                         p_iou = (iou_node_t*)p_mad_response->send_context2;\r
2087                         __ioc_profile_resp( p_iou,\r
2088                                 (ib_dm_mad_t*)p_mad_response->p_mad_buf );\r
2089                         break;\r
2090 \r
2091                 case IB_MAD_ATTR_SERVICE_ENTRIES:\r
2092                         p_ioc = (iou_ioc_t*)p_mad_response->send_context2;\r
2093                         __svc_entry_resp( p_ioc,\r
2094                                 (ib_dm_mad_t*)p_mad_response->p_mad_buf );\r
2095                         break;\r
2096 \r
2097                 default:\r
2098                         break;\r
2099                 }\r
2100         }\r
2101 \r
2102         ib_put_mad( p_mad_response );\r
2103         AL_EXIT( AL_DBG_PNP );\r
2104 }\r
2105 \r
2106 \r
2107 static void\r
2108 __iou_info_resp(\r
2109         IN      OUT                     iou_node_t* const                       p_iou,\r
2110         IN              const   ib_dm_mad_t* const                      p_mad )\r
2111 {\r
2112         AL_ENTER( AL_DBG_PNP );\r
2113         /* Copy the IOU info for post-processing. */\r
2114         p_iou->info = *((ib_iou_info_t*)p_mad->data);\r
2115         AL_EXIT( AL_DBG_PNP );\r
2116 }\r
2117 \r
2118 \r
2119 static void\r
2120 __ioc_profile_resp(\r
2121         IN      OUT                     iou_node_t* const                       p_iou,\r
2122         IN              const   ib_dm_mad_t* const                      p_mad )\r
2123 {\r
2124         iou_ioc_t               *p_ioc;\r
2125         cl_map_item_t   *p_item;\r
2126 \r
2127         AL_ENTER( AL_DBG_PNP );\r
2128         p_ioc = __get_ioc( gp_ioc_pnp, cl_ntoh32(p_mad->hdr.attr_mod),\r
2129                 (ib_ioc_profile_t*)p_mad->data );\r
2130         if( p_ioc )\r
2131         {\r
2132                 /* Need back link to process service entry failures. */\r
2133                 p_ioc->p_iou = p_iou;\r
2134                 cl_spinlock_acquire( &p_iou->lock );\r
2135                 p_item = cl_qmap_insert( &p_iou->ioc_map,\r
2136                         p_ioc->profile.ioc_guid, &p_ioc->map_item );\r
2137                 cl_spinlock_release( &p_iou->lock );\r
2138                 /* Return the IOC if it's a duplicate. */\r
2139                 if( p_item != &p_ioc->map_item )\r
2140                         __put_ioc( gp_ioc_pnp, p_ioc );\r
2141         }\r
2142         AL_EXIT( AL_DBG_PNP );\r
2143 }\r
2144 \r
2145 \r
2146 static void\r
2147 __svc_entry_resp(\r
2148         IN      OUT                     iou_ioc_t* const                        p_ioc,\r
2149         IN              const   ib_dm_mad_t* const                      p_mad )\r
2150 {\r
2151         uint16_t                        idx;\r
2152         uint8_t                         lo, hi;\r
2153         ib_svc_entries_t        *p_svc_entries;\r
2154 \r
2155         AL_ENTER( AL_DBG_PNP );\r
2156 \r
2157         ib_dm_get_slot_lo_hi( p_mad->hdr.attr_mod, NULL, &lo, &hi );\r
2158         CL_ASSERT( (hi - lo) < SVC_ENTRY_COUNT );\r
2159         p_svc_entries = (ib_svc_entries_t*)p_mad->data;\r
2160 \r
2161         /* Copy the entries. */\r
2162         for( idx = lo; idx <= hi; idx++ )\r
2163                 p_ioc->p_svc_entries[idx] = p_svc_entries->service_entry[idx - lo];\r
2164 \r
2165         /* Update the number of entries received so far. */\r
2166         p_ioc->num_valid_entries += (hi - lo) + 1;\r
2167         cl_atomic_dec(&p_ioc->ref_cnt);\r
2168         AL_EXIT( AL_DBG_PNP );\r
2169 }\r
2170 \r
2171 \r
2172 static void\r
2173 __ioc_pnp_send_cb(\r
2174         IN              const   ib_mad_svc_handle_t                     h_mad_svc,\r
2175         IN                              void                                            *mad_svc_context,\r
2176         IN                              ib_mad_element_t                        *p_request_mad )\r
2177 {\r
2178         ib_api_status_t         status;\r
2179         ioc_sweep_results_t     *p_results;\r
2180         iou_node_t                      *p_iou;\r
2181         iou_ioc_t                       *p_ioc;\r
2182         cl_fmap_item_t          *p_item;\r
2183 \r
2184         AL_ENTER( AL_DBG_PNP );\r
2185 \r
2186         UNUSED_PARAM( h_mad_svc );\r
2187         UNUSED_PARAM( mad_svc_context );\r
2188 \r
2189         CL_ASSERT( p_request_mad->p_next == NULL );\r
2190 \r
2191         p_results = (ioc_sweep_results_t*)p_request_mad->context1;\r
2192 \r
2193         if( p_request_mad->status != IB_WCS_SUCCESS )\r
2194         {\r
2195                 switch( p_request_mad->p_mad_buf->attr_id )\r
2196                 {\r
2197                 case IB_MAD_ATTR_IO_UNIT_INFO:\r
2198                         p_iou = (iou_node_t*)p_request_mad->context2;\r
2199                         if( p_request_mad->status == IB_WCS_TIMEOUT_RETRY_ERR )\r
2200                         {\r
2201                                 /* Move to the next path for the node and try the query again. */\r
2202                                 p_item = cl_fmap_next( &p_iou->p_config_path->map_item );\r
2203                                 if( p_item != cl_fmap_end( &p_iou->path_map ) )\r
2204                                 {\r
2205                                         p_iou->p_config_path =\r
2206                                                 PARENT_STRUCT( p_item, iou_path_t, map_item );\r
2207                                         __format_dm_get( p_results, p_iou, p_iou->p_config_path,\r
2208                                                 IB_MAD_ATTR_IO_UNIT_INFO, 0, p_request_mad );\r
2209 \r
2210                                         status = ib_send_mad( p_results->p_svc->h_mad_svc,\r
2211                                                 p_request_mad, &p_request_mad );\r
2212                                         if( status == IB_SUCCESS )\r
2213                                         {\r
2214                                                 AL_EXIT( AL_DBG_PNP );\r
2215                                                 return;\r
2216                                         }\r
2217                                 }\r
2218                         }\r
2219                         break;\r
2220 \r
2221                 case IB_MAD_ATTR_SERVICE_ENTRIES:\r
2222                         p_ioc = (iou_ioc_t*)p_request_mad->context2;\r
2223                         cl_spinlock_acquire( &p_ioc->p_iou->lock );\r
2224                         cl_qmap_remove_item( &p_ioc->p_iou->ioc_map, &p_ioc->map_item );\r
2225                         cl_spinlock_release( &p_ioc->p_iou->lock );\r
2226                         __put_ioc( gp_ioc_pnp, p_ioc );\r
2227                         break;\r
2228 \r
2229                 default:\r
2230                         break;\r
2231                 }\r
2232         }\r
2233 \r
2234         /* Cleanup. */\r
2235         ib_put_mad( p_request_mad );\r
2236 \r
2237         /*\r
2238          * If this is the last MAD, finish processing the IOU queries\r
2239          * in the PnP thread.\r
2240          */\r
2241         if( !cl_atomic_dec( &p_results->p_svc->query_cnt ) )\r
2242                 cl_async_proc_queue( gp_async_pnp_mgr, &p_results->async_item );\r
2243 \r
2244         AL_EXIT( AL_DBG_PNP );\r
2245 }\r
2246 \r
2247 \r
2248 static void\r
2249 __flush_duds(\r
2250         IN      OUT                     ioc_sweep_results_t                     *p_results )\r
2251 {\r
2252         cl_fmap_item_t                  *p_item;\r
2253         cl_map_item_t                   *p_ioc_item;\r
2254         iou_node_t                              *p_iou;\r
2255         iou_ioc_t                               *p_ioc;\r
2256 \r
2257         AL_ENTER( AL_DBG_PNP );\r
2258 \r
2259         /* Walk the map of IOUs and discard any that didn't respond to IOU info. */\r
2260         p_item = cl_fmap_head( &p_results->iou_map );\r
2261         /*\r
2262          * No locking required since we're protected by the serialization of the\r
2263          * PnP thread.\r
2264          */\r
2265         while( p_item != cl_fmap_end( &p_results->iou_map ) )\r
2266         {\r
2267                 p_iou = PARENT_STRUCT( p_item, iou_node_t, map_item );\r
2268 \r
2269                 p_item = cl_fmap_next( p_item );\r
2270                 switch( p_results->state )\r
2271                 {\r
2272                 case SWEEP_IOU_INFO:\r
2273                         if( p_iou->info.max_controllers )\r
2274                                 continue;\r
2275                         break;\r
2276 \r
2277                 case SWEEP_SVC_ENTRIES:\r
2278                         CL_ASSERT( cl_qmap_count( &p_iou->ioc_map ) );\r
2279                         p_ioc_item = cl_qmap_head( &p_iou->ioc_map );\r
2280                         while( p_ioc_item != cl_qmap_end( &p_iou->ioc_map ) )\r
2281                         {\r
2282                                 p_ioc = PARENT_STRUCT( p_ioc_item, iou_ioc_t, map_item );\r
2283                                 p_ioc_item = cl_qmap_next( p_ioc_item );\r
2284 \r
2285                                 if( !p_ioc->num_valid_entries ||\r
2286                                         p_ioc->num_valid_entries != p_ioc->profile.num_svc_entries )\r
2287                                 {\r
2288                                         cl_qmap_remove_item( &p_iou->ioc_map, &p_ioc->map_item );\r
2289                                         __put_ioc( gp_ioc_pnp, p_ioc );\r
2290                                 }\r
2291                         }\r
2292                         /* Fall through. */\r
2293                 case SWEEP_IOC_PROFILE:\r
2294                         if( cl_qmap_count( &p_iou->ioc_map ) )\r
2295                                 continue;\r
2296                         break;\r
2297 \r
2298                 default:\r
2299                         CL_ASSERT( p_results->state != SWEEP_COMPLETE );\r
2300                         break;\r
2301                 }\r
2302 \r
2303                 cl_fmap_remove_item( &p_results->iou_map, &p_iou->map_item );\r
2304                 __put_iou( gp_ioc_pnp, p_iou );\r
2305         }\r
2306 \r
2307         AL_EXIT( AL_DBG_PNP );\r
2308 }\r
2309 \r
2310 static void\r
2311 __process_sweep(\r
2312         IN                              cl_async_proc_item_t            *p_async_item )\r
2313 {\r
2314         ib_api_status_t                 status;\r
2315         ioc_sweep_results_t             *p_results;\r
2316 \r
2317         AL_ENTER( AL_DBG_PNP );\r
2318 \r
2319         p_results = PARENT_STRUCT( p_async_item, ioc_sweep_results_t, async_item );\r
2320         CL_ASSERT( !p_results->p_svc->query_cnt );\r
2321 \r
2322         if( p_results->p_svc->obj.state == CL_DESTROYING )\r
2323         {\r
2324                 __put_iou_map( gp_ioc_pnp, &p_results->iou_map );\r
2325                 goto err;\r
2326         }\r
2327 \r
2328         /* Walk the map of IOUs and discard any that didn't respond to IOU info. */\r
2329         __flush_duds( p_results );\r
2330         switch( p_results->state )\r
2331         {\r
2332         case SWEEP_IOU_INFO:\r
2333                 /* Next step, query IOC profiles for all IOUs. */\r
2334                 p_results->state = SWEEP_IOC_PROFILE;\r
2335                 status = __query_ioc_profiles( p_results );\r
2336                 break;\r
2337 \r
2338         case SWEEP_IOC_PROFILE:\r
2339                 /* Next step: query service entries for all IOCs. */\r
2340                 p_results->state = SWEEP_SVC_ENTRIES;\r
2341                 status = __query_svc_entries( p_results );\r
2342                 break;\r
2343 \r
2344         case SWEEP_SVC_ENTRIES:\r
2345                 /* Filter results and report changes. */\r
2346                 p_results->state = SWEEP_COMPLETE;\r
2347                 __update_results( p_results );\r
2348                 status = IB_SUCCESS;\r
2349                 break;\r
2350 \r
2351         default:\r
2352                 CL_ASSERT( p_results->state == SWEEP_IOU_INFO ||\r
2353                         p_results->state == SWEEP_IOC_PROFILE ||\r
2354                         p_results->state == SWEEP_SVC_ENTRIES );\r
2355                 status = IB_ERROR;\r
2356         }\r
2357 \r
2358         if( p_results->state == SWEEP_COMPLETE || status != IB_SUCCESS )\r
2359         {\r
2360 err:\r
2361                 if( !cl_atomic_dec( &gp_ioc_pnp->query_cnt ) )\r
2362                         cl_async_proc_queue( gp_async_pnp_mgr, &gp_ioc_pnp->async_item );\r
2363                 /* Release the reference taken for the sweep. */\r
2364                 deref_al_obj( &p_results->p_svc->obj );\r
2365                 cl_dbg_out ("~%d:[IBBUS] %s() : p_results %p, p_svc %p, ref_cnt %d", \r
2366                         KeGetCurrentProcessorNumber(), __FUNCTION__, p_results, p_svc, p_results->p_svc->obj.ref_cnt);\r
2367                 cl_free( p_results );\r
2368         }\r
2369 \r
2370         AL_EXIT( AL_DBG_PNP );\r
2371 }\r
2372 \r
2373 \r
2374 static ib_api_status_t\r
2375 __query_ioc_profiles(\r
2376         IN                              ioc_sweep_results_t* const      p_results )\r
2377 {\r
2378         ib_api_status_t         status;\r
2379         cl_fmap_item_t          *p_item;\r
2380         iou_node_t                      *p_iou;\r
2381         uint8_t                         slot;\r
2382         ib_mad_element_t        *p_mad, *p_mad_list = NULL;\r
2383 \r
2384         AL_ENTER( AL_DBG_PNP );\r
2385 \r
2386         p_item = cl_fmap_head( &p_results->iou_map );\r
2387         while( p_item != cl_fmap_end( &p_results->iou_map ) )\r
2388         {\r
2389                 p_iou = PARENT_STRUCT( p_item, iou_node_t, map_item );\r
2390                 CL_ASSERT( p_iou->info.max_controllers );\r
2391                 CL_ASSERT( cl_fmap_count( &p_iou->path_map ) );\r
2392                 CL_ASSERT( p_iou->p_config_path );\r
2393                 p_item = cl_fmap_next( p_item );\r
2394 \r
2395                 p_mad = NULL;\r
2396                 for( slot = 1; slot <= p_iou->info.max_controllers; slot++ )\r
2397                 {\r
2398                         if( ioc_at_slot( &p_iou->info, slot ) == IOC_INSTALLED )\r
2399                         {\r
2400                                 status = ib_get_mad( p_results->p_svc->pool_key,\r
2401                                         MAD_BLOCK_SIZE, &p_mad );\r
2402                                 if( status != IB_SUCCESS )\r
2403                                         break;\r
2404 \r
2405                                 __format_dm_get( p_results, p_iou, p_iou->p_config_path,\r
2406                                         IB_MAD_ATTR_IO_CONTROLLER_PROFILE, cl_hton32( slot ), p_mad );\r
2407 \r
2408                                 /* Chain the MAD up. */\r
2409                                 p_mad->p_next = p_mad_list;\r
2410                                 p_mad_list = p_mad;\r
2411 \r
2412                                 cl_atomic_inc( &p_results->p_svc->query_cnt );\r
2413                         }\r
2414                 }\r
2415                 if( !p_mad )\r
2416                 {\r
2417                         /* No IOCs installed in this IOU, or failed to get MAD. */\r
2418                         cl_fmap_remove_item( &p_results->iou_map, &p_iou->map_item );\r
2419                         __put_iou( gp_ioc_pnp, p_iou );\r
2420                 }\r
2421         }\r
2422 \r
2423         /* Trap the case where there are no queries to send. */\r
2424         if( !p_mad_list )\r
2425         {\r
2426                 AL_EXIT( AL_DBG_PNP );\r
2427                 return IB_NOT_DONE;\r
2428         }\r
2429 \r
2430         status = ib_send_mad( p_results->p_svc->h_mad_svc, p_mad_list, &p_mad );\r
2431         if( status != IB_SUCCESS )\r
2432         {\r
2433                 /* If some of the MADs were sent wait for their completion. */\r
2434                 if( p_mad_list != p_mad )\r
2435                         status = IB_SUCCESS;\r
2436 \r
2437                 while( p_mad )\r
2438                 {\r
2439                         p_mad_list = p_mad->p_next;\r
2440                         p_mad->p_next = NULL;\r
2441                         ib_put_mad( p_mad );\r
2442                         if( !cl_atomic_dec( &p_results->p_svc->query_cnt ) &&\r
2443                                 status == IB_SUCCESS )\r
2444                         {\r
2445                                 cl_async_proc_queue( gp_async_pnp_mgr,\r
2446                                         &p_results->async_item );\r
2447                         }\r
2448                         p_mad = p_mad_list;\r
2449                 }\r
2450         }\r
2451         AL_EXIT( AL_DBG_PNP );\r
2452         return status;\r
2453 }\r
2454 \r
2455 \r
2456 static ib_api_status_t\r
2457 __query_svc_entries(\r
2458         IN                              ioc_sweep_results_t* const      p_results )\r
2459 {\r
2460         ib_api_status_t         status;\r
2461         cl_fmap_item_t          *p_iou_item;\r
2462         cl_map_item_t           *p_ioc_item;\r
2463         iou_node_t                      *p_iou;\r
2464         iou_ioc_t                       *p_ioc;\r
2465         uint8_t                         i;\r
2466         uint32_t                        attr_mod;\r
2467         ib_mad_element_t        *p_mad, *p_mad_list = NULL;\r
2468 \r
2469         AL_ENTER( AL_DBG_PNP );\r
2470 \r
2471         for( p_iou_item = cl_fmap_head( &p_results->iou_map );\r
2472                 p_iou_item != cl_fmap_end( &p_results->iou_map );\r
2473                 p_iou_item = cl_fmap_next( p_iou_item ) )\r
2474         {\r
2475                 p_iou = PARENT_STRUCT( p_iou_item, iou_node_t, map_item );\r
2476                 CL_ASSERT( cl_qmap_count( &p_iou->ioc_map ) );\r
2477                 CL_ASSERT( cl_fmap_count( &p_iou->path_map ) );\r
2478                 CL_ASSERT( p_iou->p_config_path );\r
2479 \r
2480                 for( p_ioc_item = cl_qmap_head( &p_iou->ioc_map );\r
2481                         p_ioc_item != cl_qmap_end( &p_iou->ioc_map );\r
2482                         p_ioc_item = cl_qmap_next( p_ioc_item ) )\r
2483                 {\r
2484                         p_ioc = PARENT_STRUCT( p_ioc_item, iou_ioc_t, map_item );\r
2485                         CL_ASSERT( p_ioc->p_iou == p_iou );\r
2486 \r
2487                         for( i = 0; i < p_ioc->profile.num_svc_entries; i += 4 )\r
2488                         {\r
2489                                 status = ib_get_mad( p_results->p_svc->pool_key,\r
2490                                         MAD_BLOCK_SIZE, &p_mad );\r
2491                                 if( status != IB_SUCCESS )\r
2492                                         break;\r
2493 \r
2494                                 attr_mod = (((uint32_t)p_ioc->slot) << 16) | i;\r
2495                                 if( (i + 3) > p_ioc->profile.num_svc_entries )\r
2496                                         attr_mod |= ((p_ioc->profile.num_svc_entries - 1) << 8);\r
2497                                 else\r
2498                                         attr_mod |= ((i + 3) << 8);\r
2499 \r
2500                                 __format_dm_get( p_results, p_ioc, p_iou->p_config_path,\r
2501                                         IB_MAD_ATTR_SERVICE_ENTRIES, cl_hton32( attr_mod ),\r
2502                                         p_mad );\r
2503 \r
2504                                 /* Chain the MAD up. */\r
2505                                 p_mad->p_next = p_mad_list;\r
2506                                 p_mad_list = p_mad;\r
2507 \r
2508                                 cl_atomic_inc( &p_ioc->ref_cnt );\r
2509                                 cl_atomic_inc( &p_results->p_svc->query_cnt );\r
2510                         }\r
2511                 }\r
2512         }\r
2513 \r
2514         /* Trap the case where there are no queries to send. */\r
2515         if( !p_mad_list )\r
2516         {\r
2517                 AL_EXIT( AL_DBG_PNP );\r
2518                 return IB_NOT_DONE;\r
2519         }\r
2520 \r
2521         status = ib_send_mad( p_results->p_svc->h_mad_svc, p_mad_list, &p_mad );\r
2522         if( status != IB_SUCCESS )\r
2523         {\r
2524                 /* If some of the MADs were sent wait for their completion. */\r
2525                 if( p_mad_list != p_mad )\r
2526                         status = IB_SUCCESS;\r
2527 \r
2528                 while( p_mad )\r
2529                 {\r
2530                         p_mad_list = p_mad->p_next;\r
2531                         p_mad->p_next = NULL;\r
2532                         p_ioc = (iou_ioc_t*)p_mad->context2;\r
2533                         cl_atomic_dec( &p_ioc->ref_cnt );\r
2534                         ib_put_mad( p_mad );\r
2535                         if( !cl_atomic_dec( &p_results->p_svc->query_cnt ) &&\r
2536                                 status == IB_SUCCESS )\r
2537                         {\r
2538                                 cl_async_proc_queue( gp_async_pnp_mgr,\r
2539                                         &p_results->async_item );\r
2540                         }\r
2541                         p_mad = p_mad_list;\r
2542                 }\r
2543         }\r
2544         AL_EXIT( AL_DBG_PNP );\r
2545         return status;\r
2546 }\r
2547 \r
2548 \r
2549 static void\r
2550 __update_results(\r
2551         IN                              ioc_sweep_results_t* const      p_results )\r
2552 {\r
2553         cl_fmap_t                       iou_map1, iou_map2;\r
2554         cl_fmap_item_t          *p_item1, *p_item2;\r
2555         iou_node_t                      *p_iou1, *p_iou2;\r
2556 \r
2557         AL_ENTER( AL_DBG_PNP );\r
2558 \r
2559         cl_fmap_init( &iou_map1, __iou_cmp );\r
2560         cl_fmap_init( &iou_map2, __iou_cmp );\r
2561 \r
2562         /*\r
2563          * No need to lock on the sweep map since all accesses are serialized\r
2564          * by the PnP thread.\r
2565          */\r
2566         cl_fmap_delta( &gp_ioc_pnp->sweep_map, &p_results->iou_map,\r
2567                 &iou_map1, &iou_map2 );\r
2568         /* sweep_map and iou_map now contain exactly the same items. */\r
2569         p_item1 = cl_fmap_head( &gp_ioc_pnp->sweep_map );\r
2570         p_item2 = cl_fmap_head( &p_results->iou_map );\r
2571         while( p_item1 != cl_fmap_end( &gp_ioc_pnp->sweep_map ) )\r
2572         {\r
2573                 CL_ASSERT( p_item2 != cl_fmap_end( &p_results->iou_map ) );\r
2574                 p_iou1 = PARENT_STRUCT( p_item1, iou_node_t, map_item );\r
2575                 p_iou2 = PARENT_STRUCT( p_item2, iou_node_t, map_item );\r
2576                 CL_ASSERT( p_iou1->guid == p_iou2->guid );\r
2577 \r
2578                 /*\r
2579                  * Merge the IOC maps - this leaves all duplicates in\r
2580                  * p_iou2->ioc_map.\r
2581                  */\r
2582                 cl_qmap_merge( &p_iou1->ioc_map, &p_iou2->ioc_map );\r
2583 \r
2584                 /*\r
2585                  * Merge the path maps - this leaves all duplicates in\r
2586                  * p_iou2->path_map\r
2587                  */\r
2588                 cl_fmap_merge( &p_iou1->path_map, &p_iou2->path_map );\r
2589 \r
2590                 /* Return the duplicate IOU (and whatever duplicate paths and IOCs) */\r
2591                 cl_fmap_remove_item( &p_results->iou_map, p_item2 );\r
2592                 __put_iou( gp_ioc_pnp, p_iou2 );\r
2593 \r
2594                 p_item1 = cl_fmap_next( p_item1 );\r
2595                 p_item2 = cl_fmap_head( &p_results->iou_map );\r
2596         }\r
2597         CL_ASSERT( !cl_fmap_count( &p_results->iou_map ) );\r
2598 \r
2599         /* Merge in the unique items. */\r
2600         cl_fmap_merge( &gp_ioc_pnp->sweep_map, &iou_map1 );\r
2601         CL_ASSERT( !cl_fmap_count( &iou_map1 ) );\r
2602         cl_fmap_merge( &gp_ioc_pnp->sweep_map, &iou_map2 );\r
2603         CL_ASSERT( !cl_fmap_count( &iou_map2 ) );\r
2604 \r
2605         AL_EXIT( AL_DBG_PNP );\r
2606         return;\r
2607 }\r
2608 \r
2609 \r
2610 static void\r
2611 __ioc_async_cb(\r
2612         IN                              cl_async_proc_item_t            *p_item )\r
2613 {\r
2614         cl_status_t             status;\r
2615         cl_fmap_t               old_ious, new_ious;\r
2616 \r
2617         AL_ENTER( AL_DBG_PNP );\r
2618 \r
2619         CL_ASSERT( p_item == &gp_ioc_pnp->async_item );\r
2620         UNUSED_PARAM( p_item );\r
2621 \r
2622         CL_ASSERT( !gp_ioc_pnp->query_cnt );\r
2623 \r
2624         cl_fmap_init( &old_ious, __iou_cmp );\r
2625         cl_fmap_init( &new_ious, __iou_cmp );\r
2626         cl_fmap_delta(\r
2627                 &gp_ioc_pnp->iou_map, &gp_ioc_pnp->sweep_map, &new_ious, &old_ious );\r
2628 \r
2629         /* For each duplicate IOU, report changes in IOCs or paths. */\r
2630         __change_ious( &gp_ioc_pnp->iou_map, &gp_ioc_pnp->sweep_map );\r
2631 \r
2632         /* Report all new IOUs. */\r
2633         __add_ious( &gp_ioc_pnp->iou_map, &new_ious, NULL );\r
2634         CL_ASSERT( !cl_fmap_count( &new_ious ) );\r
2635 \r
2636         /* Report all removed IOUs. */\r
2637         __remove_ious( &old_ious );\r
2638         CL_ASSERT( !cl_fmap_count( &old_ious ) );\r
2639 \r
2640         /* Reset the sweep timer. */\r
2641         if( g_ioc_poll_interval )\r
2642         {\r
2643                 status = cl_timer_start(\r
2644                         &gp_ioc_pnp->sweep_timer, g_ioc_poll_interval );\r
2645                 CL_ASSERT( status == CL_SUCCESS );\r
2646         }\r
2647 \r
2648         /* Release the reference we took in the timer callback. */\r
2649         deref_al_obj( &gp_ioc_pnp->obj );\r
2650 \r
2651         AL_EXIT( AL_DBG_PNP );\r
2652 }\r
2653 \r
2654 \r
2655 static void\r
2656 __change_ious(\r
2657         IN                              cl_fmap_t* const                        p_cur_ious,\r
2658         IN                              cl_fmap_t* const                        p_dup_ious )\r
2659 {\r
2660         cl_fmap_t               new_paths, old_paths;\r
2661         cl_qmap_t               new_iocs, old_iocs;\r
2662         cl_fmap_item_t  *p_item1, *p_item2;\r
2663         iou_node_t              *p_iou1, *p_iou2;\r
2664 \r
2665         AL_ENTER( AL_DBG_PNP );\r
2666 \r
2667         cl_fmap_init( &new_paths, __path_cmp );\r
2668         cl_fmap_init( &old_paths, __path_cmp );\r
2669         cl_qmap_init( &new_iocs );\r
2670         cl_qmap_init( &old_iocs );\r
2671 \r
2672         p_item1 = cl_fmap_head( p_cur_ious );\r
2673         p_item2 = cl_fmap_head( p_dup_ious );\r
2674         while( p_item1 != cl_fmap_end( p_cur_ious ) )\r
2675         {\r
2676                 p_iou1 = PARENT_STRUCT( p_item1, iou_node_t, map_item );\r
2677                 p_iou2 = PARENT_STRUCT( p_item2, iou_node_t, map_item );\r
2678                 CL_ASSERT( p_iou1->guid == p_iou2->guid );\r
2679 \r
2680                 /* Figure out what changed. */\r
2681                 cl_fmap_delta(\r
2682                         &p_iou1->path_map, &p_iou2->path_map, &new_paths, &old_paths );\r
2683                 cl_qmap_delta(\r
2684                         &p_iou1->ioc_map, &p_iou2->ioc_map, &new_iocs, &old_iocs );\r
2685 \r
2686                 /*\r
2687                  * Report path changes before IOC changes so that new IOCs\r
2688                  * report up-to-date paths.  Report new paths before removing\r
2689                  * old ones to minimize the chance of disruption of service - \r
2690                  * i.e. the last path being removed before an alternate is available.\r
2691                  */\r
2692                 __add_paths( p_iou1, &p_iou1->ioc_map, &new_paths, NULL );\r
2693                 CL_ASSERT( !cl_fmap_count( &new_paths ) );\r
2694 \r
2695                 __remove_paths( &p_iou1->ioc_map, &old_paths );\r
2696                 CL_ASSERT( !cl_fmap_count( &old_paths ) );\r
2697 \r
2698                 /* Report IOCs. */\r
2699                 __add_iocs( p_iou1, &new_iocs, NULL );\r
2700                 CL_ASSERT( !cl_qmap_count( &new_iocs ) );\r
2701 \r
2702                 __remove_iocs( p_iou1, &old_iocs );\r
2703                 CL_ASSERT( !cl_qmap_count( &old_iocs ) );\r
2704 \r
2705                 /* Done with the duplicate IOU.  Return it to the pool */\r
2706                 cl_fmap_remove_item( p_dup_ious, p_item2 );\r
2707                 __put_iou( gp_ioc_pnp, p_iou2 );\r
2708 \r
2709                 p_item1 = cl_fmap_next( p_item1 );\r
2710                 p_item2 = cl_fmap_head( p_dup_ious );\r
2711         }\r
2712         CL_ASSERT( !cl_fmap_count( p_dup_ious ) );\r
2713 \r
2714         AL_EXIT( AL_DBG_PNP );\r
2715 }\r
2716 \r
2717 \r
2718 static void\r
2719 __add_ious(\r
2720         IN                              cl_fmap_t* const                        p_cur_ious,\r
2721         IN                              cl_fmap_t* const                        p_new_ious,\r
2722         IN                              al_pnp_t* const                         p_reg OPTIONAL )\r
2723 {\r
2724         cl_fmap_item_t  *p_item;\r
2725         iou_node_t              *p_iou;\r
2726 \r
2727         AL_ENTER( AL_DBG_PNP );\r
2728 \r
2729         p_item = cl_fmap_head( p_new_ious );\r
2730         while( p_item != cl_fmap_end( p_new_ious ) )\r
2731         {\r
2732                 p_iou = PARENT_STRUCT( p_item, iou_node_t, map_item );\r
2733 \r
2734                 /* Report the IOU addition. */\r
2735                 __report_iou_add( p_iou, p_reg );\r
2736 \r
2737                 p_item = cl_fmap_next( p_item );\r
2738         }\r
2739 \r
2740         if( p_cur_ious != p_new_ious )\r
2741         {\r
2742                 cl_fmap_merge( p_cur_ious, p_new_ious );\r
2743                 CL_ASSERT( !cl_fmap_count( p_new_ious ) );\r
2744         }\r
2745 \r
2746         AL_EXIT( AL_DBG_PNP );\r
2747 }\r
2748 \r
2749 \r
2750 static void\r
2751 __remove_ious(\r
2752         IN                              cl_fmap_t* const                        p_old_ious )\r
2753 {\r
2754         cl_fmap_item_t  *p_item;\r
2755         iou_node_t              *p_iou;\r
2756 \r
2757         AL_ENTER( AL_DBG_PNP );\r
2758 \r
2759         p_item = cl_fmap_head( p_old_ious );\r
2760         while( p_item != cl_fmap_end( p_old_ious ) )\r
2761         {\r
2762                 p_iou = PARENT_STRUCT( p_item, iou_node_t, map_item );\r
2763 \r
2764                 /* Report the IOU removal. */\r
2765                 __report_iou_remove( p_iou );\r
2766 \r
2767                 cl_fmap_remove_item( p_old_ious, p_item );\r
2768                 __put_iou( gp_ioc_pnp, p_iou );\r
2769                 p_item = cl_fmap_head( p_old_ious );\r
2770         }\r
2771         CL_ASSERT( !cl_fmap_count( p_old_ious ) );\r
2772 \r
2773         AL_EXIT( AL_DBG_PNP );\r
2774 }\r
2775 \r
2776 \r
2777 static void\r
2778 __add_iocs(\r
2779         IN                              iou_node_t* const                       p_iou,\r
2780         IN                              cl_qmap_t* const                        p_new_iocs,\r
2781         IN                              al_pnp_t* const                         p_reg OPTIONAL )\r
2782 {\r
2783         cl_map_item_t   *p_item;\r
2784         iou_ioc_t               *p_ioc;\r
2785 \r
2786         AL_ENTER( AL_DBG_PNP );\r
2787 \r
2788         p_item = cl_qmap_head( p_new_iocs );\r
2789         while( p_item != cl_qmap_end( p_new_iocs ) )\r
2790         {\r
2791                 p_ioc = PARENT_STRUCT( p_item, iou_ioc_t, map_item );\r
2792 \r
2793                 /* Report the IOU addition. */\r
2794                 __report_ioc_add( p_iou, p_ioc, p_reg );\r
2795 \r
2796                 p_item = cl_qmap_next( p_item );\r
2797         }\r
2798 \r
2799         if( p_new_iocs != &p_iou->ioc_map )\r
2800         {\r
2801                 cl_qmap_merge( &p_iou->ioc_map, p_new_iocs );\r
2802                 CL_ASSERT( !cl_qmap_count( p_new_iocs ) );\r
2803         }\r
2804         AL_EXIT( AL_DBG_PNP );\r
2805 }\r
2806 \r
2807 \r
2808 static void\r
2809 __remove_iocs(\r
2810         IN                              iou_node_t* const                       p_iou,\r
2811         IN                              cl_qmap_t* const                        p_old_iocs )\r
2812 {\r
2813         cl_map_item_t   *p_item;\r
2814         iou_ioc_t               *p_ioc;\r
2815 \r
2816         AL_ENTER( AL_DBG_PNP );\r
2817 \r
2818         p_item = cl_qmap_tail( p_old_iocs );\r
2819         while( p_item != cl_qmap_end( p_old_iocs ) )\r
2820         {\r
2821                 p_ioc = PARENT_STRUCT( p_item, iou_ioc_t, map_item );\r
2822 \r
2823                 /* Report the IOC removal. */\r
2824                 __report_ioc_remove( p_iou, p_ioc );\r
2825 \r
2826                 cl_qmap_remove_item( p_old_iocs, p_item );\r
2827                 __put_ioc( gp_ioc_pnp, p_ioc );\r
2828                 p_item = cl_qmap_tail( p_old_iocs );\r
2829         }\r
2830         CL_ASSERT( !cl_qmap_count( p_old_iocs ) );\r
2831 \r
2832         AL_EXIT( AL_DBG_PNP );\r
2833 }\r
2834 \r
2835 \r
2836 static void\r
2837 __add_paths(\r
2838         IN                              iou_node_t* const                       p_iou,\r
2839         IN                              cl_qmap_t* const                        p_ioc_map,\r
2840         IN                              cl_fmap_t* const                        p_new_paths,\r
2841         IN                              al_pnp_t* const                         p_reg OPTIONAL )\r
2842 {\r
2843         cl_map_item_t   *p_ioc_item;\r
2844         cl_fmap_item_t  *p_item;\r
2845         iou_ioc_t               *p_ioc;\r
2846         iou_path_t              *p_path;\r
2847 \r
2848         AL_ENTER( AL_DBG_PNP );\r
2849 \r
2850         p_item = cl_fmap_head( p_new_paths );\r
2851         while( p_item != cl_fmap_end( p_new_paths ) )\r
2852         {\r
2853                 p_path = PARENT_STRUCT( p_item, iou_path_t, map_item );\r
2854 \r
2855                 /* Report the path to all IOCs. */\r
2856                 for( p_ioc_item = cl_qmap_head( p_ioc_map );\r
2857                         p_ioc_item != cl_qmap_end( p_ioc_map );\r
2858                         p_ioc_item = cl_qmap_next( p_ioc_item ) )\r
2859                 {\r
2860                         p_ioc = PARENT_STRUCT( p_ioc_item, iou_ioc_t, map_item );\r
2861                         __report_path( p_ioc, p_path, IB_PNP_IOC_PATH_ADD, p_reg );\r
2862                 }\r
2863 \r
2864                 p_item = cl_fmap_next( p_item );\r
2865         }\r
2866 \r
2867         ASSERT( &p_iou->path_map != p_new_paths );\r
2868 \r
2869         cl_fmap_merge( &p_iou->path_map, p_new_paths );\r
2870         CL_ASSERT( !cl_fmap_count( p_new_paths ) );\r
2871 \r
2872         AL_EXIT( AL_DBG_PNP );\r
2873 }\r
2874 \r
2875 \r
2876 static void\r
2877 __add_ioc_paths(\r
2878         IN                              iou_ioc_t* const                        p_ioc,\r
2879         IN                              cl_fmap_t* const                        p_new_paths,\r
2880         IN                              al_pnp_t* const                         p_reg OPTIONAL )\r
2881 {\r
2882         cl_fmap_item_t  *p_item;\r
2883         iou_path_t              *p_path;\r
2884 \r
2885         AL_ENTER( AL_DBG_PNP );\r
2886 \r
2887         p_item = cl_fmap_head( p_new_paths );\r
2888         while( p_item != cl_fmap_end( p_new_paths ) )\r
2889         {\r
2890                 p_path = PARENT_STRUCT( p_item, iou_path_t, map_item );\r
2891 \r
2892                 __report_path( p_ioc, p_path, IB_PNP_IOC_PATH_ADD, p_reg );\r
2893 \r
2894                 p_item = cl_fmap_next( p_item );\r
2895         }\r
2896 \r
2897         AL_EXIT( AL_DBG_PNP );\r
2898 }\r
2899 \r
2900 \r
2901 static void\r
2902 __remove_paths(\r
2903         IN                              cl_qmap_t* const                        p_ioc_map,\r
2904         IN                              cl_fmap_t* const                        p_old_paths )\r
2905 {\r
2906         cl_map_item_t   *p_ioc_item;\r
2907         cl_fmap_item_t  *p_item;\r
2908         iou_ioc_t               *p_ioc;\r
2909         iou_path_t              *p_path;\r
2910 \r
2911         AL_ENTER( AL_DBG_PNP );\r
2912 \r
2913         p_item = cl_fmap_tail( p_old_paths );\r
2914         while( p_item != cl_fmap_end( p_old_paths ) )\r
2915         {\r
2916                 p_path = PARENT_STRUCT( p_item, iou_path_t, map_item );\r
2917 \r
2918                 for( p_ioc_item = cl_qmap_tail( p_ioc_map );\r
2919                         p_ioc_item != cl_qmap_end( p_ioc_map );\r
2920                         p_ioc_item = cl_qmap_prev( p_ioc_item ) )\r
2921                 {\r
2922                         p_ioc = PARENT_STRUCT( p_ioc_item, iou_ioc_t, map_item );\r
2923                         __report_path( p_ioc, p_path, IB_PNP_IOC_PATH_REMOVE, NULL );\r
2924                 }\r
2925 \r
2926                 cl_fmap_remove_item( p_old_paths, p_item );\r
2927                 __put_path( gp_ioc_pnp, p_path );\r
2928                 p_item = cl_fmap_tail( p_old_paths );\r
2929         }\r
2930         CL_ASSERT( !cl_fmap_count( p_old_paths ) );\r
2931 \r
2932         AL_EXIT( AL_DBG_PNP );\r
2933 }\r
2934 \r
2935 \r
2936 static cl_status_t\r
2937 __notify_users(\r
2938         IN              const   cl_list_item_t* const           p_item,\r
2939         IN                              al_pnp_ioc_event_t* const       p_event )\r
2940 {\r
2941         ib_api_status_t                 status;\r
2942         al_pnp_t                                *p_reg;\r
2943         al_pnp_context_t                *p_context;\r
2944 \r
2945         AL_ENTER( AL_DBG_PNP );\r
2946 \r
2947         p_reg = PARENT_STRUCT( p_item, al_pnp_t, list_item );\r
2948 \r
2949         /* Copy the source record into the user's record. */\r
2950         cl_memcpy( p_event->p_user_rec, p_event->p_rec, p_event->rec_size );\r
2951         p_event->p_user_rec->h_pnp = p_reg;\r
2952         p_event->p_user_rec->pnp_context = (void*)p_reg->obj.context;\r
2953 \r
2954         switch( p_event->p_rec->pnp_event )\r
2955         {\r
2956         case IB_PNP_IOU_ADD:\r
2957                 CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_IOU );\r
2958                 p_context = pnp_create_context( p_reg, &p_event->p_rec->guid);\r
2959                 break;\r
2960 \r
2961         case IB_PNP_IOU_REMOVE:\r
2962                 CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_IOU );\r
2963                 /* Lookup the context for this IOU. */\r
2964                 p_context = pnp_get_context( p_reg, &p_event->p_rec->guid );\r
2965                 break;\r
2966 \r
2967         case IB_PNP_IOC_ADD:\r
2968                 CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_IOC );\r
2969                 p_context = pnp_create_context( p_reg, &p_event->p_rec->guid);\r
2970                 break;\r
2971         case IB_PNP_IOC_REMOVE:\r
2972         case IB_PNP_IOC_PATH_ADD:\r
2973         case IB_PNP_IOC_PATH_REMOVE:\r
2974                 CL_ASSERT( pnp_get_class( p_reg->pnp_class ) == IB_PNP_IOC );\r
2975                 p_context = pnp_get_context( p_reg, &p_event->p_rec->guid );\r
2976                 break;\r
2977         default:\r
2978                 AL_PRINT_EXIT(TRACE_LEVEL_WARNING, AL_DBG_PNP,("Invalid PnP event %#x\n",\r
2979                         p_event->p_rec->pnp_event));\r
2980                 return CL_NOT_DONE;\r
2981                 break;\r
2982         }\r
2983         if( !p_context )\r
2984                 return CL_NOT_FOUND;\r
2985 \r
2986         p_event->p_user_rec->context = (void*)p_context->context;\r
2987 \r
2988         /* Notify user. */\r
2989         status = p_reg->pfn_pnp_cb( p_event->p_user_rec );\r
2990 \r
2991         /* Update contexts */\r
2992         if( status != IB_SUCCESS ||\r
2993                 p_event->p_rec->pnp_event == IB_PNP_IOU_REMOVE ||\r
2994                 p_event->p_rec->pnp_event == IB_PNP_IOC_REMOVE )\r
2995         {\r
2996                 cl_fmap_remove_item( &p_reg->context_map, &p_context->map_item );\r
2997                 cl_free( p_context );\r
2998         }\r
2999         else\r
3000         {\r
3001                 p_context->context = p_event->p_user_rec->context;\r
3002         }\r
3003 \r
3004         AL_EXIT( AL_DBG_PNP );\r
3005         return CL_NOT_FOUND;\r
3006 }\r
3007 \r
3008 \r
3009 static void\r
3010 __report_iou_add(\r
3011         IN                              iou_node_t* const                       p_iou,\r
3012         IN                              al_pnp_t* const                         p_reg OPTIONAL )\r
3013 {\r
3014         al_pnp_ioc_event_t              event;\r
3015         ib_pnp_iou_rec_t                *p_rec, *p_user_rec;\r
3016 \r
3017         AL_ENTER( AL_DBG_PNP );\r
3018 \r
3019         event.rec_size = sizeof(ib_pnp_iou_rec_t);\r
3020         event.rec_size = ROUNDUP( event.rec_size, sizeof(void*) );\r
3021 \r
3022         p_rec = cl_zalloc( event.rec_size * 2 );\r
3023         if( !p_rec )\r
3024         {\r
3025                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
3026                         ("Failed to allocate user record.\n") );\r
3027                 return;\r
3028         }\r
3029         p_rec->pnp_rec.pnp_event = IB_PNP_IOU_ADD;\r
3030         p_rec->pnp_rec.guid = p_iou->guid;\r
3031         p_rec->pnp_rec.ca_guid = p_iou->ca_guid;\r
3032         \r
3033         p_rec->ca_guid = p_iou->ca_guid;\r
3034         p_rec->guid = p_iou->guid;\r
3035         p_rec->chassis_guid = p_iou->chassis_guid;\r
3036         p_rec->vend_id = p_iou->vend_id;\r
3037         p_rec->dev_id = p_iou->dev_id;\r
3038         p_rec->revision = p_iou->revision;\r
3039         cl_memcpy( p_rec->desc, p_iou->desc, sizeof(p_rec->desc) );\r
3040         p_user_rec = (ib_pnp_iou_rec_t*)(((uint8_t*)p_rec) + event.rec_size);\r
3041         \r
3042         event.p_rec = (ib_pnp_rec_t*)p_rec;\r
3043         event.p_user_rec = (ib_pnp_rec_t*)p_user_rec;\r
3044 \r
3045         if( p_reg )\r
3046         {\r
3047                 if( pnp_get_class( p_reg->pnp_class ) == IB_PNP_IOU )\r
3048                         __notify_users( &p_reg->list_item, &event );\r
3049                 else\r
3050                         __add_iocs( p_iou, &p_iou->ioc_map, p_reg );\r
3051         }\r
3052         else\r
3053         {\r
3054                 /* Report the IOU to all clients registered for IOU events. */\r
3055                 cl_qlist_find_from_head( &gp_ioc_pnp->iou_reg_list,\r
3056                         __notify_users, &event );\r
3057 \r
3058                 /* Report IOCs - this will in turn report the paths. */\r
3059                 __add_iocs( p_iou, &p_iou->ioc_map, NULL );\r
3060         }\r
3061 \r
3062         cl_free( p_rec );\r
3063         AL_EXIT( AL_DBG_PNP );\r
3064 }\r
3065 \r
3066 \r
3067 static void\r
3068 __report_iou_remove(\r
3069         IN                              iou_node_t* const                       p_iou )\r
3070 {\r
3071         al_pnp_ioc_event_t              event;\r
3072         ib_pnp_iou_rec_t                rec, user_rec;\r
3073 \r
3074         AL_ENTER( AL_DBG_PNP );\r
3075 \r
3076         /* Report IOCs - this will in turn report the paths. */\r
3077         __remove_iocs( p_iou, &p_iou->ioc_map );\r
3078 \r
3079         cl_memclr( &rec, sizeof(ib_pnp_iou_rec_t) );\r
3080         rec.pnp_rec.pnp_event = IB_PNP_IOU_REMOVE;\r
3081         rec.pnp_rec.guid = p_iou->guid;\r
3082         rec.pnp_rec.ca_guid = p_iou->ca_guid;\r
3083 \r
3084         event.rec_size = sizeof(ib_pnp_iou_rec_t);\r
3085         event.p_rec = (ib_pnp_rec_t*)&rec;\r
3086         event.p_user_rec = (ib_pnp_rec_t*)&user_rec;\r
3087 \r
3088         /*\r
3089          * Report the IOU to all clients registered for IOU events in\r
3090          * reverse order than ADD notifications.\r
3091          */\r
3092         cl_qlist_find_from_tail( &gp_ioc_pnp->iou_reg_list,\r
3093                 __notify_users, &event );\r
3094 \r
3095         AL_EXIT( AL_DBG_PNP );\r
3096 }\r
3097 \r
3098 \r
3099 static void\r
3100 __report_ioc_add(\r
3101         IN                              iou_node_t* const                       p_iou,\r
3102         IN                              iou_ioc_t* const                        p_ioc,\r
3103         IN                              al_pnp_t* const                         p_reg OPTIONAL )\r
3104 {\r
3105         al_pnp_ioc_event_t              event;\r
3106         ib_pnp_ioc_rec_t                *p_rec;\r
3107 \r
3108         AL_ENTER( AL_DBG_PNP );\r
3109 \r
3110         event.rec_size = sizeof(ib_pnp_ioc_rec_t) +\r
3111                 (sizeof(ib_svc_entry_t) * (p_ioc->profile.num_svc_entries - 1));\r
3112         event.rec_size = ROUNDUP( event.rec_size, sizeof(void*) );\r
3113 \r
3114         /*\r
3115          * The layout of the pnp record is as follows:\r
3116          *      ib_pnp_rec_t\r
3117          *      ib_svc_entry_t\r
3118          *      ib_ioc_info_t\r
3119          *\r
3120          * This is needed to keep the service entries contiguous to the first\r
3121          * entry in the pnp record.\r
3122          */\r
3123         p_rec = (ib_pnp_ioc_rec_t*)cl_zalloc( event.rec_size * 2 );\r
3124         if( !p_rec )\r
3125                 return;\r
3126 \r
3127         p_rec->pnp_rec.pnp_event = IB_PNP_IOC_ADD;\r
3128         p_rec->pnp_rec.guid = p_ioc->profile.ioc_guid;\r
3129         p_rec->pnp_rec.ca_guid = p_ioc->p_iou->ca_guid;\r
3130         \r
3131         p_rec->ca_guid = p_ioc->p_iou->ca_guid;\r
3132         cl_memcpy( p_rec->svc_entry_array, p_ioc->p_svc_entries,\r
3133                 p_ioc->profile.num_svc_entries * sizeof(ib_svc_entry_t) );\r
3134         p_rec->info.chassis_guid = p_iou->chassis_guid;\r
3135         p_rec->info.chassis_slot = p_iou->slot;\r
3136         p_rec->info.iou_guid = p_iou->guid;\r
3137         p_rec->info.iou_slot = p_ioc->slot;\r
3138         p_rec->info.profile = p_ioc->profile;\r
3139 \r
3140         event.p_rec = (ib_pnp_rec_t*)p_rec;\r
3141         event.p_user_rec = (ib_pnp_rec_t*)(((uint8_t*)p_rec) + event.rec_size);\r
3142 \r
3143         if( p_reg )\r
3144         {\r
3145                 __notify_users( &p_reg->list_item, &event );\r
3146         }\r
3147         else\r
3148         {\r
3149                 /* Report the IOC to all clients registered for IOC events. */\r
3150                 cl_qlist_find_from_head( &gp_ioc_pnp->ioc_reg_list,\r