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