Commit 706d5860 authored by Nicholas Bellinger's avatar Nicholas Bellinger

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: default avatarEric Seppanen <eric@purestorage.com>
Cc: Roland Dreier <roland@purestorage.com>
Cc: Christoph Hellwig <hch@lst.de>
Signed-off-by: default avatarNicholas Bellinger <nab@risingtidesystems.com>
parent 16ab8e60
...@@ -1090,24 +1090,17 @@ target_emulate_unmap(struct se_task *task) ...@@ -1090,24 +1090,17 @@ target_emulate_unmap(struct se_task *task)
* Note this is not used for TCM/pSCSI passthrough * Note this is not used for TCM/pSCSI passthrough
*/ */
static int static int
target_emulate_write_same(struct se_task *task, int write_same32) target_emulate_write_same(struct se_task *task, u32 num_blocks)
{ {
struct se_cmd *cmd = task->task_se_cmd; struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev; struct se_device *dev = cmd->se_dev;
sector_t range; sector_t range;
sector_t lba = cmd->t_task_lba; sector_t lba = cmd->t_task_lba;
unsigned int num_blocks;
int ret; int ret;
/* /*
* Extract num_blocks from the WRITE_SAME_* CDB. Then use the explict * Use the explicit range when non zero is supplied, otherwise calculate
* range when non zero is supplied, otherwise calculate the remaining * the remaining range based on ->get_blocks() - starting LBA.
* range based on ->get_blocks() - starting LBA.
*/ */
if (write_same32)
num_blocks = get_unaligned_be32(&cmd->t_task_cdb[28]);
else
num_blocks = get_unaligned_be32(&cmd->t_task_cdb[10]);
if (num_blocks != 0) if (num_blocks != 0)
range = num_blocks; range = num_blocks;
else else
...@@ -1170,13 +1163,23 @@ transport_emulate_control_cdb(struct se_task *task) ...@@ -1170,13 +1163,23 @@ transport_emulate_control_cdb(struct se_task *task)
} }
ret = target_emulate_unmap(task); ret = target_emulate_unmap(task);
break; break;
case WRITE_SAME:
if (!dev->transport->do_discard) {
pr_err("WRITE_SAME emulation not supported"
" for: %s\n", dev->transport->name);
return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
}
ret = target_emulate_write_same(task,
get_unaligned_be16(&cmd->t_task_cdb[7]));
break;
case WRITE_SAME_16: case WRITE_SAME_16:
if (!dev->transport->do_discard) { if (!dev->transport->do_discard) {
pr_err("WRITE_SAME_16 emulation not supported" pr_err("WRITE_SAME_16 emulation not supported"
" for: %s\n", dev->transport->name); " for: %s\n", dev->transport->name);
return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
} }
ret = target_emulate_write_same(task, 0); ret = target_emulate_write_same(task,
get_unaligned_be32(&cmd->t_task_cdb[10]));
break; break;
case VARIABLE_LENGTH_CMD: case VARIABLE_LENGTH_CMD:
service_action = service_action =
...@@ -1189,7 +1192,8 @@ transport_emulate_control_cdb(struct se_task *task) ...@@ -1189,7 +1192,8 @@ transport_emulate_control_cdb(struct se_task *task)
dev->transport->name); dev->transport->name);
return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
} }
ret = target_emulate_write_same(task, 1); ret = target_emulate_write_same(task,
get_unaligned_be32(&cmd->t_task_cdb[28]));
break; break;
default: default:
pr_err("Unsupported VARIABLE_LENGTH_CMD SA:" pr_err("Unsupported VARIABLE_LENGTH_CMD SA:"
......
...@@ -2861,6 +2861,38 @@ static int transport_cmd_get_valid_sectors(struct se_cmd *cmd) ...@@ -2861,6 +2861,38 @@ static int transport_cmd_get_valid_sectors(struct se_cmd *cmd)
return sectors; return sectors;
} }
static int target_check_write_same_discard(unsigned char *flags, struct se_device *dev)
{
/*
* Determine if the received WRITE_SAME is used to for direct
* passthrough into Linux/SCSI with struct request via TCM/pSCSI
* or we are signaling the use of internal WRITE_SAME + UNMAP=1
* emulation for -> Linux/BLOCK disbard with TCM/IBLOCK code.
*/
int passthrough = (dev->transport->transport_type ==
TRANSPORT_PLUGIN_PHBA_PDEV);
if (!passthrough) {
if ((flags[0] & 0x04) || (flags[0] & 0x02)) {
pr_err("WRITE_SAME PBDATA and LBDATA"
" bits not supported for Block Discard"
" Emulation\n");
return -ENOSYS;
}
/*
* Currently for the emulated case we only accept
* tpws with the UNMAP=1 bit set.
*/
if (!(flags[0] & 0x08)) {
pr_err("WRITE_SAME w/o UNMAP bit not"
" supported for Block Discard Emulation\n");
return -ENOSYS;
}
}
return 0;
}
/* transport_generic_cmd_sequencer(): /* transport_generic_cmd_sequencer():
* *
* Generic Command Sequencer that should work for most DAS transport * Generic Command Sequencer that should work for most DAS transport
...@@ -3081,27 +3113,9 @@ static int transport_generic_cmd_sequencer( ...@@ -3081,27 +3113,9 @@ static int transport_generic_cmd_sequencer(
cmd->t_task_lba = get_unaligned_be64(&cdb[12]); cmd->t_task_lba = get_unaligned_be64(&cdb[12]);
cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB; cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
/* if (target_check_write_same_discard(&cdb[10], dev) < 0)
* Skip the remaining assignments for TCM/PSCSI passthrough
*/
if (passthrough)
break;
if ((cdb[10] & 0x04) || (cdb[10] & 0x02)) {
pr_err("WRITE_SAME PBDATA and LBDATA"
" bits not supported for Block Discard"
" Emulation\n");
goto out_invalid_cdb_field; goto out_invalid_cdb_field;
}
/*
* Currently for the emulated case we only accept
* tpws with the UNMAP=1 bit set.
*/
if (!(cdb[10] & 0x08)) {
pr_err("WRITE_SAME w/o UNMAP bit not"
" supported for Block Discard Emulation\n");
goto out_invalid_cdb_field;
}
break; break;
default: default:
pr_err("VARIABLE_LENGTH_CMD service action" pr_err("VARIABLE_LENGTH_CMD service action"
...@@ -3358,33 +3372,31 @@ static int transport_generic_cmd_sequencer( ...@@ -3358,33 +3372,31 @@ static int transport_generic_cmd_sequencer(
} }
cmd->t_task_lba = get_unaligned_be64(&cdb[2]); cmd->t_task_lba = get_unaligned_be64(&cdb[2]);
passthrough = (dev->transport->transport_type == cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
TRANSPORT_PLUGIN_PHBA_PDEV);
/* if (target_check_write_same_discard(&cdb[1], dev) < 0)
* Determine if the received WRITE_SAME_16 is used to for direct goto out_invalid_cdb_field;
* passthrough into Linux/SCSI with struct request via TCM/pSCSI break;
* or we are signaling the use of internal WRITE_SAME + UNMAP=1 case WRITE_SAME:
* emulation for -> Linux/BLOCK disbard with TCM/IBLOCK and sectors = transport_get_sectors_10(cdb, cmd, &sector_ret);
* TCM/FILEIO subsystem plugin backstores. if (sector_ret)
*/ goto out_unsupported_cdb;
if (!passthrough) {
if ((cdb[1] & 0x04) || (cdb[1] & 0x02)) { if (sectors)
pr_err("WRITE_SAME PBDATA and LBDATA" size = transport_get_size(sectors, cdb, cmd);
" bits not supported for Block Discard" else {
" Emulation\n"); pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n");
goto out_invalid_cdb_field; goto out_invalid_cdb_field;
} }
cmd->t_task_lba = get_unaligned_be32(&cdb[2]);
cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
/* /*
* Currently for the emulated case we only accept * Follow sbcr26 with WRITE_SAME (10) and check for the existence
* tpws with the UNMAP=1 bit set. * of byte 1 bit 3 UNMAP instead of original reserved field
*/ */
if (!(cdb[1] & 0x08)) { if (target_check_write_same_discard(&cdb[1], dev) < 0)
pr_err("WRITE_SAME w/o UNMAP bit not "
" supported for Block Discard Emulation\n");
goto out_invalid_cdb_field; goto out_invalid_cdb_field;
}
}
cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
break; break;
case ALLOW_MEDIUM_REMOVAL: case ALLOW_MEDIUM_REMOVAL:
case GPCMD_CLOSE_TRACK: case GPCMD_CLOSE_TRACK:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment