2 * Copyright (C) 2009 Fen Systems Ltd <mbrown@fensystems.co.uk>.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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
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
);
36 #include <gpxe/scsi.h>
37 #include <gpxe/xfer.h>
38 #include <gpxe/features.h>
39 #include <gpxe/ib_srp.h>
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
);
58 * Mark SRP SCSI command as complete
63 static void srp_scsi_done ( struct srp_device
*srp
, int rc
) {
65 srp
->command
->rc
= rc
;
70 * Handle SRP session failure
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 */
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
);
89 /* Otherwise, increment the retry count and try to reopen the
101 static void srp_login ( struct srp_device
*srp
) {
102 struct io_buffer
*iobuf
;
103 struct srp_login_req
*login_req
;
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
) );
114 srp
->state
|= SRP_STATE_SOCKET_OPEN
;
116 /* Allocate I/O buffer */
117 iobuf
= xfer_alloc_iob ( &srp
->socket
, sizeof ( *login_req
) );
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
) );
148 srp_fail ( srp
, rc
);
152 * Handle SRP login response
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
;
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] ) );
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
) );
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 */
192 * Handle SRP login rejection
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
;
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] ) );
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
) );
214 /* Login rejection always indicates an error */
215 DBGC ( srp
, "SRP %p login rejected (reason %08x)\n",
216 srp
, ntohl ( login_rej
->reason
) );
225 * Transmit SRP SCSI command
229 static void srp_cmd ( struct srp_device
*srp
) {
230 struct io_buffer
*iobuf
;
232 struct srp_memory_descriptor
*data_out
;
233 struct srp_memory_descriptor
*data_in
;
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
);
245 /* Construct base portion */
246 cmd
= iob_put ( iobuf
, sizeof ( *cmd
) );
247 memset ( cmd
, 0, sizeof ( *cmd
) );
249 cmd
->tag
.dwords
[1] = htonl ( ++srp_tag
);
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
) );
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
) );
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
) );
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
) );
287 srp_fail ( srp
, rc
);
291 * Handle SRP SCSI response
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
;
301 DBGC2 ( srp
, "SRP %p RX SCSI response tag %08x%08x\n", srp
,
302 ntohl ( rsp
->tag
.dwords
[0] ), ntohl ( rsp
->tag
.dwords
[1] ) );
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
) );
312 /* Report SCSI errors */
313 if ( rsp
->status
!= 0 ) {
314 DBGC ( srp
, "SRP %p response status %02x\n",
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 );
346 * Handle SRP unrecognised response
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
);
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
);
381 /* Determine IU type */
382 switch ( common
->type
) {
384 type
= srp_login_rsp
;
387 type
= srp_login_rej
;
393 type
= srp_unrecognised
;
398 if ( ( rc
= type ( srp
, iobuf
) ) != 0 )
404 srp_fail ( srp
, 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",
451 srp
->command
= command
;
453 /* Log in or issue command as appropriate */
454 if ( ! ( srp
->state
& SRP_STATE_SOCKET_OPEN
) ) {
456 } else if ( srp
->state
& SRP_STATE_LOGGED_IN
) {
459 /* Still waiting for login; do nothing */
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
;
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
);
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
);
504 ref_put ( &srp
->refcnt
);
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
);
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
;