00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
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
00044
00045
00046
00047
00048
00049 FEATURE ( FEATURE_PROTOCOL, "SRP", DHCP_EB_FEATURE_SRP, 1 );
00050
00051
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
00059
00060
00061
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
00071
00072
00073
00074
00075 static void srp_fail ( struct srp_device *srp, int rc ) {
00076
00077
00078 xfer_close ( &srp->socket, rc );
00079
00080
00081 srp->state = 0;
00082
00083
00084 if ( srp->retry_count >= SRP_MAX_RETRIES ) {
00085 srp_scsi_done ( srp, rc );
00086 return;
00087 }
00088
00089
00090
00091
00092 srp->retry_count++;
00093 srp_login ( srp );
00094 }
00095
00096
00097
00098
00099
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
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
00117 iobuf = xfer_alloc_iob ( &srp->socket, sizeof ( *login_req ) );
00118 if ( ! iobuf ) {
00119 rc = -ENOMEM;
00120 goto err;
00121 }
00122
00123
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
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
00153
00154
00155
00156
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
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
00177 srp->state |= SRP_STATE_LOGGED_IN;
00178
00179
00180 srp->retry_count = 0;
00181
00182
00183 srp_cmd ( srp );
00184
00185 rc = 0;
00186 out:
00187 free_iob ( iobuf );
00188 return rc;
00189 }
00190
00191
00192
00193
00194
00195
00196
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
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
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
00226
00227
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
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
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
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
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
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
00292
00293
00294
00295
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
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
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
00337 srp_scsi_done ( srp, 0 );
00338
00339 rc = 0;
00340 out:
00341 free_iob ( iobuf );
00342 return rc;
00343 }
00344
00345
00346
00347
00348
00349
00350
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
00366
00367
00368
00369
00370
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
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
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
00410
00411
00412
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
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
00435
00436
00437
00438
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
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
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
00460 }
00461
00462 return 0;
00463 }
00464
00465
00466
00467
00468
00469
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
00477 transport = &ib_srp_transport;
00478
00479
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
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
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
00510
00511
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
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 }