diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2011-07-28 03:07:03 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2011-08-22 15:26:21 -0400 |
commit | 706d5860969b3b24d65d9a57bd3bb5e4a1419c08 (patch) | |
tree | a6293f322a5327d3c317c09197b33d66e22d010e /drivers/target | |
parent | 16ab8e60a0ebc22cfbe61d84e620457a15f3a0bc (diff) |
target: Add WRITE_SAME (10) parsing and refactor passthrough checks
This patch adds initial WRITE_SAME (10) w/ UNMAP=1 support following updates in
sbcr26 to allow UNMAP=1 for the non 16 + 32 byte CDB case. It also refactors
current pSCSI passthrough passthrough checks into target_check_write_same_discard()
ahead of UNMAP=0 w/ write payload support into target_core_iblock.c.
This includes the support for handling WRITE_SAME in transport_emulate_control_cdb(),
and converts target_emulate_write_same to accept num_blocks directly for
WRITE_SAME, WRITE_SAME_16 and WRITE_SAME_32.
Reported-by: Eric Seppanen <eric@purestorage.com>
Cc: Roland Dreier <roland@purestorage.com>
Cc: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nicholas Bellinger <nab@risingtidesystems.com>
Diffstat (limited to 'drivers/target')
-rw-r--r-- | drivers/target/target_core_cdb.c | 28 | ||||
-rw-r--r-- | drivers/target/target_core_transport.c | 102 |
2 files changed, 73 insertions, 57 deletions
diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c index d095408dbd5f..4c1d3a98e894 100644 --- a/drivers/target/target_core_cdb.c +++ b/drivers/target/target_core_cdb.c | |||
@@ -1090,24 +1090,17 @@ err: | |||
1090 | * Note this is not used for TCM/pSCSI passthrough | 1090 | * Note this is not used for TCM/pSCSI passthrough |
1091 | */ | 1091 | */ |
1092 | static int | 1092 | static int |
1093 | target_emulate_write_same(struct se_task *task, int write_same32) | 1093 | target_emulate_write_same(struct se_task *task, u32 num_blocks) |
1094 | { | 1094 | { |
1095 | struct se_cmd *cmd = task->task_se_cmd; | 1095 | struct se_cmd *cmd = task->task_se_cmd; |
1096 | struct se_device *dev = cmd->se_dev; | 1096 | struct se_device *dev = cmd->se_dev; |
1097 | sector_t range; | 1097 | sector_t range; |
1098 | sector_t lba = cmd->t_task_lba; | 1098 | sector_t lba = cmd->t_task_lba; |
1099 | unsigned int num_blocks; | ||
1100 | int ret; | 1099 | int ret; |
1101 | /* | 1100 | /* |
1102 | * Extract num_blocks from the WRITE_SAME_* CDB. Then use the explict | 1101 | * Use the explicit range when non zero is supplied, otherwise calculate |
1103 | * range when non zero is supplied, otherwise calculate the remaining | 1102 | * the remaining range based on ->get_blocks() - starting LBA. |
1104 | * range based on ->get_blocks() - starting LBA. | ||
1105 | */ | 1103 | */ |
1106 | if (write_same32) | ||
1107 | num_blocks = get_unaligned_be32(&cmd->t_task_cdb[28]); | ||
1108 | else | ||
1109 | num_blocks = get_unaligned_be32(&cmd->t_task_cdb[10]); | ||
1110 | |||
1111 | if (num_blocks != 0) | 1104 | if (num_blocks != 0) |
1112 | range = num_blocks; | 1105 | range = num_blocks; |
1113 | else | 1106 | else |
@@ -1170,13 +1163,23 @@ transport_emulate_control_cdb(struct se_task *task) | |||
1170 | } | 1163 | } |
1171 | ret = target_emulate_unmap(task); | 1164 | ret = target_emulate_unmap(task); |
1172 | break; | 1165 | break; |
1166 | case WRITE_SAME: | ||
1167 | if (!dev->transport->do_discard) { | ||
1168 | pr_err("WRITE_SAME emulation not supported" | ||
1169 | " for: %s\n", dev->transport->name); | ||
1170 | return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; | ||
1171 | } | ||
1172 | ret = target_emulate_write_same(task, | ||
1173 | get_unaligned_be16(&cmd->t_task_cdb[7])); | ||
1174 | break; | ||
1173 | case WRITE_SAME_16: | 1175 | case WRITE_SAME_16: |
1174 | if (!dev->transport->do_discard) { | 1176 | if (!dev->transport->do_discard) { |
1175 | pr_err("WRITE_SAME_16 emulation not supported" | 1177 | pr_err("WRITE_SAME_16 emulation not supported" |
1176 | " for: %s\n", dev->transport->name); | 1178 | " for: %s\n", dev->transport->name); |
1177 | return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; | 1179 | return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; |
1178 | } | 1180 | } |
1179 | ret = target_emulate_write_same(task, 0); | 1181 | ret = target_emulate_write_same(task, |
1182 | get_unaligned_be32(&cmd->t_task_cdb[10])); | ||
1180 | break; | 1183 | break; |
1181 | case VARIABLE_LENGTH_CMD: | 1184 | case VARIABLE_LENGTH_CMD: |
1182 | service_action = | 1185 | service_action = |
@@ -1189,7 +1192,8 @@ transport_emulate_control_cdb(struct se_task *task) | |||
1189 | dev->transport->name); | 1192 | dev->transport->name); |
1190 | return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; | 1193 | return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; |
1191 | } | 1194 | } |
1192 | ret = target_emulate_write_same(task, 1); | 1195 | ret = target_emulate_write_same(task, |
1196 | get_unaligned_be32(&cmd->t_task_cdb[28])); | ||
1193 | break; | 1197 | break; |
1194 | default: | 1198 | default: |
1195 | pr_err("Unsupported VARIABLE_LENGTH_CMD SA:" | 1199 | pr_err("Unsupported VARIABLE_LENGTH_CMD SA:" |
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index fd7d4518b8ef..eb8055aa6e61 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
@@ -2861,6 +2861,38 @@ static int transport_cmd_get_valid_sectors(struct se_cmd *cmd) | |||
2861 | return sectors; | 2861 | return sectors; |
2862 | } | 2862 | } |
2863 | 2863 | ||
2864 | static int target_check_write_same_discard(unsigned char *flags, struct se_device *dev) | ||
2865 | { | ||
2866 | /* | ||
2867 | * Determine if the received WRITE_SAME is used to for direct | ||
2868 | * passthrough into Linux/SCSI with struct request via TCM/pSCSI | ||
2869 | * or we are signaling the use of internal WRITE_SAME + UNMAP=1 | ||
2870 | * emulation for -> Linux/BLOCK disbard with TCM/IBLOCK code. | ||
2871 | */ | ||
2872 | int passthrough = (dev->transport->transport_type == | ||
2873 | TRANSPORT_PLUGIN_PHBA_PDEV); | ||
2874 | |||
2875 | if (!passthrough) { | ||
2876 | if ((flags[0] & 0x04) || (flags[0] & 0x02)) { | ||
2877 | pr_err("WRITE_SAME PBDATA and LBDATA" | ||
2878 | " bits not supported for Block Discard" | ||
2879 | " Emulation\n"); | ||
2880 | return -ENOSYS; | ||
2881 | } | ||
2882 | /* | ||
2883 | * Currently for the emulated case we only accept | ||
2884 | * tpws with the UNMAP=1 bit set. | ||
2885 | */ | ||
2886 | if (!(flags[0] & 0x08)) { | ||
2887 | pr_err("WRITE_SAME w/o UNMAP bit not" | ||
2888 | " supported for Block Discard Emulation\n"); | ||
2889 | return -ENOSYS; | ||
2890 | } | ||
2891 | } | ||
2892 | |||
2893 | return 0; | ||
2894 | } | ||
2895 | |||
2864 | /* transport_generic_cmd_sequencer(): | 2896 | /* transport_generic_cmd_sequencer(): |
2865 | * | 2897 | * |
2866 | * Generic Command Sequencer that should work for most DAS transport | 2898 | * Generic Command Sequencer that should work for most DAS transport |
@@ -3081,27 +3113,9 @@ static int transport_generic_cmd_sequencer( | |||
3081 | cmd->t_task_lba = get_unaligned_be64(&cdb[12]); | 3113 | cmd->t_task_lba = get_unaligned_be64(&cdb[12]); |
3082 | cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; | 3114 | cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; |
3083 | 3115 | ||
3084 | /* | 3116 | if (target_check_write_same_discard(&cdb[10], dev) < 0) |
3085 | * Skip the remaining assignments for TCM/PSCSI passthrough | ||
3086 | */ | ||
3087 | if (passthrough) | ||
3088 | break; | ||
3089 | |||
3090 | if ((cdb[10] & 0x04) || (cdb[10] & 0x02)) { | ||
3091 | pr_err("WRITE_SAME PBDATA and LBDATA" | ||
3092 | " bits not supported for Block Discard" | ||
3093 | " Emulation\n"); | ||
3094 | goto out_invalid_cdb_field; | 3117 | goto out_invalid_cdb_field; |
3095 | } | 3118 | |
3096 | /* | ||
3097 | * Currently for the emulated case we only accept | ||
3098 | * tpws with the UNMAP=1 bit set. | ||
3099 | */ | ||
3100 | if (!(cdb[10] & 0x08)) { | ||
3101 | pr_err("WRITE_SAME w/o UNMAP bit not" | ||
3102 | " supported for Block Discard Emulation\n"); | ||
3103 | goto out_invalid_cdb_field; | ||
3104 | } | ||
3105 | break; | 3119 | break; |
3106 | default: | 3120 | default: |
3107 | pr_err("VARIABLE_LENGTH_CMD service action" | 3121 | pr_err("VARIABLE_LENGTH_CMD service action" |
@@ -3358,33 +3372,31 @@ static int transport_generic_cmd_sequencer( | |||
3358 | } | 3372 | } |
3359 | 3373 | ||
3360 | cmd->t_task_lba = get_unaligned_be64(&cdb[2]); | 3374 | cmd->t_task_lba = get_unaligned_be64(&cdb[2]); |
3361 | passthrough = (dev->transport->transport_type == | 3375 | cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; |
3362 | TRANSPORT_PLUGIN_PHBA_PDEV); | 3376 | |
3363 | /* | 3377 | if (target_check_write_same_discard(&cdb[1], dev) < 0) |
3364 | * Determine if the received WRITE_SAME_16 is used to for direct | 3378 | goto out_invalid_cdb_field; |
3365 | * passthrough into Linux/SCSI with struct request via TCM/pSCSI | 3379 | break; |
3366 | * or we are signaling the use of internal WRITE_SAME + UNMAP=1 | 3380 | case WRITE_SAME: |
3367 | * emulation for -> Linux/BLOCK disbard with TCM/IBLOCK and | 3381 | sectors = transport_get_sectors_10(cdb, cmd, §or_ret); |
3368 | * TCM/FILEIO subsystem plugin backstores. | 3382 | if (sector_ret) |
3369 | */ | 3383 | goto out_unsupported_cdb; |
3370 | if (!passthrough) { | 3384 | |
3371 | if ((cdb[1] & 0x04) || (cdb[1] & 0x02)) { | 3385 | if (sectors) |
3372 | pr_err("WRITE_SAME PBDATA and LBDATA" | 3386 | size = transport_get_size(sectors, cdb, cmd); |
3373 | " bits not supported for Block Discard" | 3387 | else { |
3374 | " Emulation\n"); | 3388 | pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n"); |
3375 | goto out_invalid_cdb_field; | 3389 | goto out_invalid_cdb_field; |
3376 | } | ||
3377 | /* | ||
3378 | * Currently for the emulated case we only accept | ||
3379 | * tpws with the UNMAP=1 bit set. | ||
3380 | */ | ||
3381 | if (!(cdb[1] & 0x08)) { | ||
3382 | pr_err("WRITE_SAME w/o UNMAP bit not " | ||
3383 | " supported for Block Discard Emulation\n"); | ||
3384 | goto out_invalid_cdb_field; | ||
3385 | } | ||
3386 | } | 3390 | } |
3391 | |||
3392 | cmd->t_task_lba = get_unaligned_be32(&cdb[2]); | ||
3387 | cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; | 3393 | cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; |
3394 | /* | ||
3395 | * Follow sbcr26 with WRITE_SAME (10) and check for the existence | ||
3396 | * of byte 1 bit 3 UNMAP instead of original reserved field | ||
3397 | */ | ||
3398 | if (target_check_write_same_discard(&cdb[1], dev) < 0) | ||
3399 | goto out_invalid_cdb_field; | ||
3388 | break; | 3400 | break; |
3389 | case ALLOW_MEDIUM_REMOVAL: | 3401 | case ALLOW_MEDIUM_REMOVAL: |
3390 | case GPCMD_CLOSE_TRACK: | 3402 | case GPCMD_CLOSE_TRACK: |