[contrib] Allow Network Protocol header to display in rom-o-matic
[gpxe.git] / src / drivers / block / srp.c
blob008f3b2607c645b2795c65e2a8ff437cfef36a51
1 /*
2 * Copyright (C) 2009 Fen Systems Ltd <mbrown@fensystems.co.uk>.
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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.
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.
31 FILE_LICENCE ( BSD2 );
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>
42 /**
43 * @file
45 * SCSI RDMA Protocol
49 FEATURE ( FEATURE_PROTOCOL, "SRP", DHCP_EB_FEATURE_SRP, 1 );
51 /** Tag to be used for next SRP IU */
52 static unsigned int srp_tag = 0;
54 static void srp_login ( struct srp_device *srp );
55 static void srp_cmd ( struct srp_device *srp );
57 /**
58 * Mark SRP SCSI command as complete
60 * @v srp SRP device
61 * @v rc Status code
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;
69 /**
70 * Handle SRP session failure
72 * @v srp SRP device
73 * @v rc Reason for failure
75 static void srp_fail ( struct srp_device *srp, int rc ) {
77 /* Close underlying socket */
78 xfer_close ( &srp->socket, rc );
80 /* Clear session state */
81 srp->state = 0;
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;
89 /* Otherwise, increment the retry count and try to reopen the
90 * connection
92 srp->retry_count++;
93 srp_login ( srp );
96 /**
97 * Initiate SRP login
99 * @v srp SRP device
101 static void srp_login ( struct srp_device *srp ) {
102 struct io_buffer *iobuf;
103 struct srp_login_req *login_req;
104 int rc;
106 assert ( ! ( srp->state & SRP_STATE_SOCKET_OPEN ) );
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;
114 srp->state |= SRP_STATE_SOCKET_OPEN;
116 /* Allocate I/O buffer */
117 iobuf = xfer_alloc_iob ( &srp->socket, sizeof ( *login_req ) );
118 if ( ! iobuf ) {
119 rc = -ENOMEM;
120 goto err;
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 ) );
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 ) );
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;
145 return;
147 err:
148 srp_fail ( srp, rc );
152 * Handle SRP login response
154 * @v srp SRP device
155 * @v iobuf I/O buffer
156 * @ret rc Return status code
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;
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] ) );
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;
174 DBGC ( srp, "SRP %p logged in\n", srp );
176 /* Mark as logged in */
177 srp->state |= SRP_STATE_LOGGED_IN;
179 /* Reset error counter */
180 srp->retry_count = 0;
182 /* Issue pending command */
183 srp_cmd ( srp );
185 rc = 0;
186 out:
187 free_iob ( iobuf );
188 return rc;
192 * Handle SRP login rejection
194 * @v srp SRP device
195 * @v iobuf I/O buffer
196 * @ret rc Return status code
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;
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] ) );
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;
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;
219 out:
220 free_iob ( iobuf );
221 return rc;
225 * Transmit SRP SCSI command
227 * @v srp SRP device
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;
236 assert ( srp->state & SRP_STATE_LOGGED_IN );
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;
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 ) );
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 );
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 );
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 ) );
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;
284 return;
286 err:
287 srp_fail ( srp, rc );
291 * Handle SRP SCSI response
293 * @v srp SRP device
294 * @v iobuf I/O buffer
295 * @ret rc Returns status code
297 static int srp_rsp ( struct srp_device *srp, struct io_buffer *iobuf ) {
298 struct srp_rsp *rsp = iobuf->data;
299 int rc;
301 DBGC2 ( srp, "SRP %p RX SCSI response tag %08x%08x\n", srp,
302 ntohl ( rsp->tag.dwords[0] ), ntohl ( rsp->tag.dwords[1] ) );
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;
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 ) );
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 ) );
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 ) );
334 srp->command->status = rsp->status;
336 /* Mark SCSI command as complete */
337 srp_scsi_done ( srp, 0 );
339 rc = 0;
340 out:
341 free_iob ( iobuf );
342 return rc;
346 * Handle SRP unrecognised response
348 * @v srp SRP device
349 * @v iobuf I/O buffer
350 * @ret rc Returns status code
352 static int srp_unrecognised ( struct srp_device *srp,
353 struct io_buffer *iobuf ) {
354 struct srp_common *common = iobuf->data;
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 );
360 free_iob ( iobuf );
361 return -ENOTSUP;
365 * Receive data from underlying socket
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
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;
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;
397 /* Handle IU */
398 if ( ( rc = type ( srp, iobuf ) ) != 0 )
399 goto err;
401 return 0;
403 err:
404 srp_fail ( srp, rc );
405 return rc;
409 * Underlying socket closed
411 * @v xfer Data transfer interface
412 * @v rc Reason for close
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 );
418 DBGC ( srp, "SRP %p socket closed: %s\n", srp, strerror ( rc ) );
420 srp_fail ( srp, rc );
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,
434 * Issue SCSI command via SRP
436 * @v scsi SCSI device
437 * @v command SCSI command
438 * @ret rc Return status code
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 );
445 /* Store SCSI command */
446 if ( srp->command ) {
447 DBGC ( srp, "SRP %p cannot handle concurrent SCSI commands\n",
448 srp );
449 return -EBUSY;
451 srp->command = command;
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 */
462 return 0;
466 * Attach SRP device
468 * @v scsi SCSI device
469 * @v root_path Root path
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;
476 /* Hard-code an IB SRP back-end for now */
477 transport = &ib_srp_transport;
479 /* Allocate and initialise structure */
480 srp = zalloc ( sizeof ( *srp ) + transport->priv_len );
481 if ( ! srp ) {
482 rc = -ENOMEM;
483 goto err_alloc;
485 ref_init ( &srp->refcnt, NULL );
486 xfer_init ( &srp->socket, &srp_xfer_operations, &srp->refcnt );
487 srp->transport = transport;
488 DBGC ( srp, "SRP %p using %s\n", srp, root_path );
490 /* Parse root path */
491 if ( ( rc = transport->parse_root_path ( srp, root_path ) ) != 0 ) {
492 DBGC ( srp, "SRP %p could not parse root path: %s\n",
493 srp, strerror ( rc ) );
494 goto err_parse_root_path;
497 /* Attach parent interface, mortalise self, and return */
498 scsi->backend = ref_get ( &srp->refcnt );
499 scsi->command = srp_command;
500 ref_put ( &srp->refcnt );
501 return 0;
503 err_parse_root_path:
504 ref_put ( &srp->refcnt );
505 err_alloc:
506 return rc;
510 * Detach SRP device
512 * @v scsi SCSI device
514 void srp_detach ( struct scsi_device *scsi ) {
515 struct srp_device *srp =
516 container_of ( scsi->backend, struct srp_device, refcnt );
518 /* Close socket */
519 xfer_nullify ( &srp->socket );
520 xfer_close ( &srp->socket, 0 );
521 scsi->command = scsi_detached_command;
522 ref_put ( scsi->backend );
523 scsi->backend = NULL;