diff options
author | Christoph Hellwig <hch@infradead.org> | 2012-05-20 11:59:12 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2012-07-16 20:25:55 -0400 |
commit | 9b3b804101db067c3889948f57031f852186ea11 (patch) | |
tree | 87dbfb7e11f1558b4e841c27857290fe89771aa7 | |
parent | 64f1db38c65fa634f4aa21e0f70480a6b8b4d47c (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.c | 90 |
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 | ||
1346 | static int transport_generic_cmd_sequencer(struct se_cmd *, unsigned char *); | 1346 | static int transport_generic_cmd_sequencer(struct se_cmd *, unsigned char *); |
1347 | 1347 | ||
1348 | static 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 | |||
1391 | out_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) { |