aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/target
diff options
context:
space:
mode:
authorNicholas Bellinger <nab@linux-iscsi.org>2011-07-28 03:07:03 -0400
committerNicholas Bellinger <nab@linux-iscsi.org>2011-08-22 15:26:21 -0400
commit706d5860969b3b24d65d9a57bd3bb5e4a1419c08 (patch)
treea6293f322a5327d3c317c09197b33d66e22d010e /drivers/target
parent16ab8e60a0ebc22cfbe61d84e620457a15f3a0bc (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.c28
-rw-r--r--drivers/target/target_core_transport.c102
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 */
1092static int 1092static int
1093target_emulate_write_same(struct se_task *task, int write_same32) 1093target_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
2864static 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, &sector_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: