aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland Dreier <roland@purestorage.com>2012-10-31 12:16:50 -0400
committerNicholas Bellinger <nab@linux-iscsi.org>2012-11-06 23:55:46 -0500
commit3a3c5e4a672c5cd61cbdcedcd027312577f9ab7c (patch)
tree9e05bfd495e4acc8e2241fe685cca166d1033acf
parent0f6d64cee9c518f5d3138a90cead62fba2031074 (diff)
target: Add emulation for MODE SELECT
This is another thing that compliance tests try, and it's easy to implement on top of the MODE SENSE refactoring; since we don't claim to support any changeable values, all we need to do is check that the page contents sent by the initiator match what we would return. Signed-off-by: Roland Dreier <roland@purestorage.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r--drivers/target/target_core_spc.c53
1 files changed, 53 insertions, 0 deletions
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c
index 6c10fce9ef09..33022a3f31fc 100644
--- a/drivers/target/target_core_spc.c
+++ b/drivers/target/target_core_spc.c
@@ -975,6 +975,57 @@ out:
975 return 0; 975 return 0;
976} 976}
977 977
978static int spc_emulate_modeselect(struct se_cmd *cmd)
979{
980 struct se_device *dev = cmd->se_dev;
981 char *cdb = cmd->t_task_cdb;
982 bool ten = cdb[0] == MODE_SELECT_10;
983 int off = ten ? 8 : 4;
984 bool pf = !!(cdb[1] & 0x10);
985 u8 page, subpage;
986 unsigned char *buf;
987 unsigned char tbuf[SE_MODE_PAGE_BUF];
988 int length;
989 int ret = 0;
990 int i;
991
992 buf = transport_kmap_data_sg(cmd);
993
994 if (!pf) {
995 cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
996 ret = -EINVAL;
997 goto out;
998 }
999
1000 page = buf[off] & 0x3f;
1001 subpage = buf[off] & 0x40 ? buf[off + 1] : 0;
1002
1003 for (i = 0; i < ARRAY_SIZE(modesense_handlers); ++i)
1004 if (modesense_handlers[i].page == page &&
1005 modesense_handlers[i].subpage == subpage) {
1006 memset(tbuf, 0, SE_MODE_PAGE_BUF);
1007 length = modesense_handlers[i].emulate(dev, 0, tbuf);
1008 goto check_contents;
1009 }
1010
1011 cmd->scsi_sense_reason = TCM_UNKNOWN_MODE_PAGE;
1012 ret = -EINVAL;
1013 goto out;
1014
1015check_contents:
1016 if (memcmp(buf + off, tbuf, length)) {
1017 cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST;
1018 ret = -EINVAL;
1019 }
1020
1021out:
1022 transport_kunmap_data_sg(cmd);
1023
1024 if (!ret)
1025 target_complete_cmd(cmd, GOOD);
1026 return ret;
1027}
1028
978static int spc_emulate_request_sense(struct se_cmd *cmd) 1029static int spc_emulate_request_sense(struct se_cmd *cmd)
979{ 1030{
980 unsigned char *cdb = cmd->t_task_cdb; 1031 unsigned char *cdb = cmd->t_task_cdb;
@@ -1113,9 +1164,11 @@ int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
1113 switch (cdb[0]) { 1164 switch (cdb[0]) {
1114 case MODE_SELECT: 1165 case MODE_SELECT:
1115 *size = cdb[4]; 1166 *size = cdb[4];
1167 cmd->execute_cmd = spc_emulate_modeselect;
1116 break; 1168 break;
1117 case MODE_SELECT_10: 1169 case MODE_SELECT_10:
1118 *size = (cdb[7] << 8) + cdb[8]; 1170 *size = (cdb[7] << 8) + cdb[8];
1171 cmd->execute_cmd = spc_emulate_modeselect;
1119 break; 1172 break;
1120 case MODE_SENSE: 1173 case MODE_SENSE:
1121 *size = cdb[4]; 1174 *size = cdb[4];