[e16e8f2] | 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 <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 | |
---|
| 49 | FEATURE ( FEATURE_PROTOCOL, "SRP", DHCP_EB_FEATURE_SRP, 1 ); |
---|
| 50 | |
---|
| 51 | /** Tag to be used for next SRP IU */ |
---|
| 52 | static unsigned int srp_tag = 0; |
---|
| 53 | |
---|
| 54 | static void srp_login ( struct srp_device *srp ); |
---|
| 55 | static 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 | */ |
---|
| 63 | static 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 | */ |
---|
| 75 | static 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 | */ |
---|
| 101 | static 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 | */ |
---|
| 158 | static 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 | */ |
---|
| 198 | static 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 | */ |
---|
| 229 | static 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 | */ |
---|
| 297 | static 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 | */ |
---|
| 352 | static 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 | */ |
---|
| 372 | static 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 | */ |
---|
| 414 | static 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 */ |
---|
| 424 | static 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 | */ |
---|
| 440 | static 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 | */ |
---|
| 471 | int 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 | */ |
---|
| 513 | void 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 | } |
---|