diff options
Diffstat (limited to 'drivers/scsi/cxgb3i/cxgb3i_ddp.h')
-rw-r--r-- | drivers/scsi/cxgb3i/cxgb3i_ddp.h | 306 |
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 | */ | ||
24 | struct 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 | */ | ||
42 | struct 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 | */ | ||
69 | struct 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 | */ | ||
96 | struct pagepod_hdr { | ||
97 | u32 vld_tid; | ||
98 | u32 pgsz_tag_clr; | ||
99 | u32 maxoffset; | ||
100 | u32 pgoffset; | ||
101 | u64 rsvd; | ||
102 | }; | ||
103 | |||
104 | struct 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 | */ | ||
143 | static 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 | |||
154 | static 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 | */ | ||
179 | static 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 | */ | ||
192 | static 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 | */ | ||
206 | static 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 | */ | ||
227 | static 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 | */ | ||
249 | static 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 | */ | ||
264 | static 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 | |||
283 | int cxgb3i_ddp_tag_reserve(struct t3cdev *, unsigned int tid, | ||
284 | struct cxgb3i_tag_format *, u32 *tag, | ||
285 | struct cxgb3i_gather_list *, gfp_t gfp); | ||
286 | void cxgb3i_ddp_tag_release(struct t3cdev *, u32 tag); | ||
287 | |||
288 | struct 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); | ||
293 | void cxgb3i_ddp_release_gl(struct cxgb3i_gather_list *gl, | ||
294 | struct pci_dev *pdev); | ||
295 | |||
296 | int cxgb3i_setup_conn_host_pagesize(struct t3cdev *, unsigned int tid, | ||
297 | int reply); | ||
298 | int cxgb3i_setup_conn_pagesize(struct t3cdev *, unsigned int tid, int reply, | ||
299 | unsigned long pgsz); | ||
300 | int cxgb3i_setup_conn_digest(struct t3cdev *, unsigned int tid, | ||
301 | int hcrc, int dcrc, int reply); | ||
302 | int cxgb3i_ddp_find_page_index(unsigned long pgsz); | ||
303 | int cxgb3i_adapter_ddp_init(struct t3cdev *, struct cxgb3i_tag_format *, | ||
304 | unsigned int *txsz, unsigned int *rxsz); | ||
305 | void cxgb3i_adapter_ddp_cleanup(struct t3cdev *); | ||
306 | #endif | ||