aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/bfa/bfa_sgpg.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/bfa/bfa_sgpg.c')
-rw-r--r--drivers/scsi/bfa/bfa_sgpg.c231
1 files changed, 231 insertions, 0 deletions
diff --git a/drivers/scsi/bfa/bfa_sgpg.c b/drivers/scsi/bfa/bfa_sgpg.c
new file mode 100644
index 000000000000..279d8f9b8907
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_sgpg.c
@@ -0,0 +1,231 @@
1/*
2 * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
3 * All rights reserved
4 * www.brocade.com
5 *
6 * Linux driver for Brocade Fibre Channel Host Bus Adapter.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License (GPL) Version 2 as
10 * published by the Free Software Foundation
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 */
17
18#include <bfa.h>
19
20BFA_TRC_FILE(HAL, SGPG);
21BFA_MODULE(sgpg);
22
23/**
24 * bfa_sgpg_mod BFA SGPG Mode module
25 */
26
27/**
28 * Compute and return memory needed by FCP(im) module.
29 */
30static void
31bfa_sgpg_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
32 u32 *dm_len)
33{
34 if (cfg->drvcfg.num_sgpgs < BFA_SGPG_MIN)
35 cfg->drvcfg.num_sgpgs = BFA_SGPG_MIN;
36
37 *km_len += (cfg->drvcfg.num_sgpgs + 1) * sizeof(struct bfa_sgpg_s);
38 *dm_len += (cfg->drvcfg.num_sgpgs + 1) * sizeof(struct bfi_sgpg_s);
39}
40
41
42static void
43bfa_sgpg_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
44 struct bfa_meminfo_s *minfo, struct bfa_pcidev_s *pcidev)
45{
46 struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
47 int i;
48 struct bfa_sgpg_s *hsgpg;
49 struct bfi_sgpg_s *sgpg;
50 u64 align_len;
51
52 union {
53 u64 pa;
54 union bfi_addr_u addr;
55 } sgpg_pa;
56
57 INIT_LIST_HEAD(&mod->sgpg_q);
58 INIT_LIST_HEAD(&mod->sgpg_wait_q);
59
60 bfa_trc(bfa, cfg->drvcfg.num_sgpgs);
61
62 mod->num_sgpgs = cfg->drvcfg.num_sgpgs;
63 mod->sgpg_arr_pa = bfa_meminfo_dma_phys(minfo);
64 align_len = (BFA_SGPG_ROUNDUP(mod->sgpg_arr_pa) - mod->sgpg_arr_pa);
65 mod->sgpg_arr_pa += align_len;
66 mod->hsgpg_arr = (struct bfa_sgpg_s *) (bfa_meminfo_kva(minfo) +
67 align_len);
68 mod->sgpg_arr = (struct bfi_sgpg_s *) (bfa_meminfo_dma_virt(minfo) +
69 align_len);
70
71 hsgpg = mod->hsgpg_arr;
72 sgpg = mod->sgpg_arr;
73 sgpg_pa.pa = mod->sgpg_arr_pa;
74 mod->free_sgpgs = mod->num_sgpgs;
75
76 bfa_assert(!(sgpg_pa.pa & (sizeof(struct bfi_sgpg_s) - 1)));
77
78 for (i = 0; i < mod->num_sgpgs; i++) {
79 bfa_os_memset(hsgpg, 0, sizeof(*hsgpg));
80 bfa_os_memset(sgpg, 0, sizeof(*sgpg));
81
82 hsgpg->sgpg = sgpg;
83 hsgpg->sgpg_pa = sgpg_pa.addr;
84 list_add_tail(&hsgpg->qe, &mod->sgpg_q);
85
86 hsgpg++;
87 sgpg++;
88 sgpg_pa.pa += sizeof(struct bfi_sgpg_s);
89 }
90
91 bfa_meminfo_kva(minfo) = (u8 *) hsgpg;
92 bfa_meminfo_dma_virt(minfo) = (u8 *) sgpg;
93 bfa_meminfo_dma_phys(minfo) = sgpg_pa.pa;
94}
95
96static void
97bfa_sgpg_initdone(struct bfa_s *bfa)
98{
99}
100
101static void
102bfa_sgpg_detach(struct bfa_s *bfa)
103{
104}
105
106static void
107bfa_sgpg_start(struct bfa_s *bfa)
108{
109}
110
111static void
112bfa_sgpg_stop(struct bfa_s *bfa)
113{
114}
115
116static void
117bfa_sgpg_iocdisable(struct bfa_s *bfa)
118{
119}
120
121
122
123/**
124 * bfa_sgpg_public BFA SGPG public functions
125 */
126
127bfa_status_t
128bfa_sgpg_malloc(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpgs)
129{
130 struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
131 struct bfa_sgpg_s *hsgpg;
132 int i;
133
134 bfa_trc_fp(bfa, nsgpgs);
135
136 if (mod->free_sgpgs < nsgpgs)
137 return BFA_STATUS_ENOMEM;
138
139 for (i = 0; i < nsgpgs; i++) {
140 bfa_q_deq(&mod->sgpg_q, &hsgpg);
141 bfa_assert(hsgpg);
142 list_add_tail(&hsgpg->qe, sgpg_q);
143 }
144
145 mod->free_sgpgs -= nsgpgs;
146 return BFA_STATUS_OK;
147}
148
149void
150bfa_sgpg_mfree(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpg)
151{
152 struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
153 struct bfa_sgpg_wqe_s *wqe;
154
155 bfa_trc_fp(bfa, nsgpg);
156
157 mod->free_sgpgs += nsgpg;
158 bfa_assert(mod->free_sgpgs <= mod->num_sgpgs);
159
160 list_splice_tail_init(sgpg_q, &mod->sgpg_q);
161
162 if (list_empty(&mod->sgpg_wait_q))
163 return;
164
165 /**
166 * satisfy as many waiting requests as possible
167 */
168 do {
169 wqe = bfa_q_first(&mod->sgpg_wait_q);
170 if (mod->free_sgpgs < wqe->nsgpg)
171 nsgpg = mod->free_sgpgs;
172 else
173 nsgpg = wqe->nsgpg;
174 bfa_sgpg_malloc(bfa, &wqe->sgpg_q, nsgpg);
175 wqe->nsgpg -= nsgpg;
176 if (wqe->nsgpg == 0) {
177 list_del(&wqe->qe);
178 wqe->cbfn(wqe->cbarg);
179 }
180 } while (mod->free_sgpgs && !list_empty(&mod->sgpg_wait_q));
181}
182
183void
184bfa_sgpg_wait(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe, int nsgpg)
185{
186 struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
187
188 bfa_assert(nsgpg > 0);
189 bfa_assert(nsgpg > mod->free_sgpgs);
190
191 wqe->nsgpg_total = wqe->nsgpg = nsgpg;
192
193 /**
194 * allocate any left to this one first
195 */
196 if (mod->free_sgpgs) {
197 /**
198 * no one else is waiting for SGPG
199 */
200 bfa_assert(list_empty(&mod->sgpg_wait_q));
201 list_splice_tail_init(&mod->sgpg_q, &wqe->sgpg_q);
202 wqe->nsgpg -= mod->free_sgpgs;
203 mod->free_sgpgs = 0;
204 }
205
206 list_add_tail(&wqe->qe, &mod->sgpg_wait_q);
207}
208
209void
210bfa_sgpg_wcancel(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe)
211{
212 struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
213
214 bfa_assert(bfa_q_is_on_q(&mod->sgpg_wait_q, wqe));
215 list_del(&wqe->qe);
216
217 if (wqe->nsgpg_total != wqe->nsgpg)
218 bfa_sgpg_mfree(bfa, &wqe->sgpg_q,
219 wqe->nsgpg_total - wqe->nsgpg);
220}
221
222void
223bfa_sgpg_winit(struct bfa_sgpg_wqe_s *wqe, void (*cbfn) (void *cbarg),
224 void *cbarg)
225{
226 INIT_LIST_HEAD(&wqe->sgpg_q);
227 wqe->cbfn = cbfn;
228 wqe->cbarg = cbarg;
229}
230
231