diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2013-06-14 19:07:47 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2013-06-25 01:35:51 -0400 |
commit | 778de368964c5b7e8100cde9f549992d521e9c89 (patch) | |
tree | 5925e16a0fa2e29925f3ee44a0f00fc11d2afb4d | |
parent | 08234e3adc7a299c9213bcfa0b5e97c359129670 (diff) |
iscsi/isert-target: Refactor ISCSI_OP_NOOP RX handling
This patch refactors ISCSI_OP_NOOP handling within iscsi-target in
order to handle iscsi_nopout payloads in a transport specific manner.
This includes splitting existing iscsit_handle_nop_out() into
iscsit_setup_nop_out() and iscsit_process_nop_out() calls, and
makes iscsit_handle_nop_out() be only used internally by traditional
iscsi socket calls.
Next update iser-target code to use new callers and add FIXME for
the handling iscsi_nopout payloads. Also fix reject response handling
in iscsit_setup_nop_out() to use proper iscsit_add_reject_from_cmd().
v2: Fix uninitialized iscsit_handle_nop_out() payload_length usage (Fengguang)
v3: Remove left-over dead code in iscsit_setup_nop_out() (DanC)
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r-- | drivers/infiniband/ulp/isert/ib_isert.c | 23 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target.c | 174 | ||||
-rw-r--r-- | include/target/iscsi/iscsi_transport.h | 6 |
3 files changed, 115 insertions, 88 deletions
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index 41712f096515..c48c9481025c 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c | |||
@@ -1001,6 +1001,25 @@ isert_handle_iscsi_dataout(struct isert_conn *isert_conn, | |||
1001 | } | 1001 | } |
1002 | 1002 | ||
1003 | static int | 1003 | static int |
1004 | isert_handle_nop_out(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd, | ||
1005 | struct iser_rx_desc *rx_desc, unsigned char *buf) | ||
1006 | { | ||
1007 | struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd; | ||
1008 | struct iscsi_conn *conn = isert_conn->conn; | ||
1009 | struct iscsi_nopout *hdr = (struct iscsi_nopout *)buf; | ||
1010 | int rc; | ||
1011 | |||
1012 | rc = iscsit_setup_nop_out(conn, cmd, hdr); | ||
1013 | if (rc < 0) | ||
1014 | return rc; | ||
1015 | /* | ||
1016 | * FIXME: Add support for NOPOUT payload using unsolicited RDMA payload | ||
1017 | */ | ||
1018 | |||
1019 | return iscsit_process_nop_out(conn, cmd, hdr); | ||
1020 | } | ||
1021 | |||
1022 | static int | ||
1004 | isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc, | 1023 | isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc, |
1005 | uint32_t read_stag, uint64_t read_va, | 1024 | uint32_t read_stag, uint64_t read_va, |
1006 | uint32_t write_stag, uint64_t write_va) | 1025 | uint32_t write_stag, uint64_t write_va) |
@@ -1032,7 +1051,9 @@ isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc, | |||
1032 | if (!cmd) | 1051 | if (!cmd) |
1033 | break; | 1052 | break; |
1034 | 1053 | ||
1035 | ret = iscsit_handle_nop_out(conn, cmd, (unsigned char *)hdr); | 1054 | isert_cmd = container_of(cmd, struct isert_cmd, iscsi_cmd); |
1055 | ret = isert_handle_nop_out(isert_conn, isert_cmd, | ||
1056 | rx_desc, (unsigned char *)hdr); | ||
1036 | break; | 1057 | break; |
1037 | case ISCSI_OP_SCSI_DATA_OUT: | 1058 | case ISCSI_OP_SCSI_DATA_OUT: |
1038 | ret = isert_handle_iscsi_dataout(isert_conn, rx_desc, | 1059 | ret = isert_handle_iscsi_dataout(isert_conn, rx_desc, |
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index cc43d4163adc..f684627244bf 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c | |||
@@ -1535,24 +1535,16 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf) | |||
1535 | return iscsit_check_dataout_payload(cmd, hdr, data_crc_failed); | 1535 | return iscsit_check_dataout_payload(cmd, hdr, data_crc_failed); |
1536 | } | 1536 | } |
1537 | 1537 | ||
1538 | int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd, | 1538 | int iscsit_setup_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd, |
1539 | unsigned char *buf) | 1539 | struct iscsi_nopout *hdr) |
1540 | { | 1540 | { |
1541 | unsigned char *ping_data = NULL; | 1541 | u32 payload_length = ntoh24(hdr->dlength); |
1542 | int cmdsn_ret, niov = 0, ret = 0, rx_got, rx_size; | ||
1543 | u32 checksum, data_crc, padding = 0, payload_length; | ||
1544 | struct iscsi_cmd *cmd_p = NULL; | ||
1545 | struct kvec *iov = NULL; | ||
1546 | struct iscsi_nopout *hdr; | ||
1547 | |||
1548 | hdr = (struct iscsi_nopout *) buf; | ||
1549 | payload_length = ntoh24(hdr->dlength); | ||
1550 | 1542 | ||
1551 | if (hdr->itt == RESERVED_ITT && !(hdr->opcode & ISCSI_OP_IMMEDIATE)) { | 1543 | if (hdr->itt == RESERVED_ITT && !(hdr->opcode & ISCSI_OP_IMMEDIATE)) { |
1552 | pr_err("NOPOUT ITT is reserved, but Immediate Bit is" | 1544 | pr_err("NOPOUT ITT is reserved, but Immediate Bit is" |
1553 | " not set, protocol error.\n"); | 1545 | " not set, protocol error.\n"); |
1554 | return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, | 1546 | return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR, |
1555 | buf, conn); | 1547 | 1, 0, (unsigned char *)hdr, cmd); |
1556 | } | 1548 | } |
1557 | 1549 | ||
1558 | if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) { | 1550 | if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) { |
@@ -1560,8 +1552,8 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd, | |||
1560 | " greater than MaxXmitDataSegmentLength: %u, protocol" | 1552 | " greater than MaxXmitDataSegmentLength: %u, protocol" |
1561 | " error.\n", payload_length, | 1553 | " error.\n", payload_length, |
1562 | conn->conn_ops->MaxXmitDataSegmentLength); | 1554 | conn->conn_ops->MaxXmitDataSegmentLength); |
1563 | return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, | 1555 | return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR, |
1564 | buf, conn); | 1556 | 1, 0, (unsigned char *)hdr, cmd); |
1565 | } | 1557 | } |
1566 | 1558 | ||
1567 | pr_debug("Got NOPOUT Ping %s ITT: 0x%08x, TTT: 0x%08x," | 1559 | pr_debug("Got NOPOUT Ping %s ITT: 0x%08x, TTT: 0x%08x," |
@@ -1577,11 +1569,6 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd, | |||
1577 | * can contain ping data. | 1569 | * can contain ping data. |
1578 | */ | 1570 | */ |
1579 | if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) { | 1571 | if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) { |
1580 | if (!cmd) | ||
1581 | return iscsit_add_reject( | ||
1582 | ISCSI_REASON_BOOKMARK_NO_RESOURCES, | ||
1583 | 1, buf, conn); | ||
1584 | |||
1585 | cmd->iscsi_opcode = ISCSI_OP_NOOP_OUT; | 1572 | cmd->iscsi_opcode = ISCSI_OP_NOOP_OUT; |
1586 | cmd->i_state = ISTATE_SEND_NOPIN; | 1573 | cmd->i_state = ISTATE_SEND_NOPIN; |
1587 | cmd->immediate_cmd = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? | 1574 | cmd->immediate_cmd = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? |
@@ -1593,8 +1580,87 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd, | |||
1593 | cmd->data_direction = DMA_NONE; | 1580 | cmd->data_direction = DMA_NONE; |
1594 | } | 1581 | } |
1595 | 1582 | ||
1583 | return 0; | ||
1584 | } | ||
1585 | EXPORT_SYMBOL(iscsit_setup_nop_out); | ||
1586 | |||
1587 | int iscsit_process_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd, | ||
1588 | struct iscsi_nopout *hdr) | ||
1589 | { | ||
1590 | struct iscsi_cmd *cmd_p = NULL; | ||
1591 | int cmdsn_ret = 0; | ||
1592 | /* | ||
1593 | * Initiator is expecting a NopIN ping reply.. | ||
1594 | */ | ||
1595 | if (hdr->itt != RESERVED_ITT) { | ||
1596 | BUG_ON(!cmd); | ||
1597 | |||
1598 | spin_lock_bh(&conn->cmd_lock); | ||
1599 | list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list); | ||
1600 | spin_unlock_bh(&conn->cmd_lock); | ||
1601 | |||
1602 | iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn)); | ||
1603 | |||
1604 | if (hdr->opcode & ISCSI_OP_IMMEDIATE) { | ||
1605 | iscsit_add_cmd_to_response_queue(cmd, conn, | ||
1606 | cmd->i_state); | ||
1607 | return 0; | ||
1608 | } | ||
1609 | |||
1610 | cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); | ||
1611 | if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) | ||
1612 | return 0; | ||
1613 | |||
1614 | if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) | ||
1615 | return iscsit_add_reject_from_cmd( | ||
1616 | ISCSI_REASON_PROTOCOL_ERROR, | ||
1617 | 1, 0, (unsigned char *)hdr, cmd); | ||
1618 | |||
1619 | return 0; | ||
1620 | } | ||
1621 | /* | ||
1622 | * This was a response to a unsolicited NOPIN ping. | ||
1623 | */ | ||
1624 | if (hdr->ttt != cpu_to_be32(0xFFFFFFFF)) { | ||
1625 | cmd_p = iscsit_find_cmd_from_ttt(conn, be32_to_cpu(hdr->ttt)); | ||
1626 | if (!cmd_p) | ||
1627 | return -EINVAL; | ||
1628 | |||
1629 | iscsit_stop_nopin_response_timer(conn); | ||
1630 | |||
1631 | cmd_p->i_state = ISTATE_REMOVE; | ||
1632 | iscsit_add_cmd_to_immediate_queue(cmd_p, conn, cmd_p->i_state); | ||
1633 | |||
1634 | iscsit_start_nopin_timer(conn); | ||
1635 | return 0; | ||
1636 | } | ||
1637 | /* | ||
1638 | * Otherwise, initiator is not expecting a NOPIN is response. | ||
1639 | * Just ignore for now. | ||
1640 | */ | ||
1641 | return 0; | ||
1642 | } | ||
1643 | EXPORT_SYMBOL(iscsit_process_nop_out); | ||
1644 | |||
1645 | static int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd, | ||
1646 | unsigned char *buf) | ||
1647 | { | ||
1648 | unsigned char *ping_data = NULL; | ||
1649 | struct iscsi_nopout *hdr = (struct iscsi_nopout *)buf; | ||
1650 | struct kvec *iov = NULL; | ||
1651 | u32 payload_length = ntoh24(hdr->dlength); | ||
1652 | int ret; | ||
1653 | |||
1654 | ret = iscsit_setup_nop_out(conn, cmd, hdr); | ||
1655 | if (ret < 0) | ||
1656 | return ret; | ||
1657 | /* | ||
1658 | * Handle NOP-OUT payload for traditional iSCSI sockets | ||
1659 | */ | ||
1596 | if (payload_length && hdr->ttt == cpu_to_be32(0xFFFFFFFF)) { | 1660 | if (payload_length && hdr->ttt == cpu_to_be32(0xFFFFFFFF)) { |
1597 | rx_size = payload_length; | 1661 | u32 checksum, data_crc, padding = 0; |
1662 | int niov = 0, rx_got, rx_size = payload_length; | ||
1663 | |||
1598 | ping_data = kzalloc(payload_length + 1, GFP_KERNEL); | 1664 | ping_data = kzalloc(payload_length + 1, GFP_KERNEL); |
1599 | if (!ping_data) { | 1665 | if (!ping_data) { |
1600 | pr_err("Unable to allocate memory for" | 1666 | pr_err("Unable to allocate memory for" |
@@ -1673,76 +1739,14 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd, | |||
1673 | pr_debug("Ping Data: \"%s\"\n", ping_data); | 1739 | pr_debug("Ping Data: \"%s\"\n", ping_data); |
1674 | } | 1740 | } |
1675 | 1741 | ||
1676 | if (hdr->itt != RESERVED_ITT) { | 1742 | return iscsit_process_nop_out(conn, cmd, hdr); |
1677 | if (!cmd) { | ||
1678 | pr_err("Checking CmdSN for NOPOUT," | ||
1679 | " but cmd is NULL!\n"); | ||
1680 | return -1; | ||
1681 | } | ||
1682 | /* | ||
1683 | * Initiator is expecting a NopIN ping reply, | ||
1684 | */ | ||
1685 | spin_lock_bh(&conn->cmd_lock); | ||
1686 | list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list); | ||
1687 | spin_unlock_bh(&conn->cmd_lock); | ||
1688 | |||
1689 | iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn)); | ||
1690 | |||
1691 | if (hdr->opcode & ISCSI_OP_IMMEDIATE) { | ||
1692 | iscsit_add_cmd_to_response_queue(cmd, conn, | ||
1693 | cmd->i_state); | ||
1694 | return 0; | ||
1695 | } | ||
1696 | |||
1697 | cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); | ||
1698 | if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) { | ||
1699 | ret = 0; | ||
1700 | goto ping_out; | ||
1701 | } | ||
1702 | if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) | ||
1703 | return iscsit_add_reject_from_cmd( | ||
1704 | ISCSI_REASON_PROTOCOL_ERROR, | ||
1705 | 1, 0, buf, cmd); | ||
1706 | |||
1707 | return 0; | ||
1708 | } | ||
1709 | |||
1710 | if (hdr->ttt != cpu_to_be32(0xFFFFFFFF)) { | ||
1711 | /* | ||
1712 | * This was a response to a unsolicited NOPIN ping. | ||
1713 | */ | ||
1714 | cmd_p = iscsit_find_cmd_from_ttt(conn, be32_to_cpu(hdr->ttt)); | ||
1715 | if (!cmd_p) | ||
1716 | return -1; | ||
1717 | |||
1718 | iscsit_stop_nopin_response_timer(conn); | ||
1719 | |||
1720 | cmd_p->i_state = ISTATE_REMOVE; | ||
1721 | iscsit_add_cmd_to_immediate_queue(cmd_p, conn, cmd_p->i_state); | ||
1722 | iscsit_start_nopin_timer(conn); | ||
1723 | } else { | ||
1724 | /* | ||
1725 | * Initiator is not expecting a NOPIN is response. | ||
1726 | * Just ignore for now. | ||
1727 | * | ||
1728 | * iSCSI v19-91 10.18 | ||
1729 | * "A NOP-OUT may also be used to confirm a changed | ||
1730 | * ExpStatSN if another PDU will not be available | ||
1731 | * for a long time." | ||
1732 | */ | ||
1733 | ret = 0; | ||
1734 | goto out; | ||
1735 | } | ||
1736 | |||
1737 | return 0; | ||
1738 | out: | 1743 | out: |
1739 | if (cmd) | 1744 | if (cmd) |
1740 | iscsit_free_cmd(cmd, false); | 1745 | iscsit_free_cmd(cmd, false); |
1741 | ping_out: | 1746 | |
1742 | kfree(ping_data); | 1747 | kfree(ping_data); |
1743 | return ret; | 1748 | return ret; |
1744 | } | 1749 | } |
1745 | EXPORT_SYMBOL(iscsit_handle_nop_out); | ||
1746 | 1750 | ||
1747 | int | 1751 | int |
1748 | iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, | 1752 | iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, |
diff --git a/include/target/iscsi/iscsi_transport.h b/include/target/iscsi/iscsi_transport.h index 23a87d0cd72c..ecb53ea6d1c7 100644 --- a/include/target/iscsi/iscsi_transport.h +++ b/include/target/iscsi/iscsi_transport.h | |||
@@ -45,8 +45,10 @@ extern int iscsit_check_dataout_hdr(struct iscsi_conn *, unsigned char *, | |||
45 | struct iscsi_cmd **); | 45 | struct iscsi_cmd **); |
46 | extern int iscsit_check_dataout_payload(struct iscsi_cmd *, struct iscsi_data *, | 46 | extern int iscsit_check_dataout_payload(struct iscsi_cmd *, struct iscsi_data *, |
47 | bool); | 47 | bool); |
48 | extern int iscsit_handle_nop_out(struct iscsi_conn *, struct iscsi_cmd *, | 48 | extern int iscsit_setup_nop_out(struct iscsi_conn *, struct iscsi_cmd *, |
49 | unsigned char *); | 49 | struct iscsi_nopout *); |
50 | extern int iscsit_process_nop_out(struct iscsi_conn *, struct iscsi_cmd *, | ||
51 | struct iscsi_nopout *); | ||
50 | extern int iscsit_handle_logout_cmd(struct iscsi_conn *, struct iscsi_cmd *, | 52 | extern int iscsit_handle_logout_cmd(struct iscsi_conn *, struct iscsi_cmd *, |
51 | unsigned char *); | 53 | unsigned char *); |
52 | extern int iscsit_handle_task_mgt_cmd(struct iscsi_conn *, struct iscsi_cmd *, | 54 | extern int iscsit_handle_task_mgt_cmd(struct iscsi_conn *, struct iscsi_cmd *, |