[infiniband] Allow SRP reconnection attempts even after reporting failures
[people/oremanj/gpxe.git] / src / drivers / block / srp.c
1 /*
2  * Copyright (C) 2009 Fen Systems Ltd <mbrown@fensystems.co.uk>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  *   Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  *   Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in
14  *   the documentation and/or other materials provided with the
15  *   distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 FILE_LICENCE ( BSD2 );
32
33 #include <stdlib.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <gpxe/scsi.h>
37 #include <gpxe/xfer.h>
38 #include <gpxe/features.h>
39 #include <gpxe/ib_srp.h>
40 #include <gpxe/srp.h>
41
42 /**
43  * @file
44  *
45  * SCSI RDMA Protocol
46  *
47  */
48
49 FEATURE ( FEATURE_PROTOCOL, "SRP", DHCP_EB_FEATURE_SRP, 1 );
50
51 /** Tag to be used for next SRP IU */
52 static unsigned int srp_tag = 0;
53
54 static void srp_login ( struct srp_device *srp );
55 static void srp_cmd ( struct srp_device *srp );
56
57 /**
58  * Mark SRP SCSI command as complete
59  *
60  * @v srp               SRP device
61  * @v rc                Status code
62  */
63 static void srp_scsi_done ( struct srp_device *srp, int rc ) {
64         if ( srp->command )
65                 srp->command->rc = rc;
66         srp->command = NULL;
67 }
68
69 /**
70  * Handle SRP session failure
71  *
72  * @v srp               SRP device
73  * @v rc                Reason for failure
74  */
75 static void srp_fail ( struct srp_device *srp, int rc ) {
76
77         /* Close underlying socket */
78         xfer_close ( &srp->socket, rc );
79
80         /* Clear session state */
81         srp->state = 0;
82
83         /* If we have reached the retry limit, report the failure */
84         if ( srp->retry_count >= SRP_MAX_RETRIES ) {
85                 srp_scsi_done ( srp, rc );
86                 return;
87         }
88
89         /* Otherwise, increment the retry count and try to reopen the
90          * connection
91          */
92         srp->retry_count++;
93         srp_login ( srp );
94 }
95
96 /**
97  * Initiate SRP login
98  *
99  * @v srp               SRP device
100  */
101 static void srp_login ( struct srp_device *srp ) {
102         struct io_buffer *iobuf;
103         struct srp_login_req *login_req;
104         int rc;
105
106         assert ( ! ( srp->state & SRP_STATE_SOCKET_OPEN ) );
107
108         /* Open underlying socket */
109         if ( ( rc = srp->transport->connect ( srp ) ) != 0 ) {
110                 DBGC ( srp, "SRP %p could not open socket: %s\n",
111                        srp, strerror ( rc ) );
112                 goto err;
113         }
114         srp->state |= SRP_STATE_SOCKET_OPEN;
115
116         /* Allocate I/O buffer */
117         iobuf = xfer_alloc_iob ( &srp->socket, sizeof ( *login_req ) );
118         if ( ! iobuf ) {
119                 rc = -ENOMEM;
120                 goto err;
121         }
122
123         /* Construct login request IU */
124         login_req = iob_put ( iobuf, sizeof ( *login_req ) );
125         memset ( login_req, 0, sizeof ( *login_req ) );
126         login_req->type = SRP_LOGIN_REQ;
127         login_req->tag.dwords[1] = htonl ( ++srp_tag );
128         login_req->max_i_t_iu_len = htonl ( SRP_MAX_I_T_IU_LEN );
129         login_req->required_buffer_formats = SRP_LOGIN_REQ_FMT_DDBD;
130         memcpy ( &login_req->port_ids, &srp->port_ids,
131                  sizeof ( login_req->port_ids ) );
132
133         DBGC2 ( srp, "SRP %p TX login request tag %08x%08x\n",
134                 srp, ntohl ( login_req->tag.dwords[0] ),
135                 ntohl ( login_req->tag.dwords[1] ) );
136         DBGC2_HDA ( srp, 0, iobuf->data, iob_len ( iobuf ) );
137
138         /* Send login request IU */
139         if ( ( rc = xfer_deliver_iob ( &srp->socket, iobuf ) ) != 0 ) {
140                 DBGC ( srp, "SRP %p could not send login request: %s\n",
141                        srp, strerror ( rc ) );
142                 goto err;
143         }
144
145         return;
146
147  err:
148         srp_fail ( srp, rc );
149 }
150
151 /**
152  * Handle SRP login response
153  *
154  * @v srp               SRP device
155  * @v iobuf             I/O buffer
156  * @ret rc              Return status code
157  */
158 static int srp_login_rsp ( struct srp_device *srp, struct io_buffer *iobuf ) {
159         struct srp_login_rsp *login_rsp = iobuf->data;
160         int rc;
161
162         DBGC2 ( srp, "SRP %p RX login response tag %08x%08x\n",
163                 srp, ntohl ( login_rsp->tag.dwords[0] ),
164                 ntohl ( login_rsp->tag.dwords[1] ) );
165
166         /* Sanity check */
167         if ( iob_len ( iobuf ) < sizeof ( *login_rsp ) ) {
168                 DBGC ( srp, "SRP %p RX login response too short (%zd bytes)\n",
169                        srp, iob_len ( iobuf ) );
170                 rc = -EINVAL;
171                 goto out;
172         }
173
174         DBGC ( srp, "SRP %p logged in\n", srp );
175
176         /* Mark as logged in */
177         srp->state |= SRP_STATE_LOGGED_IN;
178
179         /* Reset error counter */
180         srp->retry_count = 0;
181
182         /* Issue pending command */
183         srp_cmd ( srp );
184
185         rc = 0;
186  out:
187         free_iob ( iobuf );
188         return rc;
189 }
190
191 /**
192  * Handle SRP login rejection
193  *
194  * @v srp               SRP device
195  * @v iobuf             I/O buffer
196  * @ret rc              Return status code
197  */
198 static int srp_login_rej ( struct srp_device *srp, struct io_buffer *iobuf ) {
199         struct srp_login_rej *login_rej = iobuf->data;
200         int rc;
201
202         DBGC2 ( srp, "SRP %p RX login rejection tag %08x%08x\n",
203                 srp, ntohl ( login_rej->tag.dwords[0] ),
204                 ntohl ( login_rej->tag.dwords[1] ) );
205
206         /* Sanity check */
207         if ( iob_len ( iobuf ) < sizeof ( *login_rej ) ) {
208                 DBGC ( srp, "SRP %p RX login rejection too short (%zd "
209                        "bytes)\n", srp, iob_len ( iobuf ) );
210                 rc = -EINVAL;
211                 goto out;
212         }
213
214         /* Login rejection always indicates an error */
215         DBGC ( srp, "SRP %p login rejected (reason %08x)\n",
216                srp, ntohl ( login_rej->reason ) );
217         rc = -EPERM;
218
219  out:
220         free_iob ( iobuf );
221         return rc;
222 }
223
224 /**
225  * Transmit SRP SCSI command
226  *
227  * @v srp               SRP device
228  */
229 static void srp_cmd ( struct srp_device *srp ) {
230         struct io_buffer *iobuf;
231         struct srp_cmd *cmd;
232         struct srp_memory_descriptor *data_out;
233         struct srp_memory_descriptor *data_in;
234         int rc;
235
236         assert ( srp->state & SRP_STATE_LOGGED_IN );
237
238         /* Allocate I/O buffer */
239         iobuf = xfer_alloc_iob ( &srp->socket, SRP_MAX_I_T_IU_LEN );
240         if ( ! iobuf ) {
241                 rc = -ENOMEM;
242                 goto err;
243         }
244
245         /* Construct base portion */
246         cmd = iob_put ( iobuf, sizeof ( *cmd ) );
247         memset ( cmd, 0, sizeof ( *cmd ) );
248         cmd->type = SRP_CMD;
249         cmd->tag.dwords[1] = htonl ( ++srp_tag );
250         cmd->lun = srp->lun;
251         memcpy ( &cmd->cdb, &srp->command->cdb, sizeof ( cmd->cdb ) );
252
253         /* Construct data-out descriptor, if present */
254         if ( srp->command->data_out ) {
255                 cmd->data_buffer_formats |= SRP_CMD_DO_FMT_DIRECT;
256                 data_out = iob_put ( iobuf, sizeof ( *data_out ) );
257                 data_out->address =
258                     cpu_to_be64 ( user_to_phys ( srp->command->data_out, 0 ) );
259                 data_out->handle = ntohl ( srp->memory_handle );
260                 data_out->len = ntohl ( srp->command->data_out_len );
261         }
262
263         /* Construct data-in descriptor, if present */
264         if ( srp->command->data_in ) {
265                 cmd->data_buffer_formats |= SRP_CMD_DI_FMT_DIRECT;
266                 data_in = iob_put ( iobuf, sizeof ( *data_in ) );
267                 data_in->address =
268                      cpu_to_be64 ( user_to_phys ( srp->command->data_in, 0 ) );
269                 data_in->handle = ntohl ( srp->memory_handle );
270                 data_in->len = ntohl ( srp->command->data_in_len );
271         }
272
273         DBGC2 ( srp, "SRP %p TX SCSI command tag %08x%08x\n", srp,
274                 ntohl ( cmd->tag.dwords[0] ), ntohl ( cmd->tag.dwords[1] ) );
275         DBGC2_HDA ( srp, 0, iobuf->data, iob_len ( iobuf ) );
276
277         /* Send IU */
278         if ( ( rc = xfer_deliver_iob ( &srp->socket, iobuf ) ) != 0 ) {
279                 DBGC ( srp, "SRP %p could not send command: %s\n",
280                        srp, strerror ( rc ) );
281                 goto err;
282         }
283
284         return;
285
286  err:
287         srp_fail ( srp, rc );
288 }
289
290 /**
291  * Handle SRP SCSI response
292  *
293  * @v srp               SRP device
294  * @v iobuf             I/O buffer
295  * @ret rc              Returns status code
296  */
297 static int srp_rsp ( struct srp_device *srp, struct io_buffer *iobuf ) {
298         struct srp_rsp *rsp = iobuf->data;
299         int rc;
300
301         DBGC2 ( srp, "SRP %p RX SCSI response tag %08x%08x\n", srp,
302                 ntohl ( rsp->tag.dwords[0] ), ntohl ( rsp->tag.dwords[1] ) );
303
304         /* Sanity check */
305         if ( iob_len ( iobuf ) < sizeof ( *rsp ) ) {
306                 DBGC ( srp, "SRP %p RX SCSI response too short (%zd bytes)\n",
307                        srp, iob_len ( iobuf ) );
308                 rc = -EINVAL;
309                 goto out;
310         }
311
312         /* Report SCSI errors */
313         if ( rsp->status != 0 ) {
314                 DBGC ( srp, "SRP %p response status %02x\n",
315                        srp, rsp->status );
316                 if ( srp_rsp_sense_data ( rsp ) ) {
317                         DBGC ( srp, "SRP %p sense data:\n", srp );
318                         DBGC_HDA ( srp, 0, srp_rsp_sense_data ( rsp ),
319                                    srp_rsp_sense_data_len ( rsp ) );
320                 }
321         }
322         if ( rsp->valid & ( SRP_RSP_VALID_DOUNDER | SRP_RSP_VALID_DOOVER ) ) {
323                 DBGC ( srp, "SRP %p response data-out %srun by %#x bytes\n",
324                        srp, ( ( rsp->valid & SRP_RSP_VALID_DOUNDER )
325                               ? "under" : "over" ),
326                        ntohl ( rsp->data_out_residual_count ) );
327         }
328         if ( rsp->valid & ( SRP_RSP_VALID_DIUNDER | SRP_RSP_VALID_DIOVER ) ) {
329                 DBGC ( srp, "SRP %p response data-in %srun by %#x bytes\n",
330                        srp, ( ( rsp->valid & SRP_RSP_VALID_DIUNDER )
331                               ? "under" : "over" ),
332                        ntohl ( rsp->data_in_residual_count ) );
333         }
334         srp->command->status = rsp->status;
335
336         /* Mark SCSI command as complete */
337         srp_scsi_done ( srp, 0 );
338
339         rc = 0;
340  out:
341         free_iob ( iobuf );
342         return rc;
343 }
344
345 /**
346  * Handle SRP unrecognised response
347  *
348  * @v srp               SRP device
349  * @v iobuf             I/O buffer
350  * @ret rc              Returns status code
351  */
352 static int srp_unrecognised ( struct srp_device *srp,
353                               struct io_buffer *iobuf ) {
354         struct srp_common *common = iobuf->data;
355
356         DBGC ( srp, "SRP %p RX unrecognised IU tag %08x%08x type %02x\n",
357                srp, ntohl ( common->tag.dwords[0] ),
358                ntohl ( common->tag.dwords[1] ), common->type );
359
360         free_iob ( iobuf );
361         return -ENOTSUP;
362 }
363
364 /**
365  * Receive data from underlying socket
366  *
367  * @v xfer              Data transfer interface
368  * @v iobuf             Datagram I/O buffer
369  * @v meta              Data transfer metadata
370  * @ret rc              Return status code
371  */
372 static int srp_xfer_deliver_iob ( struct xfer_interface *xfer,
373                                   struct io_buffer *iobuf,
374                                   struct xfer_metadata *meta __unused ) {
375         struct srp_device *srp =
376                 container_of ( xfer, struct srp_device, socket );
377         struct srp_common *common = iobuf->data;
378         int ( * type ) ( struct srp_device *srp, struct io_buffer *iobuf );
379         int rc;
380
381         /* Determine IU type */
382         switch ( common->type ) {
383         case SRP_LOGIN_RSP:
384                 type = srp_login_rsp;
385                 break;
386         case SRP_LOGIN_REJ:
387                 type = srp_login_rej;
388                 break;
389         case SRP_RSP:
390                 type = srp_rsp;
391                 break;
392         default:
393                 type = srp_unrecognised;
394                 break;
395         }
396
397         /* Handle IU */
398         if ( ( rc = type ( srp, iobuf ) ) != 0 )
399                 goto err;
400
401         return 0;
402
403  err:
404         srp_fail ( srp, rc );
405         return rc;
406 }
407
408 /**
409  * Underlying socket closed
410  *
411  * @v xfer              Data transfer interface
412  * @v rc                Reason for close
413  */
414 static void srp_xfer_close ( struct xfer_interface *xfer, int rc ) {
415         struct srp_device *srp =
416                 container_of ( xfer, struct srp_device, socket );
417
418         DBGC ( srp, "SRP %p socket closed: %s\n", srp, strerror ( rc ) );
419
420         srp_fail ( srp, rc );
421 }
422
423 /** SRP data transfer interface operations */
424 static struct xfer_interface_operations srp_xfer_operations = {
425         .close          = srp_xfer_close,
426         .vredirect      = ignore_xfer_vredirect,
427         .window         = unlimited_xfer_window,
428         .alloc_iob      = default_xfer_alloc_iob,
429         .deliver_iob    = srp_xfer_deliver_iob,
430         .deliver_raw    = xfer_deliver_as_iob,
431 };
432
433 /**
434  * Issue SCSI command via SRP
435  *
436  * @v scsi              SCSI device
437  * @v command           SCSI command
438  * @ret rc              Return status code
439  */
440 static int srp_command ( struct scsi_device *scsi,
441                          struct scsi_command *command ) {
442         struct srp_device *srp =
443                 container_of ( scsi->backend, struct srp_device, refcnt );
444
445         /* Store SCSI command */
446         if ( srp->command ) {
447                 DBGC ( srp, "SRP %p cannot handle concurrent SCSI commands\n",
448                        srp );
449                 return -EBUSY;
450         }
451         srp->command = command;
452
453         /* Log in or issue command as appropriate */
454         if ( ! ( srp->state & SRP_STATE_SOCKET_OPEN ) ) {
455                 srp_login ( srp );
456         } else if ( srp->state & SRP_STATE_LOGGED_IN ) {
457                 srp_cmd ( srp );
458         } else {
459                 /* Still waiting for login; do nothing */
460         }
461
462         return 0;
463 }
464
465 /**
466  * Attach SRP device
467  *
468  * @v scsi              SCSI device
469  * @v root_path         Root path
470  */
471 int srp_attach ( struct scsi_device *scsi, const char *root_path ) {
472         struct srp_transport_type *transport;
473         struct srp_device *srp;
474         int rc;
475
476         /* Hard-code an IB SRP back-end for now */
477         transport = &ib_srp_transport;
478
479         /* Allocate and initialise structure */
480         srp = zalloc ( sizeof ( *srp ) + transport->priv_len );
481         if ( ! srp ) {
482                 rc = -ENOMEM;
483                 goto err_alloc;
484         }
485         xfer_init ( &srp->socket, &srp_xfer_operations, &srp->refcnt );
486         srp->transport = transport;
487         DBGC ( srp, "SRP %p using %s\n", srp, root_path );
488
489         /* Parse root path */
490         if ( ( rc = transport->parse_root_path ( srp, root_path ) ) != 0 ) {
491                 DBGC ( srp, "SRP %p could not parse root path: %s\n",
492                        srp, strerror ( rc ) );
493                 goto err_parse_root_path;
494         }
495
496         /* Attach parent interface, mortalise self, and return */
497         scsi->backend = ref_get ( &srp->refcnt );
498         scsi->command = srp_command;
499         ref_put ( &srp->refcnt );
500         return 0;
501
502  err_parse_root_path:
503         ref_put ( &srp->refcnt );
504  err_alloc:
505         return rc;
506 }
507
508 /**
509  * Detach SRP device
510  *
511  * @v scsi              SCSI device
512  */
513 void srp_detach ( struct scsi_device *scsi ) {
514         struct srp_device *srp =
515                 container_of ( scsi->backend, struct srp_device, refcnt );
516
517         /* Close socket */
518         xfer_nullify ( &srp->socket );
519         xfer_close ( &srp->socket, 0 );
520         scsi->command = scsi_detached_command;
521         ref_put ( scsi->backend );
522         scsi->backend = NULL;
523 }