|
@@ -101,9 +101,13 @@ struct san_device * sandev_find ( unsigned int drive ) {
|
101
|
101
|
static void sandev_free ( struct refcnt *refcnt ) {
|
102
|
102
|
struct san_device *sandev =
|
103
|
103
|
container_of ( refcnt, struct san_device, refcnt );
|
|
104
|
+ struct san_path *sanpath;
|
104
|
105
|
|
105
|
106
|
assert ( ! timer_running ( &sandev->timer ) );
|
106
|
|
- uri_put ( sandev->uri );
|
|
107
|
+ assert ( ! sandev->active );
|
|
108
|
+ assert ( list_empty ( &sandev->opened ) );
|
|
109
|
+ list_for_each_entry ( sanpath, &sandev->closed, list )
|
|
110
|
+ uri_put ( sanpath->uri );
|
107
|
111
|
free ( sandev );
|
108
|
112
|
}
|
109
|
113
|
|
|
@@ -163,85 +167,92 @@ static void sandev_command_expired ( struct retry_timer *timer,
|
163
|
167
|
}
|
164
|
168
|
|
165
|
169
|
/**
|
166
|
|
- * Restart SAN device interface
|
|
170
|
+ * Open SAN path
|
167
|
171
|
*
|
168
|
|
- * @v sandev SAN device
|
169
|
|
- * @v rc Reason for restart
|
|
172
|
+ * @v sanpath SAN path
|
|
173
|
+ * @ret rc Return status code
|
170
|
174
|
*/
|
171
|
|
-static void sandev_restart ( struct san_device *sandev, int rc ) {
|
|
175
|
+static int sanpath_open ( struct san_path *sanpath ) {
|
|
176
|
+ struct san_device *sandev = sanpath->sandev;
|
|
177
|
+ int rc;
|
172
|
178
|
|
173
|
|
- /* Restart block device interface */
|
174
|
|
- intfs_restart ( rc, &sandev->command, &sandev->block, NULL );
|
|
179
|
+ /* Sanity check */
|
|
180
|
+ list_check_contains_entry ( sanpath, &sandev->closed, list );
|
175
|
181
|
|
176
|
|
- /* Close any outstanding command */
|
177
|
|
- sandev_command_close ( sandev, rc );
|
|
182
|
+ /* Open interface */
|
|
183
|
+ if ( ( rc = xfer_open_uri ( &sanpath->block, sanpath->uri ) ) != 0 ) {
|
|
184
|
+ DBGC ( sandev, "SAN %#02x.%d could not (re)open URI: "
|
|
185
|
+ "%s\n", sandev->drive, sanpath->index, strerror ( rc ) );
|
|
186
|
+ return rc;
|
|
187
|
+ }
|
|
188
|
+
|
|
189
|
+ /* Start process */
|
|
190
|
+ process_add ( &sanpath->process );
|
178
|
191
|
|
179
|
|
- /* Record device error */
|
180
|
|
- sandev->block_rc = rc;
|
|
192
|
+ /* Mark as opened */
|
|
193
|
+ list_del ( &sanpath->list );
|
|
194
|
+ list_add_tail ( &sanpath->list, &sandev->opened );
|
|
195
|
+
|
|
196
|
+ /* Record as in progress */
|
|
197
|
+ sanpath->path_rc = -EINPROGRESS;
|
|
198
|
+
|
|
199
|
+ return 0;
|
181
|
200
|
}
|
182
|
201
|
|
183
|
202
|
/**
|
184
|
|
- * (Re)open SAN device
|
|
203
|
+ * Close SAN path
|
185
|
204
|
*
|
186
|
|
- * @v sandev SAN device
|
187
|
|
- * @ret rc Return status code
|
188
|
|
- *
|
189
|
|
- * This function will block until the device is available.
|
|
205
|
+ * @v sanpath SAN path
|
|
206
|
+ * @v rc Reason for close
|
190
|
207
|
*/
|
191
|
|
-int sandev_reopen ( struct san_device *sandev ) {
|
192
|
|
- int rc;
|
193
|
|
-
|
194
|
|
- /* Close any outstanding command and restart interface */
|
195
|
|
- sandev_restart ( sandev, -ECONNRESET );
|
196
|
|
-
|
197
|
|
- /* Mark device as being not yet open */
|
198
|
|
- sandev->block_rc = -EINPROGRESS;
|
199
|
|
-
|
200
|
|
- /* Open block device interface */
|
201
|
|
- if ( ( rc = xfer_open_uri ( &sandev->block, sandev->uri ) ) != 0 ) {
|
202
|
|
- DBGC ( sandev, "SAN %#02x could not (re)open URI: %s\n",
|
203
|
|
- sandev->drive, strerror ( rc ) );
|
204
|
|
- return rc;
|
|
208
|
+static void sanpath_close ( struct san_path *sanpath, int rc ) {
|
|
209
|
+ struct san_device *sandev = sanpath->sandev;
|
|
210
|
+
|
|
211
|
+ /* Record status */
|
|
212
|
+ sanpath->path_rc = rc;
|
|
213
|
+
|
|
214
|
+ /* Mark as closed */
|
|
215
|
+ list_del ( &sanpath->list );
|
|
216
|
+ list_add_tail ( &sanpath->list, &sandev->closed );
|
|
217
|
+
|
|
218
|
+ /* Stop process */
|
|
219
|
+ process_del ( &sanpath->process );
|
|
220
|
+
|
|
221
|
+ /* Restart interfaces, avoiding potential loops */
|
|
222
|
+ if ( sanpath == sandev->active ) {
|
|
223
|
+ intfs_restart ( rc, &sandev->command, &sanpath->block, NULL );
|
|
224
|
+ sandev->active = NULL;
|
|
225
|
+ sandev_command_close ( sandev, rc );
|
|
226
|
+ } else {
|
|
227
|
+ intf_restart ( &sanpath->block, rc );
|
205
|
228
|
}
|
206
|
|
-
|
207
|
|
- /* Wait for device to become available */
|
208
|
|
- while ( sandev->block_rc == -EINPROGRESS ) {
|
209
|
|
- step();
|
210
|
|
- if ( xfer_window ( &sandev->block ) != 0 ) {
|
211
|
|
- sandev->block_rc = 0;
|
212
|
|
- return 0;
|
213
|
|
- }
|
214
|
|
- }
|
215
|
|
-
|
216
|
|
- DBGC ( sandev, "SAN %#02x never became available: %s\n",
|
217
|
|
- sandev->drive, strerror ( sandev->block_rc ) );
|
218
|
|
- return sandev->block_rc;
|
219
|
229
|
}
|
220
|
230
|
|
221
|
231
|
/**
|
222
|
232
|
* Handle closure of underlying block device interface
|
223
|
233
|
*
|
224
|
|
- * @v sandev SAN device
|
225
|
|
- * @ret rc Reason for close
|
|
234
|
+ * @v sanpath SAN path
|
|
235
|
+ * @v rc Reason for close
|
226
|
236
|
*/
|
227
|
|
-static void sandev_block_close ( struct san_device *sandev, int rc ) {
|
|
237
|
+static void sanpath_block_close ( struct san_path *sanpath, int rc ) {
|
|
238
|
+ struct san_device *sandev = sanpath->sandev;
|
228
|
239
|
|
229
|
240
|
/* Any closure is an error from our point of view */
|
230
|
241
|
if ( rc == 0 )
|
231
|
242
|
rc = -ENOTCONN;
|
232
|
|
- DBGC ( sandev, "SAN %#02x went away: %s\n",
|
233
|
|
- sandev->drive, strerror ( rc ) );
|
|
243
|
+ DBGC ( sandev, "SAN %#02x.%d closed: %s\n",
|
|
244
|
+ sandev->drive, sanpath->index, strerror ( rc ) );
|
234
|
245
|
|
235
|
|
- /* Close any outstanding command and restart interface */
|
236
|
|
- sandev_restart ( sandev, rc );
|
|
246
|
+ /* Close path */
|
|
247
|
+ sanpath_close ( sanpath, rc );
|
237
|
248
|
}
|
238
|
249
|
|
239
|
250
|
/**
|
240
|
|
- * Check SAN device flow control window
|
|
251
|
+ * Check flow control window
|
241
|
252
|
*
|
242
|
|
- * @v sandev SAN device
|
|
253
|
+ * @v sanpath SAN path
|
243
|
254
|
*/
|
244
|
|
-static size_t sandev_block_window ( struct san_device *sandev __unused ) {
|
|
255
|
+static size_t sanpath_block_window ( struct san_path *sanpath __unused ) {
|
245
|
256
|
|
246
|
257
|
/* We are never ready to receive data via this interface.
|
247
|
258
|
* This prevents objects that support both block and stream
|
|
@@ -250,15 +261,125 @@ static size_t sandev_block_window ( struct san_device *sandev __unused ) {
|
250
|
261
|
return 0;
|
251
|
262
|
}
|
252
|
263
|
|
253
|
|
-/** SAN device block interface operations */
|
254
|
|
-static struct interface_operation sandev_block_op[] = {
|
255
|
|
- INTF_OP ( intf_close, struct san_device *, sandev_block_close ),
|
256
|
|
- INTF_OP ( xfer_window, struct san_device *, sandev_block_window ),
|
|
264
|
+/**
|
|
265
|
+ * SAN path process
|
|
266
|
+ *
|
|
267
|
+ * @v sanpath SAN path
|
|
268
|
+ */
|
|
269
|
+static void sanpath_step ( struct san_path *sanpath ) {
|
|
270
|
+ struct san_device *sandev = sanpath->sandev;
|
|
271
|
+
|
|
272
|
+ /* Wait until path has become available */
|
|
273
|
+ if ( ! xfer_window ( &sanpath->block ) )
|
|
274
|
+ return;
|
|
275
|
+
|
|
276
|
+ /* Record status */
|
|
277
|
+ sanpath->path_rc = 0;
|
|
278
|
+
|
|
279
|
+ /* Mark as active path or close as applicable */
|
|
280
|
+ if ( ! sandev->active ) {
|
|
281
|
+ DBGC ( sandev, "SAN %#02x.%d is active\n",
|
|
282
|
+ sandev->drive, sanpath->index );
|
|
283
|
+ sandev->active = sanpath;
|
|
284
|
+ } else {
|
|
285
|
+ DBGC ( sandev, "SAN %#02x.%d is available\n",
|
|
286
|
+ sandev->drive, sanpath->index );
|
|
287
|
+ sanpath_close ( sanpath, 0 );
|
|
288
|
+ }
|
|
289
|
+}
|
|
290
|
+
|
|
291
|
+/** SAN path block interface operations */
|
|
292
|
+static struct interface_operation sanpath_block_op[] = {
|
|
293
|
+ INTF_OP ( intf_close, struct san_path *, sanpath_block_close ),
|
|
294
|
+ INTF_OP ( xfer_window, struct san_path *, sanpath_block_window ),
|
|
295
|
+ INTF_OP ( xfer_window_changed, struct san_path *, sanpath_step ),
|
257
|
296
|
};
|
258
|
297
|
|
259
|
|
-/** SAN device block interface descriptor */
|
260
|
|
-static struct interface_descriptor sandev_block_desc =
|
261
|
|
- INTF_DESC ( struct san_device, block, sandev_block_op );
|
|
298
|
+/** SAN path block interface descriptor */
|
|
299
|
+static struct interface_descriptor sanpath_block_desc =
|
|
300
|
+ INTF_DESC ( struct san_path, block, sanpath_block_op );
|
|
301
|
+
|
|
302
|
+/** SAN path process descriptor */
|
|
303
|
+static struct process_descriptor sanpath_process_desc =
|
|
304
|
+ PROC_DESC_ONCE ( struct san_path, process, sanpath_step );
|
|
305
|
+
|
|
306
|
+/**
|
|
307
|
+ * Restart SAN device interface
|
|
308
|
+ *
|
|
309
|
+ * @v sandev SAN device
|
|
310
|
+ * @v rc Reason for restart
|
|
311
|
+ */
|
|
312
|
+static void sandev_restart ( struct san_device *sandev, int rc ) {
|
|
313
|
+ struct san_path *sanpath;
|
|
314
|
+
|
|
315
|
+ /* Restart all block device interfaces */
|
|
316
|
+ while ( ( sanpath = list_first_entry ( &sandev->opened,
|
|
317
|
+ struct san_path, list ) ) ) {
|
|
318
|
+ sanpath_close ( sanpath, rc );
|
|
319
|
+ }
|
|
320
|
+
|
|
321
|
+ /* Clear active path */
|
|
322
|
+ sandev->active = NULL;
|
|
323
|
+
|
|
324
|
+ /* Close any outstanding command */
|
|
325
|
+ sandev_command_close ( sandev, rc );
|
|
326
|
+}
|
|
327
|
+
|
|
328
|
+/**
|
|
329
|
+ * (Re)open SAN device
|
|
330
|
+ *
|
|
331
|
+ * @v sandev SAN device
|
|
332
|
+ * @ret rc Return status code
|
|
333
|
+ *
|
|
334
|
+ * This function will block until the device is available.
|
|
335
|
+ */
|
|
336
|
+int sandev_reopen ( struct san_device *sandev ) {
|
|
337
|
+ struct san_path *sanpath;
|
|
338
|
+ int rc;
|
|
339
|
+
|
|
340
|
+ /* Close any outstanding command and restart interfaces */
|
|
341
|
+ sandev_restart ( sandev, -ECONNRESET );
|
|
342
|
+ assert ( sandev->active == NULL );
|
|
343
|
+ assert ( list_empty ( &sandev->opened ) );
|
|
344
|
+
|
|
345
|
+ /* Open all paths */
|
|
346
|
+ while ( ( sanpath = list_first_entry ( &sandev->closed,
|
|
347
|
+ struct san_path, list ) ) ) {
|
|
348
|
+ if ( ( rc = sanpath_open ( sanpath ) ) != 0 )
|
|
349
|
+ goto err_open;
|
|
350
|
+ }
|
|
351
|
+
|
|
352
|
+ /* Wait for any device to become available, or for all devices
|
|
353
|
+ * to fail.
|
|
354
|
+ */
|
|
355
|
+ while ( sandev->active == NULL ) {
|
|
356
|
+ step();
|
|
357
|
+ if ( list_empty ( &sandev->opened ) ) {
|
|
358
|
+ /* Get status of the first device to be
|
|
359
|
+ * closed. Do this on the basis that earlier
|
|
360
|
+ * errors (e.g. "invalid IQN") are probably
|
|
361
|
+ * more interesting than later errors
|
|
362
|
+ * (e.g. "TCP timeout").
|
|
363
|
+ */
|
|
364
|
+ rc = -ENODEV;
|
|
365
|
+ list_for_each_entry ( sanpath, &sandev->closed, list ) {
|
|
366
|
+ rc = sanpath->path_rc;
|
|
367
|
+ break;
|
|
368
|
+ }
|
|
369
|
+ DBGC ( sandev, "SAN %#02x never became available: %s\n",
|
|
370
|
+ sandev->drive, strerror ( rc ) );
|
|
371
|
+ goto err_none;
|
|
372
|
+ }
|
|
373
|
+ }
|
|
374
|
+
|
|
375
|
+ assert ( ! list_empty ( &sandev->opened ) );
|
|
376
|
+ return 0;
|
|
377
|
+
|
|
378
|
+ err_none:
|
|
379
|
+ err_open:
|
|
380
|
+ sandev_restart ( sandev, rc );
|
|
381
|
+ return rc;
|
|
382
|
+}
|
262
|
383
|
|
263
|
384
|
/** SAN device read/write command parameters */
|
264
|
385
|
struct san_command_rw_params {
|
|
@@ -289,15 +410,19 @@ union san_command_params {
|
289
|
410
|
*/
|
290
|
411
|
static int sandev_command_rw ( struct san_device *sandev,
|
291
|
412
|
const union san_command_params *params ) {
|
|
413
|
+ struct san_path *sanpath = sandev->active;
|
292
|
414
|
size_t len = ( params->rw.count * sandev->capacity.blksize );
|
293
|
415
|
int rc;
|
294
|
416
|
|
|
417
|
+ /* Sanity check */
|
|
418
|
+ assert ( sanpath != NULL );
|
|
419
|
+
|
295
|
420
|
/* Initiate read/write command */
|
296
|
|
- if ( ( rc = params->rw.block_rw ( &sandev->block, &sandev->command,
|
|
421
|
+ if ( ( rc = params->rw.block_rw ( &sanpath->block, &sandev->command,
|
297
|
422
|
params->rw.lba, params->rw.count,
|
298
|
423
|
params->rw.buffer, len ) ) != 0 ) {
|
299
|
|
- DBGC ( sandev, "SAN %#02x could not initiate read/write: "
|
300
|
|
- "%s\n", sandev->drive, strerror ( rc ) );
|
|
424
|
+ DBGC ( sandev, "SAN %#02x.%d could not initiate read/write: "
|
|
425
|
+ "%s\n", sandev->drive, sanpath->index, strerror ( rc ) );
|
301
|
426
|
return rc;
|
302
|
427
|
}
|
303
|
428
|
|
|
@@ -314,13 +439,17 @@ static int sandev_command_rw ( struct san_device *sandev,
|
314
|
439
|
static int
|
315
|
440
|
sandev_command_read_capacity ( struct san_device *sandev,
|
316
|
441
|
const union san_command_params *params __unused){
|
|
442
|
+ struct san_path *sanpath = sandev->active;
|
317
|
443
|
int rc;
|
318
|
444
|
|
|
445
|
+ /* Sanity check */
|
|
446
|
+ assert ( sanpath != NULL );
|
|
447
|
+
|
319
|
448
|
/* Initiate read capacity command */
|
320
|
|
- if ( ( rc = block_read_capacity ( &sandev->block,
|
|
449
|
+ if ( ( rc = block_read_capacity ( &sanpath->block,
|
321
|
450
|
&sandev->command ) ) != 0 ) {
|
322
|
|
- DBGC ( sandev, "SAN %#02x could not initiate read capacity: "
|
323
|
|
- "%s\n", sandev->drive, strerror ( rc ) );
|
|
451
|
+ DBGC ( sandev, "SAN %#02x.%d could not initiate read capacity: "
|
|
452
|
+ "%s\n", sandev->drive, sanpath->index, strerror ( rc ) );
|
324
|
453
|
return rc;
|
325
|
454
|
}
|
326
|
455
|
|
|
@@ -526,22 +655,41 @@ static int sandev_parse_iso9660 ( struct san_device *sandev ) {
|
526
|
655
|
/**
|
527
|
656
|
* Allocate SAN device
|
528
|
657
|
*
|
|
658
|
+ * @v uris List of URIs
|
|
659
|
+ * @v count Number of URIs
|
|
660
|
+ * @v priv_size Size of private data
|
529
|
661
|
* @ret sandev SAN device, or NULL
|
530
|
662
|
*/
|
531
|
|
-struct san_device * alloc_sandev ( struct uri *uri, size_t priv_size ) {
|
|
663
|
+struct san_device * alloc_sandev ( struct uri **uris, unsigned int count,
|
|
664
|
+ size_t priv_size ) {
|
532
|
665
|
struct san_device *sandev;
|
|
666
|
+ struct san_path *sanpath;
|
|
667
|
+ size_t size;
|
|
668
|
+ unsigned int i;
|
533
|
669
|
|
534
|
670
|
/* Allocate and initialise structure */
|
535
|
|
- sandev = zalloc ( sizeof ( *sandev ) + priv_size );
|
|
671
|
+ size = ( sizeof ( *sandev ) + ( count * sizeof ( sandev->path[0] ) ) );
|
|
672
|
+ sandev = zalloc ( size + priv_size );
|
536
|
673
|
if ( ! sandev )
|
537
|
674
|
return NULL;
|
538
|
675
|
ref_init ( &sandev->refcnt, sandev_free );
|
539
|
|
- sandev->uri = uri_get ( uri );
|
540
|
|
- intf_init ( &sandev->block, &sandev_block_desc, &sandev->refcnt );
|
541
|
|
- sandev->block_rc = -EINPROGRESS;
|
542
|
676
|
intf_init ( &sandev->command, &sandev_command_desc, &sandev->refcnt );
|
543
|
677
|
timer_init ( &sandev->timer, sandev_command_expired, &sandev->refcnt );
|
544
|
|
- sandev->priv = ( ( ( void * ) sandev ) + sizeof ( *sandev ) );
|
|
678
|
+ sandev->priv = ( ( ( void * ) sandev ) + size );
|
|
679
|
+ INIT_LIST_HEAD ( &sandev->opened );
|
|
680
|
+ INIT_LIST_HEAD ( &sandev->closed );
|
|
681
|
+ for ( i = 0 ; i < count ; i++ ) {
|
|
682
|
+ sanpath = &sandev->path[i];
|
|
683
|
+ sanpath->sandev = sandev;
|
|
684
|
+ sanpath->index = i;
|
|
685
|
+ sanpath->uri = uri_get ( uris[i] );
|
|
686
|
+ list_add_tail ( &sanpath->list, &sandev->closed );
|
|
687
|
+ intf_init ( &sanpath->block, &sanpath_block_desc,
|
|
688
|
+ &sandev->refcnt );
|
|
689
|
+ process_init_stopped ( &sanpath->process, &sanpath_process_desc,
|
|
690
|
+ &sandev->refcnt );
|
|
691
|
+ sanpath->path_rc = -EINPROGRESS;
|
|
692
|
+ }
|
545
|
693
|
|
546
|
694
|
return sandev;
|
547
|
695
|
}
|
|
@@ -588,7 +736,7 @@ void unregister_sandev ( struct san_device *sandev ) {
|
588
|
736
|
assert ( ! timer_running ( &sandev->timer ) );
|
589
|
737
|
|
590
|
738
|
/* Shut down interfaces */
|
591
|
|
- intfs_shutdown ( 0, &sandev->block, &sandev->command, NULL );
|
|
739
|
+ sandev_restart ( sandev, 0 );
|
592
|
740
|
|
593
|
741
|
/* Remove from list of SAN devices */
|
594
|
742
|
list_del ( &sandev->list );
|