aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2012-05-20 11:59:12 -0400
committerNicholas Bellinger <nab@linux-iscsi.org>2012-07-16 20:25:55 -0400
commit9b3b804101db067c3889948f57031f852186ea11 (patch)
tree87dbfb7e11f1558b4e841c27857290fe89771aa7
parent64f1db38c65fa634f4aa21e0f70480a6b8b4d47c (diff)
target: split overflow and underflow checks into a helper
Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r--drivers/target/target_core_transport.c90
1 files changed, 53 insertions, 37 deletions
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index a181951a7aca..23657a027666 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -1345,6 +1345,55 @@ static inline void transport_generic_prepare_cdb(
1345 1345
1346static int transport_generic_cmd_sequencer(struct se_cmd *, unsigned char *); 1346static int transport_generic_cmd_sequencer(struct se_cmd *, unsigned char *);
1347 1347
1348static int target_cmd_size_check(struct se_cmd *cmd, unsigned int size)
1349{
1350 struct se_device *dev = cmd->se_dev;
1351
1352 if (cmd->unknown_data_length) {
1353 cmd->data_length = size;
1354 } else if (size != cmd->data_length) {
1355 pr_warn("TARGET_CORE[%s]: Expected Transfer Length:"
1356 " %u does not match SCSI CDB Length: %u for SAM Opcode:"
1357 " 0x%02x\n", cmd->se_tfo->get_fabric_name(),
1358 cmd->data_length, size, cmd->t_task_cdb[0]);
1359
1360 cmd->cmd_spdtl = size;
1361
1362 if (cmd->data_direction == DMA_TO_DEVICE) {
1363 pr_err("Rejecting underflow/overflow"
1364 " WRITE data\n");
1365 goto out_invalid_cdb_field;
1366 }
1367 /*
1368 * Reject READ_* or WRITE_* with overflow/underflow for
1369 * type SCF_SCSI_DATA_CDB.
1370 */
1371 if (dev->se_sub_dev->se_dev_attrib.block_size != 512) {
1372 pr_err("Failing OVERFLOW/UNDERFLOW for LBA op"
1373 " CDB on non 512-byte sector setup subsystem"
1374 " plugin: %s\n", dev->transport->name);
1375 /* Returns CHECK_CONDITION + INVALID_CDB_FIELD */
1376 goto out_invalid_cdb_field;
1377 }
1378
1379 if (size > cmd->data_length) {
1380 cmd->se_cmd_flags |= SCF_OVERFLOW_BIT;
1381 cmd->residual_count = (size - cmd->data_length);
1382 } else {
1383 cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT;
1384 cmd->residual_count = (cmd->data_length - size);
1385 }
1386 cmd->data_length = size;
1387 }
1388
1389 return 0;
1390
1391out_invalid_cdb_field:
1392 cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
1393 cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
1394 return -EINVAL;
1395}
1396
1348/* 1397/*
1349 * Used by fabric modules containing a local struct se_cmd within their 1398 * Used by fabric modules containing a local struct se_cmd within their
1350 * fabric dependent per I/O descriptor. 1399 * fabric dependent per I/O descriptor.
@@ -2431,6 +2480,7 @@ static int transport_generic_cmd_sequencer(
2431 int sector_ret = 0, passthrough; 2480 int sector_ret = 0, passthrough;
2432 u32 sectors = 0, size = 0; 2481 u32 sectors = 0, size = 0;
2433 u16 service_action; 2482 u16 service_action;
2483 int ret;
2434 2484
2435 /* 2485 /*
2436 * If we operate in passthrough mode we skip most CDB emulation and 2486 * If we operate in passthrough mode we skip most CDB emulation and
@@ -2929,43 +2979,9 @@ static int transport_generic_cmd_sequencer(
2929 goto out_unsupported_cdb; 2979 goto out_unsupported_cdb;
2930 } 2980 }
2931 2981
2932 if (cmd->unknown_data_length) 2982 ret = target_cmd_size_check(cmd, size);
2933 cmd->data_length = size; 2983 if (ret)
2934 2984 return ret;
2935 if (size != cmd->data_length) {
2936 pr_warn("TARGET_CORE[%s]: Expected Transfer Length:"
2937 " %u does not match SCSI CDB Length: %u for SAM Opcode:"
2938 " 0x%02x\n", cmd->se_tfo->get_fabric_name(),
2939 cmd->data_length, size, cdb[0]);
2940
2941 cmd->cmd_spdtl = size;
2942
2943 if (cmd->data_direction == DMA_TO_DEVICE) {
2944 pr_err("Rejecting underflow/overflow"
2945 " WRITE data\n");
2946 goto out_invalid_cdb_field;
2947 }
2948 /*
2949 * Reject READ_* or WRITE_* with overflow/underflow for
2950 * type SCF_SCSI_DATA_CDB.
2951 */
2952 if (dev->se_sub_dev->se_dev_attrib.block_size != 512) {
2953 pr_err("Failing OVERFLOW/UNDERFLOW for LBA op"
2954 " CDB on non 512-byte sector setup subsystem"
2955 " plugin: %s\n", dev->transport->name);
2956 /* Returns CHECK_CONDITION + INVALID_CDB_FIELD */
2957 goto out_invalid_cdb_field;
2958 }
2959
2960 if (size > cmd->data_length) {
2961 cmd->se_cmd_flags |= SCF_OVERFLOW_BIT;
2962 cmd->residual_count = (size - cmd->data_length);
2963 } else {
2964 cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT;
2965 cmd->residual_count = (cmd->data_length - size);
2966 }
2967 cmd->data_length = size;
2968 }
2969 2985
2970 if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) { 2986 if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) {
2971 if (sectors > su_dev->se_dev_attrib.fabric_max_sectors) { 2987 if (sectors > su_dev->se_dev_attrib.fabric_max_sectors) {