~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/ipxe/src/drivers/block/srp.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}