aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicholas Bellinger <nab@linux-iscsi.org>2015-07-30 21:28:13 -0400
committerNicholas Bellinger <nab@linux-iscsi.org>2015-09-11 03:31:39 -0400
commit8f9b565482c537821588444e09ff732c7d65ed6e (patch)
treeb411dd3479eb5f3f86e2eb390c1c973e4b31ee12
parent13a3cf08fa1e4b3a252f24202d47a556242aea03 (diff)
target/qla2xxx: Honor max_data_sg_nents I/O transfer limit
This patch adds an optional fabric driver provided SGL limit that target-core will honor as it's own internal I/O maximum transfer length limit, as exposed by EVPD=0xb0 block limits parameters. This is required for handling cases when host I/O transfer length exceeds the requested EVPD block limits maximum transfer length. The initial user of this logic is qla2xxx, so that we can avoid having to reject I/Os from some legacy FC hosts where EVPD=0xb0 parameters are not honored. When se_cmd payload length exceeds the provided limit in target_check_max_data_sg_nents() code, se_cmd->data_length + se_cmd->prot_length are reset with se_cmd->residual_count plus underflow bit for outgoing TFO response callbacks. It also checks for existing CDB level underflow + overflow and recalculates final residual_count as necessary. Note this patch currently assumes 1:1 mapping of PAGE_SIZE per struct scatterlist entry. Reported-by: Craig Watson <craig.watson@vanguard-rugged.com> Cc: Craig Watson <craig.watson@vanguard-rugged.com> Tested-by: Himanshu Madhani <himanshu.madhani@qlogic.com> Cc: Roland Dreier <roland@purestorage.com> Cc: Arun Easi <arun.easi@qlogic.com> Cc: Giridhar Malavali <giridhar.malavali@qlogic.com> Cc: Andrew Vasquez <andrew.vasquez@qlogic.com> Cc: Christoph Hellwig <hch@lst.de> Cc: Hannes Reinecke <hare@suse.de> Cc: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r--drivers/scsi/qla2xxx/tcm_qla2xxx.c5
-rw-r--r--drivers/target/target_core_spc.c13
-rw-r--r--drivers/target/target_core_transport.c51
-rw-r--r--include/target/target_core_fabric.h13
4 files changed, 78 insertions, 4 deletions
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index c621623abeed..edeb3aefa6fe 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -1808,6 +1808,11 @@ static const struct target_core_fabric_ops tcm_qla2xxx_ops = {
1808 .module = THIS_MODULE, 1808 .module = THIS_MODULE,
1809 .name = "qla2xxx", 1809 .name = "qla2xxx",
1810 .node_acl_size = sizeof(struct tcm_qla2xxx_nacl), 1810 .node_acl_size = sizeof(struct tcm_qla2xxx_nacl),
1811 /*
1812 * XXX: Limit assumes single page per scatter-gather-list entry.
1813 * Current maximum is ~4.9 MB per se_cmd->t_data_sg with PAGE_SIZE=4096
1814 */
1815 .max_data_sg_nents = 1200,
1811 .get_fabric_name = tcm_qla2xxx_get_fabric_name, 1816 .get_fabric_name = tcm_qla2xxx_get_fabric_name,
1812 .tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn, 1817 .tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn,
1813 .tpg_get_tag = tcm_qla2xxx_get_tag, 1818 .tpg_get_tag = tcm_qla2xxx_get_tag,
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c
index a07d455e0dd5..0e0456f6a282 100644
--- a/drivers/target/target_core_spc.c
+++ b/drivers/target/target_core_spc.c
@@ -477,8 +477,8 @@ static sense_reason_t
477spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) 477spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf)
478{ 478{
479 struct se_device *dev = cmd->se_dev; 479 struct se_device *dev = cmd->se_dev;
480 int have_tp = 0; 480 u32 mtl = 0;
481 int opt, min; 481 int have_tp = 0, opt, min;
482 482
483 /* 483 /*
484 * Following spc3r22 section 6.5.3 Block Limits VPD page, when 484 * Following spc3r22 section 6.5.3 Block Limits VPD page, when
@@ -509,8 +509,15 @@ spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf)
509 509
510 /* 510 /*
511 * Set MAXIMUM TRANSFER LENGTH 511 * Set MAXIMUM TRANSFER LENGTH
512 *
513 * XXX: Currently assumes single PAGE_SIZE per scatterlist for fabrics
514 * enforcing maximum HW scatter-gather-list entry limit
512 */ 515 */
513 put_unaligned_be32(dev->dev_attrib.hw_max_sectors, &buf[8]); 516 if (cmd->se_tfo->max_data_sg_nents) {
517 mtl = (cmd->se_tfo->max_data_sg_nents * PAGE_SIZE) /
518 dev->dev_attrib.block_size;
519 }
520 put_unaligned_be32(min_not_zero(mtl, dev->dev_attrib.hw_max_sectors), &buf[8]);
514 521
515 /* 522 /*
516 * Set OPTIMAL TRANSFER LENGTH 523 * Set OPTIMAL TRANSFER LENGTH
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 3f0b50082de4..62bafaa670f4 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -1075,6 +1075,55 @@ transport_set_vpd_ident(struct t10_vpd *vpd, unsigned char *page_83)
1075} 1075}
1076EXPORT_SYMBOL(transport_set_vpd_ident); 1076EXPORT_SYMBOL(transport_set_vpd_ident);
1077 1077
1078static sense_reason_t
1079target_check_max_data_sg_nents(struct se_cmd *cmd, struct se_device *dev,
1080 unsigned int size)
1081{
1082 u32 mtl;
1083
1084 if (!cmd->se_tfo->max_data_sg_nents)
1085 return TCM_NO_SENSE;
1086 /*
1087 * Check if fabric enforced maximum SGL entries per I/O descriptor
1088 * exceeds se_cmd->data_length. If true, set SCF_UNDERFLOW_BIT +
1089 * residual_count and reduce original cmd->data_length to maximum
1090 * length based on single PAGE_SIZE entry scatter-lists.
1091 */
1092 mtl = (cmd->se_tfo->max_data_sg_nents * PAGE_SIZE);
1093 if (cmd->data_length > mtl) {
1094 /*
1095 * If an existing CDB overflow is present, calculate new residual
1096 * based on CDB size minus fabric maximum transfer length.
1097 *
1098 * If an existing CDB underflow is present, calculate new residual
1099 * based on original cmd->data_length minus fabric maximum transfer
1100 * length.
1101 *
1102 * Otherwise, set the underflow residual based on cmd->data_length
1103 * minus fabric maximum transfer length.
1104 */
1105 if (cmd->se_cmd_flags & SCF_OVERFLOW_BIT) {
1106 cmd->residual_count = (size - mtl);
1107 } else if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) {
1108 u32 orig_dl = size + cmd->residual_count;
1109 cmd->residual_count = (orig_dl - mtl);
1110 } else {
1111 cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT;
1112 cmd->residual_count = (cmd->data_length - mtl);
1113 }
1114 cmd->data_length = mtl;
1115 /*
1116 * Reset sbc_check_prot() calculated protection payload
1117 * length based upon the new smaller MTL.
1118 */
1119 if (cmd->prot_length) {
1120 u32 sectors = (mtl / dev->dev_attrib.block_size);
1121 cmd->prot_length = dev->prot_length * sectors;
1122 }
1123 }
1124 return TCM_NO_SENSE;
1125}
1126
1078sense_reason_t 1127sense_reason_t
1079target_cmd_size_check(struct se_cmd *cmd, unsigned int size) 1128target_cmd_size_check(struct se_cmd *cmd, unsigned int size)
1080{ 1129{
@@ -1120,7 +1169,7 @@ target_cmd_size_check(struct se_cmd *cmd, unsigned int size)
1120 } 1169 }
1121 } 1170 }
1122 1171
1123 return 0; 1172 return target_check_max_data_sg_nents(cmd, dev, size);
1124 1173
1125} 1174}
1126 1175
diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h
index 69355feabd1d..7fb2557a760e 100644
--- a/include/target/target_core_fabric.h
+++ b/include/target/target_core_fabric.h
@@ -5,6 +5,19 @@ struct target_core_fabric_ops {
5 struct module *module; 5 struct module *module;
6 const char *name; 6 const char *name;
7 size_t node_acl_size; 7 size_t node_acl_size;
8 /*
9 * Limits number of scatterlist entries per SCF_SCSI_DATA_CDB payload.
10 * Setting this value tells target-core to enforce this limit, and
11 * report as INQUIRY EVPD=b0 MAXIMUM TRANSFER LENGTH.
12 *
13 * target-core will currently reset se_cmd->data_length to this
14 * maximum size, and set UNDERFLOW residual count if length exceeds
15 * this limit.
16 *
17 * XXX: Not all initiator hosts honor this block-limit EVPD
18 * XXX: Currently assumes single PAGE_SIZE per scatterlist entry
19 */
20 u32 max_data_sg_nents;
8 char *(*get_fabric_name)(void); 21 char *(*get_fabric_name)(void);
9 char *(*tpg_get_wwn)(struct se_portal_group *); 22 char *(*tpg_get_wwn)(struct se_portal_group *);
10 u16 (*tpg_get_tag)(struct se_portal_group *); 23 u16 (*tpg_get_tag)(struct se_portal_group *);