Browse Source

Everything except the SCSI interface should now be present

tags/v0.9.3
Michael Brown 17 years ago
parent
commit
f2fa390ae6
2 changed files with 276 additions and 44 deletions
  1. 2
    6
      src/include/gpxe/iscsi.h
  2. 274
    38
      src/net/tcp/iscsi.c

+ 2
- 6
src/include/gpxe/iscsi.h View File

@@ -493,18 +493,14 @@ struct iscsi_session {
493 493
 	/** Transport-layer socket */
494 494
 	struct xfer_interface socket;
495 495
 
496
-	/** Initiator IQN */
497
-	char *initiator_iqn;
498 496
 	/** Target address */
499 497
 	char *target_address;
498
+	/** Target port */
499
+	unsigned int target_port;
500 500
 	/** Target IQN */
501 501
 	char *target_iqn;
502 502
 	/** Logical Unit Number (LUN) */
503 503
 	uint64_t lun;
504
-	/** Username */
505
-	char *username;
506
-	/** Password */
507
-	char *password;
508 504
 
509 505
 	/** Session status
510 506
 	 *

+ 274
- 38
src/net/tcp/iscsi.c View File

@@ -31,6 +31,7 @@
31 31
 #include <gpxe/process.h>
32 32
 #include <gpxe/uaccess.h>
33 33
 #include <gpxe/tcpip.h>
34
+#include <gpxe/dhcp.h>
34 35
 #include <gpxe/iscsi.h>
35 36
 
36 37
 /** @file
@@ -39,6 +40,18 @@
39 40
  *
40 41
  */
41 42
 
43
+/** iSCSI initiator name (explicitly specified) */
44
+char *iscsi_initiator_iqn;
45
+
46
+/** Default iSCSI initiator name (constructed from hostname) */
47
+char *iscsi_default_initiator_iqn;
48
+
49
+/** iSCSI username */
50
+char *iscsi_username;
51
+
52
+/** iSCSI password */
53
+char *iscsi_password;
54
+
42 55
 static void iscsi_start_tx ( struct iscsi_session *iscsi );
43 56
 static void iscsi_start_login ( struct iscsi_session *iscsi );
44 57
 static void iscsi_start_data_out ( struct iscsi_session *iscsi,
@@ -63,11 +76,8 @@ static void iscsi_free ( struct refcnt *refcnt ) {
63 76
 	struct iscsi_session *iscsi =
64 77
 		container_of ( refcnt, struct iscsi_session, refcnt );
65 78
 
66
-	free ( iscsi->initiator_iqn );
67 79
 	free ( iscsi->target_address );
68 80
 	free ( iscsi->target_iqn );
69
-	free ( iscsi->username );
70
-	free ( iscsi->password );
71 81
 	chap_finish ( &iscsi->chap );
72 82
 	iscsi_rx_buffered_data_done ( iscsi );
73 83
 	free ( iscsi );
@@ -89,7 +99,7 @@ static int iscsi_open_connection ( struct iscsi_session *iscsi ) {
89 99
 
90 100
 	/* Open socket */
91 101
 	memset ( &target, 0, sizeof ( target ) );
92
-	target.st_port = htons ( ISCSI_PORT );
102
+	target.st_port = htons ( iscsi->target_port );
93 103
 	if ( ( rc = xfer_open_named_socket ( &iscsi->socket, SOCK_STREAM,
94 104
 					     ( struct sockaddr * ) &target,
95 105
 					     iscsi->target_address,
@@ -428,16 +438,22 @@ static int iscsi_tx_data_out ( struct iscsi_session *iscsi ) {
428 438
  */
429 439
 static int iscsi_build_login_request_strings ( struct iscsi_session *iscsi,
430 440
 					       void *data, size_t len ) {
441
+	char *initiator_iqn;
431 442
 	unsigned int used = 0;
432 443
 	unsigned int i;
433 444
 
434 445
 	if ( iscsi->status & ISCSI_STATUS_STRINGS_SECURITY ) {
446
+		initiator_iqn = iscsi_initiator_iqn;
447
+		if ( ! initiator_iqn )
448
+			initiator_iqn = iscsi_default_initiator_iqn;
449
+		if ( ! initiator_iqn )
450
+			initiator_iqn = "iqn.2000-09.org.etherboot:UNKNOWN";
435 451
 		used += ssnprintf ( data + used, len - used,
436 452
 				    "InitiatorName=%s%c"
437 453
 				    "TargetName=%s%c"
438 454
 				    "SessionType=Normal%c"
439 455
 				    "AuthMethod=CHAP,None%c",
440
-				    iscsi->initiator_iqn, 0,
456
+				    initiator_iqn, 0,
441 457
 				    iscsi->target_iqn, 0, 0, 0 );
442 458
 	}
443 459
 
@@ -446,10 +462,10 @@ static int iscsi_build_login_request_strings ( struct iscsi_session *iscsi,
446 462
 	}
447 463
 	
448 464
 	if ( ( iscsi->status & ISCSI_STATUS_STRINGS_CHAP_RESPONSE ) &&
449
-	     iscsi->username ) {
465
+	     iscsi_username ) {
450 466
 		used += ssnprintf ( data + used, len - used,
451 467
 				    "CHAP_N=%s%cCHAP_R=0x",
452
-				    iscsi->username, 0 );
468
+				    iscsi_username, 0 );
453 469
 		for ( i = 0 ; i < iscsi->chap.response_len ; i++ ) {
454 470
 			used += ssnprintf ( data + used, len - used, "%02x",
455 471
 					    iscsi->chap.response[i] );
@@ -633,9 +649,9 @@ static int iscsi_handle_chap_i_value ( struct iscsi_session *iscsi,
633 649
 	 * challenge.
634 650
 	 */
635 651
 	chap_set_identifier ( &iscsi->chap, identifier );
636
-	if ( iscsi->password ) {
637
-		chap_update ( &iscsi->chap, iscsi->password,
638
-			      strlen ( iscsi->password ) );
652
+	if ( iscsi_password ) {
653
+		chap_update ( &iscsi->chap, iscsi_password,
654
+			      strlen ( iscsi_password ) );
639 655
 	}
640 656
 
641 657
 	return 0;
@@ -1245,55 +1261,275 @@ static struct xfer_interface_operations iscsi_socket_operations = {
1245 1261
 	.deliver_raw	= iscsi_socket_deliver_raw,
1246 1262
 };
1247 1263
 
1264
+
1265
+/****************************************************************************
1266
+ *
1267
+ * iSCSI to SCSI interface
1268
+ *
1269
+ */
1270
+
1248 1271
 /**
1249
- * Issue SCSI command via iSCSI session
1272
+ * Issue SCSI command
1250 1273
  *
1251
- * @v iscsi		iSCSI session
1274
+ * @v scsi		SCSI interface
1252 1275
  * @v command		SCSI command
1253
- * @v parent		Parent asynchronous operation
1254 1276
  * @ret rc		Return status code
1255 1277
  */
1256
-int iscsi_issue ( struct iscsi_session *iscsi, struct scsi_command *command,
1257
-		  struct async *parent ) {
1278
+static int iscsi_scsi_issue ( struct scsi_interface *scsi,
1279
+			      struct scsi_command *command ) {
1280
+	struct iscsi_session *iscsi =
1281
+		container_of ( scsi, struct iscsi_session, scsi );
1258 1282
 	int rc;
1259 1283
 
1260
-	assert ( iscsi->command == NULL );
1261
-	iscsi->command = command;
1262 1284
 
1263
-	if ( iscsi->instant_rc ) {
1264
-		/* Abort immediately rather than retrying */
1285
+	/* Abort immediately if we have a recorded permanent failure */
1286
+	if ( iscsi->instant_rc )
1265 1287
 		return iscsi->instant_rc;
1266
-	} else if ( iscsi->status ) {
1267
-		/* Session already open: issue command */
1288
+
1289
+	/* Issue command or open connection as appropriate */
1290
+	if ( iscsi->status ) {
1268 1291
 		iscsi_start_command ( iscsi );
1269
-		stream_kick ( &iscsi->stream );
1270 1292
 	} else {
1271
-		/* Session not open: initiate login */
1272
-		iscsi->stream.op = &iscsi_stream_operations;
1273
-		if ( ( rc = tcp_open ( &iscsi->stream ) ) != 0 ) {
1274
-			DBGC ( iscsi, "iSCSI %p could not open stream: %s\n ",
1275
-			       iscsi, strerror ( rc ) );
1293
+		if ( ( rc = iscsi_open_connection ( iscsi ) ) != 0 )
1276 1294
 			return rc;
1295
+	}
1296
+
1297
+	return 0;
1298
+}
1299
+
1300
+/**
1301
+ * Detach SCSI interface
1302
+ *
1303
+ * @v scsi		SCSI interface
1304
+ * @v rc		Reason for close
1305
+ */
1306
+static void iscsi_scsi_detach ( struct scsi_interface *scsi, int rc ) {
1307
+	struct iscsi_session *iscsi =
1308
+		container_of ( scsi, struct iscsi_session, scsi );
1309
+
1310
+	iscsi_close_connection ( iscsi, rc );
1311
+	process_del ( &iscsi->process );
1312
+}
1313
+
1314
+/****************************************************************************
1315
+ *
1316
+ * Instantiator
1317
+ *
1318
+ */
1319
+
1320
+/** iSCSI root path components (as per RFC4173) */
1321
+enum iscsi_root_path_component {
1322
+	RP_LITERAL = 0,
1323
+	RP_SERVERNAME,
1324
+	RP_PROTOCOL,
1325
+	RP_PORT,
1326
+	RP_LUN,
1327
+	RP_TARGETNAME,
1328
+	NUM_RP_COMPONENTS
1329
+};
1330
+
1331
+/**
1332
+ * Parse iSCSI LUN
1333
+ *
1334
+ * @v iscsi		iSCSI session
1335
+ * @v lun_string	LUN string representation (as per RFC4173)
1336
+ * @ret rc		Return status code
1337
+ */
1338
+static int iscsi_parse_lun ( struct iscsi_session *iscsi,
1339
+			     const char *lun_string ) {
1340
+	char *p = ( char * ) lun_string;
1341
+	union {
1342
+		uint64_t u64;
1343
+		uint16_t u16[4];
1344
+	} lun;
1345
+	int i;
1346
+
1347
+	for ( i = 0 ; i < 4 ; i++ ) {
1348
+		lun.u16[i] = strtoul ( p, &p, 16 );
1349
+		if ( *p != '-' )
1350
+			return -EINVAL;
1351
+		p++;
1352
+	}
1353
+	if ( *p )
1354
+		return -EINVAL;
1355
+
1356
+	iscsi->lun = lun.u64;
1357
+	return 0;
1358
+}
1359
+
1360
+/**
1361
+ * Parse iSCSI root path
1362
+ *
1363
+ * @v iscsi		iSCSI session
1364
+ * @v root_path		iSCSI root path (as per RFC4173)
1365
+ * @ret rc		Return status code
1366
+ */
1367
+static int iscsi_parse_root_path ( struct iscsi_session *iscsi,
1368
+				   const char *root_path ) {
1369
+	const char *p = root_path;
1370
+	char *fragment;
1371
+	size_t len;
1372
+	enum iscsi_root_path_component i;
1373
+	int rc;
1374
+
1375
+	for ( i = 0 ; i < NUM_RP_COMPONENTS ; i++ ) {
1376
+		len = strcspn ( p, ":" );
1377
+		fragment = strndup ( p, len );
1378
+		if ( ! fragment ) {
1379
+			DBGC ( iscsi, "iSCSI %p could not duplicate root "
1380
+			       "path component at %s\n", iscsi, p );
1381
+			return -ENOMEM;
1277 1382
 		}
1278
-		if ( ( rc = stream_connect ( &iscsi->stream,
1279
-					     &iscsi->target ) ) != 0 ) {
1280
-			DBGC ( iscsi, "iSCSI %p could not connect: %s\n",
1281
-			       iscsi, strerror ( rc ) );
1282
-			return rc;
1383
+		switch ( i ) {
1384
+		case RP_SERVERNAME:
1385
+			iscsi->target_address = fragment;
1386
+			break;
1387
+		case RP_PORT:
1388
+			iscsi->target_port = strtoul ( fragment, NULL, 10 );
1389
+			if ( ! iscsi->target_port )
1390
+				iscsi->target_port = ISCSI_PORT;
1391
+			free ( fragment );
1392
+			break;
1393
+		case RP_LUN:
1394
+			rc = iscsi_parse_lun ( iscsi, fragment );
1395
+			free ( fragment );
1396
+			if ( rc != 0 ) {
1397
+				DBGC ( iscsi, "iSCSI %p invalid LUN %s\n",
1398
+				       iscsi, fragment );
1399
+				return rc;
1400
+			}
1401
+			break;
1402
+		case RP_TARGETNAME:
1403
+			iscsi->target_iqn = fragment;
1404
+			break;
1405
+		default:
1406
+			free ( fragment );
1407
+			break;
1283 1408
 		}
1409
+		p += len;
1284 1410
 	}
1285 1411
 
1286
-	async_init ( &iscsi->async, &default_async_operations, parent );
1287 1412
 	return 0;
1288 1413
 }
1289 1414
 
1290 1415
 /**
1291
- * Close down iSCSI session
1416
+ * Attach iSCSI interface
1292 1417
  *
1293
- * @v iscsi		iSCSI session
1294
- * @ret aop		Asynchronous operation
1418
+ * @v scsi		SCSI interface
1419
+ * @v root_path		iSCSI root path (as per RFC4173)
1420
+ * @ret rc		Return status code
1295 1421
  */
1296
-void iscsi_shutdown ( struct iscsi_session *iscsi ) {
1297
-	iscsi_close_connection ( iscsi, 0 );
1422
+int iscsi_attach ( struct scsi_interface *scsi, const char *root_path ) {
1423
+	struct iscsi_session *iscsi;
1424
+	int rc;
1425
+
1426
+	/* Allocate and initialise structure */
1427
+	iscsi = zalloc ( sizeof ( *iscsi ) );
1428
+	if ( ! iscsi )
1429
+		return -ENOMEM;
1430
+	xfer_init ( &iscsi->socket, &iscsi_socket_operations, &iscsi->refcnt );
1431
+	process_init ( &iscsi->process, iscsi_tx_step, &iscsi->refcnt );
1432
+
1433
+	/* Parse root path */
1434
+	if ( ( rc = iscsi_parse_root_path ( iscsi, root_path ) ) != 0 )
1435
+		goto err;
1436
+
1437
+	/* Sanity checks */
1438
+	if ( ! iscsi->target_address ) {
1439
+		DBGC ( iscsi, "iSCSI %p does not yet support discovery\n",
1440
+		       iscsi );
1441
+		rc = -ENOTSUP;
1442
+		goto err;
1443
+	}
1444
+	if ( ! iscsi->target_iqn ) {
1445
+		DBGC ( iscsi, "iSCSI %p no target address supplied in %s\n",
1446
+		       iscsi, root_path );
1447
+		rc = -EINVAL;
1448
+		goto err;
1449
+	}
1450
+
1451
+	/* Attach parent interface, mortalise self, and return */
1452
+	scsi_plug_plug ( &iscsi->scsi, scsi );
1453
+	ref_put ( &iscsi->refcnt );
1454
+	return 0;
1455
+	
1456
+ err:
1298 1457
 	ref_put ( &iscsi->refcnt );
1458
+	return rc;
1459
+}
1460
+
1461
+/****************************************************************************
1462
+ *
1463
+ * DHCP option applicators
1464
+ *
1465
+ */
1466
+
1467
+/**
1468
+ * Apply DHCP iSCSI option
1469
+ *
1470
+ * @v tag		DHCP option tag
1471
+ * @v option		DHCP option
1472
+ * @ret rc		Return status code
1473
+ */
1474
+static int apply_dhcp_iscsi_string ( unsigned int tag,
1475
+				     struct dhcp_option *option ) {
1476
+	char *prefix = "";
1477
+	size_t prefix_len;
1478
+	size_t len;
1479
+	char **string;
1480
+	char *p;
1481
+
1482
+	/* Identify string and prefix */
1483
+	switch ( tag ) {
1484
+	case DHCP_ISCSI_INITIATOR_IQN:
1485
+		string = &iscsi_initiator_iqn;
1486
+		break;
1487
+	case DHCP_EB_USERNAME:
1488
+		string = &iscsi_username;
1489
+		break;
1490
+	case DHCP_EB_PASSWORD:
1491
+		string = &iscsi_password;
1492
+		break;
1493
+	case DHCP_HOST_NAME:
1494
+		string = &iscsi_default_initiator_iqn;
1495
+		prefix = "iqn.2000-09.org.etherboot:";
1496
+		break;
1497
+	default:
1498
+		assert ( 0 );
1499
+		return -EINVAL;
1500
+	}
1501
+
1502
+	/* Free old string */
1503
+	free ( *string );
1504
+	*string = NULL;
1505
+
1506
+	/* Allocate and fill new string */
1507
+	prefix_len = strlen ( prefix );
1508
+	len = ( prefix_len + option->len + 1 );
1509
+	p = *string = malloc ( len );
1510
+	if ( ! p )
1511
+		return -ENOMEM;
1512
+	strcpy ( p, prefix );
1513
+	dhcp_snprintf ( ( p + prefix_len ), ( len - prefix_len ), option );
1514
+	return 0;
1299 1515
 }
1516
+
1517
+/** DHCP iSCSI option applicators */
1518
+struct dhcp_option_applicator dhcp_iscsi_applicators[] __dhcp_applicator = {
1519
+	{
1520
+		.tag = DHCP_ISCSI_INITIATOR_IQN,
1521
+		.apply = apply_dhcp_iscsi_string,
1522
+	},
1523
+	{
1524
+		.tag = DHCP_EB_USERNAME,
1525
+		.apply = apply_dhcp_iscsi_string,
1526
+	},
1527
+	{
1528
+		.tag = DHCP_EB_PASSWORD,
1529
+		.apply = apply_dhcp_iscsi_string,
1530
+	},
1531
+	{
1532
+		.tag = DHCP_HOST_NAME,
1533
+		.apply = apply_dhcp_iscsi_string,
1534
+	},
1535
+};

Loading…
Cancel
Save