5e36c4c785dfbeeaf86d998caad8184ffbeffa64
[mirror/winof/.git] / core / al / al_query.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. \r
4  * Portions Copyright (c) 2008 Microsoft Corporation.  All rights reserved.\r
5  *\r
6  * This software is available to you under the OpenIB.org BSD license\r
7  * below:\r
8  *\r
9  *     Redistribution and use in source and binary forms, with or\r
10  *     without modification, are permitted provided that the following\r
11  *     conditions are met:\r
12  *\r
13  *      - Redistributions of source code must retain the above\r
14  *        copyright notice, this list of conditions and the following\r
15  *        disclaimer.\r
16  *\r
17  *      - Redistributions in binary form must reproduce the above\r
18  *        copyright notice, this list of conditions and the following\r
19  *        disclaimer in the documentation and/or other materials\r
20  *        provided with the distribution.\r
21  *\r
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
23  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
25  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
26  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
27  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
28  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
29  * SOFTWARE.\r
30  *\r
31  * $Id$\r
32  */\r
33 \r
34 #include <iba/ib_al.h>\r
35 #include <complib/cl_timer.h>\r
36 \r
37 #include "al.h"\r
38 #include "al_ca.h"\r
39 #include "al_common.h"\r
40 #include "al_debug.h"\r
41 \r
42 #if defined(EVENT_TRACING)\r
43 #ifdef offsetof\r
44 #undef offsetof\r
45 #endif\r
46 #include "al_query.tmh"\r
47 #endif\r
48 #include "al_mgr.h"\r
49 #include "al_query.h"\r
50 #include "ib_common.h"\r
51 \r
52 \r
53 #define PR102982\r
54 \r
55 \r
56 static ib_api_status_t\r
57 query_sa(\r
58         IN                              al_query_t                                      *p_query,\r
59         IN              const   ib_query_req_t* const           p_query_req,\r
60         IN              const   ib_al_flags_t                           flags );\r
61 \r
62 void\r
63 query_req_cb(\r
64         IN                              al_sa_req_t                                     *p_sa_req,\r
65         IN                              ib_mad_element_t                        *p_mad_response );\r
66 \r
67 \r
68 ib_api_status_t\r
69 ib_query(\r
70         IN              const   ib_al_handle_t                          h_al,\r
71         IN              const   ib_query_req_t* const           p_query_req,\r
72                 OUT                     ib_query_handle_t* const        ph_query OPTIONAL )\r
73 {\r
74         al_query_t                              *p_query;\r
75         ib_api_status_t                 status;\r
76 \r
77         AL_ENTER( AL_DBG_QUERY );\r
78 \r
79         if( AL_OBJ_INVALID_HANDLE( h_al, AL_OBJ_TYPE_H_AL ) )\r
80         {\r
81                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_AL_HANDLE\n") );\r
82                 return IB_INVALID_AL_HANDLE;\r
83         }\r
84         if( !p_query_req )\r
85         {\r
86                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_INVALID_PARAMETER\n") );\r
87                 return IB_INVALID_PARAMETER;\r
88         }\r
89         if( (p_query_req->flags & IB_FLAGS_SYNC) && !cl_is_blockable() )\r
90         {\r
91                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("IB_UNSUPPORTED\n") );\r
92                 return IB_UNSUPPORTED;\r
93         }\r
94 \r
95         /* Allocate a new query. */\r
96         p_query = cl_zalloc( sizeof( al_query_t ) );\r
97         if( !p_query )\r
98         {\r
99                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("insufficient memory\n") );\r
100                 return IB_INSUFFICIENT_MEMORY;\r
101         }\r
102 \r
103         /* Copy the query context information. */\r
104         p_query->sa_req.pfn_sa_req_cb = query_req_cb;\r
105         p_query->sa_req.user_context = p_query_req->query_context;\r
106         p_query->pfn_query_cb = p_query_req->pfn_query_cb;\r
107         p_query->query_type = p_query_req->query_type;\r
108 \r
109         /* Track the query with the AL instance. */\r
110         al_insert_query( h_al, p_query );\r
111 \r
112         /* Issue the MAD to the SA. */\r
113         status = query_sa( p_query, p_query_req, p_query_req->flags );\r
114         if( status != IB_SUCCESS && status != IB_INVALID_GUID )\r
115         {\r
116                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
117                         ("query_sa failed: %s\n", ib_get_err_str(status) ) );\r
118         }\r
119 \r
120         /* Cleanup from issuing the query if it failed or was synchronous. */\r
121         if( status != IB_SUCCESS )\r
122         {\r
123                 al_remove_query( p_query );\r
124                 cl_free( p_query );\r
125         }\r
126         else if( ph_query )\r
127         {\r
128                 *ph_query = p_query;\r
129         }\r
130 \r
131         AL_EXIT( AL_DBG_QUERY );\r
132         return status;\r
133 }\r
134 \r
135 \r
136 \r
137 /*\r
138  * Query the SA based on the user's request.\r
139  */\r
140 static ib_api_status_t\r
141 query_sa(\r
142         IN                              al_query_t                                      *p_query,\r
143         IN              const   ib_query_req_t* const           p_query_req,\r
144         IN              const   ib_al_flags_t                           flags )\r
145 {\r
146         ib_user_query_t                         sa_req, *p_sa_req;\r
147         union _query_sa_recs\r
148         {\r
149                 ib_service_record_t             svc;\r
150                 ib_node_record_t                node;\r
151                 ib_portinfo_record_t    portinfo;\r
152                 ib_path_rec_t                   path;\r
153                 ib_class_port_info_t    class_port_info;\r
154         }       rec;\r
155         ib_api_status_t                 status;\r
156 \r
157         AL_ENTER( AL_DBG_QUERY );\r
158 \r
159         cl_memclr( &rec, sizeof(rec) );\r
160 \r
161         /* Set the request information. */\r
162         p_sa_req = &sa_req;\r
163         sa_req.method = IB_MAD_METHOD_GETTABLE;\r
164 \r
165         /* Set the MAD attributes and component mask correctly. */\r
166         switch( p_query_req->query_type )\r
167         {\r
168         case IB_QUERY_USER_DEFINED:\r
169                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_QUERY, ("USER_DEFINED\n") );\r
170                 p_sa_req = (ib_user_query_t*)p_query_req->p_query_input;\r
171                 if( !p_sa_req->method )\r
172                 {\r
173                         AL_EXIT( AL_DBG_QUERY );\r
174                         return IB_INVALID_SETTING;\r
175                 }\r
176                 break;\r
177 \r
178         case IB_QUERY_ALL_SVC_RECS:\r
179                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_QUERY, ("IB_QUERY_ALL_SVC_RECS\n") );\r
180                 sa_req.attr_id = IB_MAD_ATTR_SERVICE_RECORD;\r
181                 sa_req.attr_size = sizeof( ib_service_record_t );\r
182                 sa_req.comp_mask = 0;\r
183                 sa_req.p_attr = &rec.svc;\r
184                 break;\r
185 \r
186         case IB_QUERY_SVC_REC_BY_NAME:\r
187                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_QUERY, ("SVC_REC_BY_NAME\n") );\r
188                 sa_req.attr_id = IB_MAD_ATTR_SERVICE_RECORD;\r
189                 sa_req.attr_size = sizeof( ib_service_record_t );\r
190                 sa_req.comp_mask = IB_SR_COMPMASK_SNAME;\r
191                 sa_req.p_attr = &rec.svc;\r
192                 cl_memcpy( rec.svc.service_name, p_query_req->p_query_input,\r
193                         sizeof( ib_svc_name_t ) );\r
194                 break;\r
195 \r
196         case IB_QUERY_SVC_REC_BY_ID:\r
197                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_QUERY, ("SVC_REC_BY_ID\n") );\r
198                 sa_req.attr_id = IB_MAD_ATTR_SERVICE_RECORD;\r
199                 sa_req.attr_size = sizeof( ib_service_record_t );\r
200                 sa_req.comp_mask = IB_SR_COMPMASK_SID;\r
201                 sa_req.p_attr = &rec.svc;\r
202                 rec.svc.service_id = *(ib_net64_t*)(p_query_req->p_query_input);\r
203                 break;\r
204 \r
205         case IB_QUERY_CLASS_PORT_INFO:\r
206                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_QUERY, ("IB_QUERY_CLASS_PORT_INFO\n") );\r
207                 sa_req.method = IB_MAD_METHOD_GET;\r
208                 sa_req.attr_id = IB_MAD_ATTR_CLASS_PORT_INFO;\r
209                 sa_req.attr_size = sizeof( ib_class_port_info_t );\r
210                 sa_req.comp_mask = 0;\r
211                 sa_req.p_attr = &rec.class_port_info;\r
212                 break;\r
213 \r
214         case IB_QUERY_NODE_REC_BY_NODE_GUID:\r
215                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_QUERY, ("NODE_REC_BY_NODE_GUID\n") );\r
216                 /*\r
217                  *      15.2.5.2:\r
218                  * if >1 ports on of a CA/RTR the subnet return multiple\r
219                  * record\r
220                  */\r
221                 sa_req.attr_id = IB_MAD_ATTR_NODE_RECORD;\r
222                 sa_req.attr_size = sizeof( ib_node_record_t );\r
223                 sa_req.comp_mask = IB_NR_COMPMASK_NODEGUID;\r
224                 sa_req.p_attr = &rec.node;\r
225                 rec.node.node_info.node_guid =\r
226                         *(ib_net64_t*)(p_query_req->p_query_input);\r
227                 break;\r
228 \r
229         case IB_QUERY_PORT_REC_BY_LID:\r
230                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_QUERY, ("PORT_REC_BY_LID\n") );\r
231                 sa_req.attr_id = IB_MAD_ATTR_PORTINFO_RECORD;\r
232                 sa_req.attr_size = sizeof( ib_portinfo_record_t );\r
233                 sa_req.comp_mask = IB_PIR_COMPMASK_BASELID;\r
234                 sa_req.p_attr = &rec.portinfo;\r
235                 rec.portinfo.port_info.base_lid =\r
236                         *(ib_net16_t*)(p_query_req->p_query_input);\r
237                 break;\r
238 \r
239         case IB_QUERY_PATH_REC_BY_PORT_GUIDS:\r
240                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_QUERY, ("PATH_REC_BY_PORT_GUIDS\n") );\r
241                 sa_req.attr_id = IB_MAD_ATTR_PATH_RECORD;\r
242                 sa_req.attr_size = sizeof( ib_path_rec_t );\r
243                 sa_req.comp_mask = (IB_PR_COMPMASK_DGID |\r
244                         IB_PR_COMPMASK_SGID | IB_PR_COMPMASK_NUM_PATH);\r
245                 sa_req.p_attr = &rec.path;\r
246                 ib_gid_set_default( &rec.path.dgid, ((ib_guid_pair_t*)\r
247                         (p_query_req->p_query_input))->dest_guid );\r
248                 ib_gid_set_default( &rec.path.sgid, ((ib_guid_pair_t*)\r
249                         (p_query_req->p_query_input))->src_guid );\r
250                 rec.path.num_path = 1;\r
251                 break;\r
252 \r
253         case IB_QUERY_PATH_REC_BY_GIDS:\r
254                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_QUERY, ("PATH_REC_BY_GIDS\n") );\r
255                 sa_req.attr_id = IB_MAD_ATTR_PATH_RECORD;\r
256                 sa_req.attr_size = sizeof( ib_path_rec_t );\r
257                 sa_req.comp_mask = (IB_PR_COMPMASK_DGID |\r
258                         IB_PR_COMPMASK_SGID | IB_PR_COMPMASK_NUM_PATH);\r
259                 sa_req.p_attr = &rec.path;\r
260                 cl_memcpy( &rec.path.dgid, &((ib_gid_pair_t*)\r
261                         (p_query_req->p_query_input))->dest_gid, sizeof( ib_gid_t ) );\r
262                 cl_memcpy( &rec.path.sgid, &((ib_gid_pair_t*)\r
263                         (p_query_req->p_query_input))->src_gid, sizeof( ib_gid_t ) );\r
264                 rec.path.num_path = 1;\r
265                 break;\r
266 \r
267         case IB_QUERY_PATH_REC_BY_LIDS:\r
268                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_QUERY, ("PATH_REC_BY_LIDS\n") );\r
269                 /* SGID must be provided for GET_TABLE requests. */\r
270                 sa_req.method = IB_MAD_METHOD_GET;\r
271                 sa_req.attr_id = IB_MAD_ATTR_PATH_RECORD;\r
272                 sa_req.attr_size = sizeof( ib_path_rec_t );\r
273                 sa_req.comp_mask =\r
274                         (IB_PR_COMPMASK_DLID | IB_PR_COMPMASK_SLID);\r
275                 sa_req.p_attr = &rec.path;\r
276                 rec.path.dlid = \r
277                         ((ib_lid_pair_t*)(p_query_req->p_query_input))->dest_lid;\r
278                 rec.path.slid =\r
279                         ((ib_lid_pair_t*)(p_query_req->p_query_input))->src_lid;\r
280 #ifdef PR102982\r
281                 rec.path.num_path = 1;\r
282 #endif\r
283                 break;\r
284 \r
285         default:\r
286                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("UNKNOWN\n") );\r
287                 CL_ASSERT( p_query_req->query_type == IB_QUERY_USER_DEFINED ||\r
288                         p_query_req->query_type == IB_QUERY_ALL_SVC_RECS ||\r
289                         p_query_req->query_type == IB_QUERY_SVC_REC_BY_NAME ||\r
290                         p_query_req->query_type == IB_QUERY_SVC_REC_BY_ID ||\r
291                         p_query_req->query_type == IB_QUERY_CLASS_PORT_INFO ||\r
292                         p_query_req->query_type == IB_QUERY_NODE_REC_BY_NODE_GUID ||\r
293                         p_query_req->query_type == IB_QUERY_PORT_REC_BY_LID ||\r
294                         p_query_req->query_type == IB_QUERY_PATH_REC_BY_PORT_GUIDS ||\r
295                         p_query_req->query_type == IB_QUERY_PATH_REC_BY_GIDS ||\r
296                         p_query_req->query_type == IB_QUERY_PATH_REC_BY_LIDS );\r
297 \r
298                 return IB_ERROR;\r
299         }\r
300 \r
301         status = al_send_sa_req(\r
302                 &p_query->sa_req, p_query_req->port_guid, p_query_req->timeout_ms,\r
303                 p_query_req->retry_cnt, p_sa_req, flags );\r
304         AL_EXIT( AL_DBG_QUERY );\r
305         return status;\r
306 }\r
307 \r
308 \r
309 \r
310 /*\r
311  * Query request completion callback.\r
312  */\r
313 void\r
314 query_req_cb(\r
315         IN                              al_sa_req_t                                     *p_sa_req,\r
316         IN                              ib_mad_element_t                        *p_mad_response )\r
317 {\r
318         al_query_t                      *p_query;\r
319         ib_query_rec_t          query_rec;\r
320         ib_sa_mad_t                     *p_sa_mad;\r
321 \r
322         AL_ENTER( AL_DBG_QUERY );\r
323         p_query = PARENT_STRUCT( p_sa_req, al_query_t, sa_req );\r
324 \r
325         /* Initialize the results of the query. */\r
326         cl_memclr( &query_rec, sizeof( ib_query_rec_t ) );\r
327         query_rec.status = p_sa_req->status;\r
328         query_rec.query_context = p_query->sa_req.user_context;\r
329         query_rec.query_type = p_query->query_type;\r
330 \r
331         /* Form the result of the query, if we got one. */\r
332         if( query_rec.status == IB_SUCCESS )\r
333         {\r
334 \r
335                 CL_ASSERT( p_mad_response );\r
336                 p_sa_mad = (ib_sa_mad_t*)p_mad_response->p_mad_buf;\r
337 \r
338                 if (ib_get_attr_size( p_sa_mad->attr_offset ) != 0)\r
339                 {\r
340                         query_rec.result_cnt =\r
341                                 ( ( p_mad_response->size - IB_SA_MAD_HDR_SIZE ) /\r
342                                 ib_get_attr_size( p_sa_mad->attr_offset ) );\r
343                 }\r
344                 else\r
345                 {\r
346                         query_rec.result_cnt = 0;\r
347                 }\r
348 \r
349                 AL_PRINT( TRACE_LEVEL_INFORMATION, AL_DBG_QUERY,\r
350                         ("query succeeded with result_cnt = %d\n", query_rec.result_cnt) );\r
351 \r
352                 query_rec.p_result_mad = p_mad_response;\r
353         }\r
354         else\r
355         {\r
356                 AL_PRINT( TRACE_LEVEL_WARNING, AL_DBG_QUERY,\r
357                         ("query failed: %s\n", ib_get_err_str(query_rec.status) ) );\r
358                 if( p_mad_response )\r
359                         query_rec.p_result_mad = p_mad_response;\r
360         }\r
361 \r
362         /*\r
363          * Handing an internal MAD to a client.\r
364          * Track the MAD element with the client's AL instance.\r
365          */\r
366         if( p_mad_response )\r
367                 al_handoff_mad( p_query->h_al, p_mad_response );\r
368 \r
369         /* Notify the user of the result. */\r
370         p_query->pfn_query_cb( &query_rec );\r
371 \r
372         /* Cleanup from issuing the query. */\r
373         al_remove_query( p_query );\r
374         cl_free( p_query );\r
375 \r
376         AL_EXIT( AL_DBG_QUERY );\r
377 }\r