Fix to support Indirect Data Buffer Descriptors in SRP.
[mirror/winof/.git] / ulp / srp / kernel / srp_connection.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 "srp_data_path.h"\r
34 #include "srp_debug.h"\r
35 #include "srp_event.h"\r
36 #include "srp_hca.h"\r
37 #include "srp_session.h"\r
38 \r
39 #include "srp.h"\r
40 #include "srp_login_req.h"\r
41 #include "srp_login_rsp.h"\r
42 #include "srp_login_rej.h"\r
43 \r
44 #include "srp_connection.h"\r
45 \r
46 #include <complib/cl_math.h>\r
47 \r
48 /* __srp_create_cqs */\r
49 /*!\r
50 Creates the send/recv completion queues to be used by this connection\r
51 \r
52 @param p_srp_connection - pointer to the connection structure\r
53 @param p_hca            - pointer to the hca structure used by the connection\r
54 @param p_session        - context passed to callback functions\r
55 \r
56 @return - result of cq creation\r
57 */\r
58 static\r
59 ib_api_status_t\r
60 __srp_create_cqs(\r
61         IN OUT  srp_connection_t    *p_srp_connection,\r
62         IN      srp_hca_t           *p_hca,\r
63         IN      p_srp_session_t     p_session )\r
64 {\r
65         ib_api_status_t status;\r
66         ib_cq_create_t  cq_create;\r
67         ib_al_ifc_t             *p_ifc;\r
68 \r
69         SRP_ENTER( SRP_DBG_PNP );\r
70 \r
71         p_ifc = &p_hca->p_hba->ifc;\r
72 \r
73         // Create Send CQ\r
74         cq_create.size = SRP_DEFAULT_SEND_Q_DEPTH;\r
75         cq_create.pfn_comp_cb = srp_send_completion_cb;\r
76         cq_create.h_wait_obj = NULL;\r
77 \r
78         status = p_ifc->create_cq( p_hca->h_ca,\r
79                                                    &cq_create,\r
80                                                    p_session,\r
81                                                    srp_async_event_handler_cb,\r
82                                                    &p_srp_connection->h_send_cq );\r
83         if( status != IB_SUCCESS )\r
84         {\r
85                 SRP_TRACE( SRP_DBG_ERROR,\r
86                         ("Cannot Create Send Completion Queue. Status = %d\n", status) );\r
87                 goto exit;\r
88         }\r
89 \r
90         // Create Receive CQ\r
91         cq_create.size = SRP_DEFAULT_RECV_Q_DEPTH;\r
92         cq_create.pfn_comp_cb = srp_recv_completion_cb;\r
93         cq_create.h_wait_obj = NULL;\r
94 \r
95         status = p_ifc->create_cq( p_hca->h_ca,\r
96                                                    &cq_create,\r
97                                                    p_session,\r
98                                                    srp_async_event_handler_cb,\r
99                                                    &p_srp_connection->h_recv_cq );\r
100         if( status != IB_SUCCESS )\r
101         {\r
102                 SRP_TRACE( SRP_DBG_ERROR,\r
103                         ("Cannot Create Receive Completion Queue. Status = %d\n", status) );\r
104         }\r
105 \r
106 exit:\r
107         SRP_EXIT( SRP_DBG_PNP );\r
108 \r
109         return ( status );\r
110 }\r
111 \r
112 /* __srp_create_qp */\r
113 /*!\r
114 Creates the queue pair to be used by this connection\r
115 \r
116 @param p_srp_connection - pointer to the connection structure\r
117 @param p_hca            - pointer to the hca structure used by the connection\r
118 @param p_session        - context passed to callback functions\r
119 \r
120 @return - result of qp creation\r
121 */\r
122 static\r
123 ib_api_status_t\r
124 __srp_create_qp(\r
125         IN OUT  srp_connection_t    *p_srp_connection,\r
126         IN      srp_hca_t           *p_hca,\r
127         IN      p_srp_session_t     p_session )\r
128 {\r
129         ib_api_status_t status;\r
130         ib_qp_create_t  qp_create;\r
131         ib_al_ifc_t             *p_ifc;\r
132 \r
133         SRP_ENTER( SRP_DBG_PNP );\r
134 \r
135         p_ifc = &p_hca->p_hba->ifc;\r
136 \r
137         // Create QP\r
138         qp_create.qp_type = IB_QPT_RELIABLE_CONN;\r
139         qp_create.sq_depth = SRP_DEFAULT_SEND_Q_DEPTH;\r
140         qp_create.rq_depth = SRP_DEFAULT_RECV_Q_DEPTH;\r
141         qp_create.sq_sge = 1;\r
142         qp_create.rq_sge = 1;\r
143         qp_create.h_sq_cq = p_srp_connection->h_send_cq;\r
144         qp_create.h_rq_cq = p_srp_connection->h_recv_cq;\r
145         qp_create.sq_signaled = FALSE;//TRUE;\r
146 \r
147         status = p_ifc->create_qp( p_hca->h_pd,\r
148                                                    &qp_create,\r
149                                                    p_session,\r
150                                                    srp_async_event_handler_cb,\r
151                                                    &p_srp_connection->h_qp );\r
152         if ( status != IB_SUCCESS )\r
153         {\r
154                 SRP_TRACE( SRP_DBG_ERROR,\r
155                         ("Cannot Create Queue Pair. Status = %d\n", status) );\r
156         }\r
157 \r
158         SRP_EXIT( SRP_DBG_PNP );\r
159 \r
160         return ( status );\r
161 }\r
162 \r
163 static\r
164 cl_status_t\r
165 __srp_create_wc_free_list(\r
166         IN OUT  srp_connection_t    *p_connection,\r
167         IN      uint32_t            completion_count )\r
168 {\r
169         cl_status_t status = CL_SUCCESS;\r
170         ib_wc_t     *p_wc;\r
171         uint32_t    i;\r
172 \r
173         SRP_ENTER( SRP_DBG_PNP );\r
174 \r
175         p_connection->p_wc_array = cl_zalloc( sizeof( ib_wc_t ) * completion_count );\r
176         if ( p_connection->p_wc_array == NULL )\r
177         {\r
178                 SRP_TRACE( SRP_DBG_ERROR,\r
179                         ("Failed to allocate %d work completions.\n",  completion_count) );\r
180                 status = CL_INSUFFICIENT_MEMORY;\r
181                 goto exit;\r
182         }\r
183 \r
184         p_wc = p_connection->p_wc_array;\r
185 \r
186         for ( i = 1; i < completion_count; i++, p_wc++ )\r
187         {\r
188                 p_wc->p_next = (p_wc + 1);\r
189         }\r
190 \r
191         p_connection->p_wc_free_list = p_connection->p_wc_array;\r
192 \r
193 exit:\r
194         SRP_EXIT( SRP_DBG_PNP );\r
195 \r
196         return ( status );\r
197 }\r
198 \r
199 \r
200 /* __srp_cm_request_cb */\r
201 /*!\r
202 Callback for a connect request - not used by SRP - We initiate connections\r
203 \r
204 @param p_cm_request - pointer to the connect request structure\r
205 \r
206 @return - none\r
207 */\r
208 static\r
209 void\r
210 __srp_cm_request_cb(\r
211         IN  ib_cm_req_rec_t     *p_cm_request)\r
212 {\r
213         SRP_ENTER( SRP_DBG_PNP );\r
214 \r
215         UNUSED_PARAM ( p_cm_request );\r
216 \r
217         SRP_EXIT( SRP_DBG_PNP );\r
218 }\r
219 \r
220 /* __srp_cm_apr_cb */\r
221 /*!\r
222 Callback for alternate path response - not used by SRP\r
223 \r
224 @param p_cm_apr_rec - pointer to the alternate path response structure\r
225 \r
226 @return - none\r
227 */\r
228 static\r
229 void\r
230 __srp_cm_apr_cb(\r
231         IN  ib_cm_apr_rec_t *p_cm_apr_rec )\r
232 {\r
233         SRP_ENTER( SRP_DBG_PNP );\r
234 \r
235         UNUSED_PARAM( p_cm_apr_rec );\r
236 \r
237         SRP_EXIT( SRP_DBG_PNP );\r
238 }\r
239 \r
240 /* __srp_cm_mra_cb */\r
241 /*!\r
242 Callback for message received acknowledgement - ignored by SRP - wait for connect reply\r
243 \r
244 @param p_cm_mra_rec - pointer to the message received acknowledgement structure\r
245 \r
246 @return - none\r
247 */\r
248 static\r
249 void\r
250 __srp_cm_mra_cb(\r
251         IN  ib_cm_mra_rec_t     *p_cm_mra_rec)\r
252 {\r
253         SRP_ENTER( SRP_DBG_PNP );\r
254 \r
255         UNUSED_PARAM ( p_cm_mra_rec );\r
256 \r
257         SRP_EXIT( SRP_DBG_PNP );\r
258 }\r
259 \r
260 /* __srp_cm_dreq_cb */\r
261 /*!\r
262 Callback for disconnect request from the target\r
263 Initiates the disconnect for the session\r
264 \r
265 TODO:\r
266 \r
267 @param p_cm_dreq_rec - pointer to the disconnect request structure\r
268 \r
269 @return - none\r
270 */\r
271 static\r
272 void\r
273 __srp_cm_dreq_cb(\r
274         IN  ib_cm_dreq_rec_t    *p_cm_dreq_rec )\r
275 {\r
276         srp_session_t   *p_srp_session = (srp_session_t* __ptr64)p_cm_dreq_rec->qp_context;\r
277         srp_hba_t       *p_hba = p_srp_session->p_hba;\r
278         ib_cm_drep_t    cm_drep;\r
279         ib_api_status_t status;\r
280         int             i;\r
281         int             retry_count = 0;\r
282 \r
283         SRP_ENTER( SRP_DBG_PNP );\r
284 \r
285         SRP_TRACE( SRP_DBG_DEBUG,\r
286                 ("Target has issued a disconnect request.\n") );\r
287 \r
288         if ( p_hba->adapter_paused == FALSE )\r
289         {\r
290                 p_hba->adapter_paused = TRUE;\r
291                 StorPortBusy( p_hba->p_ext, (ULONG)-1 );\r
292                 StorPortCompleteRequest( p_hba->p_ext,\r
293                                                                  SP_UNTAGGED,\r
294                                                                  SP_UNTAGGED,\r
295                                                                  SP_UNTAGGED,\r
296                                                                  SRB_STATUS_BUSY );\r
297                 SRP_TRACE( SRP_DBG_DEBUG, ("Pausing Adapter for %s.\n", p_hba->ioc_info.profile.id_string) );\r
298         }\r
299 \r
300         cl_obj_lock( &p_srp_session->obj );\r
301         p_srp_session->connection.state = SRP_TARGET_DISCONNECTING;\r
302         cl_obj_unlock( &p_srp_session->obj );\r
303 \r
304         cm_drep.p_drep_pdata = NULL;\r
305         cm_drep.drep_length = 0;\r
306 \r
307         status = p_hba->ifc.cm_drep( p_cm_dreq_rec->h_cm_dreq, &cm_drep );\r
308         if ( status != IB_SUCCESS )\r
309         {\r
310                 SRP_TRACE( SRP_DBG_ERROR,\r
311                         ("Cannot respond to target disconnect request. Status = %d\n", status) );\r
312         }\r
313 \r
314         cl_obj_lock( &p_hba->obj );\r
315 \r
316         for ( i = 0; i < SRP_MAX_SERVICE_ENTRIES; i++ )\r
317         {\r
318                 if ( p_srp_session == p_hba->session_list[i] )\r
319                 {\r
320                         p_hba->session_list[i] = NULL;\r
321                         break;\r
322                 }\r
323         }\r
324 \r
325         cl_obj_unlock( &p_hba->obj );\r
326 \r
327         SRP_TRACE( SRP_DBG_VERBOSE, ("Session Object ref_cnt = %d\n", p_srp_session->obj.ref_cnt) );\r
328         cl_obj_destroy( &p_srp_session->obj );\r
329 \r
330         do\r
331         {\r
332                 retry_count++;\r
333 \r
334                 SRP_TRACE( SRP_DBG_DEBUG,\r
335                         ("Attempting to reconnect %s. Connection Attempt Count = %d.\n",\r
336                          p_hba->ioc_info.profile.id_string,\r
337                          retry_count) );\r
338 \r
339                 SRP_TRACE( SRP_DBG_VERBOSE,\r
340                         ("Creating New Session For Service Entry Index %d.\n", p_hba->ioc_info.profile.num_svc_entries));\r
341                 p_srp_session = srp_new_session( p_hba,\r
342                                                                                  p_hba->ioc_info.profile.ioc_guid,\r
343                                                                                  &p_hba->p_svc_entries[i],\r
344                                                                                  &status );\r
345                 if ( p_srp_session == NULL )\r
346                 {\r
347                         status = IB_INSUFFICIENT_MEMORY;\r
348                         break;\r
349                 }\r
350 \r
351                 SRP_TRACE( SRP_DBG_VERBOSE,\r
352                         ("New Session For Service Entry Index %d Created.\n", p_hba->ioc_info.profile.num_svc_entries));\r
353                 SRP_TRACE( SRP_DBG_VERBOSE,\r
354                         ("Logging Into Session.\n"));\r
355                 status = srp_session_login( p_srp_session );\r
356                 if ( status == IB_SUCCESS )\r
357                 {\r
358                         if ( p_hba->max_sg > p_srp_session->connection.max_scatter_gather_entries )\r
359                         {\r
360                                 p_hba->max_sg = p_srp_session->connection.max_scatter_gather_entries;\r
361                         }\r
362 \r
363                         if ( p_hba->max_srb_ext_sz > p_srp_session->connection.init_to_targ_iu_sz )\r
364                         {\r
365                                 p_hba->max_srb_ext_sz =\r
366                                         sizeof( srp_send_descriptor_t ) -\r
367                                         SRP_MIN_IU_SIZE +\r
368                                         p_srp_session->connection.init_to_targ_iu_sz;\r
369                         }\r
370 \r
371                         cl_obj_lock( &p_hba->obj );\r
372                         p_hba->session_list[i] = p_srp_session;\r
373                         cl_obj_unlock( &p_hba->obj );\r
374 \r
375                         SRP_TRACE( SRP_DBG_VERBOSE,\r
376                                 ("Session Login Issued Successfully.\n"));\r
377                 }\r
378                 else\r
379                 {\r
380                         SRP_TRACE( SRP_DBG_ERROR,\r
381                                 ("Session Login Failure Status = %d.\n", status));\r
382                         SRP_TRACE( SRP_DBG_VERBOSE, ("Session Object ref_cnt = %d\n", p_srp_session->obj.ref_cnt) );\r
383                         cl_obj_destroy( &p_srp_session->obj );\r
384                 }\r
385         } while ( (status != IB_SUCCESS) && (retry_count < 3) );\r
386 \r
387         if ( status == IB_SUCCESS )\r
388         {\r
389                 SRP_TRACE( SRP_DBG_DEBUG, ("Resuming Adapter for %s.\n", p_hba->ioc_info.profile.id_string) );\r
390                 p_hba->adapter_paused = FALSE;\r
391                 StorPortReady( p_hba->p_ext );\r
392 //              StorPortNotification( BusChangeDetected, p_hba->p_ext, 0 );\r
393         }\r
394 \r
395         SRP_EXIT( SRP_DBG_PNP );\r
396 }\r
397 \r
398 /* __srp_cm_reply_cb */\r
399 /*!\r
400 Callback for connect reply from the target\r
401 The target has accepted our connect/login request\r
402 \r
403 @param p_cm_reply - pointer to the connect reply structure\r
404 \r
405 @return - none\r
406 */\r
407 static\r
408 void\r
409 __srp_cm_reply_cb(\r
410         IN  ib_cm_rep_rec_t     *p_cm_reply)\r
411 {\r
412         srp_session_t       *p_srp_session = (srp_session_t* __ptr64)p_cm_reply->qp_context;\r
413         srp_connection_t    *p_connection;\r
414         srp_login_rsp_t     *p_srp_login_rsp = (srp_login_rsp_t* __ptr64)p_cm_reply->p_rep_pdata;\r
415         ib_api_status_t     status;\r
416         ib_cm_mra_t         cm_mra;\r
417         ib_cm_rtu_t         cm_rtu;\r
418         cl_status_t         cl_status;\r
419         ib_al_ifc_t                     *p_ifc;\r
420 \r
421         SRP_ENTER( SRP_DBG_PNP );\r
422 \r
423         p_ifc = &p_srp_session->p_hba->ifc;\r
424         p_connection = &p_srp_session->connection;\r
425 \r
426         set_srp_login_response_from_network_to_host( p_srp_login_rsp );\r
427         p_connection->descriptor_format = get_srp_login_response_supported_data_buffer_formats( p_srp_login_rsp );\r
428 \r
429         p_connection->request_limit      =\r
430                 MIN( get_srp_login_response_request_limit_delta( p_srp_login_rsp ), SRP_DEFAULT_RECV_Q_DEPTH );\r
431         p_connection->send_queue_depth   = p_connection->request_limit;\r
432         p_connection->recv_queue_depth   = p_connection->request_limit;\r
433         p_connection->init_to_targ_iu_sz = get_srp_login_response_max_init_to_targ_iu( p_srp_login_rsp );\r
434         p_connection->targ_to_init_iu_sz = get_srp_login_response_max_targ_to_init_iu( p_srp_login_rsp );\r
435 \r
436         p_connection->signaled_send_completion_count  = p_connection->send_queue_depth / 2;\r
437         \r
438         if (( p_connection->descriptor_format & DBDF_INDIRECT_DATA_BUFFER_DESCRIPTORS ) == DBDF_INDIRECT_DATA_BUFFER_DESCRIPTORS )\r
439         {\r
440                 p_connection->max_scatter_gather_entries =\r
441                                 ( MAX( SRP_MAX_IU_SIZE, p_connection->init_to_targ_iu_sz ) - offsetof( srp_cmd_t, additional_cdb )- sizeof(srp_memory_table_descriptor_t)) / sizeof( srp_memory_descriptor_t );\r
442         }\r
443         else if (( p_connection->descriptor_format & DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR ) == DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR )\r
444         {\r
445                 p_connection->max_scatter_gather_entries = \r
446                                 (p_connection->init_to_targ_iu_sz - offsetof( srp_cmd_t, additional_cdb ))/ sizeof( srp_memory_descriptor_t );\r
447         }\r
448         else /* not reported any descriptor format */\r
449         {\r
450                 SRP_TRACE( SRP_DBG_DEBUG,(" Target does not support valid descriptor formats\n") );\r
451                 p_connection->state = SRP_CONNECT_FAILURE;\r
452                 goto exit;\r
453         }\r
454         SRP_TRACE( SRP_DBG_DEBUG,\r
455                         ("Request Limit = %d, SendQ Depth = %d, RecvQDepth = %d, ItoT size = %d, TtoI size = %d, Max S/G = %d\n",\r
456                         p_connection->request_limit,\r
457                         p_connection->send_queue_depth,\r
458                         p_connection->recv_queue_depth,\r
459                         p_connection->init_to_targ_iu_sz,\r
460                         p_connection->targ_to_init_iu_sz,\r
461                         p_connection->max_scatter_gather_entries) );\r
462 \r
463         cm_mra.svc_timeout = 0x08;\r
464         cm_mra.p_mra_pdata = NULL;\r
465         cm_mra.mra_length = 0;\r
466 \r
467         status = p_ifc->cm_mra( p_cm_reply->h_cm_rep, &cm_mra );\r
468         if ( status != IB_SUCCESS )\r
469         {\r
470                 SRP_TRACE( SRP_DBG_ERROR,\r
471                         ("Cannot Send MRA. Status = %d\n", status) );\r
472                 p_connection->state = SRP_CONNECT_FAILURE;\r
473                 goto exit;\r
474         }\r
475 \r
476         status = p_ifc->modify_cq( p_connection->h_send_cq, &p_connection->send_queue_depth );\r
477         if ( status != IB_SUCCESS )\r
478         {\r
479                 SRP_TRACE( SRP_DBG_WARN,\r
480                         ("Cannot Modify Send Completion Queue Depth. Status = %d\n", status) );\r
481         }\r
482 \r
483         status = p_ifc->modify_cq( p_connection->h_recv_cq, &p_connection->recv_queue_depth );\r
484         if ( status != IB_SUCCESS )\r
485         {\r
486                 SRP_TRACE( SRP_DBG_WARN,\r
487                         ("Cannot Modify Recv Completion Queue Depth. Status = %d\n", status) );\r
488         }\r
489 \r
490         cl_status = __srp_create_wc_free_list( p_connection, (p_connection->request_limit * 2) );/* Send/Recv */\r
491         if ( cl_status != CL_SUCCESS )\r
492         {\r
493                 p_connection->state = SRP_CONNECT_FAILURE;\r
494                 goto exit;\r
495         }\r
496 \r
497         status = srp_init_descriptors( &p_srp_session->descriptors,\r
498                                                                    p_connection->request_limit,\r
499                                                                    p_connection->targ_to_init_iu_sz,\r
500                                                                    &p_srp_session->p_hba->ifc,\r
501                                                                    p_srp_session->hca.h_pd,\r
502                                                                    p_connection->h_qp );\r
503         if ( status != IB_SUCCESS )\r
504         {\r
505                 cl_free( p_connection->p_wc_array );\r
506                 p_connection->p_wc_array = NULL;\r
507                 p_connection->p_wc_free_list = NULL;\r
508                 p_connection->state = SRP_CONNECT_FAILURE;\r
509                 goto exit;\r
510         }\r
511 \r
512         cm_rtu.access_ctrl = IB_AC_LOCAL_WRITE | IB_AC_RDMA_READ | IB_AC_RDMA_WRITE;\r
513 \r
514         /* Have to set to 0 to indicate not to modify because Tavor doesn't support this */\r
515         cm_rtu.sq_depth = 0 /*p_connection->request_limit*/;\r
516         cm_rtu.rq_depth = 0 /*p_connection->request_limit*/;\r
517 \r
518         cm_rtu.p_rtu_pdata = NULL;\r
519         cm_rtu.rtu_length = 0;\r
520         cm_rtu.pfn_cm_apr_cb = __srp_cm_apr_cb;\r
521         cm_rtu.pfn_cm_dreq_cb = __srp_cm_dreq_cb;\r
522 \r
523         status = p_ifc->cm_rtu( p_cm_reply->h_cm_rep, &cm_rtu );\r
524         if ( status != IB_SUCCESS )\r
525         {\r
526                 SRP_TRACE( SRP_DBG_ERROR,\r
527                         ("Cannot Send RTU. Status = %d\n", status) );\r
528                 p_connection->state = SRP_CONNECT_FAILURE;\r
529                 goto exit;\r
530         }\r
531 \r
532         p_connection->state = SRP_CONNECTED;\r
533 \r
534         status = p_ifc->rearm_cq( p_connection->h_send_cq, FALSE );\r
535         if ( status != IB_SUCCESS)\r
536         {\r
537                 SRP_TRACE( SRP_DBG_ERROR,\r
538                         ("ib_rearm_cq() for send cq failed!, status 0x%x", status) );\r
539 \r
540                 // TODO: Kill session and inform port driver link down storportnotification\r
541                 return;\r
542         }\r
543 \r
544         status = p_ifc->rearm_cq( p_connection->h_recv_cq, FALSE );\r
545         if ( status != IB_SUCCESS)\r
546         {\r
547                 SRP_TRACE( SRP_DBG_ERROR,\r
548                         ("ib_rearm_cq() for recv failed!, status 0x%x", status) );\r
549 \r
550                 // TODO: Kill session and inform port driver link down storportnotification\r
551                 return;\r
552         }\r
553 \r
554 \r
555 exit:\r
556         cl_status = cl_event_signal( &p_connection->conn_req_event );\r
557 \r
558         SRP_EXIT( SRP_DBG_PNP );\r
559 }\r
560 \r
561 \r
562 /* __srp_cm_rej_cb */\r
563 /*!\r
564 Callback for connect reject from the target\r
565 The target has rejected our connect/login request\r
566 \r
567 @param p_cm_reject - pointer to the connect reject structure\r
568 \r
569 @return - none\r
570 */\r
571 static\r
572 void\r
573 __srp_cm_rej_cb(\r
574         IN  ib_cm_rej_rec_t     *p_cm_reject)\r
575 {\r
576         srp_session_t       *p_srp_session = (srp_session_t* __ptr64)p_cm_reject->qp_context;\r
577         srp_connection_t    *p_connection;\r
578         srp_login_rej_t     *p_srp_login_rej = (srp_login_rej_t* __ptr64)p_cm_reject->p_rej_pdata;\r
579         cl_status_t         cl_status;\r
580 \r
581         SRP_ENTER( SRP_DBG_PNP );\r
582 \r
583         p_connection = &p_srp_session->connection;\r
584 \r
585         if( p_srp_login_rej )\r
586         {\r
587                 set_srp_login_reject_from_network_to_host( p_srp_login_rej ); // <-- Is this coming back NULL?\r
588                 p_connection->reject_reason = get_srp_login_reject_reason( p_srp_login_rej );\r
589 \r
590                 SRP_TRACE( SRP_DBG_ERROR,\r
591                         ("Login Rejected. IBT Code = 0x%x, SRP Code = 0x%x\n",\r
592                         p_cm_reject->rej_status, p_connection->reject_reason ) );\r
593                 switch( p_connection->reject_reason )\r
594                 {\r
595                         case LIREJ_INIT_TO_TARG_IU_LENGTH_TOO_LARGE:\r
596                                 SRP_TRACE( SRP_DBG_ERROR, ("REQUESTED IU_SIZE %d\n", p_connection->req_max_iu_msg_size ));\r
597                                 break;\r
598                         case LIREJ_UNSUPPORTED_DATA_BUFFER_DESCRIPTOR_FORMAT:\r
599                                 SRP_TRACE( SRP_DBG_ERROR, ("REQUESTED DESC FORMAT: %#x, SUPPORTED FORMAT %#x\n",\r
600                                         p_connection->descriptor_format, \r
601                                         get_srp_login_reject_supported_data_buffer_formats(p_srp_login_rej) ));\r
602                                         __srp_issue_session_login( p_connection, (srp_hca_t *)&p_srp_session->hca, p_connection->ioc_max_send_msg_depth );\r
603                                         return;\r
604                         default:\r
605                                 break;\r
606                 }\r
607         }\r
608         else\r
609         {\r
610                 SRP_TRACE( SRP_DBG_ERROR,\r
611                         ("Login Rejected. IBT Code = 0x%x\n",\r
612                         p_cm_reject->rej_status) );\r
613 }\r
614         p_connection->state = SRP_CONNECT_FAILURE;\r
615 \r
616         cl_status = cl_event_signal( &p_connection->conn_req_event );\r
617 \r
618         SRP_EXIT( SRP_DBG_PNP );\r
619 }\r
620 \r
621 /* __srp_issue_session_login */\r
622 /*!\r
623 Initializes and issues a login/cm connect request to the target\r
624 \r
625 @param p_connection   - pointer to the connection structure\r
626 @param p_hca          - pointer to the hca structure used by this connection\r
627 @param send_msg_depth - initial request limit delta value\r
628 \r
629 @return - result of login/cm connect request operations\r
630 */\r
631 #pragma optimize( "", off )\r
632 static\r
633 ib_api_status_t\r
634 __srp_issue_session_login(\r
635         IN OUT  srp_connection_t    *p_connection,\r
636         IN      srp_hca_t           *p_hca,\r
637         IN      uint8_t             send_msg_depth )\r
638 {\r
639         ib_api_status_t status;\r
640         ib_cm_req_t     cm_req;\r
641         srp_login_req_t login_req;\r
642 \r
643         SRP_ENTER( SRP_DBG_PNP );\r
644 \r
645         cl_memclr( &cm_req, sizeof(ib_cm_req_t) );\r
646 \r
647         cm_req.svc_id = p_connection->service_id;\r
648 \r
649         cm_req.flags = 0; // event used instead of IB_FLAGS_SYNC\r
650         cm_req.max_cm_retries = 8;\r
651         cm_req.p_primary_path = p_connection->p_path_rec;\r
652         \r
653         /*already tried to login before and failed ? */\r
654         if ( !p_connection->reject_reason )\r
655         {\r
656                 p_connection->descriptor_format = DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR | DBDF_INDIRECT_DATA_BUFFER_DESCRIPTORS;\r
657         }\r
658         else if ( p_connection->reject_reason == LIREJ_UNSUPPORTED_DATA_BUFFER_DESCRIPTOR_FORMAT )\r
659         {\r
660                 p_connection->descriptor_format = DBDF_DIRECT_DATA_BUFFER_DESCRIPTOR;\r
661         }\r
662         else\r
663         {\r
664                 p_connection->state = SRP_CONNECT_FAILURE;\r
665                 status = IB_ERROR;\r
666                 goto exit;\r
667         }\r
668         p_connection->req_max_iu_msg_size = ( p_connection->ioc_max_send_msg_size >= SRP_MAX_IU_SIZE )? SRP_MAX_IU_SIZE: p_connection->ioc_max_send_msg_size;\r
669         /*\r
670            Build SRP Login request\r
671          */\r
672         setup_srp_login_request( &login_req,\r
673                                                          0, /* tag */\r
674                                                          p_connection->req_max_iu_msg_size,\r
675                                                          p_connection->descriptor_format,\r
676                                                          MCA_TERMINATE_EXISTING,\r
677                                                          &p_connection->init_port_id,\r
678                                                          &p_connection->targ_port_id );\r
679         set_srp_login_request_from_host_to_network(&login_req);\r
680 \r
681         cm_req.p_req_pdata = (const uint8_t *)&login_req;\r
682         cm_req.req_length = (uint8_t)get_srp_login_request_length( &login_req );\r
683 \r
684         cm_req.qp_type = IB_QPT_RELIABLE_CONN;\r
685         cm_req.h_qp = p_connection->h_qp;\r
686 \r
687          /* The maximum number of outstanding RDMA read/atomic operations. */\r
688         status = srp_get_responder_resources( p_hca, &cm_req.resp_res );\r
689         if ( status != IB_SUCCESS )\r
690         {\r
691                 goto exit;\r
692         }\r
693 \r
694         cm_req.init_depth = send_msg_depth;\r
695 \r
696         cm_req.remote_resp_timeout = 15;\r
697         cm_req.flow_ctrl = FALSE;\r
698         cm_req.local_resp_timeout = 16;\r
699         cm_req.retry_cnt = 1;\r
700         cm_req.rnr_nak_timeout = 0; /* 655.36 ms */\r
701         cm_req.rnr_retry_cnt = 6;\r
702 \r
703         cm_req.pfn_cm_rep_cb = __srp_cm_reply_cb;\r
704         cm_req.pfn_cm_req_cb = NULL; /* Set only for P2P */\r
705         cm_req.pfn_cm_mra_cb = __srp_cm_mra_cb;\r
706         cm_req.pfn_cm_rej_cb = __srp_cm_rej_cb;\r
707 \r
708         cm_req.pkey = p_connection->p_path_rec->pkey;\r
709 \r
710         status = p_hca->p_hba->ifc.cm_req( &cm_req );\r
711         if ( status == IB_SUCCESS )\r
712         {\r
713                 p_connection->state = SRP_CONNECT_REQUESTED;\r
714         }\r
715         else\r
716         {\r
717                 SRP_TRACE( SRP_DBG_ERROR,\r
718                         ("Cannot Send Connect Request. Status = %d\n", status) );\r
719                 p_connection->state = SRP_CONNECT_FAILURE;\r
720         }\r
721 \r
722 exit:\r
723         SRP_EXIT( SRP_DBG_PNP );\r
724 \r
725         return ( status );\r
726 }\r
727 #pragma optimize( "", on )\r
728 \r
729 /* srp_init_connection */\r
730 /*!\r
731 Initializes a connection structure\r
732 \r
733 @param p_connection   - pointer to the connection structure\r
734 @param p_path_rec     - pointer to the path to the target\r
735 @param p_targ_port_id - pointer to the target port id to which we want to connect\r
736 @param service_id     - service id to which we want to connect\r
737 \r
738 @return - always success (for now)\r
739 */\r
740 ib_api_status_t\r
741 srp_init_connection(\r
742         IN OUT  srp_connection_t        *p_connection,\r
743         IN      ib_path_rec_t           *p_path_rec,\r
744         IN      srp_ib_targ_port_id_t   *p_targ_port_id,\r
745         IN      ib_net64_t              service_id )\r
746 {\r
747         SRP_ENTER( SRP_DBG_PNP );\r
748 \r
749         cl_memclr( p_connection, sizeof(*p_connection) );\\r
750 \r
751         p_connection->initialized = TRUE;\r
752 \r
753         p_connection->state = SRP_NOT_CONNECTED;\r
754 \r
755         p_connection->p_path_rec = p_path_rec;\r
756         p_connection->targ_port_id = *p_targ_port_id;\r
757         p_connection->service_id = service_id;\r
758         p_connection->send_queue_depth = SRP_DEFAULT_SEND_Q_DEPTH;\r
759         p_connection->recv_queue_depth = SRP_DEFAULT_RECV_Q_DEPTH;\r
760 \r
761         SRP_EXIT( SRP_DBG_PNP );\r
762 \r
763         return ( IB_SUCCESS );\r
764 }\r
765 \r
766 /* srp_connect */\r
767 /*!\r
768 Orchestrates the processing required to connect to a target device\r
769 \r
770 @param p_connection        - pointer to the connection structure\r
771 @param p_hca               - pointer to the hca structure used by this connection\r
772 @param initiator_extension - value used for id_extension of the initiator port id\r
773 @param send_msg_depth      - initial request limit delta value\r
774 @param p_session           - context passed to callback functions\r
775 \r
776 @return -  result of connect operations\r
777 */\r
778 ib_api_status_t\r
779 srp_connect(\r
780         IN OUT  srp_connection_t    *p_connection,\r
781         IN      srp_hca_t           *p_hca,\r
782         IN      uint64_t            initiator_extension,\r
783         IN      uint8_t             send_msg_depth,\r
784         IN      p_srp_session_t     p_session )\r
785 {\r
786         ib_api_status_t status;\r
787         cl_status_t     cl_status;\r
788 \r
789         SRP_ENTER( SRP_DBG_PNP );\r
790 \r
791         p_connection->init_port_id.guid = p_hca->ca_guid;\r
792         p_connection->init_port_id.id_extension = initiator_extension;\r
793         p_connection->ioc_max_send_msg_size = cl_ntoh32 (p_session->p_hba->ioc_info.profile.send_msg_size);\r
794         p_connection->ioc_max_send_msg_depth = send_msg_depth;\r
795         p_connection->reject_reason = 0;\r
796 \r
797         status = __srp_create_cqs( p_connection, p_hca, p_session );\r
798         if ( status != IB_SUCCESS )\r
799         {\r
800                 goto exit;\r
801         }\r
802 \r
803         status = __srp_create_qp( p_connection, p_hca, p_session );\r
804         if ( status != IB_SUCCESS )\r
805         {\r
806                 goto exit;\r
807         }\r
808 \r
809         cl_status = cl_event_init( &p_connection->conn_req_event, TRUE );\r
810         if ( cl_status != CL_SUCCESS )\r
811         {\r
812                 SRP_TRACE( SRP_DBG_ERROR,\r
813                         ("Cannot Initialize Connect Request Event. Status = %d\n", cl_status) );\r
814                 status = cl_status;\r
815                 goto exit;\r
816         }\r
817 \r
818         status = __srp_issue_session_login( p_connection, p_hca, send_msg_depth );\r
819         if ( status != IB_SUCCESS )\r
820         {\r
821                 cl_event_destroy( &p_connection->conn_req_event );\r
822                 goto exit;\r
823         }\r
824 \r
825         cl_status = cl_event_wait_on( &p_connection->conn_req_event, EVENT_NO_TIMEOUT, FALSE );\r
826         if ( cl_status != CL_SUCCESS )\r
827         {\r
828                 SRP_TRACE( SRP_DBG_ERROR,\r
829                         ("Wait On Connect Request Event Failed. Status = %d\n", cl_status) );\r
830                 status = cl_status;\r
831                 cl_event_destroy( &p_connection->conn_req_event );\r
832                 goto exit;\r
833         }\r
834 \r
835         cl_event_destroy( &p_connection->conn_req_event );\r
836 \r
837         if ( p_connection->state != SRP_CONNECTED )\r
838         {\r
839                 status = IB_ERROR;\r
840                 goto exit;\r
841         }\r
842 \r
843 exit:\r
844         SRP_EXIT( SRP_DBG_PNP );\r
845 \r
846         return ( status );\r
847 }\r
848 \r
849 /* srp_free_connection */\r
850 /*!\r
851 Frees connection resources\r
852 \r
853 @param p_connection  - pointer to the connection structure\r
854 \r
855 @return -  none\r
856 */\r
857 void\r
858 srp_free_connection(\r
859         IN  srp_connection_t    *p_srp_connection )\r
860 {\r
861         SRP_ENTER( SRP_DBG_PNP );\r
862 \r
863         if ( p_srp_connection->initialized == TRUE )\r
864         {\r
865                 if ( p_srp_connection->p_wc_array != NULL )\r
866                 {\r
867                         cl_free( p_srp_connection->p_wc_array );\r
868                 }\r
869 \r
870                 cl_event_destroy( &p_srp_connection->conn_req_event );\r
871 \r
872                 cl_memclr( p_srp_connection, sizeof( *p_srp_connection ) );\r
873         }\r
874 \r
875         SRP_EXIT( SRP_DBG_PNP );\r
876 }\r
877 \r