diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-09-17 19:52:13 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-09-17 19:52:13 -0400 |
commit | 4be0ed42c56c84d980a851f0bdd0fc20b45c3944 (patch) | |
tree | 5a77c7b0a2778aa12d426bfdef45375e04c6767e | |
parent | 279b1e0fd90ef63c7acb34a5ca573f065a6fefb4 (diff) | |
parent | 40b054970afcf067896d62cd6f7e617c62665304 (diff) |
Merge branch '3.1-rc-fixes' of git://linux-iscsi.org/target-pending
* '3.1-rc-fixes' of git://linux-iscsi.org/target-pending:
iscsi-target: Fix sendpage breakage with proper padding+DataDigest iovec offsets
iscsi-target: Disable markers + remove dangerous local scope array usage
target: Skip non hex characters for VPD=0x83 NAA IEEE Registered Extended
tcm_fc: Work queue based approach instead of managing own thread and event based mechanism
tcm_fc: Invalidation of DDP context for FCoE target in error conditions
target: Fix race between multiple invocations of target_qf_do_work()
-rw-r--r-- | drivers/target/iscsi/iscsi_target_parameters.c | 2 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_util.c | 270 | ||||
-rw-r--r-- | drivers/target/target_core_cdb.c | 35 | ||||
-rw-r--r-- | drivers/target/target_core_transport.c | 9 | ||||
-rw-r--r-- | drivers/target/tcm_fc/tcm_fc.h | 12 | ||||
-rw-r--r-- | drivers/target/tcm_fc/tfc_cmd.c | 90 | ||||
-rw-r--r-- | drivers/target/tcm_fc/tfc_conf.c | 7 | ||||
-rw-r--r-- | drivers/target/tcm_fc/tfc_io.c | 62 |
8 files changed, 105 insertions, 382 deletions
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c index 497b2e718a76..5b773160200f 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.c +++ b/drivers/target/iscsi/iscsi_target_parameters.c | |||
@@ -1430,7 +1430,7 @@ static int iscsi_enforce_integrity_rules( | |||
1430 | u8 DataSequenceInOrder = 0; | 1430 | u8 DataSequenceInOrder = 0; |
1431 | u8 ErrorRecoveryLevel = 0, SessionType = 0; | 1431 | u8 ErrorRecoveryLevel = 0, SessionType = 0; |
1432 | u8 IFMarker = 0, OFMarker = 0; | 1432 | u8 IFMarker = 0, OFMarker = 0; |
1433 | u8 IFMarkInt_Reject = 0, OFMarkInt_Reject = 0; | 1433 | u8 IFMarkInt_Reject = 1, OFMarkInt_Reject = 1; |
1434 | u32 FirstBurstLength = 0, MaxBurstLength = 0; | 1434 | u32 FirstBurstLength = 0, MaxBurstLength = 0; |
1435 | struct iscsi_param *param = NULL; | 1435 | struct iscsi_param *param = NULL; |
1436 | 1436 | ||
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index a0d23bc0fc98..f00137f377b2 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c | |||
@@ -875,40 +875,6 @@ void iscsit_inc_session_usage_count(struct iscsi_session *sess) | |||
875 | } | 875 | } |
876 | 876 | ||
877 | /* | 877 | /* |
878 | * Used before iscsi_do[rx,tx]_data() to determine iov and [rx,tx]_marker | ||
879 | * array counts needed for sync and steering. | ||
880 | */ | ||
881 | static int iscsit_determine_sync_and_steering_counts( | ||
882 | struct iscsi_conn *conn, | ||
883 | struct iscsi_data_count *count) | ||
884 | { | ||
885 | u32 length = count->data_length; | ||
886 | u32 marker, markint; | ||
887 | |||
888 | count->sync_and_steering = 1; | ||
889 | |||
890 | marker = (count->type == ISCSI_RX_DATA) ? | ||
891 | conn->of_marker : conn->if_marker; | ||
892 | markint = (count->type == ISCSI_RX_DATA) ? | ||
893 | (conn->conn_ops->OFMarkInt * 4) : | ||
894 | (conn->conn_ops->IFMarkInt * 4); | ||
895 | count->ss_iov_count = count->iov_count; | ||
896 | |||
897 | while (length > 0) { | ||
898 | if (length >= marker) { | ||
899 | count->ss_iov_count += 3; | ||
900 | count->ss_marker_count += 2; | ||
901 | |||
902 | length -= marker; | ||
903 | marker = markint; | ||
904 | } else | ||
905 | length = 0; | ||
906 | } | ||
907 | |||
908 | return 0; | ||
909 | } | ||
910 | |||
911 | /* | ||
912 | * Setup conn->if_marker and conn->of_marker values based upon | 878 | * Setup conn->if_marker and conn->of_marker values based upon |
913 | * the initial marker-less interval. (see iSCSI v19 A.2) | 879 | * the initial marker-less interval. (see iSCSI v19 A.2) |
914 | */ | 880 | */ |
@@ -1290,7 +1256,7 @@ int iscsit_fe_sendpage_sg( | |||
1290 | struct kvec iov; | 1256 | struct kvec iov; |
1291 | u32 tx_hdr_size, data_len; | 1257 | u32 tx_hdr_size, data_len; |
1292 | u32 offset = cmd->first_data_sg_off; | 1258 | u32 offset = cmd->first_data_sg_off; |
1293 | int tx_sent; | 1259 | int tx_sent, iov_off; |
1294 | 1260 | ||
1295 | send_hdr: | 1261 | send_hdr: |
1296 | tx_hdr_size = ISCSI_HDR_LEN; | 1262 | tx_hdr_size = ISCSI_HDR_LEN; |
@@ -1310,9 +1276,19 @@ send_hdr: | |||
1310 | } | 1276 | } |
1311 | 1277 | ||
1312 | data_len = cmd->tx_size - tx_hdr_size - cmd->padding; | 1278 | data_len = cmd->tx_size - tx_hdr_size - cmd->padding; |
1313 | if (conn->conn_ops->DataDigest) | 1279 | /* |
1280 | * Set iov_off used by padding and data digest tx_data() calls below | ||
1281 | * in order to determine proper offset into cmd->iov_data[] | ||
1282 | */ | ||
1283 | if (conn->conn_ops->DataDigest) { | ||
1314 | data_len -= ISCSI_CRC_LEN; | 1284 | data_len -= ISCSI_CRC_LEN; |
1315 | 1285 | if (cmd->padding) | |
1286 | iov_off = (cmd->iov_data_count - 2); | ||
1287 | else | ||
1288 | iov_off = (cmd->iov_data_count - 1); | ||
1289 | } else { | ||
1290 | iov_off = (cmd->iov_data_count - 1); | ||
1291 | } | ||
1316 | /* | 1292 | /* |
1317 | * Perform sendpage() for each page in the scatterlist | 1293 | * Perform sendpage() for each page in the scatterlist |
1318 | */ | 1294 | */ |
@@ -1341,8 +1317,7 @@ send_pg: | |||
1341 | 1317 | ||
1342 | send_padding: | 1318 | send_padding: |
1343 | if (cmd->padding) { | 1319 | if (cmd->padding) { |
1344 | struct kvec *iov_p = | 1320 | struct kvec *iov_p = &cmd->iov_data[iov_off++]; |
1345 | &cmd->iov_data[cmd->iov_data_count-1]; | ||
1346 | 1321 | ||
1347 | tx_sent = tx_data(conn, iov_p, 1, cmd->padding); | 1322 | tx_sent = tx_data(conn, iov_p, 1, cmd->padding); |
1348 | if (cmd->padding != tx_sent) { | 1323 | if (cmd->padding != tx_sent) { |
@@ -1356,8 +1331,7 @@ send_padding: | |||
1356 | 1331 | ||
1357 | send_datacrc: | 1332 | send_datacrc: |
1358 | if (conn->conn_ops->DataDigest) { | 1333 | if (conn->conn_ops->DataDigest) { |
1359 | struct kvec *iov_d = | 1334 | struct kvec *iov_d = &cmd->iov_data[iov_off]; |
1360 | &cmd->iov_data[cmd->iov_data_count]; | ||
1361 | 1335 | ||
1362 | tx_sent = tx_data(conn, iov_d, 1, ISCSI_CRC_LEN); | 1336 | tx_sent = tx_data(conn, iov_d, 1, ISCSI_CRC_LEN); |
1363 | if (ISCSI_CRC_LEN != tx_sent) { | 1337 | if (ISCSI_CRC_LEN != tx_sent) { |
@@ -1431,8 +1405,7 @@ static int iscsit_do_rx_data( | |||
1431 | struct iscsi_data_count *count) | 1405 | struct iscsi_data_count *count) |
1432 | { | 1406 | { |
1433 | int data = count->data_length, rx_loop = 0, total_rx = 0, iov_len; | 1407 | int data = count->data_length, rx_loop = 0, total_rx = 0, iov_len; |
1434 | u32 rx_marker_val[count->ss_marker_count], rx_marker_iov = 0; | 1408 | struct kvec *iov_p; |
1435 | struct kvec iov[count->ss_iov_count], *iov_p; | ||
1436 | struct msghdr msg; | 1409 | struct msghdr msg; |
1437 | 1410 | ||
1438 | if (!conn || !conn->sock || !conn->conn_ops) | 1411 | if (!conn || !conn->sock || !conn->conn_ops) |
@@ -1440,93 +1413,8 @@ static int iscsit_do_rx_data( | |||
1440 | 1413 | ||
1441 | memset(&msg, 0, sizeof(struct msghdr)); | 1414 | memset(&msg, 0, sizeof(struct msghdr)); |
1442 | 1415 | ||
1443 | if (count->sync_and_steering) { | 1416 | iov_p = count->iov; |
1444 | int size = 0; | 1417 | iov_len = count->iov_count; |
1445 | u32 i, orig_iov_count = 0; | ||
1446 | u32 orig_iov_len = 0, orig_iov_loc = 0; | ||
1447 | u32 iov_count = 0, per_iov_bytes = 0; | ||
1448 | u32 *rx_marker, old_rx_marker = 0; | ||
1449 | struct kvec *iov_record; | ||
1450 | |||
1451 | memset(&rx_marker_val, 0, | ||
1452 | count->ss_marker_count * sizeof(u32)); | ||
1453 | memset(&iov, 0, count->ss_iov_count * sizeof(struct kvec)); | ||
1454 | |||
1455 | iov_record = count->iov; | ||
1456 | orig_iov_count = count->iov_count; | ||
1457 | rx_marker = &conn->of_marker; | ||
1458 | |||
1459 | i = 0; | ||
1460 | size = data; | ||
1461 | orig_iov_len = iov_record[orig_iov_loc].iov_len; | ||
1462 | while (size > 0) { | ||
1463 | pr_debug("rx_data: #1 orig_iov_len %u," | ||
1464 | " orig_iov_loc %u\n", orig_iov_len, orig_iov_loc); | ||
1465 | pr_debug("rx_data: #2 rx_marker %u, size" | ||
1466 | " %u\n", *rx_marker, size); | ||
1467 | |||
1468 | if (orig_iov_len >= *rx_marker) { | ||
1469 | iov[iov_count].iov_len = *rx_marker; | ||
1470 | iov[iov_count++].iov_base = | ||
1471 | (iov_record[orig_iov_loc].iov_base + | ||
1472 | per_iov_bytes); | ||
1473 | |||
1474 | iov[iov_count].iov_len = (MARKER_SIZE / 2); | ||
1475 | iov[iov_count++].iov_base = | ||
1476 | &rx_marker_val[rx_marker_iov++]; | ||
1477 | iov[iov_count].iov_len = (MARKER_SIZE / 2); | ||
1478 | iov[iov_count++].iov_base = | ||
1479 | &rx_marker_val[rx_marker_iov++]; | ||
1480 | old_rx_marker = *rx_marker; | ||
1481 | |||
1482 | /* | ||
1483 | * OFMarkInt is in 32-bit words. | ||
1484 | */ | ||
1485 | *rx_marker = (conn->conn_ops->OFMarkInt * 4); | ||
1486 | size -= old_rx_marker; | ||
1487 | orig_iov_len -= old_rx_marker; | ||
1488 | per_iov_bytes += old_rx_marker; | ||
1489 | |||
1490 | pr_debug("rx_data: #3 new_rx_marker" | ||
1491 | " %u, size %u\n", *rx_marker, size); | ||
1492 | } else { | ||
1493 | iov[iov_count].iov_len = orig_iov_len; | ||
1494 | iov[iov_count++].iov_base = | ||
1495 | (iov_record[orig_iov_loc].iov_base + | ||
1496 | per_iov_bytes); | ||
1497 | |||
1498 | per_iov_bytes = 0; | ||
1499 | *rx_marker -= orig_iov_len; | ||
1500 | size -= orig_iov_len; | ||
1501 | |||
1502 | if (size) | ||
1503 | orig_iov_len = | ||
1504 | iov_record[++orig_iov_loc].iov_len; | ||
1505 | |||
1506 | pr_debug("rx_data: #4 new_rx_marker" | ||
1507 | " %u, size %u\n", *rx_marker, size); | ||
1508 | } | ||
1509 | } | ||
1510 | data += (rx_marker_iov * (MARKER_SIZE / 2)); | ||
1511 | |||
1512 | iov_p = &iov[0]; | ||
1513 | iov_len = iov_count; | ||
1514 | |||
1515 | if (iov_count > count->ss_iov_count) { | ||
1516 | pr_err("iov_count: %d, count->ss_iov_count:" | ||
1517 | " %d\n", iov_count, count->ss_iov_count); | ||
1518 | return -1; | ||
1519 | } | ||
1520 | if (rx_marker_iov > count->ss_marker_count) { | ||
1521 | pr_err("rx_marker_iov: %d, count->ss_marker" | ||
1522 | "_count: %d\n", rx_marker_iov, | ||
1523 | count->ss_marker_count); | ||
1524 | return -1; | ||
1525 | } | ||
1526 | } else { | ||
1527 | iov_p = count->iov; | ||
1528 | iov_len = count->iov_count; | ||
1529 | } | ||
1530 | 1418 | ||
1531 | while (total_rx < data) { | 1419 | while (total_rx < data) { |
1532 | rx_loop = kernel_recvmsg(conn->sock, &msg, iov_p, iov_len, | 1420 | rx_loop = kernel_recvmsg(conn->sock, &msg, iov_p, iov_len, |
@@ -1541,16 +1429,6 @@ static int iscsit_do_rx_data( | |||
1541 | rx_loop, total_rx, data); | 1429 | rx_loop, total_rx, data); |
1542 | } | 1430 | } |
1543 | 1431 | ||
1544 | if (count->sync_and_steering) { | ||
1545 | int j; | ||
1546 | for (j = 0; j < rx_marker_iov; j++) { | ||
1547 | pr_debug("rx_data: #5 j: %d, offset: %d\n", | ||
1548 | j, rx_marker_val[j]); | ||
1549 | conn->of_marker_offset = rx_marker_val[j]; | ||
1550 | } | ||
1551 | total_rx -= (rx_marker_iov * (MARKER_SIZE / 2)); | ||
1552 | } | ||
1553 | |||
1554 | return total_rx; | 1432 | return total_rx; |
1555 | } | 1433 | } |
1556 | 1434 | ||
@@ -1559,8 +1437,7 @@ static int iscsit_do_tx_data( | |||
1559 | struct iscsi_data_count *count) | 1437 | struct iscsi_data_count *count) |
1560 | { | 1438 | { |
1561 | int data = count->data_length, total_tx = 0, tx_loop = 0, iov_len; | 1439 | int data = count->data_length, total_tx = 0, tx_loop = 0, iov_len; |
1562 | u32 tx_marker_val[count->ss_marker_count], tx_marker_iov = 0; | 1440 | struct kvec *iov_p; |
1563 | struct kvec iov[count->ss_iov_count], *iov_p; | ||
1564 | struct msghdr msg; | 1441 | struct msghdr msg; |
1565 | 1442 | ||
1566 | if (!conn || !conn->sock || !conn->conn_ops) | 1443 | if (!conn || !conn->sock || !conn->conn_ops) |
@@ -1573,98 +1450,8 @@ static int iscsit_do_tx_data( | |||
1573 | 1450 | ||
1574 | memset(&msg, 0, sizeof(struct msghdr)); | 1451 | memset(&msg, 0, sizeof(struct msghdr)); |
1575 | 1452 | ||
1576 | if (count->sync_and_steering) { | 1453 | iov_p = count->iov; |
1577 | int size = 0; | 1454 | iov_len = count->iov_count; |
1578 | u32 i, orig_iov_count = 0; | ||
1579 | u32 orig_iov_len = 0, orig_iov_loc = 0; | ||
1580 | u32 iov_count = 0, per_iov_bytes = 0; | ||
1581 | u32 *tx_marker, old_tx_marker = 0; | ||
1582 | struct kvec *iov_record; | ||
1583 | |||
1584 | memset(&tx_marker_val, 0, | ||
1585 | count->ss_marker_count * sizeof(u32)); | ||
1586 | memset(&iov, 0, count->ss_iov_count * sizeof(struct kvec)); | ||
1587 | |||
1588 | iov_record = count->iov; | ||
1589 | orig_iov_count = count->iov_count; | ||
1590 | tx_marker = &conn->if_marker; | ||
1591 | |||
1592 | i = 0; | ||
1593 | size = data; | ||
1594 | orig_iov_len = iov_record[orig_iov_loc].iov_len; | ||
1595 | while (size > 0) { | ||
1596 | pr_debug("tx_data: #1 orig_iov_len %u," | ||
1597 | " orig_iov_loc %u\n", orig_iov_len, orig_iov_loc); | ||
1598 | pr_debug("tx_data: #2 tx_marker %u, size" | ||
1599 | " %u\n", *tx_marker, size); | ||
1600 | |||
1601 | if (orig_iov_len >= *tx_marker) { | ||
1602 | iov[iov_count].iov_len = *tx_marker; | ||
1603 | iov[iov_count++].iov_base = | ||
1604 | (iov_record[orig_iov_loc].iov_base + | ||
1605 | per_iov_bytes); | ||
1606 | |||
1607 | tx_marker_val[tx_marker_iov] = | ||
1608 | (size - *tx_marker); | ||
1609 | iov[iov_count].iov_len = (MARKER_SIZE / 2); | ||
1610 | iov[iov_count++].iov_base = | ||
1611 | &tx_marker_val[tx_marker_iov++]; | ||
1612 | iov[iov_count].iov_len = (MARKER_SIZE / 2); | ||
1613 | iov[iov_count++].iov_base = | ||
1614 | &tx_marker_val[tx_marker_iov++]; | ||
1615 | old_tx_marker = *tx_marker; | ||
1616 | |||
1617 | /* | ||
1618 | * IFMarkInt is in 32-bit words. | ||
1619 | */ | ||
1620 | *tx_marker = (conn->conn_ops->IFMarkInt * 4); | ||
1621 | size -= old_tx_marker; | ||
1622 | orig_iov_len -= old_tx_marker; | ||
1623 | per_iov_bytes += old_tx_marker; | ||
1624 | |||
1625 | pr_debug("tx_data: #3 new_tx_marker" | ||
1626 | " %u, size %u\n", *tx_marker, size); | ||
1627 | pr_debug("tx_data: #4 offset %u\n", | ||
1628 | tx_marker_val[tx_marker_iov-1]); | ||
1629 | } else { | ||
1630 | iov[iov_count].iov_len = orig_iov_len; | ||
1631 | iov[iov_count++].iov_base | ||
1632 | = (iov_record[orig_iov_loc].iov_base + | ||
1633 | per_iov_bytes); | ||
1634 | |||
1635 | per_iov_bytes = 0; | ||
1636 | *tx_marker -= orig_iov_len; | ||
1637 | size -= orig_iov_len; | ||
1638 | |||
1639 | if (size) | ||
1640 | orig_iov_len = | ||
1641 | iov_record[++orig_iov_loc].iov_len; | ||
1642 | |||
1643 | pr_debug("tx_data: #5 new_tx_marker" | ||
1644 | " %u, size %u\n", *tx_marker, size); | ||
1645 | } | ||
1646 | } | ||
1647 | |||
1648 | data += (tx_marker_iov * (MARKER_SIZE / 2)); | ||
1649 | |||
1650 | iov_p = &iov[0]; | ||
1651 | iov_len = iov_count; | ||
1652 | |||
1653 | if (iov_count > count->ss_iov_count) { | ||
1654 | pr_err("iov_count: %d, count->ss_iov_count:" | ||
1655 | " %d\n", iov_count, count->ss_iov_count); | ||
1656 | return -1; | ||
1657 | } | ||
1658 | if (tx_marker_iov > count->ss_marker_count) { | ||
1659 | pr_err("tx_marker_iov: %d, count->ss_marker" | ||
1660 | "_count: %d\n", tx_marker_iov, | ||
1661 | count->ss_marker_count); | ||
1662 | return -1; | ||
1663 | } | ||
1664 | } else { | ||
1665 | iov_p = count->iov; | ||
1666 | iov_len = count->iov_count; | ||
1667 | } | ||
1668 | 1455 | ||
1669 | while (total_tx < data) { | 1456 | while (total_tx < data) { |
1670 | tx_loop = kernel_sendmsg(conn->sock, &msg, iov_p, iov_len, | 1457 | tx_loop = kernel_sendmsg(conn->sock, &msg, iov_p, iov_len, |
@@ -1679,9 +1466,6 @@ static int iscsit_do_tx_data( | |||
1679 | tx_loop, total_tx, data); | 1466 | tx_loop, total_tx, data); |
1680 | } | 1467 | } |
1681 | 1468 | ||
1682 | if (count->sync_and_steering) | ||
1683 | total_tx -= (tx_marker_iov * (MARKER_SIZE / 2)); | ||
1684 | |||
1685 | return total_tx; | 1469 | return total_tx; |
1686 | } | 1470 | } |
1687 | 1471 | ||
@@ -1702,12 +1486,6 @@ int rx_data( | |||
1702 | c.data_length = data; | 1486 | c.data_length = data; |
1703 | c.type = ISCSI_RX_DATA; | 1487 | c.type = ISCSI_RX_DATA; |
1704 | 1488 | ||
1705 | if (conn->conn_ops->OFMarker && | ||
1706 | (conn->conn_state >= TARG_CONN_STATE_LOGGED_IN)) { | ||
1707 | if (iscsit_determine_sync_and_steering_counts(conn, &c) < 0) | ||
1708 | return -1; | ||
1709 | } | ||
1710 | |||
1711 | return iscsit_do_rx_data(conn, &c); | 1489 | return iscsit_do_rx_data(conn, &c); |
1712 | } | 1490 | } |
1713 | 1491 | ||
@@ -1728,12 +1506,6 @@ int tx_data( | |||
1728 | c.data_length = data; | 1506 | c.data_length = data; |
1729 | c.type = ISCSI_TX_DATA; | 1507 | c.type = ISCSI_TX_DATA; |
1730 | 1508 | ||
1731 | if (conn->conn_ops->IFMarker && | ||
1732 | (conn->conn_state >= TARG_CONN_STATE_LOGGED_IN)) { | ||
1733 | if (iscsit_determine_sync_and_steering_counts(conn, &c) < 0) | ||
1734 | return -1; | ||
1735 | } | ||
1736 | |||
1737 | return iscsit_do_tx_data(conn, &c); | 1509 | return iscsit_do_tx_data(conn, &c); |
1738 | } | 1510 | } |
1739 | 1511 | ||
diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c index 89ae923c5da6..f04d4ef99dca 100644 --- a/drivers/target/target_core_cdb.c +++ b/drivers/target/target_core_cdb.c | |||
@@ -24,6 +24,7 @@ | |||
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
27 | #include <linux/ctype.h> | ||
27 | #include <asm/unaligned.h> | 28 | #include <asm/unaligned.h> |
28 | #include <scsi/scsi.h> | 29 | #include <scsi/scsi.h> |
29 | 30 | ||
@@ -154,6 +155,37 @@ target_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf) | |||
154 | return 0; | 155 | return 0; |
155 | } | 156 | } |
156 | 157 | ||
158 | static void | ||
159 | target_parse_naa_6h_vendor_specific(struct se_device *dev, unsigned char *buf_off) | ||
160 | { | ||
161 | unsigned char *p = &dev->se_sub_dev->t10_wwn.unit_serial[0]; | ||
162 | unsigned char *buf = buf_off; | ||
163 | int cnt = 0, next = 1; | ||
164 | /* | ||
165 | * Generate up to 36 bits of VENDOR SPECIFIC IDENTIFIER starting on | ||
166 | * byte 3 bit 3-0 for NAA IEEE Registered Extended DESIGNATOR field | ||
167 | * format, followed by 64 bits of VENDOR SPECIFIC IDENTIFIER EXTENSION | ||
168 | * to complete the payload. These are based from VPD=0x80 PRODUCT SERIAL | ||
169 | * NUMBER set via vpd_unit_serial in target_core_configfs.c to ensure | ||
170 | * per device uniqeness. | ||
171 | */ | ||
172 | while (*p != '\0') { | ||
173 | if (cnt >= 13) | ||
174 | break; | ||
175 | if (!isxdigit(*p)) { | ||
176 | p++; | ||
177 | continue; | ||
178 | } | ||
179 | if (next != 0) { | ||
180 | buf[cnt++] |= hex_to_bin(*p++); | ||
181 | next = 0; | ||
182 | } else { | ||
183 | buf[cnt] = hex_to_bin(*p++) << 4; | ||
184 | next = 1; | ||
185 | } | ||
186 | } | ||
187 | } | ||
188 | |||
157 | /* | 189 | /* |
158 | * Device identification VPD, for a complete list of | 190 | * Device identification VPD, for a complete list of |
159 | * DESIGNATOR TYPEs see spc4r17 Table 459. | 191 | * DESIGNATOR TYPEs see spc4r17 Table 459. |
@@ -219,8 +251,7 @@ target_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf) | |||
219 | * VENDOR_SPECIFIC_IDENTIFIER and | 251 | * VENDOR_SPECIFIC_IDENTIFIER and |
220 | * VENDOR_SPECIFIC_IDENTIFIER_EXTENTION | 252 | * VENDOR_SPECIFIC_IDENTIFIER_EXTENTION |
221 | */ | 253 | */ |
222 | buf[off++] |= hex_to_bin(dev->se_sub_dev->t10_wwn.unit_serial[0]); | 254 | target_parse_naa_6h_vendor_specific(dev, &buf[off]); |
223 | hex2bin(&buf[off], &dev->se_sub_dev->t10_wwn.unit_serial[1], 12); | ||
224 | 255 | ||
225 | len = 20; | 256 | len = 20; |
226 | off = (len + 4); | 257 | off = (len + 4); |
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 8d0c58ea6316..a4b0a8d27f25 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
@@ -977,15 +977,17 @@ static void target_qf_do_work(struct work_struct *work) | |||
977 | { | 977 | { |
978 | struct se_device *dev = container_of(work, struct se_device, | 978 | struct se_device *dev = container_of(work, struct se_device, |
979 | qf_work_queue); | 979 | qf_work_queue); |
980 | LIST_HEAD(qf_cmd_list); | ||
980 | struct se_cmd *cmd, *cmd_tmp; | 981 | struct se_cmd *cmd, *cmd_tmp; |
981 | 982 | ||
982 | spin_lock_irq(&dev->qf_cmd_lock); | 983 | spin_lock_irq(&dev->qf_cmd_lock); |
983 | list_for_each_entry_safe(cmd, cmd_tmp, &dev->qf_cmd_list, se_qf_node) { | 984 | list_splice_init(&dev->qf_cmd_list, &qf_cmd_list); |
985 | spin_unlock_irq(&dev->qf_cmd_lock); | ||
984 | 986 | ||
987 | list_for_each_entry_safe(cmd, cmd_tmp, &qf_cmd_list, se_qf_node) { | ||
985 | list_del(&cmd->se_qf_node); | 988 | list_del(&cmd->se_qf_node); |
986 | atomic_dec(&dev->dev_qf_count); | 989 | atomic_dec(&dev->dev_qf_count); |
987 | smp_mb__after_atomic_dec(); | 990 | smp_mb__after_atomic_dec(); |
988 | spin_unlock_irq(&dev->qf_cmd_lock); | ||
989 | 991 | ||
990 | pr_debug("Processing %s cmd: %p QUEUE_FULL in work queue" | 992 | pr_debug("Processing %s cmd: %p QUEUE_FULL in work queue" |
991 | " context: %s\n", cmd->se_tfo->get_fabric_name(), cmd, | 993 | " context: %s\n", cmd->se_tfo->get_fabric_name(), cmd, |
@@ -997,10 +999,7 @@ static void target_qf_do_work(struct work_struct *work) | |||
997 | * has been added to head of queue | 999 | * has been added to head of queue |
998 | */ | 1000 | */ |
999 | transport_add_cmd_to_queue(cmd, cmd->t_state); | 1001 | transport_add_cmd_to_queue(cmd, cmd->t_state); |
1000 | |||
1001 | spin_lock_irq(&dev->qf_cmd_lock); | ||
1002 | } | 1002 | } |
1003 | spin_unlock_irq(&dev->qf_cmd_lock); | ||
1004 | } | 1003 | } |
1005 | 1004 | ||
1006 | unsigned char *transport_dump_cmd_direction(struct se_cmd *cmd) | 1005 | unsigned char *transport_dump_cmd_direction(struct se_cmd *cmd) |
diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h index bd4fe21a23b8..3749d8b4b423 100644 --- a/drivers/target/tcm_fc/tcm_fc.h +++ b/drivers/target/tcm_fc/tcm_fc.h | |||
@@ -98,8 +98,7 @@ struct ft_tpg { | |||
98 | struct list_head list; /* linkage in ft_lport_acl tpg_list */ | 98 | struct list_head list; /* linkage in ft_lport_acl tpg_list */ |
99 | struct list_head lun_list; /* head of LUNs */ | 99 | struct list_head lun_list; /* head of LUNs */ |
100 | struct se_portal_group se_tpg; | 100 | struct se_portal_group se_tpg; |
101 | struct task_struct *thread; /* processing thread */ | 101 | struct workqueue_struct *workqueue; |
102 | struct se_queue_obj qobj; /* queue for processing thread */ | ||
103 | }; | 102 | }; |
104 | 103 | ||
105 | struct ft_lport_acl { | 104 | struct ft_lport_acl { |
@@ -110,16 +109,10 @@ struct ft_lport_acl { | |||
110 | struct se_wwn fc_lport_wwn; | 109 | struct se_wwn fc_lport_wwn; |
111 | }; | 110 | }; |
112 | 111 | ||
113 | enum ft_cmd_state { | ||
114 | FC_CMD_ST_NEW = 0, | ||
115 | FC_CMD_ST_REJ | ||
116 | }; | ||
117 | |||
118 | /* | 112 | /* |
119 | * Commands | 113 | * Commands |
120 | */ | 114 | */ |
121 | struct ft_cmd { | 115 | struct ft_cmd { |
122 | enum ft_cmd_state state; | ||
123 | u32 lun; /* LUN from request */ | 116 | u32 lun; /* LUN from request */ |
124 | struct ft_sess *sess; /* session held for cmd */ | 117 | struct ft_sess *sess; /* session held for cmd */ |
125 | struct fc_seq *seq; /* sequence in exchange mgr */ | 118 | struct fc_seq *seq; /* sequence in exchange mgr */ |
@@ -127,7 +120,7 @@ struct ft_cmd { | |||
127 | struct fc_frame *req_frame; | 120 | struct fc_frame *req_frame; |
128 | unsigned char *cdb; /* pointer to CDB inside frame */ | 121 | unsigned char *cdb; /* pointer to CDB inside frame */ |
129 | u32 write_data_len; /* data received on writes */ | 122 | u32 write_data_len; /* data received on writes */ |
130 | struct se_queue_req se_req; | 123 | struct work_struct work; |
131 | /* Local sense buffer */ | 124 | /* Local sense buffer */ |
132 | unsigned char ft_sense_buffer[TRANSPORT_SENSE_BUFFER]; | 125 | unsigned char ft_sense_buffer[TRANSPORT_SENSE_BUFFER]; |
133 | u32 was_ddp_setup:1; /* Set only if ddp is setup */ | 126 | u32 was_ddp_setup:1; /* Set only if ddp is setup */ |
@@ -177,7 +170,6 @@ int ft_is_state_remove(struct se_cmd *); | |||
177 | /* | 170 | /* |
178 | * other internal functions. | 171 | * other internal functions. |
179 | */ | 172 | */ |
180 | int ft_thread(void *); | ||
181 | void ft_recv_req(struct ft_sess *, struct fc_frame *); | 173 | void ft_recv_req(struct ft_sess *, struct fc_frame *); |
182 | struct ft_tpg *ft_lport_find_tpg(struct fc_lport *); | 174 | struct ft_tpg *ft_lport_find_tpg(struct fc_lport *); |
183 | struct ft_node_acl *ft_acl_get(struct ft_tpg *, struct fc_rport_priv *); | 175 | struct ft_node_acl *ft_acl_get(struct ft_tpg *, struct fc_rport_priv *); |
diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index 5654dc22f7ae..80fbcde00cb6 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c | |||
@@ -62,8 +62,8 @@ void ft_dump_cmd(struct ft_cmd *cmd, const char *caller) | |||
62 | int count; | 62 | int count; |
63 | 63 | ||
64 | se_cmd = &cmd->se_cmd; | 64 | se_cmd = &cmd->se_cmd; |
65 | pr_debug("%s: cmd %p state %d sess %p seq %p se_cmd %p\n", | 65 | pr_debug("%s: cmd %p sess %p seq %p se_cmd %p\n", |
66 | caller, cmd, cmd->state, cmd->sess, cmd->seq, se_cmd); | 66 | caller, cmd, cmd->sess, cmd->seq, se_cmd); |
67 | pr_debug("%s: cmd %p cdb %p\n", | 67 | pr_debug("%s: cmd %p cdb %p\n", |
68 | caller, cmd, cmd->cdb); | 68 | caller, cmd, cmd->cdb); |
69 | pr_debug("%s: cmd %p lun %d\n", caller, cmd, cmd->lun); | 69 | pr_debug("%s: cmd %p lun %d\n", caller, cmd, cmd->lun); |
@@ -90,38 +90,6 @@ void ft_dump_cmd(struct ft_cmd *cmd, const char *caller) | |||
90 | 16, 4, cmd->cdb, MAX_COMMAND_SIZE, 0); | 90 | 16, 4, cmd->cdb, MAX_COMMAND_SIZE, 0); |
91 | } | 91 | } |
92 | 92 | ||
93 | static void ft_queue_cmd(struct ft_sess *sess, struct ft_cmd *cmd) | ||
94 | { | ||
95 | struct ft_tpg *tpg = sess->tport->tpg; | ||
96 | struct se_queue_obj *qobj = &tpg->qobj; | ||
97 | unsigned long flags; | ||
98 | |||
99 | qobj = &sess->tport->tpg->qobj; | ||
100 | spin_lock_irqsave(&qobj->cmd_queue_lock, flags); | ||
101 | list_add_tail(&cmd->se_req.qr_list, &qobj->qobj_list); | ||
102 | atomic_inc(&qobj->queue_cnt); | ||
103 | spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); | ||
104 | |||
105 | wake_up_process(tpg->thread); | ||
106 | } | ||
107 | |||
108 | static struct ft_cmd *ft_dequeue_cmd(struct se_queue_obj *qobj) | ||
109 | { | ||
110 | unsigned long flags; | ||
111 | struct se_queue_req *qr; | ||
112 | |||
113 | spin_lock_irqsave(&qobj->cmd_queue_lock, flags); | ||
114 | if (list_empty(&qobj->qobj_list)) { | ||
115 | spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); | ||
116 | return NULL; | ||
117 | } | ||
118 | qr = list_first_entry(&qobj->qobj_list, struct se_queue_req, qr_list); | ||
119 | list_del(&qr->qr_list); | ||
120 | atomic_dec(&qobj->queue_cnt); | ||
121 | spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); | ||
122 | return container_of(qr, struct ft_cmd, se_req); | ||
123 | } | ||
124 | |||
125 | static void ft_free_cmd(struct ft_cmd *cmd) | 93 | static void ft_free_cmd(struct ft_cmd *cmd) |
126 | { | 94 | { |
127 | struct fc_frame *fp; | 95 | struct fc_frame *fp; |
@@ -282,9 +250,7 @@ u32 ft_get_task_tag(struct se_cmd *se_cmd) | |||
282 | 250 | ||
283 | int ft_get_cmd_state(struct se_cmd *se_cmd) | 251 | int ft_get_cmd_state(struct se_cmd *se_cmd) |
284 | { | 252 | { |
285 | struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); | 253 | return 0; |
286 | |||
287 | return cmd->state; | ||
288 | } | 254 | } |
289 | 255 | ||
290 | int ft_is_state_remove(struct se_cmd *se_cmd) | 256 | int ft_is_state_remove(struct se_cmd *se_cmd) |
@@ -505,6 +471,8 @@ int ft_queue_tm_resp(struct se_cmd *se_cmd) | |||
505 | return 0; | 471 | return 0; |
506 | } | 472 | } |
507 | 473 | ||
474 | static void ft_send_work(struct work_struct *work); | ||
475 | |||
508 | /* | 476 | /* |
509 | * Handle incoming FCP command. | 477 | * Handle incoming FCP command. |
510 | */ | 478 | */ |
@@ -523,7 +491,9 @@ static void ft_recv_cmd(struct ft_sess *sess, struct fc_frame *fp) | |||
523 | goto busy; | 491 | goto busy; |
524 | } | 492 | } |
525 | cmd->req_frame = fp; /* hold frame during cmd */ | 493 | cmd->req_frame = fp; /* hold frame during cmd */ |
526 | ft_queue_cmd(sess, cmd); | 494 | |
495 | INIT_WORK(&cmd->work, ft_send_work); | ||
496 | queue_work(sess->tport->tpg->workqueue, &cmd->work); | ||
527 | return; | 497 | return; |
528 | 498 | ||
529 | busy: | 499 | busy: |
@@ -563,12 +533,13 @@ void ft_recv_req(struct ft_sess *sess, struct fc_frame *fp) | |||
563 | /* | 533 | /* |
564 | * Send new command to target. | 534 | * Send new command to target. |
565 | */ | 535 | */ |
566 | static void ft_send_cmd(struct ft_cmd *cmd) | 536 | static void ft_send_work(struct work_struct *work) |
567 | { | 537 | { |
538 | struct ft_cmd *cmd = container_of(work, struct ft_cmd, work); | ||
568 | struct fc_frame_header *fh = fc_frame_header_get(cmd->req_frame); | 539 | struct fc_frame_header *fh = fc_frame_header_get(cmd->req_frame); |
569 | struct se_cmd *se_cmd; | 540 | struct se_cmd *se_cmd; |
570 | struct fcp_cmnd *fcp; | 541 | struct fcp_cmnd *fcp; |
571 | int data_dir; | 542 | int data_dir = 0; |
572 | u32 data_len; | 543 | u32 data_len; |
573 | int task_attr; | 544 | int task_attr; |
574 | int ret; | 545 | int ret; |
@@ -675,42 +646,3 @@ static void ft_send_cmd(struct ft_cmd *cmd) | |||
675 | err: | 646 | err: |
676 | ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID); | 647 | ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID); |
677 | } | 648 | } |
678 | |||
679 | /* | ||
680 | * Handle request in the command thread. | ||
681 | */ | ||
682 | static void ft_exec_req(struct ft_cmd *cmd) | ||
683 | { | ||
684 | pr_debug("cmd state %x\n", cmd->state); | ||
685 | switch (cmd->state) { | ||
686 | case FC_CMD_ST_NEW: | ||
687 | ft_send_cmd(cmd); | ||
688 | break; | ||
689 | default: | ||
690 | break; | ||
691 | } | ||
692 | } | ||
693 | |||
694 | /* | ||
695 | * Processing thread. | ||
696 | * Currently one thread per tpg. | ||
697 | */ | ||
698 | int ft_thread(void *arg) | ||
699 | { | ||
700 | struct ft_tpg *tpg = arg; | ||
701 | struct se_queue_obj *qobj = &tpg->qobj; | ||
702 | struct ft_cmd *cmd; | ||
703 | |||
704 | while (!kthread_should_stop()) { | ||
705 | schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT); | ||
706 | if (kthread_should_stop()) | ||
707 | goto out; | ||
708 | |||
709 | cmd = ft_dequeue_cmd(qobj); | ||
710 | if (cmd) | ||
711 | ft_exec_req(cmd); | ||
712 | } | ||
713 | |||
714 | out: | ||
715 | return 0; | ||
716 | } | ||
diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index b15879d43e22..8fa39b74f22c 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c | |||
@@ -327,7 +327,6 @@ static struct se_portal_group *ft_add_tpg( | |||
327 | tpg->index = index; | 327 | tpg->index = index; |
328 | tpg->lport_acl = lacl; | 328 | tpg->lport_acl = lacl; |
329 | INIT_LIST_HEAD(&tpg->lun_list); | 329 | INIT_LIST_HEAD(&tpg->lun_list); |
330 | transport_init_queue_obj(&tpg->qobj); | ||
331 | 330 | ||
332 | ret = core_tpg_register(&ft_configfs->tf_ops, wwn, &tpg->se_tpg, | 331 | ret = core_tpg_register(&ft_configfs->tf_ops, wwn, &tpg->se_tpg, |
333 | tpg, TRANSPORT_TPG_TYPE_NORMAL); | 332 | tpg, TRANSPORT_TPG_TYPE_NORMAL); |
@@ -336,8 +335,8 @@ static struct se_portal_group *ft_add_tpg( | |||
336 | return NULL; | 335 | return NULL; |
337 | } | 336 | } |
338 | 337 | ||
339 | tpg->thread = kthread_run(ft_thread, tpg, "ft_tpg%lu", index); | 338 | tpg->workqueue = alloc_workqueue("tcm_fc", 0, 1); |
340 | if (IS_ERR(tpg->thread)) { | 339 | if (!tpg->workqueue) { |
341 | kfree(tpg); | 340 | kfree(tpg); |
342 | return NULL; | 341 | return NULL; |
343 | } | 342 | } |
@@ -356,7 +355,7 @@ static void ft_del_tpg(struct se_portal_group *se_tpg) | |||
356 | pr_debug("del tpg %s\n", | 355 | pr_debug("del tpg %s\n", |
357 | config_item_name(&tpg->se_tpg.tpg_group.cg_item)); | 356 | config_item_name(&tpg->se_tpg.tpg_group.cg_item)); |
358 | 357 | ||
359 | kthread_stop(tpg->thread); | 358 | destroy_workqueue(tpg->workqueue); |
360 | 359 | ||
361 | /* Wait for sessions to be freed thru RCU, for BUG_ON below */ | 360 | /* Wait for sessions to be freed thru RCU, for BUG_ON below */ |
362 | synchronize_rcu(); | 361 | synchronize_rcu(); |
diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c index c37f4cd96452..d35ea5a3d56c 100644 --- a/drivers/target/tcm_fc/tfc_io.c +++ b/drivers/target/tcm_fc/tfc_io.c | |||
@@ -219,43 +219,41 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp) | |||
219 | if (cmd->was_ddp_setup) { | 219 | if (cmd->was_ddp_setup) { |
220 | BUG_ON(!ep); | 220 | BUG_ON(!ep); |
221 | BUG_ON(!lport); | 221 | BUG_ON(!lport); |
222 | } | 222 | /* |
223 | 223 | * Since DDP (Large Rx offload) was setup for this request, | |
224 | /* | 224 | * payload is expected to be copied directly to user buffers. |
225 | * Doesn't expect payload if DDP is setup. Payload | 225 | */ |
226 | * is expected to be copied directly to user buffers | 226 | buf = fc_frame_payload_get(fp, 1); |
227 | * due to DDP (Large Rx offload), | 227 | if (buf) |
228 | */ | 228 | pr_err("%s: xid 0x%x, f_ctl 0x%x, cmd->sg %p, " |
229 | buf = fc_frame_payload_get(fp, 1); | ||
230 | if (buf) | ||
231 | pr_err("%s: xid 0x%x, f_ctl 0x%x, cmd->sg %p, " | ||
232 | "cmd->sg_cnt 0x%x. DDP was setup" | 229 | "cmd->sg_cnt 0x%x. DDP was setup" |
233 | " hence not expected to receive frame with " | 230 | " hence not expected to receive frame with " |
234 | "payload, Frame will be dropped if " | 231 | "payload, Frame will be dropped if" |
235 | "'Sequence Initiative' bit in f_ctl is " | 232 | "'Sequence Initiative' bit in f_ctl is" |
236 | "not set\n", __func__, ep->xid, f_ctl, | 233 | "not set\n", __func__, ep->xid, f_ctl, |
237 | cmd->sg, cmd->sg_cnt); | 234 | cmd->sg, cmd->sg_cnt); |
238 | /* | 235 | /* |
239 | * Invalidate HW DDP context if it was setup for respective | 236 | * Invalidate HW DDP context if it was setup for respective |
240 | * command. Invalidation of HW DDP context is requited in both | 237 | * command. Invalidation of HW DDP context is requited in both |
241 | * situation (success and error). | 238 | * situation (success and error). |
242 | */ | 239 | */ |
243 | ft_invl_hw_context(cmd); | 240 | ft_invl_hw_context(cmd); |
244 | 241 | ||
245 | /* | 242 | /* |
246 | * If "Sequence Initiative (TSI)" bit set in f_ctl, means last | 243 | * If "Sequence Initiative (TSI)" bit set in f_ctl, means last |
247 | * write data frame is received successfully where payload is | 244 | * write data frame is received successfully where payload is |
248 | * posted directly to user buffer and only the last frame's | 245 | * posted directly to user buffer and only the last frame's |
249 | * header is posted in receive queue. | 246 | * header is posted in receive queue. |
250 | * | 247 | * |
251 | * If "Sequence Initiative (TSI)" bit is not set, means error | 248 | * If "Sequence Initiative (TSI)" bit is not set, means error |
252 | * condition w.r.t. DDP, hence drop the packet and let explict | 249 | * condition w.r.t. DDP, hence drop the packet and let explict |
253 | * ABORTS from other end of exchange timer trigger the recovery. | 250 | * ABORTS from other end of exchange timer trigger the recovery. |
254 | */ | 251 | */ |
255 | if (f_ctl & FC_FC_SEQ_INIT) | 252 | if (f_ctl & FC_FC_SEQ_INIT) |
256 | goto last_frame; | 253 | goto last_frame; |
257 | else | 254 | else |
258 | goto drop; | 255 | goto drop; |
256 | } | ||
259 | 257 | ||
260 | rel_off = ntohl(fh->fh_parm_offset); | 258 | rel_off = ntohl(fh->fh_parm_offset); |
261 | frame_len = fr_len(fp); | 259 | frame_len = fr_len(fp); |