Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / 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 <ipxe/scsi.h>
37 #include <ipxe/xfer.h>
38 #include <ipxe/features.h>
39 #include <ipxe/srp.h>
40
41 /**
42  * @file
43  *
44  * SCSI RDMA Protocol
45  *
46  */
47
48 FEATURE ( FEATURE_PROTOCOL, "SRP", DHCP_EB_FEATURE_SRP, 1 );
49
50 /** Maximum length of any initiator-to-target IU that we will send
51  *
52  * The longest IU is a SRP_CMD with no additional CDB and two direct
53  * data buffer descriptors, which comes to 80 bytes.
54  */
55 #define SRP_MAX_I_T_IU_LEN 80
56
57 /* Error numbers generated by SRP login rejection */
58 #define EINFO_SRP_LOGIN_REJ( reason, desc )                                   \
59         __einfo_uniqify ( EINFO_EPERM, ( (reason) & 0x0f ), desc )
60 #define EPERM_UNKNOWN                                                         \
61         __einfo_error ( EINFO_EPERM_UNKNOWN )
62 #define EINFO_EPERM_UNKNOWN EINFO_SRP_LOGIN_REJ (                             \
63         SRP_LOGIN_REJ_REASON_UNKNOWN,                                         \
64         "Unable to establish RDMA channel, no reason specified" )
65 #define EPERM_INSUFFICIENT_RESOURCES                                          \
66         __einfo_error ( EINFO_EPERM_INSUFFICIENT_RESOURCES )
67 #define EINFO_EPERM_INSUFFICIENT_RESOURCES EINFO_SRP_LOGIN_REJ (              \
68         SRP_LOGIN_REJ_REASON_INSUFFICIENT_RESOURCES,                          \
69         "Insufficient RDMA channel resources" )
70 #define EPERM_BAD_MAX_I_T_IU_LEN                                              \
71         __einfo_error ( EINFO_EPERM_BAD_MAX_I_T_IU_LEN )
72 #define EINFO_EPERM_BAD_MAX_I_T_IU_LEN EINFO_SRP_LOGIN_REJ (                  \
73         SRP_LOGIN_REJ_REASON_BAD_MAX_I_T_IU_LEN,                              \
74         "Requested maximum initiator to target IU length value too large" )
75 #define EPERM_CANNOT_ASSOCIATE                                                \
76         __einfo_error ( EINFO_EPERM_CANNOT_ASSOCIATE )
77 #define EINFO_EPERM_CANNOT_ASSOCIATE EINFO_SRP_LOGIN_REJ (                    \
78         SRP_LOGIN_REJ_REASON_CANNOT_ASSOCIATE,                                \
79         "Unable to associate RDMA channel with specified I_T nexus" )
80 #define EPERM_UNSUPPORTED_BUFFER_FORMAT                                       \
81         __einfo_error ( EINFO_EPERM_UNSUPPORTED_BUFFER_FORMAT )
82 #define EINFO_EPERM_UNSUPPORTED_BUFFER_FORMAT EINFO_SRP_LOGIN_REJ (           \
83         SRP_LOGIN_REJ_REASON_UNSUPPORTED_BUFFER_FORMAT,                       \
84         "One or more requested data buffer descriptor formats not supported" )
85 #define EPERM_NO_MULTIPLE_CHANNELS                                            \
86         __einfo_error ( EINFO_EPERM_NO_MULTIPLE_CHANNELS )
87 #define EINFO_EPERM_NO_MULTIPLE_CHANNELS EINFO_SRP_LOGIN_REJ (                \
88         SRP_LOGIN_REJ_REASON_NO_MULTIPLE_CHANNELS,                            \
89         "SRP target does not support multiple RDMA channels per I_T nexus" )
90 #define EPERM_NO_MORE_CHANNELS                                                \
91         __einfo_error ( EINFO_EPERM_NO_MORE_CHANNELS )
92 #define EINFO_EPERM_NO_MORE_CHANNELS EINFO_SRP_LOGIN_REJ (                    \
93         SRP_LOGIN_REJ_REASON_NO_MORE_CHANNELS,                                \
94         "RDMA channel limit reached for this initiator" )
95 #define EPERM_LOGIN_REJ( reason_nibble )                                      \
96         EUNIQ ( EINFO_EPERM, (reason_nibble), EPERM_UNKNOWN,                  \
97                 EPERM_INSUFFICIENT_RESOURCES, EPERM_BAD_MAX_I_T_IU_LEN,       \
98                 EPERM_CANNOT_ASSOCIATE, EPERM_UNSUPPORTED_BUFFER_FORMAT,      \
99                 EPERM_NO_MULTIPLE_CHANNELS, EPERM_NO_MORE_CHANNELS )
100
101 /** An SRP device */
102 struct srp_device {
103         /** Reference count */
104         struct refcnt refcnt;
105
106         /** SCSI command issuing interface */
107         struct interface scsi;
108         /** Underlying data transfer interface */
109         struct interface socket;
110
111         /** RDMA memory handle */
112         uint32_t memory_handle;
113         /** Login completed successfully */
114         int logged_in;
115
116         /** Initiator port ID (for boot firmware table) */
117         union srp_port_id initiator;
118         /** Target port ID (for boot firmware table) */
119         union srp_port_id target;
120         /** SCSI LUN (for boot firmware table) */
121         struct scsi_lun lun;
122
123         /** List of active commands */
124         struct list_head commands;
125 };
126
127 /** An SRP command */
128 struct srp_command {
129         /** Reference count */
130         struct refcnt refcnt;
131         /** SRP device */
132         struct srp_device *srpdev;
133         /** List of active commands */
134         struct list_head list;
135
136         /** SCSI command interface */
137         struct interface scsi;
138         /** Command tag */
139         uint32_t tag;
140 };
141
142 /**
143  * Get reference to SRP device
144  *
145  * @v srpdev            SRP device
146  * @ret srpdev          SRP device
147  */
148 static inline __attribute__ (( always_inline )) struct srp_device *
149 srpdev_get ( struct srp_device *srpdev ) {
150         ref_get ( &srpdev->refcnt );
151         return srpdev;
152 }
153
154 /**
155  * Drop reference to SRP device
156  *
157  * @v srpdev            SRP device
158  */
159 static inline __attribute__ (( always_inline )) void
160 srpdev_put ( struct srp_device *srpdev ) {
161         ref_put ( &srpdev->refcnt );
162 }
163
164 /**
165  * Get reference to SRP command
166  *
167  * @v srpcmd            SRP command
168  * @ret srpcmd          SRP command
169  */
170 static inline __attribute__ (( always_inline )) struct srp_command *
171 srpcmd_get ( struct srp_command *srpcmd ) {
172         ref_get ( &srpcmd->refcnt );
173         return srpcmd;
174 }
175
176 /**
177  * Drop reference to SRP command
178  *
179  * @v srpcmd            SRP command
180  */
181 static inline __attribute__ (( always_inline )) void
182 srpcmd_put ( struct srp_command *srpcmd ) {
183         ref_put ( &srpcmd->refcnt );
184 }
185
186 /**
187  * Free SRP command
188  *
189  * @v refcnt            Reference count
190  */
191 static void srpcmd_free ( struct refcnt *refcnt ) {
192         struct srp_command *srpcmd =
193                 container_of ( refcnt, struct srp_command, refcnt );
194
195         assert ( list_empty ( &srpcmd->list ) );
196
197         srpdev_put ( srpcmd->srpdev );
198         free ( srpcmd );
199 }
200
201 /**
202  * Close SRP command
203  *
204  * @v srpcmd            SRP command
205  * @v rc                Reason for close
206  */
207 static void srpcmd_close ( struct srp_command *srpcmd, int rc ) {
208         struct srp_device *srpdev = srpcmd->srpdev;
209
210         if ( rc != 0 ) {
211                 DBGC ( srpdev, "SRP %p tag %08x closed: %s\n",
212                        srpdev, srpcmd->tag, strerror ( rc ) );
213         }
214
215         /* Remove from list of commands */
216         if ( ! list_empty ( &srpcmd->list ) ) {
217                 list_del ( &srpcmd->list );
218                 INIT_LIST_HEAD ( &srpcmd->list );
219                 srpcmd_put ( srpcmd );
220         }
221
222         /* Shut down interfaces */
223         intf_shutdown ( &srpcmd->scsi, rc );
224 }
225
226 /**
227  * Close SRP device
228  *
229  * @v srpdev            SRP device
230  * @v rc                Reason for close
231  */
232 static void srpdev_close ( struct srp_device *srpdev, int rc ) {
233         struct srp_command *srpcmd;
234         struct srp_command *tmp;
235
236         if ( rc != 0 ) {
237                 DBGC ( srpdev, "SRP %p closed: %s\n",
238                        srpdev, strerror ( rc ) );
239         }
240
241         /* Shut down interfaces */
242         intf_shutdown ( &srpdev->socket, rc );
243         intf_shutdown ( &srpdev->scsi, rc );
244
245         /* Shut down any active commands */
246         list_for_each_entry_safe ( srpcmd, tmp, &srpdev->commands, list ) {
247                 srpcmd_get ( srpcmd );
248                 srpcmd_close ( srpcmd, rc );
249                 srpcmd_put ( srpcmd );
250         }
251 }
252
253 /**
254  * Identify SRP command by tag
255  *
256  * @v srpdev            SRP device
257  * @v tag               Command tag
258  * @ret srpcmd          SRP command, or NULL
259  */
260 static struct srp_command * srp_find_tag ( struct srp_device *srpdev,
261                                            uint32_t tag ) {
262         struct srp_command *srpcmd;
263
264         list_for_each_entry ( srpcmd, &srpdev->commands, list ) {
265                 if ( srpcmd->tag == tag )
266                         return srpcmd;
267         }
268         return NULL;
269 }
270
271 /**
272  * Choose an SRP command tag
273  *
274  * @v srpdev            SRP device
275  * @ret tag             New tag, or negative error
276  */
277 static int srp_new_tag ( struct srp_device *srpdev ) {
278         static uint16_t tag_idx;
279         unsigned int i;
280
281         for ( i = 0 ; i < 65536 ; i++ ) {
282                 tag_idx++;
283                 if ( srp_find_tag ( srpdev, tag_idx ) == NULL )
284                         return tag_idx;
285         }
286         return -EADDRINUSE;
287 }
288
289 /**
290  * Transmit SRP login request
291  *
292  * @v srpdev            SRP device
293  * @v initiator         Initiator port ID
294  * @v target            Target port ID
295  * @v tag               Command tag
296  * @ret rc              Return status code
297  */
298 static int srp_login ( struct srp_device *srpdev, union srp_port_id *initiator,
299                        union srp_port_id *target, uint32_t tag ) {
300         struct io_buffer *iobuf;
301         struct srp_login_req *login_req;
302         int rc;
303
304         /* Allocate I/O buffer */
305         iobuf = xfer_alloc_iob ( &srpdev->socket, sizeof ( *login_req ) );
306         if ( ! iobuf )
307                 return -ENOMEM;
308
309         /* Construct login request IU */
310         login_req = iob_put ( iobuf, sizeof ( *login_req ) );
311         memset ( login_req, 0, sizeof ( *login_req ) );
312         login_req->type = SRP_LOGIN_REQ;
313         login_req->tag.dwords[0] = htonl ( SRP_TAG_MAGIC );
314         login_req->tag.dwords[1] = htonl ( tag );
315         login_req->max_i_t_iu_len = htonl ( SRP_MAX_I_T_IU_LEN );
316         login_req->required_buffer_formats = SRP_LOGIN_REQ_FMT_DDBD;
317         memcpy ( &login_req->initiator, initiator,
318                  sizeof ( login_req->initiator ) );
319         memcpy ( &login_req->target, target, sizeof ( login_req->target ) );
320
321         DBGC ( srpdev, "SRP %p tag %08x LOGIN_REQ:\n", srpdev, tag );
322         DBGC_HDA ( srpdev, 0, iobuf->data, iob_len ( iobuf ) );
323
324         /* Send login request IU */
325         if ( ( rc = xfer_deliver_iob ( &srpdev->socket, iobuf ) ) != 0 ) {
326                 DBGC ( srpdev, "SRP %p tag %08x could not send LOGIN_REQ: "
327                        "%s\n", srpdev, tag, strerror ( rc ) );
328                 return rc;
329         }
330
331         return 0;
332 }
333
334 /**
335  * Receive SRP login response
336  *
337  * @v srpdev            SRP device
338  * @v data              SRP IU
339  * @v len               Length of SRP IU
340  * @ret rc              Return status code
341  */
342 static int srp_login_rsp ( struct srp_device *srpdev,
343                            const void *data, size_t len ) {
344         const struct srp_login_rsp *login_rsp = data;
345
346         /* Sanity check */
347         if ( len < sizeof ( *login_rsp ) ) {
348                 DBGC ( srpdev, "SRP %p LOGIN_RSP too short (%zd bytes)\n",
349                        srpdev, len );
350                 return -EINVAL;
351         }
352         DBGC ( srpdev, "SRP %p tag %08x LOGIN_RSP:\n",
353                srpdev, ntohl ( login_rsp->tag.dwords[1] ) );
354         DBGC_HDA ( srpdev, 0, data, len );
355
356         /* Mark as logged in */
357         srpdev->logged_in = 1;
358         DBGC ( srpdev, "SRP %p logged in\n", srpdev );
359
360         /* Notify of window change */
361         xfer_window_changed ( &srpdev->scsi );
362
363         return 0;
364 }
365
366 /**
367  * Receive SRP login rejection
368  *
369  * @v srpdev            SRP device
370  * @v data              SRP IU
371  * @v len               Length of SRP IU
372  * @ret rc              Return status code
373  */
374 static int srp_login_rej ( struct srp_device *srpdev,
375                            const void *data, size_t len ) {
376         const struct srp_login_rej *login_rej = data;
377         uint32_t reason;
378
379         /* Sanity check */
380         if ( len < sizeof ( *login_rej ) ) {
381                 DBGC ( srpdev, "SRP %p LOGIN_REJ too short (%zd bytes)\n",
382                        srpdev, len );
383                 return -EINVAL;
384         }
385         reason = ntohl ( login_rej->reason );
386         DBGC ( srpdev, "SRP %p tag %08x LOGIN_REJ reason %08x:\n",
387                srpdev, ntohl ( login_rej->tag.dwords[1] ), reason );
388         DBGC_HDA ( srpdev, 0, data, len );
389
390         /* Login rejection always indicates an error */
391         return ( SRP_LOGIN_REJ_REASON_DEFINED ( reason ) ?
392                  -EPERM_LOGIN_REJ ( reason ) : -EACCES );
393 }
394
395 /**
396  * Transmit SRP SCSI command
397  *
398  * @v srpdev            SRP device
399  * @v command           SCSI command
400  * @v tag               Command tag
401  * @ret rc              Return status code
402  */
403 static int srp_cmd ( struct srp_device *srpdev,
404                      struct scsi_cmd *command,
405                      uint32_t tag ) {
406         struct io_buffer *iobuf;
407         struct srp_cmd *cmd;
408         struct srp_memory_descriptor *data_out;
409         struct srp_memory_descriptor *data_in;
410         int rc;
411
412         /* Sanity check */
413         if ( ! srpdev->logged_in ) {
414                 DBGC ( srpdev, "SRP %p tag %08x cannot send CMD before "
415                        "login completes\n", srpdev, tag );
416                 return -EBUSY;
417         }
418
419         /* Allocate I/O buffer */
420         iobuf = xfer_alloc_iob ( &srpdev->socket, SRP_MAX_I_T_IU_LEN );
421         if ( ! iobuf )
422                 return -ENOMEM;
423
424         /* Construct base portion */
425         cmd = iob_put ( iobuf, sizeof ( *cmd ) );
426         memset ( cmd, 0, sizeof ( *cmd ) );
427         cmd->type = SRP_CMD;
428         cmd->tag.dwords[0] = htonl ( SRP_TAG_MAGIC );
429         cmd->tag.dwords[1] = htonl ( tag );
430         memcpy ( &cmd->lun, &command->lun, sizeof ( cmd->lun ) );
431         memcpy ( &cmd->cdb, &command->cdb, sizeof ( cmd->cdb ) );
432
433         /* Construct data-out descriptor, if present */
434         if ( command->data_out ) {
435                 cmd->data_buffer_formats |= SRP_CMD_DO_FMT_DIRECT;
436                 data_out = iob_put ( iobuf, sizeof ( *data_out ) );
437                 data_out->address =
438                     cpu_to_be64 ( user_to_phys ( command->data_out, 0 ) );
439                 data_out->handle = ntohl ( srpdev->memory_handle );
440                 data_out->len = ntohl ( command->data_out_len );
441         }
442
443         /* Construct data-in descriptor, if present */
444         if ( command->data_in ) {
445                 cmd->data_buffer_formats |= SRP_CMD_DI_FMT_DIRECT;
446                 data_in = iob_put ( iobuf, sizeof ( *data_in ) );
447                 data_in->address =
448                      cpu_to_be64 ( user_to_phys ( command->data_in, 0 ) );
449                 data_in->handle = ntohl ( srpdev->memory_handle );
450                 data_in->len = ntohl ( command->data_in_len );
451         }
452
453         DBGC2 ( srpdev, "SRP %p tag %08x CMD " SCSI_CDB_FORMAT "\n",
454                 srpdev, tag, SCSI_CDB_DATA ( cmd->cdb ) );
455
456         /* Send IU */
457         if ( ( rc = xfer_deliver_iob ( &srpdev->socket, iobuf ) ) != 0 ) {
458                 DBGC ( srpdev, "SRP %p tag %08x could not send CMD: %s\n",
459                        srpdev, tag, strerror ( rc ) );
460                 return rc;
461         }
462
463         return 0;
464 }
465
466 /**
467  * Receive SRP SCSI response
468  *
469  * @v srpdev            SRP device
470  * @v data              SRP IU
471  * @v len               Length of SRP IU
472  * @ret rc              Returns status code
473  */
474 static int srp_rsp ( struct srp_device *srpdev,
475                      const void *data, size_t len ) {
476         const struct srp_rsp *rsp = data;
477         struct srp_command *srpcmd;
478         struct scsi_rsp response;
479         ssize_t data_out_residual_count;
480         ssize_t data_in_residual_count;
481
482         /* Sanity check */
483         if ( ( len < sizeof ( *rsp ) ) ||
484              ( len < ( sizeof ( *rsp ) +
485                        srp_rsp_response_data_len ( rsp ) +
486                        srp_rsp_sense_data_len ( rsp ) ) ) ) {
487                 DBGC ( srpdev, "SRP %p RSP too short (%zd bytes)\n",
488                        srpdev, len );
489                 return -EINVAL;
490         }
491         DBGC2 ( srpdev, "SRP %p tag %08x RSP stat %02x dores %08x dires "
492                 "%08x valid %02x%s%s%s%s%s%s\n",
493                 srpdev, ntohl ( rsp->tag.dwords[1] ), rsp->status,
494                 ntohl ( rsp->data_out_residual_count ),
495                 ntohl ( rsp->data_in_residual_count ), rsp->valid,
496                 ( ( rsp->valid & SRP_RSP_VALID_DIUNDER ) ? " diunder" : "" ),
497                 ( ( rsp->valid & SRP_RSP_VALID_DIOVER ) ? " diover" : "" ),
498                 ( ( rsp->valid & SRP_RSP_VALID_DOUNDER ) ? " dounder" : "" ),
499                 ( ( rsp->valid & SRP_RSP_VALID_DOOVER ) ? " doover" : "" ),
500                 ( ( rsp->valid & SRP_RSP_VALID_SNSVALID ) ? " sns" : "" ),
501                 ( ( rsp->valid & SRP_RSP_VALID_RSPVALID ) ? " rsp" : "" ) );
502
503         /* Identify command by tag */
504         srpcmd = srp_find_tag ( srpdev, ntohl ( rsp->tag.dwords[1] ) );
505         if ( ! srpcmd ) {
506                 DBGC ( srpdev, "SRP %p tag %08x unrecognised RSP\n",
507                        srpdev, ntohl ( rsp->tag.dwords[1] ) );
508                 return -ENOENT;
509         }
510
511         /* Hold command reference for remainder of function */
512         srpcmd_get ( srpcmd );
513
514         /* Build SCSI response */
515         memset ( &response, 0, sizeof ( response ) );
516         response.status = rsp->status;
517         data_out_residual_count = ntohl ( rsp->data_out_residual_count );
518         data_in_residual_count = ntohl ( rsp->data_in_residual_count );
519         if ( rsp->valid & SRP_RSP_VALID_DOOVER ) {
520                 response.overrun = data_out_residual_count;
521         } else if ( rsp->valid & SRP_RSP_VALID_DOUNDER ) {
522                 response.overrun = -(data_out_residual_count);
523         } else if ( rsp->valid & SRP_RSP_VALID_DIOVER ) {
524                 response.overrun = data_in_residual_count;
525         } else if ( rsp->valid & SRP_RSP_VALID_DIUNDER ) {
526                 response.overrun = -(data_in_residual_count);
527         }
528         scsi_parse_sense ( srp_rsp_sense_data ( rsp ),
529                            srp_rsp_sense_data_len ( rsp ), &response.sense );
530
531         /* Report SCSI response */
532         scsi_response ( &srpcmd->scsi, &response );
533
534         /* Close SCSI command */
535         srpcmd_close ( srpcmd, 0 );
536
537         /* Drop temporary command reference */
538         srpcmd_put ( srpcmd );
539
540         return 0;
541 }
542
543 /**
544  * Receive SRP unrecognised response IU
545  *
546  * @v srpdev            SRP device
547  * @v data              SRP IU
548  * @v len               Length of SRP IU
549  * @ret rc              Returns status code
550  */
551 static int srp_unrecognised ( struct srp_device *srpdev,
552                               const void *data, size_t len ) {
553         const struct srp_common *common = data;
554
555         DBGC ( srpdev, "SRP %p tag %08x unrecognised IU type %02x:\n",
556                srpdev, ntohl ( common->tag.dwords[1] ), common->type );
557         DBGC_HDA ( srpdev, 0, data, len );
558
559         return -ENOTSUP;
560 }
561
562 /** SRP command SCSI interface operations */
563 static struct interface_operation srpcmd_scsi_op[] = {
564         INTF_OP ( intf_close, struct srp_command *, srpcmd_close ),
565 };
566
567 /** SRP command SCSI interface descriptor */
568 static struct interface_descriptor srpcmd_scsi_desc =
569         INTF_DESC ( struct srp_command, scsi, srpcmd_scsi_op );
570
571 /**
572  * Issue SRP SCSI command
573  *
574  * @v srpdev            SRP device
575  * @v parent            Parent interface
576  * @v command           SCSI command
577  * @ret tag             Command tag, or negative error
578  */
579 static int srpdev_scsi_command ( struct srp_device *srpdev,
580                                  struct interface *parent,
581                                  struct scsi_cmd *command ) {
582         struct srp_command *srpcmd;
583         int tag;
584         int rc;
585
586         /* Allocate command tag */
587         tag = srp_new_tag ( srpdev );
588         if ( tag < 0 ) {
589                 rc = tag;
590                 goto err_tag;
591         }
592
593         /* Allocate and initialise structure */
594         srpcmd = zalloc ( sizeof ( *srpcmd ) );
595         if ( ! srpcmd ) {
596                 rc = -ENOMEM;
597                 goto err_zalloc;
598         }
599         ref_init ( &srpcmd->refcnt, srpcmd_free );
600         intf_init ( &srpcmd->scsi, &srpcmd_scsi_desc, &srpcmd->refcnt );
601         srpcmd->srpdev = srpdev_get ( srpdev );
602         list_add ( &srpcmd->list, &srpdev->commands );
603         srpcmd->tag = tag;
604
605         /* Send command IU */
606         if ( ( rc = srp_cmd ( srpdev, command, srpcmd->tag ) ) != 0 )
607                 goto err_cmd;
608
609         /* Attach to parent interface, leave reference with command
610          * list, and return.
611          */
612         intf_plug_plug ( &srpcmd->scsi, parent );
613         return srpcmd->tag;
614
615  err_cmd:
616         srpcmd_close ( srpcmd, rc );
617  err_zalloc:
618  err_tag:
619         return rc;
620 }
621
622 /**
623  * Receive data from SRP socket
624  *
625  * @v srpdev            SRP device
626  * @v iobuf             Datagram I/O buffer
627  * @v meta              Data transfer metadata
628  * @ret rc              Return status code
629  */
630 static int srpdev_deliver ( struct srp_device *srpdev,
631                             struct io_buffer *iobuf,
632                             struct xfer_metadata *meta __unused ) {
633         struct srp_common *common = iobuf->data;
634         int ( * type ) ( struct srp_device *srp, const void *data, size_t len );
635         int rc;
636
637         /* Sanity check */
638         if ( iob_len ( iobuf ) < sizeof ( *common ) ) {
639                 DBGC ( srpdev, "SRP %p IU too short (%zd bytes)\n",
640                        srpdev, iob_len ( iobuf ) );
641                 rc = -EINVAL;
642                 goto err;
643         }
644
645         /* Determine IU type */
646         switch ( common->type ) {
647         case SRP_LOGIN_RSP:
648                 type = srp_login_rsp;
649                 break;
650         case SRP_LOGIN_REJ:
651                 type = srp_login_rej;
652                 break;
653         case SRP_RSP:
654                 type = srp_rsp;
655                 break;
656         default:
657                 type = srp_unrecognised;
658                 break;
659         }
660
661         /* Handle IU */
662         if ( ( rc = type ( srpdev, iobuf->data, iob_len ( iobuf ) ) ) != 0 )
663                 goto err;
664
665         free_iob ( iobuf );
666         return 0;
667
668  err:
669         DBGC ( srpdev, "SRP %p closing due to received IU (%s):\n",
670                srpdev, strerror ( rc ) );
671         DBGC_HDA ( srpdev, 0, iobuf->data, iob_len ( iobuf ) );
672         free_iob ( iobuf );
673         srpdev_close ( srpdev, rc );
674         return rc;
675 }
676
677 /**
678  * Check SRP device flow-control window
679  *
680  * @v srpdev            SRP device
681  * @ret len             Length of window
682  */
683 static size_t srpdev_window ( struct srp_device *srpdev ) {
684         return ( srpdev->logged_in ? ~( ( size_t ) 0 ) : 0 );
685 }
686
687 /**
688  * A (transport-independent) sBFT created by iPXE
689  */
690 struct ipxe_sbft {
691         /** The table header */
692         struct sbft_table table;
693         /** The SCSI subtable */
694         struct sbft_scsi_subtable scsi;
695         /** The SRP subtable */
696         struct sbft_srp_subtable srp;
697 } __attribute__ (( packed, aligned ( 16 ) ));
698
699 /**
700  * Describe SRP device in an ACPI table
701  *
702  * @v srpdev            SRP device
703  * @v acpi              ACPI table
704  * @v len               Length of ACPI table
705  * @ret rc              Return status code
706  */
707 static int srpdev_describe ( struct srp_device *srpdev,
708                              struct acpi_description_header *acpi,
709                              size_t len ) {
710         struct ipxe_sbft *sbft =
711                 container_of ( acpi, struct ipxe_sbft, table.acpi );
712         int rc;
713
714         /* Sanity check */
715         if ( len < sizeof ( *sbft ) )
716                 return -ENOBUFS;
717
718         /* Populate table */
719         sbft->table.acpi.signature = cpu_to_le32 ( SBFT_SIG );
720         sbft->table.acpi.length = cpu_to_le32 ( sizeof ( *sbft ) );
721         sbft->table.acpi.revision = 1;
722         sbft->table.scsi_offset =
723                 cpu_to_le16 ( offsetof ( typeof ( *sbft ), scsi ) );
724         memcpy ( &sbft->scsi.lun, &srpdev->lun, sizeof ( sbft->scsi.lun ) );
725         sbft->table.srp_offset =
726                 cpu_to_le16 ( offsetof ( typeof ( *sbft ), srp ) );
727         memcpy ( &sbft->srp.initiator, &srpdev->initiator,
728                  sizeof ( sbft->srp.initiator ) );
729         memcpy ( &sbft->srp.target, &srpdev->target,
730                  sizeof ( sbft->srp.target ) );
731
732         /* Ask transport layer to describe transport-specific portions */
733         if ( ( rc = acpi_describe ( &srpdev->socket, acpi, len ) ) != 0 ) {
734                 DBGC ( srpdev, "SRP %p cannot describe transport layer: %s\n",
735                        srpdev, strerror ( rc ) );
736                 return rc;
737         }
738
739         return 0;
740 }
741
742 /** SRP device socket interface operations */
743 static struct interface_operation srpdev_socket_op[] = {
744         INTF_OP ( xfer_deliver, struct srp_device *, srpdev_deliver ),
745         INTF_OP ( intf_close, struct srp_device *, srpdev_close ),
746 };
747
748 /** SRP device socket interface descriptor */
749 static struct interface_descriptor srpdev_socket_desc =
750         INTF_DESC_PASSTHRU ( struct srp_device, socket, srpdev_socket_op,
751                              scsi );
752
753 /** SRP device SCSI interface operations */
754 static struct interface_operation srpdev_scsi_op[] = {
755         INTF_OP ( scsi_command, struct srp_device *, srpdev_scsi_command ),
756         INTF_OP ( xfer_window, struct srp_device *, srpdev_window ),
757         INTF_OP ( intf_close, struct srp_device *, srpdev_close ),
758         INTF_OP ( acpi_describe, struct srp_device *, srpdev_describe ),
759 };
760
761 /** SRP device SCSI interface descriptor */
762 static struct interface_descriptor srpdev_scsi_desc =
763         INTF_DESC_PASSTHRU ( struct srp_device, scsi, srpdev_scsi_op, socket  );
764
765 /**
766  * Open SRP device
767  *
768  * @v block             Block control interface
769  * @v socket            Socket interface
770  * @v initiator         Initiator port ID
771  * @v target            Target port ID
772  * @v memory_handle     RDMA memory handle
773  * @v lun               SCSI LUN
774  * @ret rc              Return status code
775  */
776 int srp_open ( struct interface *block, struct interface *socket,
777                union srp_port_id *initiator, union srp_port_id *target,
778                uint32_t memory_handle, struct scsi_lun *lun ) {
779         struct srp_device *srpdev;
780         int tag;
781         int rc;
782
783         /* Allocate and initialise structure */
784         srpdev = zalloc ( sizeof ( *srpdev ) );
785         if ( ! srpdev ) {
786                 rc = -ENOMEM;
787                 goto err_zalloc;
788         }
789         ref_init ( &srpdev->refcnt, NULL );
790         intf_init ( &srpdev->scsi, &srpdev_scsi_desc, &srpdev->refcnt );
791         intf_init ( &srpdev->socket, &srpdev_socket_desc, &srpdev->refcnt );
792         INIT_LIST_HEAD ( &srpdev->commands );
793         srpdev->memory_handle = memory_handle;
794         DBGC ( srpdev, "SRP %p %08x%08x%08x%08x->%08x%08x%08x%08x\n", srpdev,
795                ntohl ( initiator->dwords[0] ), ntohl ( initiator->dwords[1] ),
796                ntohl ( initiator->dwords[2] ), ntohl ( initiator->dwords[3] ),
797                ntohl ( target->dwords[0] ), ntohl ( target->dwords[1] ),
798                ntohl ( target->dwords[2] ), ntohl ( target->dwords[3] ) );
799
800         /* Preserve parameters required for boot firmware table */
801         memcpy ( &srpdev->initiator, initiator, sizeof ( srpdev->initiator ) );
802         memcpy ( &srpdev->target, target, sizeof ( srpdev->target ) );
803         memcpy ( &srpdev->lun, lun, sizeof ( srpdev->lun ) );
804
805         /* Attach to socket interface and initiate login */
806         intf_plug_plug ( &srpdev->socket, socket );
807         tag = srp_new_tag ( srpdev );
808         assert ( tag >= 0 ); /* Cannot fail when no commands in progress */
809         if ( ( rc = srp_login ( srpdev, initiator, target, tag ) ) != 0 )
810                 goto err_login;
811
812         /* Attach SCSI device to parent interface */
813         if ( ( rc = scsi_open ( block, &srpdev->scsi, lun ) ) != 0 ) {
814                 DBGC ( srpdev, "SRP %p could not create SCSI device: %s\n",
815                        srpdev, strerror ( rc ) );
816                 goto err_scsi_open;
817         }
818
819         /* Mortalise self and return */
820         ref_put ( &srpdev->refcnt );
821         return 0;
822
823  err_scsi_open:
824  err_login:
825         srpdev_close ( srpdev, rc );
826         ref_put ( &srpdev->refcnt );
827  err_zalloc:
828         return rc;
829 }