aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBoaz Harrosh <bharrosh@panasas.com>2007-12-13 13:43:23 -0500
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-01-11 19:28:23 -0500
commit004d6530f83bee43a55b51bb5960db96e7ae0ffa (patch)
treea7bb6ffb3e6e89ca6ee9b164d5f19899a0c100dd
parent7207fea452cfdd2d4e2f4419e2c31f570edbade3 (diff)
[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: Boaz Harrosh <bharrosh@panasas.com> Signed-off-by: Olaf Kirch <olaf.kirch@oracle.com> Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r--drivers/scsi/iscsi_tcp.c16
-rw-r--r--drivers/scsi/iscsi_tcp.h13
-rw-r--r--drivers/scsi/libiscsi.c41
-rw-r--r--include/scsi/iscsi_proto.h10
-rw-r--r--include/scsi/libiscsi.h33
5 files changed, 94 insertions, 19 deletions
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index fd88777df28b..491845f18710 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -113,7 +113,7 @@ iscsi_hdr_digest(struct iscsi_conn *conn, struct iscsi_buf *buf,
113 struct iscsi_tcp_conn *tcp_conn = conn->dd_data; 113 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
114 114
115 crypto_hash_digest(&tcp_conn->tx_hash, &buf->sg, buf->sg.length, crc); 115 crypto_hash_digest(&tcp_conn->tx_hash, &buf->sg, buf->sg.length, crc);
116 buf->sg.length += sizeof(u32); 116 buf->sg.length += ISCSI_DIGEST_SIZE;
117} 117}
118 118
119/* 119/*
@@ -220,6 +220,7 @@ static inline int
220iscsi_tcp_chunk_done(struct iscsi_chunk *chunk) 220iscsi_tcp_chunk_done(struct iscsi_chunk *chunk)
221{ 221{
222 static unsigned char padbuf[ISCSI_PAD_LEN]; 222 static unsigned char padbuf[ISCSI_PAD_LEN];
223 unsigned int pad;
223 224
224 if (chunk->copied < chunk->size) { 225 if (chunk->copied < chunk->size) {
225 iscsi_tcp_chunk_map(chunk); 226 iscsi_tcp_chunk_map(chunk);
@@ -243,10 +244,8 @@ iscsi_tcp_chunk_done(struct iscsi_chunk *chunk)
243 } 244 }
244 245
245 /* Do we need to handle padding? */ 246 /* Do we need to handle padding? */
246 if (chunk->total_copied & (ISCSI_PAD_LEN-1)) { 247 pad = iscsi_padding(chunk->total_copied);
247 unsigned int pad; 248 if (pad != 0) {
248
249 pad = ISCSI_PAD_LEN - (chunk->total_copied & (ISCSI_PAD_LEN-1));
250 debug_tcp("consume %d pad bytes\n", pad); 249 debug_tcp("consume %d pad bytes\n", pad);
251 chunk->total_size += pad; 250 chunk->total_size += pad;
252 chunk->size = pad; 251 chunk->size = pad;
@@ -1385,11 +1384,11 @@ iscsi_send_cmd_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
1385 } 1384 }
1386 1385
1387 iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)ctask->hdr, 1386 iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)ctask->hdr,
1388 sizeof(struct iscsi_hdr)); 1387 ctask->hdr_len);
1389 1388
1390 if (conn->hdrdgst_en) 1389 if (conn->hdrdgst_en)
1391 iscsi_hdr_digest(conn, &tcp_ctask->headbuf, 1390 iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
1392 (u8*)tcp_ctask->hdrext); 1391 iscsi_next_hdr(ctask));
1393 tcp_ctask->xmstate &= ~XMSTATE_CMD_HDR_INIT; 1392 tcp_ctask->xmstate &= ~XMSTATE_CMD_HDR_INIT;
1394 tcp_ctask->xmstate |= XMSTATE_CMD_HDR_XMIT; 1393 tcp_ctask->xmstate |= XMSTATE_CMD_HDR_XMIT;
1395 } 1394 }
@@ -2176,7 +2175,8 @@ iscsi_tcp_session_create(struct iscsi_transport *iscsit,
2176 struct iscsi_cmd_task *ctask = session->cmds[cmd_i]; 2175 struct iscsi_cmd_task *ctask = session->cmds[cmd_i];
2177 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; 2176 struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
2178 2177
2179 ctask->hdr = &tcp_ctask->hdr; 2178 ctask->hdr = &tcp_ctask->hdr.cmd_hdr;
2179 ctask->hdr_max = sizeof(tcp_ctask->hdr) - ISCSI_DIGEST_SIZE;
2180 } 2180 }
2181 2181
2182 for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) { 2182 for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) {
diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h
index f1c541151100..eb3784f949fd 100644
--- a/drivers/scsi/iscsi_tcp.h
+++ b/drivers/scsi/iscsi_tcp.h
@@ -41,7 +41,6 @@
41#define XMSTATE_IMM_HDR_INIT 0x1000 41#define XMSTATE_IMM_HDR_INIT 0x1000
42#define XMSTATE_SOL_HDR_INIT 0x2000 42#define XMSTATE_SOL_HDR_INIT 0x2000
43 43
44#define ISCSI_PAD_LEN 4
45#define ISCSI_SG_TABLESIZE SG_ALL 44#define ISCSI_SG_TABLESIZE SG_ALL
46#define ISCSI_TCP_MAX_CMD_LEN 16 45#define ISCSI_TCP_MAX_CMD_LEN 16
47 46
@@ -130,14 +129,14 @@ struct iscsi_buf {
130 129
131struct iscsi_data_task { 130struct iscsi_data_task {
132 struct iscsi_data hdr; /* PDU */ 131 struct iscsi_data hdr; /* PDU */
133 char hdrext[sizeof(__u32)]; /* Header-Digest */ 132 char hdrext[ISCSI_DIGEST_SIZE];/* Header-Digest */
134 struct iscsi_buf digestbuf; /* digest buffer */ 133 struct iscsi_buf digestbuf; /* digest buffer */
135 uint32_t digest; /* data digest */ 134 uint32_t digest; /* data digest */
136}; 135};
137 136
138struct iscsi_tcp_mgmt_task { 137struct iscsi_tcp_mgmt_task {
139 struct iscsi_hdr hdr; 138 struct iscsi_hdr hdr;
140 char hdrext[sizeof(__u32)]; /* Header-Digest */ 139 char hdrext[ISCSI_DIGEST_SIZE]; /* Header-Digest */
141 int xmstate; /* mgmt xmit progress */ 140 int xmstate; /* mgmt xmit progress */
142 struct iscsi_buf headbuf; /* header buffer */ 141 struct iscsi_buf headbuf; /* header buffer */
143 struct iscsi_buf sendbuf; /* in progress buffer */ 142 struct iscsi_buf sendbuf; /* in progress buffer */
@@ -159,9 +158,11 @@ struct iscsi_r2t_info {
159}; 158};
160 159
161struct iscsi_tcp_cmd_task { 160struct iscsi_tcp_cmd_task {
162 struct iscsi_cmd hdr; 161 struct iscsi_hdr_buff {
163 char hdrext[4*sizeof(__u16)+ /* AHS */ 162 struct iscsi_cmd cmd_hdr;
164 sizeof(__u32)]; /* HeaderDigest */ 163 char hdrextbuf[ISCSI_MAX_AHS_SIZE +
164 ISCSI_DIGEST_SIZE];
165 } hdr;
165 char pad[ISCSI_PAD_LEN]; 166 char pad[ISCSI_PAD_LEN];
166 int pad_count; /* padded bytes */ 167 int pad_count; /* padded bytes */
167 struct iscsi_buf headbuf; /* header buf (xmit) */ 168 struct iscsi_buf headbuf; /* header buf (xmit) */
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 0beb4c620962..0d7914fd8ef3 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -37,6 +37,9 @@
37#include <scsi/scsi_transport_iscsi.h> 37#include <scsi/scsi_transport_iscsi.h>
38#include <scsi/libiscsi.h> 38#include <scsi/libiscsi.h>
39 39
40static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
41 int err);
42
40struct iscsi_session * 43struct iscsi_session *
41class_to_transport_session(struct iscsi_cls_session *cls_session) 44class_to_transport_session(struct iscsi_cls_session *cls_session)
42{ 45{
@@ -122,6 +125,20 @@ void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask,
122} 125}
123EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu); 126EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu);
124 127
128static int iscsi_add_hdr(struct iscsi_cmd_task *ctask, unsigned len)
129{
130 unsigned exp_len = ctask->hdr_len + len;
131
132 if (exp_len > ctask->hdr_max) {
133 WARN_ON(1);
134 return -EINVAL;
135 }
136
137 WARN_ON(len & (ISCSI_PAD_LEN - 1)); /* caller must pad the AHS */
138 ctask->hdr_len = exp_len;
139 return 0;
140}
141
125/** 142/**
126 * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu 143 * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu
127 * @ctask: iscsi cmd task 144 * @ctask: iscsi cmd task
@@ -129,13 +146,19 @@ EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu);
129 * Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set 146 * Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set
130 * fields like dlength or final based on how much data it sends 147 * fields like dlength or final based on how much data it sends
131 */ 148 */
132static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) 149static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
133{ 150{
134 struct iscsi_conn *conn = ctask->conn; 151 struct iscsi_conn *conn = ctask->conn;
135 struct iscsi_session *session = conn->session; 152 struct iscsi_session *session = conn->session;
136 struct iscsi_cmd *hdr = ctask->hdr; 153 struct iscsi_cmd *hdr = ctask->hdr;
137 struct scsi_cmnd *sc = ctask->sc; 154 struct scsi_cmnd *sc = ctask->sc;
155 unsigned hdrlength;
156 int rc;
138 157
158 ctask->hdr_len = 0;
159 rc = iscsi_add_hdr(ctask, sizeof(*hdr));
160 if (rc)
161 return rc;
139 hdr->opcode = ISCSI_OP_SCSI_CMD; 162 hdr->opcode = ISCSI_OP_SCSI_CMD;
140 hdr->flags = ISCSI_ATTR_SIMPLE; 163 hdr->flags = ISCSI_ATTR_SIMPLE;
141 int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); 164 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 hdr->flags |= ISCSI_FLAG_CMD_READ; 222 hdr->flags |= ISCSI_FLAG_CMD_READ;
200 } 223 }
201 224
225 /* calculate size of additional header segments (AHSs) */
226 hdrlength = ctask->hdr_len - sizeof(*hdr);
227
228 WARN_ON(hdrlength & (ISCSI_PAD_LEN-1));
229 hdrlength /= ISCSI_PAD_LEN;
230
231 WARN_ON(hdrlength >= 256);
232 hdr->hlength = hdrlength & 0xFF;
233
202 conn->scsicmd_pdus_cnt++; 234 conn->scsicmd_pdus_cnt++;
203 235
204 debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d " 236 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 sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", 238 sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
207 conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc), 239 conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc),
208 session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); 240 session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
241 return 0;
209} 242}
210 243
211/** 244/**
@@ -744,7 +777,10 @@ check_mgmt:
744 777
745 conn->ctask = list_entry(conn->xmitqueue.next, 778 conn->ctask = list_entry(conn->xmitqueue.next,
746 struct iscsi_cmd_task, running); 779 struct iscsi_cmd_task, running);
747 iscsi_prep_scsi_cmd_pdu(conn->ctask); 780 if (iscsi_prep_scsi_cmd_pdu(conn->ctask)) {
781 fail_command(conn, conn->ctask, DID_ABORT << 16);
782 continue;
783 }
748 conn->session->tt->init_cmd_task(conn->ctask); 784 conn->session->tt->init_cmd_task(conn->ctask);
749 conn->ctask->state = ISCSI_TASK_RUNNING; 785 conn->ctask->state = ISCSI_TASK_RUNNING;
750 list_move_tail(conn->xmitqueue.next, &conn->run_list); 786 list_move_tail(conn->xmitqueue.next, &conn->run_list);
@@ -1534,6 +1570,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit,
1534 if (cmd_task_size) 1570 if (cmd_task_size)
1535 ctask->dd_data = &ctask[1]; 1571 ctask->dd_data = &ctask[1];
1536 ctask->itt = cmd_i; 1572 ctask->itt = cmd_i;
1573 ctask->hdr_max = sizeof(struct iscsi_cmd);
1537 INIT_LIST_HEAD(&ctask->running); 1574 INIT_LIST_HEAD(&ctask->running);
1538 } 1575 }
1539 1576
diff --git a/include/scsi/iscsi_proto.h b/include/scsi/iscsi_proto.h
index 751c81eaa7f3..6947082eee6d 100644
--- a/include/scsi/iscsi_proto.h
+++ b/include/scsi/iscsi_proto.h
@@ -27,7 +27,7 @@
27#define ISCSI_LISTEN_PORT 3260 27#define ISCSI_LISTEN_PORT 3260
28 28
29/* Padding word length */ 29/* Padding word length */
30#define PAD_WORD_LEN 4 30#define ISCSI_PAD_LEN 4
31 31
32/* 32/*
33 * useful common(control and data pathes) macro 33 * useful common(control and data pathes) macro
@@ -147,6 +147,14 @@ struct iscsi_rlength_ahdr {
147 __be32 read_length; 147 __be32 read_length;
148}; 148};
149 149
150/* Extended CDB AHS */
151struct iscsi_ecdb_ahdr {
152 __be16 ahslength; /* CDB length - 15, including reserved byte */
153 uint8_t ahstype;
154 uint8_t reserved;
155 uint8_t ecdb[260 - 16]; /* 4-byte aligned extended CDB spillover */
156};
157
150/* SCSI Response Header */ 158/* SCSI Response Header */
151struct iscsi_cmd_rsp { 159struct iscsi_cmd_rsp {
152 uint8_t opcode; 160 uint8_t opcode;
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index e1fb3d0927b0..a9a9e869188d 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -78,6 +78,9 @@ enum {
78#define ISCSI_ADDRESS_BUF_LEN 64 78#define ISCSI_ADDRESS_BUF_LEN 64
79 79
80enum { 80enum {
81 /* this is the maximum possible storage for AHSs */
82 ISCSI_MAX_AHS_SIZE = sizeof(struct iscsi_ecdb_ahdr) +
83 sizeof(struct iscsi_rlength_ahdr),
81 ISCSI_DIGEST_SIZE = sizeof(__u32), 84 ISCSI_DIGEST_SIZE = sizeof(__u32),
82}; 85};
83 86
@@ -102,10 +105,13 @@ enum {
102 105
103struct iscsi_cmd_task { 106struct iscsi_cmd_task {
104 /* 107 /*
105 * Becuae LLDs allocate their hdr differently, this is a pointer to 108 * Because LLDs allocate their hdr differently, this is a pointer
106 * that storage. It must be setup at session creation time. 109 * and length to that storage. It must be setup at session
110 * creation time.
107 */ 111 */
108 struct iscsi_cmd *hdr; 112 struct iscsi_cmd *hdr;
113 unsigned short hdr_max;
114 unsigned short hdr_len; /* accumulated size of hdr used */
109 int itt; /* this ITT */ 115 int itt; /* this ITT */
110 116
111 uint32_t unsol_datasn; 117 uint32_t unsol_datasn;
@@ -124,6 +130,11 @@ struct iscsi_cmd_task {
124 void *dd_data; /* driver/transport data */ 130 void *dd_data; /* driver/transport data */
125}; 131};
126 132
133static inline void* iscsi_next_hdr(struct iscsi_cmd_task *ctask)
134{
135 return (void*)ctask->hdr + ctask->hdr_len;
136}
137
127struct iscsi_conn { 138struct iscsi_conn {
128 struct iscsi_cls_conn *cls_conn; /* ptr to class connection */ 139 struct iscsi_cls_conn *cls_conn; /* ptr to class connection */
129 void *dd_data; /* iscsi_transport data */ 140 void *dd_data; /* iscsi_transport data */
@@ -342,4 +353,22 @@ extern void iscsi_requeue_ctask(struct iscsi_cmd_task *ctask);
342extern void iscsi_pool_free(struct iscsi_queue *, void **); 353extern void iscsi_pool_free(struct iscsi_queue *, void **);
343extern int iscsi_pool_init(struct iscsi_queue *, int, void ***, int); 354extern int iscsi_pool_init(struct iscsi_queue *, int, void ***, int);
344 355
356/*
357 * inline functions to deal with padding.
358 */
359static inline unsigned int
360iscsi_padded(unsigned int len)
361{
362 return (len + ISCSI_PAD_LEN - 1) & ~(ISCSI_PAD_LEN - 1);
363}
364
365static inline unsigned int
366iscsi_padding(unsigned int len)
367{
368 len &= (ISCSI_PAD_LEN - 1);
369 if (len)
370 len = ISCSI_PAD_LEN - len;
371 return len;
372}
373
345#endif 374#endif