aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/cxgb3i/cxgb3i_ddp.h
diff options
context:
space:
mode:
authorKaren Xie <kxie@chelsio.com>2008-12-09 17:15:32 -0500
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-12-30 11:45:33 -0500
commitc3673464ebc004a3d82063cd41b9cf74d1b55db2 (patch)
treeb061ecd04da7dd3ddddad8f39a4922f437493311 /drivers/scsi/cxgb3i/cxgb3i_ddp.h
parentb632ade282895562924d18b8eedd11a825f4b08c (diff)
[SCSI] cxgb3i: Add cxgb3i iSCSI driver.
This patch implements the cxgb3i iscsi connection acceleration for the open-iscsi initiator. The cxgb3i driver offers the iscsi PDU based offload: - digest insertion and verification - payload direct-placement into host memory buffer. Signed-off-by: Karen Xie <kxie@chelsio.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/cxgb3i/cxgb3i_ddp.h')
-rw-r--r--drivers/scsi/cxgb3i/cxgb3i_ddp.h306
1 files changed, 306 insertions, 0 deletions
diff --git a/drivers/scsi/cxgb3i/cxgb3i_ddp.h b/drivers/scsi/cxgb3i/cxgb3i_ddp.h
new file mode 100644
index 000000000000..5c7c4d95c493
--- /dev/null
+++ b/drivers/scsi/cxgb3i/cxgb3i_ddp.h
@@ -0,0 +1,306 @@
1/*
2 * cxgb3i_ddp.h: Chelsio S3xx iSCSI DDP Manager.
3 *
4 * Copyright (c) 2008 Chelsio Communications, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation.
9 *
10 * Written by: Karen Xie (kxie@chelsio.com)
11 */
12
13#ifndef __CXGB3I_ULP2_DDP_H__
14#define __CXGB3I_ULP2_DDP_H__
15
16/**
17 * struct cxgb3i_tag_format - cxgb3i ulp tag format for an iscsi entity
18 *
19 * @sw_bits: # of bits used by iscsi software layer
20 * @rsvd_bits: # of bits used by h/w
21 * @rsvd_shift: h/w bits shift left
22 * @rsvd_mask: reserved bit mask
23 */
24struct cxgb3i_tag_format {
25 unsigned char sw_bits;
26 unsigned char rsvd_bits;
27 unsigned char rsvd_shift;
28 unsigned char filler[1];
29 u32 rsvd_mask;
30};
31
32/**
33 * struct cxgb3i_gather_list - cxgb3i direct data placement memory
34 *
35 * @tag: ddp tag
36 * @length: total data buffer length
37 * @offset: initial offset to the 1st page
38 * @nelem: # of pages
39 * @pages: page pointers
40 * @phys_addr: physical address
41 */
42struct cxgb3i_gather_list {
43 u32 tag;
44 unsigned int length;
45 unsigned int offset;
46 unsigned int nelem;
47 struct page **pages;
48 dma_addr_t phys_addr[0];
49};
50
51/**
52 * struct cxgb3i_ddp_info - cxgb3i direct data placement for pdu payload
53 *
54 * @list: list head to link elements
55 * @tdev: pointer to t3cdev used by cxgb3 driver
56 * @max_txsz: max tx packet size for ddp
57 * @max_rxsz: max rx packet size for ddp
58 * @llimit: lower bound of the page pod memory
59 * @ulimit: upper bound of the page pod memory
60 * @nppods: # of page pod entries
61 * @idx_last: page pod entry last used
62 * @idx_bits: # of bits the pagepod index would take
63 * @idx_mask: pagepod index mask
64 * @rsvd_tag_mask: tag mask
65 * @map_lock: lock to synchonize access to the page pod map
66 * @gl_map: ddp memory gather list
67 * @gl_skb: skb used to program the pagepod
68 */
69struct cxgb3i_ddp_info {
70 struct list_head list;
71 struct t3cdev *tdev;
72 struct pci_dev *pdev;
73 unsigned int max_txsz;
74 unsigned int max_rxsz;
75 unsigned int llimit;
76 unsigned int ulimit;
77 unsigned int nppods;
78 unsigned int idx_last;
79 unsigned char idx_bits;
80 unsigned char filler[3];
81 u32 idx_mask;
82 u32 rsvd_tag_mask;
83 spinlock_t map_lock;
84 struct cxgb3i_gather_list **gl_map;
85 struct sk_buff **gl_skb;
86};
87
88#define ULP2_MAX_PKT_SIZE 16224
89#define ULP2_MAX_PDU_PAYLOAD (ULP2_MAX_PKT_SIZE - ISCSI_PDU_NONPAYLOAD_MAX)
90#define PPOD_PAGES_MAX 4
91#define PPOD_PAGES_SHIFT 2 /* 4 pages per pod */
92
93/*
94 * struct pagepod_hdr, pagepod - pagepod format
95 */
96struct pagepod_hdr {
97 u32 vld_tid;
98 u32 pgsz_tag_clr;
99 u32 maxoffset;
100 u32 pgoffset;
101 u64 rsvd;
102};
103
104struct pagepod {
105 struct pagepod_hdr hdr;
106 u64 addr[PPOD_PAGES_MAX + 1];
107};
108
109#define PPOD_SIZE sizeof(struct pagepod) /* 64 */
110#define PPOD_SIZE_SHIFT 6
111
112#define PPOD_COLOR_SHIFT 0
113#define PPOD_COLOR_SIZE 6
114#define PPOD_COLOR_MASK ((1 << PPOD_COLOR_SIZE) - 1)
115
116#define PPOD_IDX_SHIFT PPOD_COLOR_SIZE
117#define PPOD_IDX_MAX_SIZE 24
118
119#define S_PPOD_TID 0
120#define M_PPOD_TID 0xFFFFFF
121#define V_PPOD_TID(x) ((x) << S_PPOD_TID)
122
123#define S_PPOD_VALID 24
124#define V_PPOD_VALID(x) ((x) << S_PPOD_VALID)
125#define F_PPOD_VALID V_PPOD_VALID(1U)
126
127#define S_PPOD_COLOR 0
128#define M_PPOD_COLOR 0x3F
129#define V_PPOD_COLOR(x) ((x) << S_PPOD_COLOR)
130
131#define S_PPOD_TAG 6
132#define M_PPOD_TAG 0xFFFFFF
133#define V_PPOD_TAG(x) ((x) << S_PPOD_TAG)
134
135#define S_PPOD_PGSZ 30
136#define M_PPOD_PGSZ 0x3
137#define V_PPOD_PGSZ(x) ((x) << S_PPOD_PGSZ)
138
139/*
140 * large memory chunk allocation/release
141 * use vmalloc() if kmalloc() fails
142 */
143static inline void *cxgb3i_alloc_big_mem(unsigned int size,
144 gfp_t gfp)
145{
146 void *p = kmalloc(size, gfp);
147 if (!p)
148 p = vmalloc(size);
149 if (p)
150 memset(p, 0, size);
151 return p;
152}
153
154static inline void cxgb3i_free_big_mem(void *addr)
155{
156 if (is_vmalloc_addr(addr))
157 vfree(addr);
158 else
159 kfree(addr);
160}
161
162/*
163 * cxgb3i ddp tag are 32 bits, it consists of reserved bits used by h/w and
164 * non-reserved bits that can be used by the iscsi s/w.
165 * The reserved bits are identified by the rsvd_bits and rsvd_shift fields
166 * in struct cxgb3i_tag_format.
167 *
168 * The upper most reserved bit can be used to check if a tag is ddp tag or not:
169 * if the bit is 0, the tag is a valid ddp tag
170 */
171
172/**
173 * cxgb3i_is_ddp_tag - check if a given tag is a hw/ddp tag
174 * @tformat: tag format information
175 * @tag: tag to be checked
176 *
177 * return true if the tag is a ddp tag, false otherwise.
178 */
179static inline int cxgb3i_is_ddp_tag(struct cxgb3i_tag_format *tformat, u32 tag)
180{
181 return !(tag & (1 << (tformat->rsvd_bits + tformat->rsvd_shift - 1)));
182}
183
184/**
185 * cxgb3i_sw_tag_usable - check if a given s/w tag has enough bits left for
186 * the reserved/hw bits
187 * @tformat: tag format information
188 * @sw_tag: s/w tag to be checked
189 *
190 * return true if the tag is a ddp tag, false otherwise.
191 */
192static inline int cxgb3i_sw_tag_usable(struct cxgb3i_tag_format *tformat,
193 u32 sw_tag)
194{
195 sw_tag >>= (32 - tformat->rsvd_bits);
196 return !sw_tag;
197}
198
199/**
200 * cxgb3i_set_non_ddp_tag - mark a given s/w tag as an invalid ddp tag
201 * @tformat: tag format information
202 * @sw_tag: s/w tag to be checked
203 *
204 * insert 1 at the upper most reserved bit to mark it as an invalid ddp tag.
205 */
206static inline u32 cxgb3i_set_non_ddp_tag(struct cxgb3i_tag_format *tformat,
207 u32 sw_tag)
208{
209 unsigned char shift = tformat->rsvd_bits + tformat->rsvd_shift - 1;
210 u32 mask = (1 << shift) - 1;
211
212 if (sw_tag && (sw_tag & ~mask)) {
213 u32 v1 = sw_tag & ((1 << shift) - 1);
214 u32 v2 = (sw_tag >> (shift - 1)) << shift;
215
216 return v2 | v1 | 1 << shift;
217 }
218 return sw_tag | 1 << shift;
219}
220
221/**
222 * cxgb3i_ddp_tag_base - shift the s/w tag bits so that reserved bits are not
223 * used.
224 * @tformat: tag format information
225 * @sw_tag: s/w tag to be checked
226 */
227static inline u32 cxgb3i_ddp_tag_base(struct cxgb3i_tag_format *tformat,
228 u32 sw_tag)
229{
230 u32 mask = (1 << tformat->rsvd_shift) - 1;
231
232 if (sw_tag && (sw_tag & ~mask)) {
233 u32 v1 = sw_tag & mask;
234 u32 v2 = sw_tag >> tformat->rsvd_shift;
235
236 v2 <<= tformat->rsvd_shift + tformat->rsvd_bits;
237 return v2 | v1;
238 }
239 return sw_tag;
240}
241
242/**
243 * cxgb3i_tag_rsvd_bits - get the reserved bits used by the h/w
244 * @tformat: tag format information
245 * @tag: tag to be checked
246 *
247 * return the reserved bits in the tag
248 */
249static inline u32 cxgb3i_tag_rsvd_bits(struct cxgb3i_tag_format *tformat,
250 u32 tag)
251{
252 if (cxgb3i_is_ddp_tag(tformat, tag))
253 return (tag >> tformat->rsvd_shift) & tformat->rsvd_mask;
254 return 0;
255}
256
257/**
258 * cxgb3i_tag_nonrsvd_bits - get the non-reserved bits used by the s/w
259 * @tformat: tag format information
260 * @tag: tag to be checked
261 *
262 * return the non-reserved bits in the tag.
263 */
264static inline u32 cxgb3i_tag_nonrsvd_bits(struct cxgb3i_tag_format *tformat,
265 u32 tag)
266{
267 unsigned char shift = tformat->rsvd_bits + tformat->rsvd_shift - 1;
268 u32 v1, v2;
269
270 if (cxgb3i_is_ddp_tag(tformat, tag)) {
271 v1 = tag & ((1 << tformat->rsvd_shift) - 1);
272 v2 = (tag >> (shift + 1)) << tformat->rsvd_shift;
273 } else {
274 u32 mask = (1 << shift) - 1;
275
276 tag &= ~(1 << shift);
277 v1 = tag & mask;
278 v2 = (tag >> 1) & ~mask;
279 }
280 return v1 | v2;
281}
282
283int cxgb3i_ddp_tag_reserve(struct t3cdev *, unsigned int tid,
284 struct cxgb3i_tag_format *, u32 *tag,
285 struct cxgb3i_gather_list *, gfp_t gfp);
286void cxgb3i_ddp_tag_release(struct t3cdev *, u32 tag);
287
288struct cxgb3i_gather_list *cxgb3i_ddp_make_gl(unsigned int xferlen,
289 struct scatterlist *sgl,
290 unsigned int sgcnt,
291 struct pci_dev *pdev,
292 gfp_t gfp);
293void cxgb3i_ddp_release_gl(struct cxgb3i_gather_list *gl,
294 struct pci_dev *pdev);
295
296int cxgb3i_setup_conn_host_pagesize(struct t3cdev *, unsigned int tid,
297 int reply);
298int cxgb3i_setup_conn_pagesize(struct t3cdev *, unsigned int tid, int reply,
299 unsigned long pgsz);
300int cxgb3i_setup_conn_digest(struct t3cdev *, unsigned int tid,
301 int hcrc, int dcrc, int reply);
302int cxgb3i_ddp_find_page_index(unsigned long pgsz);
303int cxgb3i_adapter_ddp_init(struct t3cdev *, struct cxgb3i_tag_format *,
304 unsigned int *txsz, unsigned int *rxsz);
305void cxgb3i_adapter_ddp_cleanup(struct t3cdev *);
306#endif