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