Преглед на файлове

[block] Retry any SAN device operation

The SCSI layer currently implements a retry loop in order to retry
commands that fail due to spurious "error" conditions such as "power
on occurred".  Move this retry loop to the generic SAN device layer:
this allow for retries due to other transient error conditions such as
an iSCSI target having dropped the connection due to inactivity.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown преди 7 години
родител
ревизия
d9886f1961
променени са 2 файла, в които са добавени 36 реда и са изтрити 43 реда
  1. 35
    19
      src/core/sanboot.c
  2. 1
    24
      src/drivers/block/scsi.c

+ 35
- 19
src/core/sanboot.c Целия файл

@@ -64,6 +64,16 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
64 64
  */
65 65
 #define SAN_COMMAND_TIMEOUT ( 15 * TICKS_PER_SEC )
66 66
 
67
+/**
68
+ * Number of times to retry commands
69
+ *
70
+ * We may need to retry commands.  For example, the underlying
71
+ * connection may be closed by the SAN target due to an inactivity
72
+ * timeout, or the SAN target may return pointless "error" messages
73
+ * such as "SCSI power-on occurred".
74
+ */
75
+#define SAN_COMMAND_MAX_RETRIES 10
76
+
67 77
 /** List of SAN devices */
68 78
 LIST_HEAD ( san_devices );
69 79
 
@@ -331,36 +341,42 @@ sandev_command ( struct san_device *sandev,
331 341
 		 int ( * command ) ( struct san_device *sandev,
332 342
 				     const union san_command_params *params ),
333 343
 		 const union san_command_params *params ) {
344
+	unsigned int retries;
334 345
 	int rc;
335 346
 
336 347
 	/* Sanity check */
337 348
 	assert ( ! timer_running ( &sandev->timer ) );
338 349
 
339
-	/* Reopen block device if applicable */
340
-	if ( sandev_needs_reopen ( sandev ) &&
341
-	     ( ( rc = sandev_reopen ( sandev ) ) != 0 ) ) {
342
-	     goto err_reopen;
343
-	}
350
+	/* (Re)try command */
351
+	for ( retries = 0 ; retries < SAN_COMMAND_MAX_RETRIES ; retries++ ) {
344 352
 
345
-	/* Start expiry timer */
346
-	start_timer_fixed ( &sandev->timer, SAN_COMMAND_TIMEOUT );
353
+		/* Reopen block device if applicable */
354
+		if ( sandev_needs_reopen ( sandev ) &&
355
+		     ( ( rc = sandev_reopen ( sandev ) ) != 0 ) ) {
356
+			continue;
357
+		}
347 358
 
348
-	/* Initiate command */
349
-	if ( ( rc = command ( sandev, params ) ) != 0 )
350
-		goto err_op;
359
+		/* Start expiry timer */
360
+		start_timer_fixed ( &sandev->timer, SAN_COMMAND_TIMEOUT );
351 361
 
352
-	/* Wait for command to complete */
353
-	while ( timer_running ( &sandev->timer ) )
354
-		step();
362
+		/* Initiate command */
363
+		if ( ( rc = command ( sandev, params ) ) != 0 ) {
364
+			stop_timer ( &sandev->timer );
365
+			continue;
366
+		}
355 367
 
356
-	/* Collect return status */
357
-	rc = sandev->command_rc;
368
+		/* Wait for command to complete */
369
+		while ( timer_running ( &sandev->timer ) )
370
+			step();
358 371
 
359
-	return rc;
372
+		/* Exit on success */
373
+		if ( ( rc = sandev->command_rc ) == 0 )
374
+			return 0;
375
+	}
376
+
377
+	/* Sanity check */
378
+	assert ( ! timer_running ( &sandev->timer ) );
360 379
 
361
- err_op:
362
-	stop_timer ( &sandev->timer );
363
- err_reopen:
364 380
 	return rc;
365 381
 }
366 382
 

+ 1
- 24
src/drivers/block/scsi.c Целия файл

@@ -40,9 +40,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
40 40
  *
41 41
  */
42 42
 
43
-/** Maximum number of command retries */
44
-#define SCSICMD_MAX_RETRIES 10
45
-
46 43
 /* Error numbers generated by SCSI sense data */
47 44
 #define EIO_NO_SENSE __einfo_error ( EINFO_EIO_NO_SENSE )
48 45
 #define EINFO_EIO_NO_SENSE \
@@ -283,9 +280,6 @@ struct scsi_command {
283 280
 	/** Command tag */
284 281
 	uint32_t tag;
285 282
 
286
-	/** Retry count */
287
-	unsigned int retries;
288
-
289 283
 	/** Private data */
290 284
 	uint8_t priv[0];
291 285
 };
@@ -449,28 +443,11 @@ static int scsicmd_command ( struct scsi_command *scsicmd ) {
449 443
  * @v rc		Reason for close
450 444
  */
451 445
 static void scsicmd_done ( struct scsi_command *scsicmd, int rc ) {
452
-	struct scsi_device *scsidev = scsicmd->scsidev;
453 446
 
454 447
 	/* Restart SCSI interface */
455 448
 	intf_restart ( &scsicmd->scsi, rc );
456 449
 
457
-	/* SCSI targets have an annoying habit of returning occasional
458
-	 * pointless "error" messages such as "power-on occurred", so
459
-	 * we have to be prepared to retry commands.
460
-	 */
461
-	if ( ( rc != 0 ) && ( scsicmd->retries++ < SCSICMD_MAX_RETRIES ) ) {
462
-		/* Retry command */
463
-		DBGC ( scsidev, "SCSI %p tag %08x failed: %s\n",
464
-		       scsidev, scsicmd->tag, strerror ( rc ) );
465
-		DBGC ( scsidev, "SCSI %p tag %08x retrying (retry %d)\n",
466
-		       scsidev, scsicmd->tag, scsicmd->retries );
467
-		if ( ( rc = scsicmd_command ( scsicmd ) ) == 0 )
468
-			return;
469
-	}
470
-
471
-	/* If we didn't (successfully) reissue the command, hand over
472
-	 * to the command completion handler.
473
-	 */
450
+	/* Hand over to the command completion handler */
474 451
 	scsicmd->type->done ( scsicmd, rc );
475 452
 }
476 453
 

Loading…
Отказ
Запис