Commit 004d6530 authored by Boaz Harrosh's avatar Boaz Harrosh Committed by James Bottomley

[SCSI] iscsi_tcp, libiscsi: initial AHS Support

  at libiscsi generic code
  - currently code assumes a storage space of pdu header is allocated
    at llds ctask and is pointed to by iscsi_cmd_task->hdr. Here I add
    a hdr_max field pertaining to that storage, and an hdr_len that
    accumulates the current use of the pdu-header.

  - Add an iscsi_next_hdr() inline which returns the next free space
    to write new Header at. Also iscsi_next_hdr() is used to retrieve
    the address at which to write the header-digest.

  - Add iscsi_add_hdr(length). What the user do is calls iscsi_next_hdr()
    for address of the new header, than calls iscsi_add_hdr(length) with
    the size of the new header. iscsi_add_hdr() will check if space is
    available and update to the new size. length must be padded according
    to standard.

  - Add 2 padding inline helpers thanks to Olaf. Current patch does not
    use them but Following patches will.
    Also moved definition of ISCSI_PAD_LEN to iscsi_proto.h which had
    PAD_WORD_LEN that was never used anywhere.

  - Let iscsi_prep_scsi_cmd_pdu() signal an Error return since now  it is
    possible that it will fail.

  - I was tired of yet again writing a "this is a digest" comment next to
    sizeof(__u32) so I defined a new ISCSI_DIGEST_SIZE. Now I don't need
    any comments. Changed all places that used sizeof(__u32) or "4" in
    connection to a digest.

  iscsi_tcp specific code
  - At struct iscsi_tcp_cmd_task allocate maximum space allowed in
    standard for all headers following the iscsi_cmd header. and mark
    it so in iscsi_tcp_session_create()
  - At iscsi_send_cmd_hdr() retrieve the correct headers size and
    write header digest at iscsi_next_hdr().
Signed-off-by: default avatarBoaz Harrosh <bharrosh@panasas.com>
Signed-off-by: default avatarOlaf Kirch <olaf.kirch@oracle.com>
Signed-off-by: default avatarMike Christie <michaelc@cs.wisc.edu>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent 7207fea4
...@@ -113,7 +113,7 @@ iscsi_hdr_digest(struct iscsi_conn *conn, struct iscsi_buf *buf, ...@@ -113,7 +113,7 @@ iscsi_hdr_digest(struct iscsi_conn *conn, struct iscsi_buf *buf,
struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
crypto_hash_digest(&tcp_conn->tx_hash, &buf->sg, buf->sg.length, crc); crypto_hash_digest(&tcp_conn->tx_hash, &buf->sg, buf->sg.length, crc);
buf->sg.length += sizeof(u32); buf->sg.length += ISCSI_DIGEST_SIZE;
} }
/* /*
...@@ -220,6 +220,7 @@ static inline int ...@@ -220,6 +220,7 @@ static inline int
iscsi_tcp_chunk_done(struct iscsi_chunk *chunk) iscsi_tcp_chunk_done(struct iscsi_chunk *chunk)
{ {
static unsigned char padbuf[ISCSI_PAD_LEN]; static unsigned char padbuf[ISCSI_PAD_LEN];
unsigned int pad;
if (chunk->copied < chunk->size) { if (chunk->copied < chunk->size) {
iscsi_tcp_chunk_map(chunk); iscsi_tcp_chunk_map(chunk);
...@@ -243,10 +244,8 @@ iscsi_tcp_chunk_done(struct iscsi_chunk *chunk) ...@@ -243,10 +244,8 @@ iscsi_tcp_chunk_done(struct iscsi_chunk *chunk)
} }
/* Do we need to handle padding? */ /* Do we need to handle padding? */
if (chunk->total_copied & (ISCSI_PAD_LEN-1)) { pad = iscsi_padding(chunk->total_copied);
unsigned int pad; if (pad != 0) {
pad = ISCSI_PAD_LEN - (chunk->total_copied & (ISCSI_PAD_LEN-1));
debug_tcp("consume %d pad bytes\n", pad); debug_tcp("consume %d pad bytes\n", pad);
chunk->total_size += pad; chunk->total_size += pad;
chunk->size = pad; chunk->size = pad;
...@@ -1385,11 +1384,11 @@ iscsi_send_cmd_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) ...@@ -1385,11 +1384,11 @@ iscsi_send_cmd_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
} }
iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)ctask->hdr, iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)ctask->hdr,
sizeof(struct iscsi_hdr)); ctask->hdr_len);
if (conn->hdrdgst_en) if (conn->hdrdgst_en)
iscsi_hdr_digest(conn, &tcp_ctask->headbuf, iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
(u8*)tcp_ctask->hdrext); iscsi_next_hdr(ctask));
tcp_ctask->xmstate &= ~XMSTATE_CMD_HDR_INIT; tcp_ctask->xmstate &= ~XMSTATE_CMD_HDR_INIT;
tcp_ctask->xmstate |= XMSTATE_CMD_HDR_XMIT; tcp_ctask->xmstate |= XMSTATE_CMD_HDR_XMIT;
} }
...@@ -2176,7 +2175,8 @@ iscsi_tcp_session_create(struct iscsi_transport *iscsit, ...@@ -2176,7 +2175,8 @@ iscsi_tcp_session_create(struct iscsi_transport *iscsit,
struct iscsi_cmd_task *ctask = session->cmds[cmd_i]; struct iscsi_cmd_task *ctask = session->cmds[cmd_i];
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
ctask->hdr = &tcp_ctask->hdr; ctask->hdr = &tcp_ctask->hdr.cmd_hdr;
ctask->hdr_max = sizeof(tcp_ctask->hdr) - ISCSI_DIGEST_SIZE;
} }
for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) { for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) {
......
...@@ -41,7 +41,6 @@ ...@@ -41,7 +41,6 @@
#define XMSTATE_IMM_HDR_INIT 0x1000 #define XMSTATE_IMM_HDR_INIT 0x1000
#define XMSTATE_SOL_HDR_INIT 0x2000 #define XMSTATE_SOL_HDR_INIT 0x2000
#define ISCSI_PAD_LEN 4
#define ISCSI_SG_TABLESIZE SG_ALL #define ISCSI_SG_TABLESIZE SG_ALL
#define ISCSI_TCP_MAX_CMD_LEN 16 #define ISCSI_TCP_MAX_CMD_LEN 16
...@@ -130,14 +129,14 @@ struct iscsi_buf { ...@@ -130,14 +129,14 @@ struct iscsi_buf {
struct iscsi_data_task { struct iscsi_data_task {
struct iscsi_data hdr; /* PDU */ struct iscsi_data hdr; /* PDU */
char hdrext[sizeof(__u32)]; /* Header-Digest */ char hdrext[ISCSI_DIGEST_SIZE];/* Header-Digest */
struct iscsi_buf digestbuf; /* digest buffer */ struct iscsi_buf digestbuf; /* digest buffer */
uint32_t digest; /* data digest */ uint32_t digest; /* data digest */
}; };
struct iscsi_tcp_mgmt_task { struct iscsi_tcp_mgmt_task {
struct iscsi_hdr hdr; struct iscsi_hdr hdr;
char hdrext[sizeof(__u32)]; /* Header-Digest */ char hdrext[ISCSI_DIGEST_SIZE]; /* Header-Digest */
int xmstate; /* mgmt xmit progress */ int xmstate; /* mgmt xmit progress */
struct iscsi_buf headbuf; /* header buffer */ struct iscsi_buf headbuf; /* header buffer */
struct iscsi_buf sendbuf; /* in progress buffer */ struct iscsi_buf sendbuf; /* in progress buffer */
...@@ -159,9 +158,11 @@ struct iscsi_r2t_info { ...@@ -159,9 +158,11 @@ struct iscsi_r2t_info {
}; };
struct iscsi_tcp_cmd_task { struct iscsi_tcp_cmd_task {
struct iscsi_cmd hdr; struct iscsi_hdr_buff {
char hdrext[4*sizeof(__u16)+ /* AHS */ struct iscsi_cmd cmd_hdr;
sizeof(__u32)]; /* HeaderDigest */ char hdrextbuf[ISCSI_MAX_AHS_SIZE +
ISCSI_DIGEST_SIZE];
} hdr;
char pad[ISCSI_PAD_LEN]; char pad[ISCSI_PAD_LEN];
int pad_count; /* padded bytes */ int pad_count; /* padded bytes */
struct iscsi_buf headbuf; /* header buf (xmit) */ struct iscsi_buf headbuf; /* header buf (xmit) */
......
...@@ -37,6 +37,9 @@ ...@@ -37,6 +37,9 @@
#include <scsi/scsi_transport_iscsi.h> #include <scsi/scsi_transport_iscsi.h>
#include <scsi/libiscsi.h> #include <scsi/libiscsi.h>
static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
int err);
struct iscsi_session * struct iscsi_session *
class_to_transport_session(struct iscsi_cls_session *cls_session) class_to_transport_session(struct iscsi_cls_session *cls_session)
{ {
...@@ -122,6 +125,20 @@ void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask, ...@@ -122,6 +125,20 @@ void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask,
} }
EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu); EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu);
static int iscsi_add_hdr(struct iscsi_cmd_task *ctask, unsigned len)
{
unsigned exp_len = ctask->hdr_len + len;
if (exp_len > ctask->hdr_max) {
WARN_ON(1);
return -EINVAL;
}
WARN_ON(len & (ISCSI_PAD_LEN - 1)); /* caller must pad the AHS */
ctask->hdr_len = exp_len;
return 0;
}
/** /**
* iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu
* @ctask: iscsi cmd task * @ctask: iscsi cmd task
...@@ -129,13 +146,19 @@ EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu); ...@@ -129,13 +146,19 @@ EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu);
* Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set * Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set
* fields like dlength or final based on how much data it sends * fields like dlength or final based on how much data it sends
*/ */
static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
{ {
struct iscsi_conn *conn = ctask->conn; struct iscsi_conn *conn = ctask->conn;
struct iscsi_session *session = conn->session; struct iscsi_session *session = conn->session;
struct iscsi_cmd *hdr = ctask->hdr; struct iscsi_cmd *hdr = ctask->hdr;
struct scsi_cmnd *sc = ctask->sc; struct scsi_cmnd *sc = ctask->sc;
unsigned hdrlength;
int rc;
ctask->hdr_len = 0;
rc = iscsi_add_hdr(ctask, sizeof(*hdr));
if (rc)
return rc;
hdr->opcode = ISCSI_OP_SCSI_CMD; hdr->opcode = ISCSI_OP_SCSI_CMD;
hdr->flags = ISCSI_ATTR_SIMPLE; hdr->flags = ISCSI_ATTR_SIMPLE;
int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
...@@ -199,6 +222,15 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) ...@@ -199,6 +222,15 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
hdr->flags |= ISCSI_FLAG_CMD_READ; hdr->flags |= ISCSI_FLAG_CMD_READ;
} }
/* calculate size of additional header segments (AHSs) */
hdrlength = ctask->hdr_len - sizeof(*hdr);
WARN_ON(hdrlength & (ISCSI_PAD_LEN-1));
hdrlength /= ISCSI_PAD_LEN;
WARN_ON(hdrlength >= 256);
hdr->hlength = hdrlength & 0xFF;
conn->scsicmd_pdus_cnt++; conn->scsicmd_pdus_cnt++;
debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d " debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d "
...@@ -206,6 +238,7 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) ...@@ -206,6 +238,7 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc), conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc),
session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
return 0;
} }
/** /**
...@@ -744,7 +777,10 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) ...@@ -744,7 +777,10 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
conn->ctask = list_entry(conn->xmitqueue.next, conn->ctask = list_entry(conn->xmitqueue.next,
struct iscsi_cmd_task, running); struct iscsi_cmd_task, running);
iscsi_prep_scsi_cmd_pdu(conn->ctask); if (iscsi_prep_scsi_cmd_pdu(conn->ctask)) {
fail_command(conn, conn->ctask, DID_ABORT << 16);
continue;
}
conn->session->tt->init_cmd_task(conn->ctask); conn->session->tt->init_cmd_task(conn->ctask);
conn->ctask->state = ISCSI_TASK_RUNNING; conn->ctask->state = ISCSI_TASK_RUNNING;
list_move_tail(conn->xmitqueue.next, &conn->run_list); list_move_tail(conn->xmitqueue.next, &conn->run_list);
...@@ -1534,6 +1570,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, ...@@ -1534,6 +1570,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit,
if (cmd_task_size) if (cmd_task_size)
ctask->dd_data = &ctask[1]; ctask->dd_data = &ctask[1];
ctask->itt = cmd_i; ctask->itt = cmd_i;
ctask->hdr_max = sizeof(struct iscsi_cmd);
INIT_LIST_HEAD(&ctask->running); INIT_LIST_HEAD(&ctask->running);
} }
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#define ISCSI_LISTEN_PORT 3260 #define ISCSI_LISTEN_PORT 3260
/* Padding word length */ /* Padding word length */
#define PAD_WORD_LEN 4 #define ISCSI_PAD_LEN 4
/* /*
* useful common(control and data pathes) macro * useful common(control and data pathes) macro
...@@ -147,6 +147,14 @@ struct iscsi_rlength_ahdr { ...@@ -147,6 +147,14 @@ struct iscsi_rlength_ahdr {
__be32 read_length; __be32 read_length;
}; };
/* Extended CDB AHS */
struct iscsi_ecdb_ahdr {
__be16 ahslength; /* CDB length - 15, including reserved byte */
uint8_t ahstype;
uint8_t reserved;
uint8_t ecdb[260 - 16]; /* 4-byte aligned extended CDB spillover */
};
/* SCSI Response Header */ /* SCSI Response Header */
struct iscsi_cmd_rsp { struct iscsi_cmd_rsp {
uint8_t opcode; uint8_t opcode;
......
...@@ -78,6 +78,9 @@ enum { ...@@ -78,6 +78,9 @@ enum {
#define ISCSI_ADDRESS_BUF_LEN 64 #define ISCSI_ADDRESS_BUF_LEN 64
enum { enum {
/* this is the maximum possible storage for AHSs */
ISCSI_MAX_AHS_SIZE = sizeof(struct iscsi_ecdb_ahdr) +
sizeof(struct iscsi_rlength_ahdr),
ISCSI_DIGEST_SIZE = sizeof(__u32), ISCSI_DIGEST_SIZE = sizeof(__u32),
}; };
...@@ -102,10 +105,13 @@ enum { ...@@ -102,10 +105,13 @@ enum {
struct iscsi_cmd_task { struct iscsi_cmd_task {
/* /*
* Becuae LLDs allocate their hdr differently, this is a pointer to * Because LLDs allocate their hdr differently, this is a pointer
* that storage. It must be setup at session creation time. * and length to that storage. It must be setup at session
* creation time.
*/ */
struct iscsi_cmd *hdr; struct iscsi_cmd *hdr;
unsigned short hdr_max;
unsigned short hdr_len; /* accumulated size of hdr used */
int itt; /* this ITT */ int itt; /* this ITT */
uint32_t unsol_datasn; uint32_t unsol_datasn;
...@@ -124,6 +130,11 @@ struct iscsi_cmd_task { ...@@ -124,6 +130,11 @@ struct iscsi_cmd_task {
void *dd_data; /* driver/transport data */ void *dd_data; /* driver/transport data */
}; };
static inline void* iscsi_next_hdr(struct iscsi_cmd_task *ctask)
{
return (void*)ctask->hdr + ctask->hdr_len;
}
struct iscsi_conn { struct iscsi_conn {
struct iscsi_cls_conn *cls_conn; /* ptr to class connection */ struct iscsi_cls_conn *cls_conn; /* ptr to class connection */
void *dd_data; /* iscsi_transport data */ void *dd_data; /* iscsi_transport data */
...@@ -342,4 +353,22 @@ extern void iscsi_requeue_ctask(struct iscsi_cmd_task *ctask); ...@@ -342,4 +353,22 @@ extern void iscsi_requeue_ctask(struct iscsi_cmd_task *ctask);
extern void iscsi_pool_free(struct iscsi_queue *, void **); extern void iscsi_pool_free(struct iscsi_queue *, void **);
extern int iscsi_pool_init(struct iscsi_queue *, int, void ***, int); extern int iscsi_pool_init(struct iscsi_queue *, int, void ***, int);
/*
* inline functions to deal with padding.
*/
static inline unsigned int
iscsi_padded(unsigned int len)
{
return (len + ISCSI_PAD_LEN - 1) & ~(ISCSI_PAD_LEN - 1);
}
static inline unsigned int
iscsi_padding(unsigned int len)
{
len &= (ISCSI_PAD_LEN - 1);
if (len)
len = ISCSI_PAD_LEN - len;
return len;
}
#endif #endif
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