srp.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2009 Fen Systems Ltd <mbrown@fensystems.co.uk>.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  *   Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  *
00012  *   Redistributions in binary form must reproduce the above copyright
00013  *   notice, this list of conditions and the following disclaimer in
00014  *   the documentation and/or other materials provided with the
00015  *   distribution.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00018  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00021  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
00022  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00023  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00024  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00025  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
00026  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00027  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
00028  * OF THE POSSIBILITY OF SUCH DAMAGE.
00029  */
00030 
00031 FILE_LICENCE ( BSD2 );
00032 
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <errno.h>
00036 #include <gpxe/scsi.h>
00037 #include <gpxe/xfer.h>
00038 #include <gpxe/features.h>
00039 #include <gpxe/ib_srp.h>
00040 #include <gpxe/srp.h>
00041 
00042 /**
00043  * @file
00044  *
00045  * SCSI RDMA Protocol
00046  *
00047  */
00048 
00049 FEATURE ( FEATURE_PROTOCOL, "SRP", DHCP_EB_FEATURE_SRP, 1 );
00050 
00051 /** Tag to be used for next SRP IU */
00052 static unsigned int srp_tag = 0;
00053 
00054 static void srp_login ( struct srp_device *srp );
00055 static void srp_cmd ( struct srp_device *srp );
00056 
00057 /**
00058  * Mark SRP SCSI command as complete
00059  *
00060  * @v srp               SRP device
00061  * @v rc                Status code
00062  */
00063 static void srp_scsi_done ( struct srp_device *srp, int rc ) {
00064         if ( srp->command )
00065                 srp->command->rc = rc;
00066         srp->command = NULL;
00067 }
00068 
00069 /**
00070  * Handle SRP session failure
00071  *
00072  * @v srp               SRP device
00073  * @v rc                Reason for failure
00074  */
00075 static void srp_fail ( struct srp_device *srp, int rc ) {
00076 
00077         /* Close underlying socket */
00078         xfer_close ( &srp->socket, rc );
00079 
00080         /* Clear session state */
00081         srp->state = 0;
00082 
00083         /* If we have reached the retry limit, report the failure */
00084         if ( srp->retry_count >= SRP_MAX_RETRIES ) {
00085                 srp_scsi_done ( srp, rc );
00086                 return;
00087         }
00088 
00089         /* Otherwise, increment the retry count and try to reopen the
00090          * connection
00091          */
00092         srp->retry_count++;
00093         srp_login ( srp );
00094 }
00095 
00096 /**
00097  * Initiate SRP login
00098  *
00099  * @v srp               SRP device
00100  */
00101 static void srp_login ( struct srp_device *srp ) {
00102         struct io_buffer *iobuf;
00103         struct srp_login_req *login_req;
00104         int rc;
00105 
00106         assert ( ! ( srp->state & SRP_STATE_SOCKET_OPEN ) );
00107 
00108         /* Open underlying socket */
00109         if ( ( rc = srp->transport->connect ( srp ) ) != 0 ) {
00110                 DBGC ( srp, "SRP %p could not open socket: %s\n",
00111                        srp, strerror ( rc ) );
00112                 goto err;
00113         }
00114         srp->state |= SRP_STATE_SOCKET_OPEN;
00115 
00116         /* Allocate I/O buffer */
00117         iobuf = xfer_alloc_iob ( &srp->socket, sizeof ( *login_req ) );
00118         if ( ! iobuf ) {
00119                 rc = -ENOMEM;
00120                 goto err;
00121         }
00122 
00123         /* Construct login request IU */
00124         login_req = iob_put ( iobuf, sizeof ( *login_req ) );
00125         memset ( login_req, 0, sizeof ( *login_req ) );
00126         login_req->type = SRP_LOGIN_REQ;
00127         login_req->tag.dwords[1] = htonl ( ++srp_tag );
00128         login_req->max_i_t_iu_len = htonl ( SRP_MAX_I_T_IU_LEN );
00129         login_req->required_buffer_formats = SRP_LOGIN_REQ_FMT_DDBD;
00130         memcpy ( &login_req->port_ids, &srp->port_ids,
00131                  sizeof ( login_req->port_ids ) );
00132 
00133         DBGC2 ( srp, "SRP %p TX login request tag %08x%08x\n",
00134                 srp, ntohl ( login_req->tag.dwords[0] ),
00135                 ntohl ( login_req->tag.dwords[1] ) );
00136         DBGC2_HDA ( srp, 0, iobuf->data, iob_len ( iobuf ) );
00137 
00138         /* Send login request IU */
00139         if ( ( rc = xfer_deliver_iob ( &srp->socket, iobuf ) ) != 0 ) {
00140                 DBGC ( srp, "SRP %p could not send login request: %s\n",
00141                        srp, strerror ( rc ) );
00142                 goto err;
00143         }
00144 
00145         return;
00146 
00147  err:
00148         srp_fail ( srp, rc );
00149 }
00150 
00151 /**
00152  * Handle SRP login response
00153  *
00154  * @v srp               SRP device
00155  * @v iobuf             I/O buffer
00156  * @ret rc              Return status code
00157  */
00158 static int srp_login_rsp ( struct srp_device *srp, struct io_buffer *iobuf ) {
00159         struct srp_login_rsp *login_rsp = iobuf->data;
00160         int rc;
00161 
00162         DBGC2 ( srp, "SRP %p RX login response tag %08x%08x\n",
00163                 srp, ntohl ( login_rsp->tag.dwords[0] ),
00164                 ntohl ( login_rsp->tag.dwords[1] ) );
00165 
00166         /* Sanity check */
00167         if ( iob_len ( iobuf ) < sizeof ( *login_rsp ) ) {
00168                 DBGC ( srp, "SRP %p RX login response too short (%zd bytes)\n",
00169                        srp, iob_len ( iobuf ) );
00170                 rc = -EINVAL;
00171                 goto out;
00172         }
00173 
00174         DBGC ( srp, "SRP %p logged in\n", srp );
00175 
00176         /* Mark as logged in */
00177         srp->state |= SRP_STATE_LOGGED_IN;
00178 
00179         /* Reset error counter */
00180         srp->retry_count = 0;
00181 
00182         /* Issue pending command */
00183         srp_cmd ( srp );
00184 
00185         rc = 0;
00186  out:
00187         free_iob ( iobuf );
00188         return rc;
00189 }
00190 
00191 /**
00192  * Handle SRP login rejection
00193  *
00194  * @v srp               SRP device
00195  * @v iobuf             I/O buffer
00196  * @ret rc              Return status code
00197  */
00198 static int srp_login_rej ( struct srp_device *srp, struct io_buffer *iobuf ) {
00199         struct srp_login_rej *login_rej = iobuf->data;
00200         int rc;
00201 
00202         DBGC2 ( srp, "SRP %p RX login rejection tag %08x%08x\n",
00203                 srp, ntohl ( login_rej->tag.dwords[0] ),
00204                 ntohl ( login_rej->tag.dwords[1] ) );
00205 
00206         /* Sanity check */
00207         if ( iob_len ( iobuf ) < sizeof ( *login_rej ) ) {
00208                 DBGC ( srp, "SRP %p RX login rejection too short (%zd "
00209                        "bytes)\n", srp, iob_len ( iobuf ) );
00210                 rc = -EINVAL;
00211                 goto out;
00212         }
00213 
00214         /* Login rejection always indicates an error */
00215         DBGC ( srp, "SRP %p login rejected (reason %08x)\n",
00216                srp, ntohl ( login_rej->reason ) );
00217         rc = -EPERM;
00218 
00219  out:
00220         free_iob ( iobuf );
00221         return rc;
00222 }
00223 
00224 /**
00225  * Transmit SRP SCSI command
00226  *
00227  * @v srp               SRP device
00228  */
00229 static void srp_cmd ( struct srp_device *srp ) {
00230         struct io_buffer *iobuf;
00231         struct srp_cmd *cmd;
00232         struct srp_memory_descriptor *data_out;
00233         struct srp_memory_descriptor *data_in;
00234         int rc;
00235 
00236         assert ( srp->state & SRP_STATE_LOGGED_IN );
00237 
00238         /* Allocate I/O buffer */
00239         iobuf = xfer_alloc_iob ( &srp->socket, SRP_MAX_I_T_IU_LEN );
00240         if ( ! iobuf ) {
00241                 rc = -ENOMEM;
00242                 goto err;
00243         }
00244 
00245         /* Construct base portion */
00246         cmd = iob_put ( iobuf, sizeof ( *cmd ) );
00247         memset ( cmd, 0, sizeof ( *cmd ) );
00248         cmd->type = SRP_CMD;
00249         cmd->tag.dwords[1] = htonl ( ++srp_tag );
00250         cmd->lun = srp->lun;
00251         memcpy ( &cmd->cdb, &srp->command->cdb, sizeof ( cmd->cdb ) );
00252 
00253         /* Construct data-out descriptor, if present */
00254         if ( srp->command->data_out ) {
00255                 cmd->data_buffer_formats |= SRP_CMD_DO_FMT_DIRECT;
00256                 data_out = iob_put ( iobuf, sizeof ( *data_out ) );
00257                 data_out->address =
00258                     cpu_to_be64 ( user_to_phys ( srp->command->data_out, 0 ) );
00259                 data_out->handle = ntohl ( srp->memory_handle );
00260                 data_out->len = ntohl ( srp->command->data_out_len );
00261         }
00262 
00263         /* Construct data-in descriptor, if present */
00264         if ( srp->command->data_in ) {
00265                 cmd->data_buffer_formats |= SRP_CMD_DI_FMT_DIRECT;
00266                 data_in = iob_put ( iobuf, sizeof ( *data_in ) );
00267                 data_in->address =
00268                      cpu_to_be64 ( user_to_phys ( srp->command->data_in, 0 ) );
00269                 data_in->handle = ntohl ( srp->memory_handle );
00270                 data_in->len = ntohl ( srp->command->data_in_len );
00271         }
00272 
00273         DBGC2 ( srp, "SRP %p TX SCSI command tag %08x%08x\n", srp,
00274                 ntohl ( cmd->tag.dwords[0] ), ntohl ( cmd->tag.dwords[1] ) );
00275         DBGC2_HDA ( srp, 0, iobuf->data, iob_len ( iobuf ) );
00276 
00277         /* Send IU */
00278         if ( ( rc = xfer_deliver_iob ( &srp->socket, iobuf ) ) != 0 ) {
00279                 DBGC ( srp, "SRP %p could not send command: %s\n",
00280                        srp, strerror ( rc ) );
00281                 goto err;
00282         }
00283 
00284         return;
00285 
00286  err:
00287         srp_fail ( srp, rc );
00288 }
00289 
00290 /**
00291  * Handle SRP SCSI response
00292  *
00293  * @v srp               SRP device
00294  * @v iobuf             I/O buffer
00295  * @ret rc              Returns status code
00296  */
00297 static int srp_rsp ( struct srp_device *srp, struct io_buffer *iobuf ) {
00298         struct srp_rsp *rsp = iobuf->data;
00299         int rc;
00300 
00301         DBGC2 ( srp, "SRP %p RX SCSI response tag %08x%08x\n", srp,
00302                 ntohl ( rsp->tag.dwords[0] ), ntohl ( rsp->tag.dwords[1] ) );
00303 
00304         /* Sanity check */
00305         if ( iob_len ( iobuf ) < sizeof ( *rsp ) ) {
00306                 DBGC ( srp, "SRP %p RX SCSI response too short (%zd bytes)\n",
00307                        srp, iob_len ( iobuf ) );
00308                 rc = -EINVAL;
00309                 goto out;
00310         }
00311 
00312         /* Report SCSI errors */
00313         if ( rsp->status != 0 ) {
00314                 DBGC ( srp, "SRP %p response status %02x\n",
00315                        srp, rsp->status );
00316                 if ( srp_rsp_sense_data ( rsp ) ) {
00317                         DBGC ( srp, "SRP %p sense data:\n", srp );
00318                         DBGC_HDA ( srp, 0, srp_rsp_sense_data ( rsp ),
00319                                    srp_rsp_sense_data_len ( rsp ) );
00320                 }
00321         }
00322         if ( rsp->valid & ( SRP_RSP_VALID_DOUNDER | SRP_RSP_VALID_DOOVER ) ) {
00323                 DBGC ( srp, "SRP %p response data-out %srun by %#x bytes\n",
00324                        srp, ( ( rsp->valid & SRP_RSP_VALID_DOUNDER )
00325                               ? "under" : "over" ),
00326                        ntohl ( rsp->data_out_residual_count ) );
00327         }
00328         if ( rsp->valid & ( SRP_RSP_VALID_DIUNDER | SRP_RSP_VALID_DIOVER ) ) {
00329                 DBGC ( srp, "SRP %p response data-in %srun by %#x bytes\n",
00330                        srp, ( ( rsp->valid & SRP_RSP_VALID_DIUNDER )
00331                               ? "under" : "over" ),
00332                        ntohl ( rsp->data_in_residual_count ) );
00333         }
00334         srp->command->status = rsp->status;
00335 
00336         /* Mark SCSI command as complete */
00337         srp_scsi_done ( srp, 0 );
00338 
00339         rc = 0;
00340  out:
00341         free_iob ( iobuf );
00342         return rc;
00343 }
00344 
00345 /**
00346  * Handle SRP unrecognised response
00347  *
00348  * @v srp               SRP device
00349  * @v iobuf             I/O buffer
00350  * @ret rc              Returns status code
00351  */
00352 static int srp_unrecognised ( struct srp_device *srp,
00353                               struct io_buffer *iobuf ) {
00354         struct srp_common *common = iobuf->data;
00355 
00356         DBGC ( srp, "SRP %p RX unrecognised IU tag %08x%08x type %02x\n",
00357                srp, ntohl ( common->tag.dwords[0] ),
00358                ntohl ( common->tag.dwords[1] ), common->type );
00359 
00360         free_iob ( iobuf );
00361         return -ENOTSUP;
00362 }
00363 
00364 /**
00365  * Receive data from underlying socket
00366  *
00367  * @v xfer              Data transfer interface
00368  * @v iobuf             Datagram I/O buffer
00369  * @v meta              Data transfer metadata
00370  * @ret rc              Return status code
00371  */
00372 static int srp_xfer_deliver_iob ( struct xfer_interface *xfer,
00373                                   struct io_buffer *iobuf,
00374                                   struct xfer_metadata *meta __unused ) {
00375         struct srp_device *srp =
00376                 container_of ( xfer, struct srp_device, socket );
00377         struct srp_common *common = iobuf->data;
00378         int ( * type ) ( struct srp_device *srp, struct io_buffer *iobuf );
00379         int rc;
00380 
00381         /* Determine IU type */
00382         switch ( common->type ) {
00383         case SRP_LOGIN_RSP:
00384                 type = srp_login_rsp;
00385                 break;
00386         case SRP_LOGIN_REJ:
00387                 type = srp_login_rej;
00388                 break;
00389         case SRP_RSP:
00390                 type = srp_rsp;
00391                 break;
00392         default:
00393                 type = srp_unrecognised;
00394                 break;
00395         }
00396 
00397         /* Handle IU */
00398         if ( ( rc = type ( srp, iobuf ) ) != 0 )
00399                 goto err;
00400 
00401         return 0;
00402 
00403  err:
00404         srp_fail ( srp, rc );
00405         return rc;
00406 }
00407 
00408 /**
00409  * Underlying socket closed
00410  *
00411  * @v xfer              Data transfer interface
00412  * @v rc                Reason for close
00413  */
00414 static void srp_xfer_close ( struct xfer_interface *xfer, int rc ) {
00415         struct srp_device *srp =
00416                 container_of ( xfer, struct srp_device, socket );
00417 
00418         DBGC ( srp, "SRP %p socket closed: %s\n", srp, strerror ( rc ) );
00419 
00420         srp_fail ( srp, rc );
00421 }
00422 
00423 /** SRP data transfer interface operations */
00424 static struct xfer_interface_operations srp_xfer_operations = {
00425         .close          = srp_xfer_close,
00426         .vredirect      = ignore_xfer_vredirect,
00427         .window         = unlimited_xfer_window,
00428         .alloc_iob      = default_xfer_alloc_iob,
00429         .deliver_iob    = srp_xfer_deliver_iob,
00430         .deliver_raw    = xfer_deliver_as_iob,
00431 };
00432 
00433 /**
00434  * Issue SCSI command via SRP
00435  *
00436  * @v scsi              SCSI device
00437  * @v command           SCSI command
00438  * @ret rc              Return status code
00439  */
00440 static int srp_command ( struct scsi_device *scsi,
00441                          struct scsi_command *command ) {
00442         struct srp_device *srp =
00443                 container_of ( scsi->backend, struct srp_device, refcnt );
00444 
00445         /* Store SCSI command */
00446         if ( srp->command ) {
00447                 DBGC ( srp, "SRP %p cannot handle concurrent SCSI commands\n",
00448                        srp );
00449                 return -EBUSY;
00450         }
00451         srp->command = command;
00452 
00453         /* Log in or issue command as appropriate */
00454         if ( ! ( srp->state & SRP_STATE_SOCKET_OPEN ) ) {
00455                 srp_login ( srp );
00456         } else if ( srp->state & SRP_STATE_LOGGED_IN ) {
00457                 srp_cmd ( srp );
00458         } else {
00459                 /* Still waiting for login; do nothing */
00460         }
00461 
00462         return 0;
00463 }
00464 
00465 /**
00466  * Attach SRP device
00467  *
00468  * @v scsi              SCSI device
00469  * @v root_path         Root path
00470  */
00471 int srp_attach ( struct scsi_device *scsi, const char *root_path ) {
00472         struct srp_transport_type *transport;
00473         struct srp_device *srp;
00474         int rc;
00475 
00476         /* Hard-code an IB SRP back-end for now */
00477         transport = &ib_srp_transport;
00478 
00479         /* Allocate and initialise structure */
00480         srp = zalloc ( sizeof ( *srp ) + transport->priv_len );
00481         if ( ! srp ) {
00482                 rc = -ENOMEM;
00483                 goto err_alloc;
00484         }
00485         xfer_init ( &srp->socket, &srp_xfer_operations, &srp->refcnt );
00486         srp->transport = transport;
00487         DBGC ( srp, "SRP %p using %s\n", srp, root_path );
00488 
00489         /* Parse root path */
00490         if ( ( rc = transport->parse_root_path ( srp, root_path ) ) != 0 ) {
00491                 DBGC ( srp, "SRP %p could not parse root path: %s\n",
00492                        srp, strerror ( rc ) );
00493                 goto err_parse_root_path;
00494         }
00495 
00496         /* Attach parent interface, mortalise self, and return */
00497         scsi->backend = ref_get ( &srp->refcnt );
00498         scsi->command = srp_command;
00499         ref_put ( &srp->refcnt );
00500         return 0;
00501 
00502  err_parse_root_path:
00503         ref_put ( &srp->refcnt );
00504  err_alloc:
00505         return rc;
00506 }
00507 
00508 /**
00509  * Detach SRP device
00510  *
00511  * @v scsi              SCSI device
00512  */
00513 void srp_detach ( struct scsi_device *scsi ) {
00514         struct srp_device *srp =
00515                 container_of ( scsi->backend, struct srp_device, refcnt );
00516 
00517         /* Close socket */
00518         xfer_nullify ( &srp->socket );
00519         xfer_close ( &srp->socket, 0 );
00520         scsi->command = scsi_detached_command;
00521         ref_put ( scsi->backend );
00522         scsi->backend = NULL;
00523 }

Generated on Tue Apr 6 20:00:52 2010 for gPXE by  doxygen 1.5.7.1