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