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