[SCSI] cxgb3i: added per-task data to track transmit progress
[linux-2.6] / drivers / scsi / cxgb3i / cxgb3i_pdu.c
1 /*
2  * cxgb3i_pdu.c: Chelsio S3xx iSCSI driver.
3  *
4  * Copyright (c) 2008 Chelsio Communications, Inc.
5  * Copyright (c) 2008 Mike Christie
6  * Copyright (c) 2008 Red Hat, Inc.  All rights reserved.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation.
11  *
12  * Written by: Karen Xie (kxie@chelsio.com)
13  */
14
15 #include <linux/skbuff.h>
16 #include <linux/crypto.h>
17 #include <scsi/scsi_cmnd.h>
18 #include <scsi/scsi_host.h>
19
20 #include "cxgb3i.h"
21 #include "cxgb3i_pdu.h"
22
23 #ifdef __DEBUG_CXGB3I_RX__
24 #define cxgb3i_rx_debug         cxgb3i_log_debug
25 #else
26 #define cxgb3i_rx_debug(fmt...)
27 #endif
28
29 #ifdef __DEBUG_CXGB3I_TX__
30 #define cxgb3i_tx_debug         cxgb3i_log_debug
31 #else
32 #define cxgb3i_tx_debug(fmt...)
33 #endif
34
35 static struct page *pad_page;
36
37 /*
38  * pdu receive, interact with libiscsi_tcp
39  */
40 static inline int read_pdu_skb(struct iscsi_conn *conn, struct sk_buff *skb,
41                                unsigned int offset, int offloaded)
42 {
43         int status = 0;
44         int bytes_read;
45
46         bytes_read = iscsi_tcp_recv_skb(conn, skb, offset, offloaded, &status);
47         switch (status) {
48         case ISCSI_TCP_CONN_ERR:
49                 return -EIO;
50         case ISCSI_TCP_SUSPENDED:
51                 /* no transfer - just have caller flush queue */
52                 return bytes_read;
53         case ISCSI_TCP_SKB_DONE:
54                 /*
55                  * pdus should always fit in the skb and we should get
56                  * segment done notifcation.
57                  */
58                 iscsi_conn_printk(KERN_ERR, conn, "Invalid pdu or skb.");
59                 return -EFAULT;
60         case ISCSI_TCP_SEGMENT_DONE:
61                 return bytes_read;
62         default:
63                 iscsi_conn_printk(KERN_ERR, conn, "Invalid iscsi_tcp_recv_skb "
64                                   "status %d\n", status);
65                 return -EINVAL;
66         }
67 }
68
69 static int cxgb3i_conn_read_pdu_skb(struct iscsi_conn *conn,
70                                     struct sk_buff *skb)
71 {
72         struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
73         bool offloaded = 0;
74         unsigned int offset;
75         int rc;
76
77         cxgb3i_rx_debug("conn 0x%p, skb 0x%p, len %u, flag 0x%x.\n",
78                         conn, skb, skb->len, skb_ulp_mode(skb));
79
80         if (!iscsi_tcp_recv_segment_is_hdr(tcp_conn)) {
81                 iscsi_conn_failure(conn, ISCSI_ERR_PROTO);
82                 return -EIO;
83         }
84
85         if (conn->hdrdgst_en && (skb_ulp_mode(skb) & ULP2_FLAG_HCRC_ERROR)) {
86                 iscsi_conn_failure(conn, ISCSI_ERR_HDR_DGST);
87                 return -EIO;
88         }
89
90         if (conn->datadgst_en && (skb_ulp_mode(skb) & ULP2_FLAG_DCRC_ERROR)) {
91                 iscsi_conn_failure(conn, ISCSI_ERR_DATA_DGST);
92                 return -EIO;
93         }
94
95         /* iscsi hdr */
96         rc = read_pdu_skb(conn, skb, 0, 0);
97         if (rc <= 0)
98                 return rc;
99
100         if (iscsi_tcp_recv_segment_is_hdr(tcp_conn))
101                 return 0;
102
103         offset = rc;
104         if (conn->hdrdgst_en)
105                 offset += ISCSI_DIGEST_SIZE;
106
107         /* iscsi data */
108         if (skb_ulp_mode(skb) & ULP2_FLAG_DATA_DDPED) {
109                 cxgb3i_rx_debug("skb 0x%p, opcode 0x%x, data %u, ddp'ed, "
110                                 "itt 0x%x.\n",
111                                 skb,
112                                 tcp_conn->in.hdr->opcode & ISCSI_OPCODE_MASK,
113                                 tcp_conn->in.datalen,
114                                 ntohl(tcp_conn->in.hdr->itt));
115                 offloaded = 1;
116         } else {
117                 cxgb3i_rx_debug("skb 0x%p, opcode 0x%x, data %u, NOT ddp'ed, "
118                                 "itt 0x%x.\n",
119                                 skb,
120                                 tcp_conn->in.hdr->opcode & ISCSI_OPCODE_MASK,
121                                 tcp_conn->in.datalen,
122                                 ntohl(tcp_conn->in.hdr->itt));
123                 offset += sizeof(struct cpl_iscsi_hdr_norss);
124         }
125
126         rc = read_pdu_skb(conn, skb, offset, offloaded);
127         if (rc < 0)
128                 return rc;
129         else
130                 return 0;
131 }
132
133 /*
134  * pdu transmit, interact with libiscsi_tcp
135  */
136 static inline void tx_skb_setmode(struct sk_buff *skb, int hcrc, int dcrc)
137 {
138         u8 submode = 0;
139
140         if (hcrc)
141                 submode |= 1;
142         if (dcrc)
143                 submode |= 2;
144         skb_ulp_mode(skb) = (ULP_MODE_ISCSI << 4) | submode;
145 }
146
147 void cxgb3i_conn_cleanup_task(struct iscsi_task *task)
148 {
149         struct iscsi_tcp_task *tcp_task = task->dd_data;
150
151         /* never reached the xmit task callout */
152         if (tcp_task->dd_data)
153                 kfree_skb(tcp_task->dd_data);
154         tcp_task->dd_data = NULL;
155
156         /* MNC - Do we need a check in case this is called but
157          * cxgb3i_conn_alloc_pdu has never been called on the task */
158         cxgb3i_release_itt(task, task->hdr_itt);
159         iscsi_tcp_cleanup_task(task);
160 }
161
162 /*
163  * We do not support ahs yet
164  */
165 int cxgb3i_conn_alloc_pdu(struct iscsi_task *task, u8 opcode)
166 {
167         struct iscsi_tcp_task *tcp_task = task->dd_data;
168         struct sk_buff *skb;
169
170         task->hdr = NULL;
171         /* always allocate rooms for AHS */
172         skb = alloc_skb(sizeof(struct iscsi_hdr) + ISCSI_MAX_AHS_SIZE +
173                         TX_HEADER_LEN,  GFP_ATOMIC);
174         if (!skb)
175                 return -ENOMEM;
176
177         cxgb3i_tx_debug("task 0x%p, opcode 0x%x, skb 0x%p.\n",
178                         task, opcode, skb);
179
180         tcp_task->dd_data = skb;
181         skb_reserve(skb, TX_HEADER_LEN);
182         task->hdr = (struct iscsi_hdr *)skb->data;
183         task->hdr_max = sizeof(struct iscsi_hdr);
184
185         /* data_out uses scsi_cmd's itt */
186         if (opcode != ISCSI_OP_SCSI_DATA_OUT)
187                 cxgb3i_reserve_itt(task, &task->hdr->itt);
188
189         return 0;
190 }
191
192 int cxgb3i_conn_init_pdu(struct iscsi_task *task, unsigned int offset,
193                               unsigned int count)
194 {
195         struct iscsi_tcp_task *tcp_task = task->dd_data;
196         struct sk_buff *skb = tcp_task->dd_data;
197         struct iscsi_conn *conn = task->conn;
198         struct page *pg;
199         unsigned int datalen = count;
200         int i, padlen = iscsi_padding(count);
201         skb_frag_t *frag;
202
203         cxgb3i_tx_debug("task 0x%p,0x%p, offset %u, count %u, skb 0x%p.\n",
204                         task, task->sc, offset, count, skb);
205
206         skb_put(skb, task->hdr_len);
207         tx_skb_setmode(skb, conn->hdrdgst_en, datalen ? conn->datadgst_en : 0);
208         if (!count)
209                 return 0;
210
211         if (task->sc) {
212                 struct scatterlist *sg;
213                 struct scsi_data_buffer *sdb;
214                 unsigned int sgoffset = offset;
215                 struct page *sgpg;
216                 unsigned int sglen;
217
218                 sdb = scsi_out(task->sc);
219                 sg = sdb->table.sgl;
220
221                 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
222                         cxgb3i_tx_debug("sg %d, page 0x%p, len %u offset %u\n",
223                                         i, sg_page(sg), sg->length, sg->offset);
224
225                         if (sgoffset < sg->length)
226                                 break;
227                         sgoffset -= sg->length;
228                 }
229                 sgpg = sg_page(sg);
230                 sglen = sg->length - sgoffset;
231
232                 do {
233                         int j = skb_shinfo(skb)->nr_frags;
234                         unsigned int copy;
235
236                         if (!sglen) {
237                                 sg = sg_next(sg);
238                                 sgpg = sg_page(sg);
239                                 sgoffset = 0;
240                                 sglen = sg->length;
241                                 ++i;
242                         }
243                         copy = min(sglen, datalen);
244                         if (j && skb_can_coalesce(skb, j, sgpg,
245                                                   sg->offset + sgoffset)) {
246                                 skb_shinfo(skb)->frags[j - 1].size += copy;
247                         } else {
248                                 get_page(sgpg);
249                                 skb_fill_page_desc(skb, j, sgpg,
250                                                    sg->offset + sgoffset, copy);
251                         }
252                         sgoffset += copy;
253                         sglen -= copy;
254                         datalen -= copy;
255                 } while (datalen);
256         } else {
257                 pg = virt_to_page(task->data);
258
259                 while (datalen) {
260                         i = skb_shinfo(skb)->nr_frags;
261                         frag = &skb_shinfo(skb)->frags[i];
262
263                         get_page(pg);
264                         frag->page = pg;
265                         frag->page_offset = 0;
266                         frag->size = min((unsigned int)PAGE_SIZE, datalen);
267
268                         skb_shinfo(skb)->nr_frags++;
269                         datalen -= frag->size;
270                         pg++;
271                 }
272         }
273
274         if (padlen) {
275                 i = skb_shinfo(skb)->nr_frags;
276                 frag = &skb_shinfo(skb)->frags[i];
277                 frag->page = pad_page;
278                 frag->page_offset = 0;
279                 frag->size = padlen;
280                 skb_shinfo(skb)->nr_frags++;
281         }
282
283         datalen = count + padlen;
284         skb->data_len += datalen;
285         skb->truesize += datalen;
286         skb->len += datalen;
287         return 0;
288 }
289
290 int cxgb3i_conn_xmit_pdu(struct iscsi_task *task)
291 {
292         struct iscsi_tcp_task *tcp_task = task->dd_data;
293         struct sk_buff *skb = tcp_task->dd_data;
294         struct iscsi_tcp_conn *tcp_conn = task->conn->dd_data;
295         struct cxgb3i_conn *cconn = tcp_conn->dd_data;
296         unsigned int datalen;
297         int err;
298
299         if (!skb)
300                 return 0;
301
302         datalen = skb->data_len;
303         tcp_task->dd_data = NULL;
304         err = cxgb3i_c3cn_send_pdus(cconn->cep->c3cn, skb);
305         cxgb3i_tx_debug("task 0x%p, skb 0x%p, len %u/%u, rv %d.\n",
306                         task, skb, skb->len, skb->data_len, err);
307         if (err > 0) {
308                 int pdulen = err;
309
310                 if (task->conn->hdrdgst_en)
311                         pdulen += ISCSI_DIGEST_SIZE;
312                 if (datalen && task->conn->datadgst_en)
313                         pdulen += ISCSI_DIGEST_SIZE;
314
315                 task->conn->txdata_octets += pdulen;
316                 return 0;
317         }
318
319         if (err < 0 && err != -EAGAIN) {
320                 kfree_skb(skb);
321                 cxgb3i_tx_debug("itt 0x%x, skb 0x%p, len %u/%u, xmit err %d.\n",
322                                 task->itt, skb, skb->len, skb->data_len, err);
323                 iscsi_conn_printk(KERN_ERR, task->conn, "xmit err %d.\n", err);
324                 iscsi_conn_failure(task->conn, ISCSI_ERR_XMIT_FAILED);
325                 return err;
326         }
327         /* reset skb to send when we are called again */
328         tcp_task->dd_data = skb;
329         return -EAGAIN;
330 }
331
332 int cxgb3i_pdu_init(void)
333 {
334         pad_page = alloc_page(GFP_KERNEL);
335         if (!pad_page)
336                 return -ENOMEM;
337         memset(page_address(pad_page), 0, PAGE_SIZE);
338         return 0;
339 }
340
341 void cxgb3i_pdu_cleanup(void)
342 {
343         if (pad_page) {
344                 __free_page(pad_page);
345                 pad_page = NULL;
346         }
347 }
348
349 void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn)
350 {
351         struct sk_buff *skb;
352         unsigned int read = 0;
353         struct iscsi_conn *conn = c3cn->user_data;
354         int err = 0;
355
356         cxgb3i_rx_debug("cn 0x%p.\n", c3cn);
357
358         read_lock(&c3cn->callback_lock);
359         if (unlikely(!conn || conn->suspend_rx)) {
360                 cxgb3i_rx_debug("conn 0x%p, id %d, suspend_rx %lu!\n",
361                                 conn, conn ? conn->id : 0xFF,
362                                 conn ? conn->suspend_rx : 0xFF);
363                 read_unlock(&c3cn->callback_lock);
364                 return;
365         }
366         skb = skb_peek(&c3cn->receive_queue);
367         while (!err && skb) {
368                 __skb_unlink(skb, &c3cn->receive_queue);
369                 read += skb_ulp_pdulen(skb);
370                 err = cxgb3i_conn_read_pdu_skb(conn, skb);
371                 __kfree_skb(skb);
372                 skb = skb_peek(&c3cn->receive_queue);
373         }
374         read_unlock(&c3cn->callback_lock);
375         if (c3cn) {
376                 c3cn->copied_seq += read;
377                 cxgb3i_c3cn_rx_credits(c3cn, read);
378         }
379         conn->rxdata_octets += read;
380 }
381
382 void cxgb3i_conn_tx_open(struct s3_conn *c3cn)
383 {
384         struct iscsi_conn *conn = c3cn->user_data;
385
386         cxgb3i_tx_debug("cn 0x%p.\n", c3cn);
387         if (conn) {
388                 cxgb3i_tx_debug("cn 0x%p, cid %d.\n", c3cn, conn->id);
389                 scsi_queue_work(conn->session->host, &conn->xmitwork);
390         }
391 }
392
393 void cxgb3i_conn_closing(struct s3_conn *c3cn)
394 {
395         struct iscsi_conn *conn;
396
397         read_lock(&c3cn->callback_lock);
398         conn = c3cn->user_data;
399         if (conn && c3cn->state != C3CN_STATE_ESTABLISHED)
400                 iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
401         read_unlock(&c3cn->callback_lock);
402 }