source: bootcd/isolinux/syslinux-6.03/gpxe/src/drivers/block/srp.c @ dd1be7c

Last change on this file since dd1be7c was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 13.1 KB
Line 
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
31FILE_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
49FEATURE ( FEATURE_PROTOCOL, "SRP", DHCP_EB_FEATURE_SRP, 1 );
50
51/** Tag to be used for next SRP IU */
52static unsigned int srp_tag = 0;
53
54static void srp_login ( struct srp_device *srp );
55static 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 */
63static 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 */
75static 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 */
101static 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 */
158static 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 */
198static 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 */
229static 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 */
297static 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 */
352static 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 */
372static 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 */
414static 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 */
424static 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 */
440static 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 */
471int 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 */
513void 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}
Note: See TracBrowser for help on using the repository browser.