[infiniband] Add support for SRP over Infiniband
[people/pravin/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         /* Increment retry count */
84         srp->retry_count++;
85
86         /* If we have reached the retry limit, permanently abort the
87          * session.
88          */
89         if ( srp->retry_count >= SRP_MAX_RETRIES ) {
90                 srp->instant_rc = rc;
91                 srp_scsi_done ( srp, rc );
92                 return;
93         }
94
95         /* Otherwise, try to reopen the connection */
96         srp_login ( srp );
97 }
98
99 /**
100  * Initiate SRP login
101  *
102  * @v srp               SRP device
103  */
104 static void srp_login ( struct srp_device *srp ) {
105         struct io_buffer *iobuf;
106         struct srp_login_req *login_req;
107         int rc;
108
109         assert ( ! ( srp->state & SRP_STATE_SOCKET_OPEN ) );
110
111         /* Open underlying socket */
112         if ( ( rc = srp->transport->connect ( srp ) ) != 0 ) {
113                 DBGC ( srp, "SRP %p could not open socket: %s\n",
114                        srp, strerror ( rc ) );
115                 goto err;
116         }
117         srp->state |= SRP_STATE_SOCKET_OPEN;
118
119         /* Allocate I/O buffer */
120         iobuf = xfer_alloc_iob ( &srp->socket, sizeof ( *login_req ) );
121         if ( ! iobuf ) {
122                 rc = -ENOMEM;
123                 goto err;
124         }
125
126         /* Construct login request IU */
127         login_req = iob_put ( iobuf, sizeof ( *login_req ) );
128         memset ( login_req, 0, sizeof ( *login_req ) );
129         login_req->type = SRP_LOGIN_REQ;
130         login_req->tag.dwords[1] = htonl ( ++srp_tag );
131         login_req->max_i_t_iu_len = htonl ( SRP_MAX_I_T_IU_LEN );
132         login_req->required_buffer_formats = SRP_LOGIN_REQ_FMT_DDBD;
133         memcpy ( &login_req->port_ids, &srp->port_ids,
134                  sizeof ( login_req->port_ids ) );
135
136         DBGC2 ( srp, "SRP %p TX login request tag %08x%08x\n",
137                 srp, ntohl ( login_req->tag.dwords[0] ),
138                 ntohl ( login_req->tag.dwords[1] ) );
139         DBGC2_HDA ( srp, 0, iobuf->data, iob_len ( iobuf ) );
140
141         /* Send login request IU */
142         if ( ( rc = xfer_deliver_iob ( &srp->socket, iobuf ) ) != 0 ) {
143                 DBGC ( srp, "SRP %p could not send login request: %s\n",
144                        srp, strerror ( rc ) );
145                 goto err;
146         }
147
148         return;
149
150  err:
151         srp_fail ( srp, rc );
152 }
153
154 /**
155  * Handle SRP login response
156  *
157  * @v srp               SRP device
158  * @v iobuf             I/O buffer
159  * @ret rc              Return status code
160  */
161 static int srp_login_rsp ( struct srp_device *srp, struct io_buffer *iobuf ) {
162         struct srp_login_rsp *login_rsp = iobuf->data;
163         int rc;
164
165         DBGC2 ( srp, "SRP %p RX login response tag %08x%08x\n",
166                 srp, ntohl ( login_rsp->tag.dwords[0] ),
167                 ntohl ( login_rsp->tag.dwords[1] ) );
168
169         /* Sanity check */
170         if ( iob_len ( iobuf ) < sizeof ( *login_rsp ) ) {
171                 DBGC ( srp, "SRP %p RX login response too short (%zd bytes)\n",
172                        srp, iob_len ( iobuf ) );
173                 rc = -EINVAL;
174                 goto out;
175         }
176
177         DBGC ( srp, "SRP %p logged in\n", srp );
178
179         /* Mark as logged in */
180         srp->state |= SRP_STATE_LOGGED_IN;
181
182         /* Reset error counter */
183         srp->retry_count = 0;
184
185         /* Issue pending command */
186         srp_cmd ( srp );
187
188         rc = 0;
189  out:
190         free_iob ( iobuf );
191         return rc;
192 }
193
194 /**
195  * Handle SRP login rejection
196  *
197  * @v srp               SRP device
198  * @v iobuf             I/O buffer
199  * @ret rc              Return status code
200  */
201 static int srp_login_rej ( struct srp_device *srp, struct io_buffer *iobuf ) {
202         struct srp_login_rej *login_rej = iobuf->data;
203         int rc;
204
205         DBGC2 ( srp, "SRP %p RX login rejection tag %08x%08x\n",
206                 srp, ntohl ( login_rej->tag.dwords[0] ),
207                 ntohl ( login_rej->tag.dwords[1] ) );
208
209         /* Sanity check */
210         if ( iob_len ( iobuf ) < sizeof ( *login_rej ) ) {
211                 DBGC ( srp, "SRP %p RX login rejection too short (%zd "
212                        "bytes)\n", srp, iob_len ( iobuf ) );
213                 rc = -EINVAL;
214                 goto out;
215         }
216
217         /* Login rejection always indicates an error */
218         DBGC ( srp, "SRP %p login rejected (reason %08x)\n",
219                srp, ntohl ( login_rej->reason ) );
220         rc = -EPERM;
221
222  out:
223         free_iob ( iobuf );
224         return rc;
225 }
226
227 /**
228  * Transmit SRP SCSI command
229  *
230  * @v srp               SRP device
231  */
232 static void srp_cmd ( struct srp_device *srp ) {
233         struct io_buffer *iobuf;
234         struct srp_cmd *cmd;
235         struct srp_memory_descriptor *data_out;
236         struct srp_memory_descriptor *data_in;
237         int rc;
238
239         assert ( srp->state & SRP_STATE_LOGGED_IN );
240
241         /* Allocate I/O buffer */
242         iobuf = xfer_alloc_iob ( &srp->socket, SRP_MAX_I_T_IU_LEN );
243         if ( ! iobuf ) {
244                 rc = -ENOMEM;
245                 goto err;
246         }
247
248         /* Construct base portion */
249         cmd = iob_put ( iobuf, sizeof ( *cmd ) );
250         memset ( cmd, 0, sizeof ( *cmd ) );
251         cmd->type = SRP_CMD;
252         cmd->tag.dwords[1] = htonl ( ++srp_tag );
253         cmd->lun = srp->lun;
254         memcpy ( &cmd->cdb, &srp->command->cdb, sizeof ( cmd->cdb ) );
255
256         /* Construct data-out descriptor, if present */
257         if ( srp->command->data_out ) {
258                 cmd->data_buffer_formats |= SRP_CMD_DO_FMT_DIRECT;
259                 data_out = iob_put ( iobuf, sizeof ( *data_out ) );
260                 data_out->address =
261                     cpu_to_be64 ( user_to_phys ( srp->command->data_out, 0 ) );
262                 data_out->handle = ntohl ( srp->memory_handle );
263                 data_out->len = ntohl ( srp->command->data_out_len );
264         }
265
266         /* Construct data-in descriptor, if present */
267         if ( srp->command->data_in ) {
268                 cmd->data_buffer_formats |= SRP_CMD_DI_FMT_DIRECT;
269                 data_in = iob_put ( iobuf, sizeof ( *data_in ) );
270                 data_in->address =
271                      cpu_to_be64 ( user_to_phys ( srp->command->data_in, 0 ) );
272                 data_in->handle = ntohl ( srp->memory_handle );
273                 data_in->len = ntohl ( srp->command->data_in_len );
274         }
275
276         DBGC2 ( srp, "SRP %p TX SCSI command tag %08x%08x\n", srp,
277                 ntohl ( cmd->tag.dwords[0] ), ntohl ( cmd->tag.dwords[1] ) );
278         DBGC2_HDA ( srp, 0, iobuf->data, iob_len ( iobuf ) );
279
280         /* Send IU */
281         if ( ( rc = xfer_deliver_iob ( &srp->socket, iobuf ) ) != 0 ) {
282                 DBGC ( srp, "SRP %p could not send command: %s\n",
283                        srp, strerror ( rc ) );
284                 goto err;
285         }
286
287         return;
288
289  err:
290         srp_fail ( srp, rc );
291 }
292
293 /**
294  * Handle SRP SCSI response
295  *
296  * @v srp               SRP device
297  * @v iobuf             I/O buffer
298  * @ret rc              Returns status code
299  */
300 static int srp_rsp ( struct srp_device *srp, struct io_buffer *iobuf ) {
301         struct srp_rsp *rsp = iobuf->data;
302         int rc;
303
304         DBGC2 ( srp, "SRP %p RX SCSI response tag %08x%08x\n", srp,
305                 ntohl ( rsp->tag.dwords[0] ), ntohl ( rsp->tag.dwords[1] ) );
306
307         /* Sanity check */
308         if ( iob_len ( iobuf ) < sizeof ( *rsp ) ) {
309                 DBGC ( srp, "SRP %p RX SCSI response too short (%zd bytes)\n",
310                        srp, iob_len ( iobuf ) );
311                 rc = -EINVAL;
312                 goto out;
313         }
314
315         /* Report SCSI errors */
316         if ( rsp->status != 0 ) {
317                 DBGC ( srp, "SRP %p response status %02x\n",
318                        srp, rsp->status );
319                 if ( srp_rsp_sense_data ( rsp ) ) {
320                         DBGC ( srp, "SRP %p sense data:\n", srp );
321                         DBGC_HDA ( srp, 0, srp_rsp_sense_data ( rsp ),
322                                    srp_rsp_sense_data_len ( rsp ) );
323                 }
324         }
325         if ( rsp->valid & ( SRP_RSP_VALID_DOUNDER | SRP_RSP_VALID_DOOVER ) ) {
326                 DBGC ( srp, "SRP %p response data-out %srun by %#x bytes\n",
327                        srp, ( ( rsp->valid & SRP_RSP_VALID_DOUNDER )
328                               ? "under" : "over" ),
329                        ntohl ( rsp->data_out_residual_count ) );
330         }
331         if ( rsp->valid & ( SRP_RSP_VALID_DIUNDER | SRP_RSP_VALID_DIOVER ) ) {
332                 DBGC ( srp, "SRP %p response data-in %srun by %#x bytes\n",
333                        srp, ( ( rsp->valid & SRP_RSP_VALID_DIUNDER )
334                               ? "under" : "over" ),
335                        ntohl ( rsp->data_in_residual_count ) );
336         }
337         srp->command->status = rsp->status;
338
339         /* Mark SCSI command as complete */
340         srp_scsi_done ( srp, 0 );
341
342         rc = 0;
343  out:
344         free_iob ( iobuf );
345         return rc;
346 }
347
348 /**
349  * Handle SRP unrecognised response
350  *
351  * @v srp               SRP device
352  * @v iobuf             I/O buffer
353  * @ret rc              Returns status code
354  */
355 static int srp_unrecognised ( struct srp_device *srp,
356                               struct io_buffer *iobuf ) {
357         struct srp_common *common = iobuf->data;
358
359         DBGC ( srp, "SRP %p RX unrecognised IU tag %08x%08x type %02x\n",
360                srp, ntohl ( common->tag.dwords[0] ),
361                ntohl ( common->tag.dwords[1] ), common->type );
362
363         free_iob ( iobuf );
364         return -ENOTSUP;
365 }
366
367 /**
368  * Receive data from underlying socket
369  *
370  * @v xfer              Data transfer interface
371  * @v iobuf             Datagram I/O buffer
372  * @v meta              Data transfer metadata
373  * @ret rc              Return status code
374  */
375 static int srp_xfer_deliver_iob ( struct xfer_interface *xfer,
376                                   struct io_buffer *iobuf,
377                                   struct xfer_metadata *meta __unused ) {
378         struct srp_device *srp =
379                 container_of ( xfer, struct srp_device, socket );
380         struct srp_common *common = iobuf->data;
381         int ( * type ) ( struct srp_device *srp, struct io_buffer *iobuf );
382         int rc;
383
384         /* Determine IU type */
385         switch ( common->type ) {
386         case SRP_LOGIN_RSP:
387                 type = srp_login_rsp;
388                 break;
389         case SRP_LOGIN_REJ:
390                 type = srp_login_rej;
391                 break;
392         case SRP_RSP:
393                 type = srp_rsp;
394                 break;
395         default:
396                 type = srp_unrecognised;
397                 break;
398         }
399
400         /* Handle IU */
401         if ( ( rc = type ( srp, iobuf ) ) != 0 )
402                 goto err;
403
404         return 0;
405
406  err:
407         srp_fail ( srp, rc );
408         return rc;
409 }
410
411 /**
412  * Underlying socket closed
413  *
414  * @v xfer              Data transfer interface
415  * @v rc                Reason for close
416  */
417 static void srp_xfer_close ( struct xfer_interface *xfer, int rc ) {
418         struct srp_device *srp =
419                 container_of ( xfer, struct srp_device, socket );
420
421         DBGC ( srp, "SRP %p socket closed: %s\n", srp, strerror ( rc ) );
422
423         srp_fail ( srp, rc );
424 }
425
426 /** SRP data transfer interface operations */
427 static struct xfer_interface_operations srp_xfer_operations = {
428         .close          = srp_xfer_close,
429         .vredirect      = ignore_xfer_vredirect,
430         .window         = unlimited_xfer_window,
431         .alloc_iob      = default_xfer_alloc_iob,
432         .deliver_iob    = srp_xfer_deliver_iob,
433         .deliver_raw    = xfer_deliver_as_iob,
434 };
435
436 /**
437  * Issue SCSI command via SRP
438  *
439  * @v scsi              SCSI device
440  * @v command           SCSI command
441  * @ret rc              Return status code
442  */
443 static int srp_command ( struct scsi_device *scsi,
444                          struct scsi_command *command ) {
445         struct srp_device *srp =
446                 container_of ( scsi->backend, struct srp_device, refcnt );
447
448         /* Return instant failure, if we have already aborted the session */
449         if ( srp->instant_rc )
450                 return srp->instant_rc;
451
452         /* Store SCSI command */
453         if ( srp->command ) {
454                 DBGC ( srp, "SRP %p cannot handle concurrent SCSI commands\n",
455                        srp );
456                 return -EBUSY;
457         }
458         srp->command = command;
459
460         /* Log in or issue command as appropriate */
461         if ( ! ( srp->state & SRP_STATE_SOCKET_OPEN ) ) {
462                 srp_login ( srp );
463         } else if ( srp->state & SRP_STATE_LOGGED_IN ) {
464                 srp_cmd ( srp );
465         } else {
466                 /* Still waiting for login; do nothing */
467         }
468
469         return 0;
470 }
471
472 /**
473  * Attach SRP device
474  *
475  * @v scsi              SCSI device
476  * @v root_path         Root path
477  */
478 int srp_attach ( struct scsi_device *scsi, const char *root_path ) {
479         struct srp_transport_type *transport;
480         struct srp_device *srp;
481         int rc;
482
483         /* Hard-code an IB SRP back-end for now */
484         transport = &ib_srp_transport;
485
486         /* Allocate and initialise structure */
487         srp = zalloc ( sizeof ( *srp ) + transport->priv_len );
488         if ( ! srp ) {
489                 rc = -ENOMEM;
490                 goto err_alloc;
491         }
492         xfer_init ( &srp->socket, &srp_xfer_operations, &srp->refcnt );
493         srp->transport = transport;
494         DBGC ( srp, "SRP %p using %s\n", srp, root_path );
495
496         /* Parse root path */
497         if ( ( rc = transport->parse_root_path ( srp, root_path ) ) != 0 ) {
498                 DBGC ( srp, "SRP %p could not parse root path: %s\n",
499                        srp, strerror ( rc ) );
500                 goto err_parse_root_path;
501         }
502
503         /* Attach parent interface, mortalise self, and return */
504         scsi->backend = ref_get ( &srp->refcnt );
505         scsi->command = srp_command;
506         ref_put ( &srp->refcnt );
507         return 0;
508
509  err_parse_root_path:
510         ref_put ( &srp->refcnt );
511  err_alloc:
512         return rc;
513 }
514
515 /**
516  * Detach SRP device
517  *
518  * @v scsi              SCSI device
519  */
520 void srp_detach ( struct scsi_device *scsi ) {
521         struct srp_device *srp =
522                 container_of ( scsi->backend, struct srp_device, refcnt );
523
524         /* Close socket */
525         xfer_nullify ( &srp->socket );
526         xfer_close ( &srp->socket, 0 );
527         scsi->command = scsi_detached_command;
528         ref_put ( scsi->backend );
529         scsi->backend = NULL;
530 }