diff options
| -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); |
