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 | } |
---|