Browse Source

[block] Add basic multipath support

Add basic support for multipath block devices.  The "sanboot" and
"sanhook" commands now accept a list of SAN URIs.  We open all URIs
concurrently.  The first connection to become available for issuing
block device commands is marked as the active path and used for all
subsequent commands; all other connections are then closed.  Whenever
the active path fails, we reopen all URIs and repeat the process.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 7 years ago
parent
commit
bb5a54b79a

+ 14
- 6
src/arch/x86/interface/pcbios/int13.c View File

@@ -833,6 +833,7 @@ static int int13_extended_seek ( struct san_device *sandev,
833 833
  */
834 834
 static int int13_device_path_info ( struct san_device *sandev,
835 835
 				    struct edd_device_path_information *dpi ) {
836
+	struct san_path *sanpath;
836 837
 	struct device *device;
837 838
 	struct device_description *desc;
838 839
 	unsigned int i;
@@ -843,9 +844,11 @@ static int int13_device_path_info ( struct san_device *sandev,
843 844
 	if ( sandev_needs_reopen ( sandev ) &&
844 845
 	     ( ( rc = sandev_reopen ( sandev ) ) != 0 ) )
845 846
 		return rc;
847
+	sanpath = sandev->active;
848
+	assert ( sanpath != NULL );
846 849
 
847 850
 	/* Get underlying hardware device */
848
-	device = identify_device ( &sandev->block );
851
+	device = identify_device ( &sanpath->block );
849 852
 	if ( ! device ) {
850 853
 		DBGC ( sandev, "INT13 drive %02x cannot identify hardware "
851 854
 		       "device\n", sandev->drive );
@@ -869,7 +872,7 @@ static int int13_device_path_info ( struct san_device *sandev,
869 872
 	}
870 873
 
871 874
 	/* Get EDD block device description */
872
-	if ( ( rc = edd_describe ( &sandev->block, &dpi->interface_type,
875
+	if ( ( rc = edd_describe ( &sanpath->block, &dpi->interface_type,
873 876
 				   &dpi->device_path ) ) != 0 ) {
874 877
 		DBGC ( sandev, "INT13 drive %02x cannot identify block device: "
875 878
 		       "%s\n", sandev->drive, strerror ( rc ) );
@@ -1199,14 +1202,16 @@ static void int13_unhook_vector ( void ) {
1199 1202
 /**
1200 1203
  * Hook INT 13 SAN device
1201 1204
  *
1202
- * @v uri		URI
1203 1205
  * @v drive		Drive number
1206
+ * @v uris		List of URIs
1207
+ * @v count		Number of URIs
1204 1208
  * @ret drive		Drive number, or negative error
1205 1209
  *
1206 1210
  * Registers the drive with the INT 13 emulation subsystem, and hooks
1207 1211
  * the INT 13 interrupt vector (if not already hooked).
1208 1212
  */
1209
-static int int13_hook ( struct uri *uri, unsigned int drive ) {
1213
+static int int13_hook ( unsigned int drive, struct uri **uris,
1214
+			unsigned int count ) {
1210 1215
 	struct san_device *sandev;
1211 1216
 	struct int13_data *int13;
1212 1217
 	unsigned int natural_drive;
@@ -1223,7 +1228,7 @@ static int int13_hook ( struct uri *uri, unsigned int drive ) {
1223 1228
 		drive = natural_drive;
1224 1229
 
1225 1230
 	/* Allocate SAN device */
1226
-	sandev = alloc_sandev ( uri, sizeof ( *int13 ) );
1231
+	sandev = alloc_sandev ( uris, count, sizeof ( *int13 ) );
1227 1232
 	if ( ! sandev ) {
1228 1233
 		rc = -ENOMEM;
1229 1234
 		goto err_alloc;
@@ -1525,6 +1530,7 @@ static union xbft_table __bss16 ( xbftab ) __attribute__ (( aligned ( 16 ) ));
1525 1530
  */
1526 1531
 static int int13_describe ( unsigned int drive ) {
1527 1532
 	struct san_device *sandev;
1533
+	struct san_path *sanpath;
1528 1534
 	struct segoff xbft_address;
1529 1535
 	int rc;
1530 1536
 
@@ -1539,6 +1545,8 @@ static int int13_describe ( unsigned int drive ) {
1539 1545
 	if ( sandev_needs_reopen ( sandev ) &&
1540 1546
 	     ( ( rc = sandev_reopen ( sandev ) ) != 0 ) )
1541 1547
 		return rc;
1548
+	sanpath = sandev->active;
1549
+	assert ( sanpath != NULL );
1542 1550
 
1543 1551
 	/* Clear table */
1544 1552
 	memset ( &xbftab, 0, sizeof ( xbftab ) );
@@ -1550,7 +1558,7 @@ static int int13_describe ( unsigned int drive ) {
1550 1558
 		  sizeof ( xbftab.acpi.oem_table_id ) );
1551 1559
 
1552 1560
 	/* Fill in remaining parameters */
1553
-	if ( ( rc = acpi_describe ( &sandev->block, &xbftab.acpi,
1561
+	if ( ( rc = acpi_describe ( &sanpath->block, &xbftab.acpi,
1554 1562
 				    sizeof ( xbftab ) ) ) != 0 ) {
1555 1563
 		DBGC ( sandev, "INT13 drive %02x could not create ACPI "
1556 1564
 		       "description: %s\n", sandev->drive, strerror ( rc ) );

+ 5
- 3
src/core/dummy_sanboot.c View File

@@ -35,16 +35,18 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
35 35
 /**
36 36
  * Hook dummy SAN device
37 37
  *
38
- * @v uri		URI
39 38
  * @v drive		Drive number
39
+ * @v uris		List of URIs
40
+ * @v count		Number of URIs
40 41
  * @ret drive		Drive number, or negative error
41 42
  */
42
-static int dummy_san_hook ( struct uri *uri, unsigned int drive ) {
43
+static int dummy_san_hook ( unsigned int drive, struct uri **uris,
44
+			    unsigned int count ) {
43 45
 	struct san_device *sandev;
44 46
 	int rc;
45 47
 
46 48
 	/* Allocate SAN device */
47
-	sandev = alloc_sandev ( uri, 0 );
49
+	sandev = alloc_sandev ( uris, count, 0 );
48 50
 	if ( ! sandev ) {
49 51
 		rc = -ENOMEM;
50 52
 		goto err_alloc;

+ 3
- 2
src/core/null_sanboot.c View File

@@ -26,8 +26,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
26 26
 #include <errno.h>
27 27
 #include <ipxe/sanboot.h>
28 28
 
29
-static int null_san_hook ( struct uri *uri __unused,
30
-			   unsigned int drive __unused ) {
29
+static int null_san_hook ( unsigned int drive __unused,
30
+			   struct uri **uris __unused,
31
+			   unsigned int count __unused ) {
31 32
 	return -EOPNOTSUPP;
32 33
 }
33 34
 

+ 221
- 73
src/core/sanboot.c View File

@@ -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 );

+ 15
- 15
src/hci/commands/sanboot_cmd.c View File

@@ -71,12 +71,12 @@ static union {
71 71
 
72 72
 /** "sanhook" command descriptor */
73 73
 static struct command_descriptor sanhook_cmd =
74
-	COMMAND_DESC ( struct sanboot_options, opts.sanhook, 1, 1,
74
+	COMMAND_DESC ( struct sanboot_options, opts.sanhook, 1, MAX_ARGUMENTS,
75 75
 		       "<root-path>" );
76 76
 
77 77
 /** "sanboot" command descriptor */
78 78
 static struct command_descriptor sanboot_cmd =
79
-	COMMAND_DESC ( struct sanboot_options, opts.sanboot, 0, 1,
79
+	COMMAND_DESC ( struct sanboot_options, opts.sanboot, 0, MAX_ARGUMENTS,
80 80
 		       "[<root-path>]" );
81 81
 
82 82
 /** "sanunhook" command descriptor */
@@ -96,9 +96,10 @@ static int sanboot_core_exec ( int argc, char **argv,
96 96
 			       struct command_descriptor *cmd,
97 97
 			       int default_flags, int no_root_path_flags ) {
98 98
 	struct sanboot_options opts;
99
-	const char *root_path;
100
-	struct uri *uri;
99
+	struct uri *uris[argc];
100
+	int count;
101 101
 	int flags;
102
+	int i;
102 103
 	int rc;
103 104
 
104 105
 	/* Initialise options */
@@ -109,17 +110,14 @@ static int sanboot_core_exec ( int argc, char **argv,
109 110
 	if ( ( rc = reparse_options ( argc, argv, cmd, &opts ) ) != 0 )
110 111
 		goto err_parse_options;
111 112
 
112
-	/* Parse root path, if present */
113
-	if ( argc > optind ) {
114
-		root_path = argv[optind];
115
-		uri = parse_uri ( root_path );
116
-		if ( ! uri ) {
113
+	/* Parse root paths, if present */
114
+	count = ( argc - optind );
115
+	for ( i = 0 ; i < count ; i++ ) {
116
+		uris[i] = parse_uri ( argv[ optind + i ] );
117
+		if ( ! uris[i] ) {
117 118
 			rc = -ENOMEM;
118 119
 			goto err_parse_uri;
119 120
 		}
120
-	} else {
121
-		root_path = NULL;
122
-		uri = NULL;
123 121
 	}
124 122
 
125 123
 	/* Construct flags */
@@ -128,16 +126,18 @@ static int sanboot_core_exec ( int argc, char **argv,
128 126
 		flags |= URIBOOT_NO_SAN_DESCRIBE;
129 127
 	if ( opts.keep )
130 128
 		flags |= URIBOOT_NO_SAN_UNHOOK;
131
-	if ( ! root_path )
129
+	if ( ! count )
132 130
 		flags |= no_root_path_flags;
133 131
 
134 132
 	/* Boot from root path */
135
-	if ( ( rc = uriboot ( NULL, uri, opts.drive, flags ) ) != 0 )
133
+	if ( ( rc = uriboot ( NULL, uris, count, opts.drive, flags ) ) != 0 )
136 134
 		goto err_uriboot;
137 135
 
138 136
  err_uriboot:
139
-	uri_put ( uri );
137
+	i = count;
140 138
  err_parse_uri:
139
+	for ( i-- ; i >= 0 ; i-- )
140
+		uri_put ( uris[i] );
141 141
  err_parse_options:
142 142
 	return rc;
143 143
 }

+ 35
- 11
src/include/ipxe/sanboot.h View File

@@ -16,9 +16,29 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
16 16
 #include <ipxe/list.h>
17 17
 #include <ipxe/uri.h>
18 18
 #include <ipxe/retry.h>
19
+#include <ipxe/process.h>
19 20
 #include <ipxe/blockdev.h>
20 21
 #include <config/sanboot.h>
21 22
 
23
+/** A SAN path */
24
+struct san_path {
25
+	/** Containing SAN device */
26
+	struct san_device *sandev;
27
+	/** Path index */
28
+	unsigned int index;
29
+	/** SAN device URI */
30
+	struct uri *uri;
31
+	/** List of open/closed paths */
32
+	struct list_head list;
33
+
34
+	/** Underlying block device interface */
35
+	struct interface block;
36
+	/** Process */
37
+	struct process process;
38
+	/** Path status */
39
+	int path_rc;
40
+};
41
+
22 42
 /** A SAN device */
23 43
 struct san_device {
24 44
 	/** Reference count */
@@ -26,16 +46,9 @@ struct san_device {
26 46
 	/** List of SAN devices */
27 47
 	struct list_head list;
28 48
 
29
-	/** SAN device URI */
30
-	struct uri *uri;
31 49
 	/** Drive number */
32 50
 	unsigned int drive;
33 51
 
34
-	/** Underlying block device interface */
35
-	struct interface block;
36
-	/** Current device status */
37
-	int block_rc;
38
-
39 52
 	/** Command interface */
40 53
 	struct interface command;
41 54
 	/** Command timeout timer */
@@ -57,6 +70,15 @@ struct san_device {
57 70
 
58 71
 	/** Driver private data */
59 72
 	void *priv;
73
+
74
+	/** Current active path */
75
+	struct san_path *active;
76
+	/** List of opened SAN paths */
77
+	struct list_head opened;
78
+	/** List of closed SAN paths */
79
+	struct list_head closed;
80
+	/** SAN paths */
81
+	struct san_path path[0];
60 82
 };
61 83
 
62 84
 /**
@@ -99,11 +121,12 @@ struct san_device {
99 121
 /**
100 122
  * Hook SAN device
101 123
  *
102
- * @v uri		URI
103 124
  * @v drive		Drive number
125
+ * @v uris		List of URIs
126
+ * @v count		Number of URIs
104 127
  * @ret drive		Drive number, or negative error
105 128
  */
106
-int san_hook ( struct uri *uri, unsigned int drive );
129
+int san_hook ( unsigned int drive, struct uri **uris, unsigned int count );
107 130
 
108 131
 /**
109 132
  * Unhook SAN device
@@ -191,7 +214,7 @@ static inline uint64_t sandev_capacity ( struct san_device *sandev ) {
191 214
  * @ret needs_reopen	SAN device needs to be reopened
192 215
  */
193 216
 static inline int sandev_needs_reopen ( struct san_device *sandev ) {
194
-	return ( sandev->block_rc != 0 );
217
+	return ( sandev->active == NULL );
195 218
 }
196 219
 
197 220
 extern struct san_device * sandev_find ( unsigned int drive );
@@ -203,7 +226,8 @@ extern int sandev_rw ( struct san_device *sandev, uint64_t lba,
203 226
 					    struct interface *data,
204 227
 					    uint64_t lba, unsigned int count,
205 228
 					    userptr_t buffer, size_t len ) );
206
-extern struct san_device * alloc_sandev ( struct uri *uri, size_t priv_size );
229
+extern struct san_device * alloc_sandev ( struct uri **uris, unsigned int count,
230
+					  size_t priv_size );
207 231
 extern int register_sandev ( struct san_device *sandev );
208 232
 extern void unregister_sandev ( struct san_device *sandev );
209 233
 extern unsigned int san_default_drive ( void );

+ 2
- 1
src/include/usr/autoboot.h View File

@@ -30,7 +30,8 @@ extern void set_autoboot_busloc ( unsigned int bus_type,
30 30
 				  unsigned int location );
31 31
 extern void set_autoboot_ll_addr ( const void *ll_addr, size_t len );
32 32
 
33
-extern int uriboot ( struct uri *filename, struct uri *root_path, int drive,
33
+extern int uriboot ( struct uri *filename, struct uri **root_paths,
34
+		     unsigned int root_path_count, int drive,
34 35
 		     unsigned int flags );
35 36
 extern struct uri *
36 37
 fetch_next_server_and_filename ( struct settings *settings );

+ 19
- 6
src/interface/efi/efi_block.c View File

@@ -251,11 +251,13 @@ static void efi_block_connect ( struct san_device *sandev ) {
251 251
 /**
252 252
  * Hook EFI block device
253 253
  *
254
- * @v uri		URI
255 254
  * @v drive		Drive number
255
+ * @v uris		List of URIs
256
+ * @v count		Number of URIs
256 257
  * @ret drive		Drive number, or negative error
257 258
  */
258
-static int efi_block_hook ( struct uri *uri, unsigned int drive ) {
259
+static int efi_block_hook ( unsigned int drive, struct uri **uris,
260
+			    unsigned int count ) {
259 261
 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
260 262
 	EFI_DEVICE_PATH_PROTOCOL *end;
261 263
 	struct efi_block_vendor_path *vendor;
@@ -270,6 +272,13 @@ static int efi_block_hook ( struct uri *uri, unsigned int drive ) {
270 272
 	EFI_STATUS efirc;
271 273
 	int rc;
272 274
 
275
+	/* Sanity check */
276
+	if ( ! count ) {
277
+		DBG ( "EFIBLK has no URIs\n" );
278
+		rc = -ENOTTY;
279
+		goto err_no_uris;
280
+	}
281
+
273 282
 	/* Find an appropriate parent device handle */
274 283
 	snpdev = last_opened_snpdev();
275 284
 	if ( ! snpdev ) {
@@ -280,14 +289,14 @@ static int efi_block_hook ( struct uri *uri, unsigned int drive ) {
280 289
 
281 290
 	/* Calculate length of private data */
282 291
 	prefix_len = efi_devpath_len ( snpdev->path );
283
-	uri_len = format_uri ( uri, NULL, 0 );
292
+	uri_len = format_uri ( uris[0], NULL, 0 );
284 293
 	vendor_len = ( sizeof ( *vendor ) +
285 294
 		       ( ( uri_len + 1 /* NUL */ ) * sizeof ( wchar_t ) ) );
286 295
 	len = ( sizeof ( *block ) + uri_len + 1 /* NUL */ + prefix_len +
287 296
 		vendor_len + sizeof ( *end ) );
288 297
 
289 298
 	/* Allocate and initialise structure */
290
-	sandev = alloc_sandev ( uri, len );
299
+	sandev = alloc_sandev ( uris, count, len );
291 300
 	if ( ! sandev ) {
292 301
 		rc = -ENOMEM;
293 302
 		goto err_alloc;
@@ -315,7 +324,7 @@ static int efi_block_hook ( struct uri *uri, unsigned int drive ) {
315 324
 	vendor->vendor.Header.Length[1] = ( vendor_len >> 8 );
316 325
 	memcpy ( &vendor->vendor.Guid, &ipxe_block_device_path_guid,
317 326
 		 sizeof ( vendor->vendor.Guid ) );
318
-	format_uri ( uri, uri_buf, ( uri_len + 1 /* NUL */ ) );
327
+	format_uri ( uris[0], uri_buf, ( uri_len + 1 /* NUL */ ) );
319 328
 	efi_snprintf ( vendor->uri, ( uri_len + 1 /* NUL */ ), "%s", uri_buf );
320 329
 	end = ( ( ( void * ) vendor ) + vendor_len );
321 330
 	end->Type = END_DEVICE_PATH_TYPE;
@@ -364,6 +373,7 @@ static int efi_block_hook ( struct uri *uri, unsigned int drive ) {
364 373
 	sandev_put ( sandev );
365 374
  err_alloc:
366 375
  err_no_snpdev:
376
+ err_no_uris:
367 377
 	return rc;
368 378
 }
369 379
 
@@ -413,6 +423,7 @@ static int efi_block_describe ( unsigned int drive ) {
413 423
 	} xbftab;
414 424
 	static UINTN key;
415 425
 	struct san_device *sandev;
426
+	struct san_path *sanpath;
416 427
 	size_t len;
417 428
 	EFI_STATUS efirc;
418 429
 	int rc;
@@ -446,6 +457,8 @@ static int efi_block_describe ( unsigned int drive ) {
446 457
 	if ( sandev_needs_reopen ( sandev ) &&
447 458
 	     ( ( rc = sandev_reopen ( sandev ) ) != 0 ) )
448 459
 		return rc;
460
+	sanpath = sandev->active;
461
+	assert ( sanpath != NULL );
449 462
 
450 463
 	/* Clear table */
451 464
 	memset ( &xbftab, 0, sizeof ( xbftab ) );
@@ -457,7 +470,7 @@ static int efi_block_describe ( unsigned int drive ) {
457 470
 		  sizeof ( xbftab.acpi.oem_table_id ) );
458 471
 
459 472
 	/* Fill in remaining parameters */
460
-	if ( ( rc = acpi_describe ( &sandev->block, &xbftab.acpi,
473
+	if ( ( rc = acpi_describe ( &sanpath->block, &xbftab.acpi,
461 474
 				    sizeof ( xbftab ) ) ) != 0 ) {
462 475
 		DBGC ( sandev, "EFIBLK %#02x could not create ACPI "
463 476
 		       "description: %s\n", sandev->drive, strerror ( rc ) );

+ 8
- 6
src/usr/autoboot.c View File

@@ -109,7 +109,8 @@ const struct setting skip_san_boot_setting __setting ( SETTING_SANBOOT_EXTRA,
109 109
  * Boot from filename and root-path URIs
110 110
  *
111 111
  * @v filename		Filename
112
- * @v root_path		Root path
112
+ * @v root_paths	Root path(s)
113
+ * @v root_path_count	Number of root paths
113 114
  * @v drive		SAN drive (if applicable)
114 115
  * @v flags		Boot action flags
115 116
  * @ret rc		Return status code
@@ -120,14 +121,14 @@ const struct setting skip_san_boot_setting __setting ( SETTING_SANBOOT_EXTRA,
120 121
  * provide backwards compatibility for the "keep-san" and
121 122
  * "skip-san-boot" options.
122 123
  */
123
-int uriboot ( struct uri *filename, struct uri *root_path, int drive,
124
-	      unsigned int flags ) {
124
+int uriboot ( struct uri *filename, struct uri **root_paths,
125
+	      unsigned int root_path_count, int drive, unsigned int flags ) {
125 126
 	struct image *image;
126 127
 	int rc;
127 128
 
128 129
 	/* Hook SAN device, if applicable */
129
-	if ( root_path ) {
130
-		drive = san_hook ( root_path, drive );
130
+	if ( root_path_count ) {
131
+		drive = san_hook ( drive, root_paths, root_path_count );
131 132
 		if ( drive < 0 ) {
132 133
 			rc = drive;
133 134
 			printf ( "Could not open SAN device: %s\n",
@@ -396,7 +397,8 @@ int netboot ( struct net_device *netdev ) {
396 397
 	}
397 398
 
398 399
 	/* Boot using next server, filename and root path */
399
-	if ( ( rc = uriboot ( filename, root_path, san_default_drive(),
400
+	if ( ( rc = uriboot ( filename, &root_path, ( root_path ? 1 : 0 ),
401
+			      san_default_drive(),
400 402
 			      ( root_path ? 0 : URIBOOT_NO_SAN ) ) ) != 0 )
401 403
 		goto err_uriboot;
402 404
 

+ 1
- 1
src/usr/pxemenu.c View File

@@ -378,7 +378,7 @@ int pxe_menu_boot ( struct net_device *netdev ) {
378 378
 		return -ENOMEM;
379 379
 
380 380
 	/* Attempt boot */
381
-	rc = uriboot ( uri, NULL, 0, URIBOOT_NO_SAN );
381
+	rc = uriboot ( uri, NULL, 0, 0, URIBOOT_NO_SAN );
382 382
 	uri_put ( uri );
383 383
 	return rc;
384 384
 }

Loading…
Cancel
Save