Skip to content

Commit 8f1f7d2

Browse files
logostmartinkpetersen
authored andcommitted
scsi: target: iscsi: Add support for extended CDB AHS
Variable length SCSI commands are transferred over iSCSI via two CDB buffers - in Basic Header Segment and in Additional Header Segment (AHS). Since AHS is not supported yet, a target reads just BHS (48 byte) from TCP and treats the remaining octets as a next new iSCSI PDU that causes protocol errors. Add support for the Extended CDB AHS type. Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Mike Christie <[email protected]> Signed-off-by: Dmitry Bogdanov <[email protected]> Signed-off-by: Martin K. Petersen <[email protected]>
1 parent 2f3b320 commit 8f1f7d2

File tree

1 file changed

+52
-3
lines changed

1 file changed

+52
-3
lines changed

drivers/target/iscsi/iscsi_target.c

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,8 +1004,10 @@ int iscsit_setup_scsi_cmd(struct iscsit_conn *conn, struct iscsit_cmd *cmd,
10041004
unsigned char *buf)
10051005
{
10061006
int data_direction, payload_length;
1007+
struct iscsi_ecdb_ahdr *ecdb_ahdr;
10071008
struct iscsi_scsi_req *hdr;
10081009
int iscsi_task_attr;
1010+
unsigned char *cdb;
10091011
int sam_task_attr;
10101012

10111013
atomic_long_inc(&conn->sess->cmd_pdus);
@@ -1106,6 +1108,27 @@ int iscsit_setup_scsi_cmd(struct iscsit_conn *conn, struct iscsit_cmd *cmd,
11061108
ISCSI_REASON_BOOKMARK_INVALID, buf);
11071109
}
11081110

1111+
cdb = hdr->cdb;
1112+
1113+
if (hdr->hlength) {
1114+
ecdb_ahdr = (struct iscsi_ecdb_ahdr *) (hdr + 1);
1115+
if (ecdb_ahdr->ahstype != ISCSI_AHSTYPE_CDB) {
1116+
pr_err("Additional Header Segment type %d not supported!\n",
1117+
ecdb_ahdr->ahstype);
1118+
return iscsit_add_reject_cmd(cmd,
1119+
ISCSI_REASON_CMD_NOT_SUPPORTED, buf);
1120+
}
1121+
1122+
cdb = kmalloc(be16_to_cpu(ecdb_ahdr->ahslength) + 15,
1123+
GFP_KERNEL);
1124+
if (cdb == NULL)
1125+
return iscsit_add_reject_cmd(cmd,
1126+
ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
1127+
memcpy(cdb, hdr->cdb, ISCSI_CDB_SIZE);
1128+
memcpy(cdb + ISCSI_CDB_SIZE, ecdb_ahdr->ecdb,
1129+
be16_to_cpu(ecdb_ahdr->ahslength) - 1);
1130+
}
1131+
11091132
data_direction = (hdr->flags & ISCSI_FLAG_CMD_WRITE) ? DMA_TO_DEVICE :
11101133
(hdr->flags & ISCSI_FLAG_CMD_READ) ? DMA_FROM_DEVICE :
11111134
DMA_NONE;
@@ -1153,9 +1176,12 @@ int iscsit_setup_scsi_cmd(struct iscsit_conn *conn, struct iscsit_cmd *cmd,
11531176
struct iscsi_datain_req *dr;
11541177

11551178
dr = iscsit_allocate_datain_req();
1156-
if (!dr)
1179+
if (!dr) {
1180+
if (cdb != hdr->cdb)
1181+
kfree(cdb);
11571182
return iscsit_add_reject_cmd(cmd,
11581183
ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
1184+
}
11591185

11601186
iscsit_attach_datain_req(cmd, dr);
11611187
}
@@ -1176,9 +1202,12 @@ int iscsit_setup_scsi_cmd(struct iscsit_conn *conn, struct iscsit_cmd *cmd,
11761202
target_get_sess_cmd(&cmd->se_cmd, true);
11771203

11781204
cmd->se_cmd.tag = (__force u32)cmd->init_task_tag;
1179-
cmd->sense_reason = target_cmd_init_cdb(&cmd->se_cmd, hdr->cdb,
1205+
cmd->sense_reason = target_cmd_init_cdb(&cmd->se_cmd, cdb,
11801206
GFP_KERNEL);
11811207

1208+
if (cdb != hdr->cdb)
1209+
kfree(cdb);
1210+
11821211
if (cmd->sense_reason) {
11831212
if (cmd->sense_reason == TCM_OUT_OF_RESOURCES) {
11841213
return iscsit_add_reject_cmd(cmd,
@@ -4036,8 +4065,9 @@ static bool iscsi_target_check_conn_state(struct iscsit_conn *conn)
40364065
static void iscsit_get_rx_pdu(struct iscsit_conn *conn)
40374066
{
40384067
int ret;
4039-
u8 *buffer, opcode;
4068+
u8 *buffer, *tmp_buf, opcode;
40404069
u32 checksum = 0, digest = 0;
4070+
struct iscsi_hdr *hdr;
40414071
struct kvec iov;
40424072

40434073
buffer = kcalloc(ISCSI_HDR_LEN, sizeof(*buffer), GFP_KERNEL);
@@ -4062,6 +4092,25 @@ static void iscsit_get_rx_pdu(struct iscsit_conn *conn)
40624092
break;
40634093
}
40644094

4095+
hdr = (struct iscsi_hdr *) buffer;
4096+
if (hdr->hlength) {
4097+
iov.iov_len = hdr->hlength * 4;
4098+
tmp_buf = krealloc(buffer,
4099+
ISCSI_HDR_LEN + iov.iov_len,
4100+
GFP_KERNEL);
4101+
if (!tmp_buf)
4102+
break;
4103+
4104+
buffer = tmp_buf;
4105+
iov.iov_base = &buffer[ISCSI_HDR_LEN];
4106+
4107+
ret = rx_data(conn, &iov, 1, iov.iov_len);
4108+
if (ret != iov.iov_len) {
4109+
iscsit_rx_thread_wait_for_tcp(conn);
4110+
break;
4111+
}
4112+
}
4113+
40654114
if (conn->conn_ops->HeaderDigest) {
40664115
iov.iov_base = &digest;
40674116
iov.iov_len = ISCSI_CRC_LEN;

0 commit comments

Comments
 (0)