Selaa lähdekoodia

[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 vuotta sitten
vanhempi
commit
bb5a54b79a

+ 14
- 6
src/arch/x86/interface/pcbios/int13.c Näytä tiedosto

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

+ 5
- 3
src/core/dummy_sanboot.c Näytä tiedosto

35
 /**
35
 /**
36
  * Hook dummy SAN device
36
  * Hook dummy SAN device
37
  *
37
  *
38
- * @v uri		URI
39
  * @v drive		Drive number
38
  * @v drive		Drive number
39
+ * @v uris		List of URIs
40
+ * @v count		Number of URIs
40
  * @ret drive		Drive number, or negative error
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
 	struct san_device *sandev;
45
 	struct san_device *sandev;
44
 	int rc;
46
 	int rc;
45
 
47
 
46
 	/* Allocate SAN device */
48
 	/* Allocate SAN device */
47
-	sandev = alloc_sandev ( uri, 0 );
49
+	sandev = alloc_sandev ( uris, count, 0 );
48
 	if ( ! sandev ) {
50
 	if ( ! sandev ) {
49
 		rc = -ENOMEM;
51
 		rc = -ENOMEM;
50
 		goto err_alloc;
52
 		goto err_alloc;

+ 3
- 2
src/core/null_sanboot.c Näytä tiedosto

26
 #include <errno.h>
26
 #include <errno.h>
27
 #include <ipxe/sanboot.h>
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
 	return -EOPNOTSUPP;
32
 	return -EOPNOTSUPP;
32
 }
33
 }
33
 
34
 

+ 221
- 73
src/core/sanboot.c Näytä tiedosto

101
 static void sandev_free ( struct refcnt *refcnt ) {
101
 static void sandev_free ( struct refcnt *refcnt ) {
102
 	struct san_device *sandev =
102
 	struct san_device *sandev =
103
 		container_of ( refcnt, struct san_device, refcnt );
103
 		container_of ( refcnt, struct san_device, refcnt );
104
+	struct san_path *sanpath;
104
 
105
 
105
 	assert ( ! timer_running ( &sandev->timer ) );
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
 	free ( sandev );
111
 	free ( sandev );
108
 }
112
 }
109
 
113
 
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
  * Handle closure of underlying block device interface
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
 	/* Any closure is an error from our point of view */
240
 	/* Any closure is an error from our point of view */
230
 	if ( rc == 0 )
241
 	if ( rc == 0 )
231
 		rc = -ENOTCONN;
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
 	/* We are never ready to receive data via this interface.
257
 	/* We are never ready to receive data via this interface.
247
 	 * This prevents objects that support both block and stream
258
 	 * This prevents objects that support both block and stream
250
 	return 0;
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
 /** SAN device read/write command parameters */
384
 /** SAN device read/write command parameters */
264
 struct san_command_rw_params {
385
 struct san_command_rw_params {
289
  */
410
  */
290
 static int sandev_command_rw ( struct san_device *sandev,
411
 static int sandev_command_rw ( struct san_device *sandev,
291
 			       const union san_command_params *params ) {
412
 			       const union san_command_params *params ) {
413
+	struct san_path *sanpath = sandev->active;
292
 	size_t len = ( params->rw.count * sandev->capacity.blksize );
414
 	size_t len = ( params->rw.count * sandev->capacity.blksize );
293
 	int rc;
415
 	int rc;
294
 
416
 
417
+	/* Sanity check */
418
+	assert ( sanpath != NULL );
419
+
295
 	/* Initiate read/write command */
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
 					  params->rw.lba, params->rw.count,
422
 					  params->rw.lba, params->rw.count,
298
 					  params->rw.buffer, len ) ) != 0 ) {
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
 		return rc;
426
 		return rc;
302
 	}
427
 	}
303
 
428
 
314
 static int
439
 static int
315
 sandev_command_read_capacity ( struct san_device *sandev,
440
 sandev_command_read_capacity ( struct san_device *sandev,
316
 			       const union san_command_params *params __unused){
441
 			       const union san_command_params *params __unused){
442
+	struct san_path *sanpath = sandev->active;
317
 	int rc;
443
 	int rc;
318
 
444
 
445
+	/* Sanity check */
446
+	assert ( sanpath != NULL );
447
+
319
 	/* Initiate read capacity command */
448
 	/* Initiate read capacity command */
320
-	if ( ( rc = block_read_capacity ( &sandev->block,
449
+	if ( ( rc = block_read_capacity ( &sanpath->block,
321
 					  &sandev->command ) ) != 0 ) {
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
 		return rc;
453
 		return rc;
325
 	}
454
 	}
326
 
455
 
526
 /**
655
 /**
527
  * Allocate SAN device
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
  * @ret sandev		SAN device, or NULL
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
 	struct san_device *sandev;
665
 	struct san_device *sandev;
666
+	struct san_path *sanpath;
667
+	size_t size;
668
+	unsigned int i;
533
 
669
 
534
 	/* Allocate and initialise structure */
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
 	if ( ! sandev )
673
 	if ( ! sandev )
537
 		return NULL;
674
 		return NULL;
538
 	ref_init ( &sandev->refcnt, sandev_free );
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
 	intf_init ( &sandev->command, &sandev_command_desc, &sandev->refcnt );
676
 	intf_init ( &sandev->command, &sandev_command_desc, &sandev->refcnt );
543
 	timer_init ( &sandev->timer, sandev_command_expired, &sandev->refcnt );
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
 	return sandev;
694
 	return sandev;
547
 }
695
 }
588
 	assert ( ! timer_running ( &sandev->timer ) );
736
 	assert ( ! timer_running ( &sandev->timer ) );
589
 
737
 
590
 	/* Shut down interfaces */
738
 	/* Shut down interfaces */
591
-	intfs_shutdown ( 0, &sandev->block, &sandev->command, NULL );
739
+	sandev_restart ( sandev, 0 );
592
 
740
 
593
 	/* Remove from list of SAN devices */
741
 	/* Remove from list of SAN devices */
594
 	list_del ( &sandev->list );
742
 	list_del ( &sandev->list );

+ 15
- 15
src/hci/commands/sanboot_cmd.c Näytä tiedosto

71
 
71
 
72
 /** "sanhook" command descriptor */
72
 /** "sanhook" command descriptor */
73
 static struct command_descriptor sanhook_cmd =
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
 		       "<root-path>" );
75
 		       "<root-path>" );
76
 
76
 
77
 /** "sanboot" command descriptor */
77
 /** "sanboot" command descriptor */
78
 static struct command_descriptor sanboot_cmd =
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
 		       "[<root-path>]" );
80
 		       "[<root-path>]" );
81
 
81
 
82
 /** "sanunhook" command descriptor */
82
 /** "sanunhook" command descriptor */
96
 			       struct command_descriptor *cmd,
96
 			       struct command_descriptor *cmd,
97
 			       int default_flags, int no_root_path_flags ) {
97
 			       int default_flags, int no_root_path_flags ) {
98
 	struct sanboot_options opts;
98
 	struct sanboot_options opts;
99
-	const char *root_path;
100
-	struct uri *uri;
99
+	struct uri *uris[argc];
100
+	int count;
101
 	int flags;
101
 	int flags;
102
+	int i;
102
 	int rc;
103
 	int rc;
103
 
104
 
104
 	/* Initialise options */
105
 	/* Initialise options */
109
 	if ( ( rc = reparse_options ( argc, argv, cmd, &opts ) ) != 0 )
110
 	if ( ( rc = reparse_options ( argc, argv, cmd, &opts ) ) != 0 )
110
 		goto err_parse_options;
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
 			rc = -ENOMEM;
118
 			rc = -ENOMEM;
118
 			goto err_parse_uri;
119
 			goto err_parse_uri;
119
 		}
120
 		}
120
-	} else {
121
-		root_path = NULL;
122
-		uri = NULL;
123
 	}
121
 	}
124
 
122
 
125
 	/* Construct flags */
123
 	/* Construct flags */
128
 		flags |= URIBOOT_NO_SAN_DESCRIBE;
126
 		flags |= URIBOOT_NO_SAN_DESCRIBE;
129
 	if ( opts.keep )
127
 	if ( opts.keep )
130
 		flags |= URIBOOT_NO_SAN_UNHOOK;
128
 		flags |= URIBOOT_NO_SAN_UNHOOK;
131
-	if ( ! root_path )
129
+	if ( ! count )
132
 		flags |= no_root_path_flags;
130
 		flags |= no_root_path_flags;
133
 
131
 
134
 	/* Boot from root path */
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
 		goto err_uriboot;
134
 		goto err_uriboot;
137
 
135
 
138
  err_uriboot:
136
  err_uriboot:
139
-	uri_put ( uri );
137
+	i = count;
140
  err_parse_uri:
138
  err_parse_uri:
139
+	for ( i-- ; i >= 0 ; i-- )
140
+		uri_put ( uris[i] );
141
  err_parse_options:
141
  err_parse_options:
142
 	return rc;
142
 	return rc;
143
 }
143
 }

+ 35
- 11
src/include/ipxe/sanboot.h Näytä tiedosto

16
 #include <ipxe/list.h>
16
 #include <ipxe/list.h>
17
 #include <ipxe/uri.h>
17
 #include <ipxe/uri.h>
18
 #include <ipxe/retry.h>
18
 #include <ipxe/retry.h>
19
+#include <ipxe/process.h>
19
 #include <ipxe/blockdev.h>
20
 #include <ipxe/blockdev.h>
20
 #include <config/sanboot.h>
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
 /** A SAN device */
42
 /** A SAN device */
23
 struct san_device {
43
 struct san_device {
24
 	/** Reference count */
44
 	/** Reference count */
26
 	/** List of SAN devices */
46
 	/** List of SAN devices */
27
 	struct list_head list;
47
 	struct list_head list;
28
 
48
 
29
-	/** SAN device URI */
30
-	struct uri *uri;
31
 	/** Drive number */
49
 	/** Drive number */
32
 	unsigned int drive;
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
 	/** Command interface */
52
 	/** Command interface */
40
 	struct interface command;
53
 	struct interface command;
41
 	/** Command timeout timer */
54
 	/** Command timeout timer */
57
 
70
 
58
 	/** Driver private data */
71
 	/** Driver private data */
59
 	void *priv;
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
 /**
121
 /**
100
  * Hook SAN device
122
  * Hook SAN device
101
  *
123
  *
102
- * @v uri		URI
103
  * @v drive		Drive number
124
  * @v drive		Drive number
125
+ * @v uris		List of URIs
126
+ * @v count		Number of URIs
104
  * @ret drive		Drive number, or negative error
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
  * Unhook SAN device
132
  * Unhook SAN device
191
  * @ret needs_reopen	SAN device needs to be reopened
214
  * @ret needs_reopen	SAN device needs to be reopened
192
  */
215
  */
193
 static inline int sandev_needs_reopen ( struct san_device *sandev ) {
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
 extern struct san_device * sandev_find ( unsigned int drive );
220
 extern struct san_device * sandev_find ( unsigned int drive );
203
 					    struct interface *data,
226
 					    struct interface *data,
204
 					    uint64_t lba, unsigned int count,
227
 					    uint64_t lba, unsigned int count,
205
 					    userptr_t buffer, size_t len ) );
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
 extern int register_sandev ( struct san_device *sandev );
231
 extern int register_sandev ( struct san_device *sandev );
208
 extern void unregister_sandev ( struct san_device *sandev );
232
 extern void unregister_sandev ( struct san_device *sandev );
209
 extern unsigned int san_default_drive ( void );
233
 extern unsigned int san_default_drive ( void );

+ 2
- 1
src/include/usr/autoboot.h Näytä tiedosto

30
 				  unsigned int location );
30
 				  unsigned int location );
31
 extern void set_autoboot_ll_addr ( const void *ll_addr, size_t len );
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
 		     unsigned int flags );
35
 		     unsigned int flags );
35
 extern struct uri *
36
 extern struct uri *
36
 fetch_next_server_and_filename ( struct settings *settings );
37
 fetch_next_server_and_filename ( struct settings *settings );

+ 19
- 6
src/interface/efi/efi_block.c Näytä tiedosto

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

+ 8
- 6
src/usr/autoboot.c Näytä tiedosto

109
  * Boot from filename and root-path URIs
109
  * Boot from filename and root-path URIs
110
  *
110
  *
111
  * @v filename		Filename
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
  * @v drive		SAN drive (if applicable)
114
  * @v drive		SAN drive (if applicable)
114
  * @v flags		Boot action flags
115
  * @v flags		Boot action flags
115
  * @ret rc		Return status code
116
  * @ret rc		Return status code
120
  * provide backwards compatibility for the "keep-san" and
121
  * provide backwards compatibility for the "keep-san" and
121
  * "skip-san-boot" options.
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
 	struct image *image;
126
 	struct image *image;
126
 	int rc;
127
 	int rc;
127
 
128
 
128
 	/* Hook SAN device, if applicable */
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
 		if ( drive < 0 ) {
132
 		if ( drive < 0 ) {
132
 			rc = drive;
133
 			rc = drive;
133
 			printf ( "Could not open SAN device: %s\n",
134
 			printf ( "Could not open SAN device: %s\n",
396
 	}
397
 	}
397
 
398
 
398
 	/* Boot using next server, filename and root path */
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
 			      ( root_path ? 0 : URIBOOT_NO_SAN ) ) ) != 0 )
402
 			      ( root_path ? 0 : URIBOOT_NO_SAN ) ) ) != 0 )
401
 		goto err_uriboot;
403
 		goto err_uriboot;
402
 
404
 

+ 1
- 1
src/usr/pxemenu.c Näytä tiedosto

378
 		return -ENOMEM;
378
 		return -ENOMEM;
379
 
379
 
380
 	/* Attempt boot */
380
 	/* Attempt boot */
381
-	rc = uriboot ( uri, NULL, 0, URIBOOT_NO_SAN );
381
+	rc = uriboot ( uri, NULL, 0, 0, URIBOOT_NO_SAN );
382
 	uri_put ( uri );
382
 	uri_put ( uri );
383
 	return rc;
383
 	return rc;
384
 }
384
 }

Loading…
Peruuta
Tallenna