Linux 2.6.34-rc3
[pohmelfs.git] / drivers / scsi / fnic / fnic_res.c
blob50488f8e169dc89c8333bc6d395b12669f5544df
1 /*
2 * Copyright 2008 Cisco Systems, Inc. All rights reserved.
3 * Copyright 2007 Nuova Systems, Inc. All rights reserved.
5 * This program is free software; you may redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 2 of the License.
9 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
10 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
11 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
12 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
13 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
14 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
15 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
16 * SOFTWARE.
18 #include <linux/errno.h>
19 #include <linux/types.h>
20 #include <linux/pci.h>
21 #include "wq_enet_desc.h"
22 #include "rq_enet_desc.h"
23 #include "cq_enet_desc.h"
24 #include "vnic_resource.h"
25 #include "vnic_dev.h"
26 #include "vnic_wq.h"
27 #include "vnic_rq.h"
28 #include "vnic_cq.h"
29 #include "vnic_intr.h"
30 #include "vnic_stats.h"
31 #include "vnic_nic.h"
32 #include "fnic.h"
34 int fnic_get_vnic_config(struct fnic *fnic)
36 struct vnic_fc_config *c = &fnic->config;
37 int err;
39 #define GET_CONFIG(m) \
40 do { \
41 err = vnic_dev_spec(fnic->vdev, \
42 offsetof(struct vnic_fc_config, m), \
43 sizeof(c->m), &c->m); \
44 if (err) { \
45 shost_printk(KERN_ERR, fnic->lport->host, \
46 "Error getting %s, %d\n", #m, \
47 err); \
48 return err; \
49 } \
50 } while (0);
52 GET_CONFIG(node_wwn);
53 GET_CONFIG(port_wwn);
54 GET_CONFIG(wq_enet_desc_count);
55 GET_CONFIG(wq_copy_desc_count);
56 GET_CONFIG(rq_desc_count);
57 GET_CONFIG(maxdatafieldsize);
58 GET_CONFIG(ed_tov);
59 GET_CONFIG(ra_tov);
60 GET_CONFIG(intr_timer);
61 GET_CONFIG(intr_timer_type);
62 GET_CONFIG(flags);
63 GET_CONFIG(flogi_retries);
64 GET_CONFIG(flogi_timeout);
65 GET_CONFIG(plogi_retries);
66 GET_CONFIG(plogi_timeout);
67 GET_CONFIG(io_throttle_count);
68 GET_CONFIG(link_down_timeout);
69 GET_CONFIG(port_down_timeout);
70 GET_CONFIG(port_down_io_retries);
71 GET_CONFIG(luns_per_tgt);
73 c->wq_enet_desc_count =
74 min_t(u32, VNIC_FNIC_WQ_DESCS_MAX,
75 max_t(u32, VNIC_FNIC_WQ_DESCS_MIN,
76 c->wq_enet_desc_count));
77 c->wq_enet_desc_count = ALIGN(c->wq_enet_desc_count, 16);
79 c->wq_copy_desc_count =
80 min_t(u32, VNIC_FNIC_WQ_COPY_DESCS_MAX,
81 max_t(u32, VNIC_FNIC_WQ_COPY_DESCS_MIN,
82 c->wq_copy_desc_count));
83 c->wq_copy_desc_count = ALIGN(c->wq_copy_desc_count, 16);
85 c->rq_desc_count =
86 min_t(u32, VNIC_FNIC_RQ_DESCS_MAX,
87 max_t(u32, VNIC_FNIC_RQ_DESCS_MIN,
88 c->rq_desc_count));
89 c->rq_desc_count = ALIGN(c->rq_desc_count, 16);
91 c->maxdatafieldsize =
92 min_t(u16, VNIC_FNIC_MAXDATAFIELDSIZE_MAX,
93 max_t(u16, VNIC_FNIC_MAXDATAFIELDSIZE_MIN,
94 c->maxdatafieldsize));
95 c->ed_tov =
96 min_t(u32, VNIC_FNIC_EDTOV_MAX,
97 max_t(u32, VNIC_FNIC_EDTOV_MIN,
98 c->ed_tov));
100 c->ra_tov =
101 min_t(u32, VNIC_FNIC_RATOV_MAX,
102 max_t(u32, VNIC_FNIC_RATOV_MIN,
103 c->ra_tov));
105 c->flogi_retries =
106 min_t(u32, VNIC_FNIC_FLOGI_RETRIES_MAX, c->flogi_retries);
108 c->flogi_timeout =
109 min_t(u32, VNIC_FNIC_FLOGI_TIMEOUT_MAX,
110 max_t(u32, VNIC_FNIC_FLOGI_TIMEOUT_MIN,
111 c->flogi_timeout));
113 c->plogi_retries =
114 min_t(u32, VNIC_FNIC_PLOGI_RETRIES_MAX, c->plogi_retries);
116 c->plogi_timeout =
117 min_t(u32, VNIC_FNIC_PLOGI_TIMEOUT_MAX,
118 max_t(u32, VNIC_FNIC_PLOGI_TIMEOUT_MIN,
119 c->plogi_timeout));
121 c->io_throttle_count =
122 min_t(u32, VNIC_FNIC_IO_THROTTLE_COUNT_MAX,
123 max_t(u32, VNIC_FNIC_IO_THROTTLE_COUNT_MIN,
124 c->io_throttle_count));
126 c->link_down_timeout =
127 min_t(u32, VNIC_FNIC_LINK_DOWN_TIMEOUT_MAX,
128 c->link_down_timeout);
130 c->port_down_timeout =
131 min_t(u32, VNIC_FNIC_PORT_DOWN_TIMEOUT_MAX,
132 c->port_down_timeout);
134 c->port_down_io_retries =
135 min_t(u32, VNIC_FNIC_PORT_DOWN_IO_RETRIES_MAX,
136 c->port_down_io_retries);
138 c->luns_per_tgt =
139 min_t(u32, VNIC_FNIC_LUNS_PER_TARGET_MAX,
140 max_t(u32, VNIC_FNIC_LUNS_PER_TARGET_MIN,
141 c->luns_per_tgt));
143 c->intr_timer = min_t(u16, VNIC_INTR_TIMER_MAX, c->intr_timer);
144 c->intr_timer_type = c->intr_timer_type;
146 shost_printk(KERN_INFO, fnic->lport->host,
147 "vNIC MAC addr %pM "
148 "wq/wq_copy/rq %d/%d/%d\n",
149 fnic->ctlr.ctl_src_addr,
150 c->wq_enet_desc_count, c->wq_copy_desc_count,
151 c->rq_desc_count);
152 shost_printk(KERN_INFO, fnic->lport->host,
153 "vNIC node wwn %llx port wwn %llx\n",
154 c->node_wwn, c->port_wwn);
155 shost_printk(KERN_INFO, fnic->lport->host,
156 "vNIC ed_tov %d ra_tov %d\n",
157 c->ed_tov, c->ra_tov);
158 shost_printk(KERN_INFO, fnic->lport->host,
159 "vNIC mtu %d intr timer %d\n",
160 c->maxdatafieldsize, c->intr_timer);
161 shost_printk(KERN_INFO, fnic->lport->host,
162 "vNIC flags 0x%x luns per tgt %d\n",
163 c->flags, c->luns_per_tgt);
164 shost_printk(KERN_INFO, fnic->lport->host,
165 "vNIC flogi_retries %d flogi timeout %d\n",
166 c->flogi_retries, c->flogi_timeout);
167 shost_printk(KERN_INFO, fnic->lport->host,
168 "vNIC plogi retries %d plogi timeout %d\n",
169 c->plogi_retries, c->plogi_timeout);
170 shost_printk(KERN_INFO, fnic->lport->host,
171 "vNIC io throttle count %d link dn timeout %d\n",
172 c->io_throttle_count, c->link_down_timeout);
173 shost_printk(KERN_INFO, fnic->lport->host,
174 "vNIC port dn io retries %d port dn timeout %d\n",
175 c->port_down_io_retries, c->port_down_timeout);
177 return 0;
180 int fnic_set_nic_config(struct fnic *fnic, u8 rss_default_cpu,
181 u8 rss_hash_type,
182 u8 rss_hash_bits, u8 rss_base_cpu, u8 rss_enable,
183 u8 tso_ipid_split_en, u8 ig_vlan_strip_en)
185 u64 a0, a1;
186 u32 nic_cfg;
187 int wait = 1000;
189 vnic_set_nic_cfg(&nic_cfg, rss_default_cpu,
190 rss_hash_type, rss_hash_bits, rss_base_cpu,
191 rss_enable, tso_ipid_split_en, ig_vlan_strip_en);
193 a0 = nic_cfg;
194 a1 = 0;
196 return vnic_dev_cmd(fnic->vdev, CMD_NIC_CFG, &a0, &a1, wait);
199 void fnic_get_res_counts(struct fnic *fnic)
201 fnic->wq_count = vnic_dev_get_res_count(fnic->vdev, RES_TYPE_WQ);
202 fnic->raw_wq_count = fnic->wq_count - 1;
203 fnic->wq_copy_count = fnic->wq_count - fnic->raw_wq_count;
204 fnic->rq_count = vnic_dev_get_res_count(fnic->vdev, RES_TYPE_RQ);
205 fnic->cq_count = vnic_dev_get_res_count(fnic->vdev, RES_TYPE_CQ);
206 fnic->intr_count = vnic_dev_get_res_count(fnic->vdev,
207 RES_TYPE_INTR_CTRL);
210 void fnic_free_vnic_resources(struct fnic *fnic)
212 unsigned int i;
214 for (i = 0; i < fnic->raw_wq_count; i++)
215 vnic_wq_free(&fnic->wq[i]);
217 for (i = 0; i < fnic->wq_copy_count; i++)
218 vnic_wq_copy_free(&fnic->wq_copy[i]);
220 for (i = 0; i < fnic->rq_count; i++)
221 vnic_rq_free(&fnic->rq[i]);
223 for (i = 0; i < fnic->cq_count; i++)
224 vnic_cq_free(&fnic->cq[i]);
226 for (i = 0; i < fnic->intr_count; i++)
227 vnic_intr_free(&fnic->intr[i]);
230 int fnic_alloc_vnic_resources(struct fnic *fnic)
232 enum vnic_dev_intr_mode intr_mode;
233 unsigned int mask_on_assertion;
234 unsigned int interrupt_offset;
235 unsigned int error_interrupt_enable;
236 unsigned int error_interrupt_offset;
237 unsigned int i, cq_index;
238 unsigned int wq_copy_cq_desc_count;
239 int err;
241 intr_mode = vnic_dev_get_intr_mode(fnic->vdev);
243 shost_printk(KERN_INFO, fnic->lport->host, "vNIC interrupt mode: %s\n",
244 intr_mode == VNIC_DEV_INTR_MODE_INTX ? "legacy PCI INTx" :
245 intr_mode == VNIC_DEV_INTR_MODE_MSI ? "MSI" :
246 intr_mode == VNIC_DEV_INTR_MODE_MSIX ?
247 "MSI-X" : "unknown");
249 shost_printk(KERN_INFO, fnic->lport->host, "vNIC resources avail: "
250 "wq %d cp_wq %d raw_wq %d rq %d cq %d intr %d\n",
251 fnic->wq_count, fnic->wq_copy_count, fnic->raw_wq_count,
252 fnic->rq_count, fnic->cq_count, fnic->intr_count);
254 /* Allocate Raw WQ used for FCS frames */
255 for (i = 0; i < fnic->raw_wq_count; i++) {
256 err = vnic_wq_alloc(fnic->vdev, &fnic->wq[i], i,
257 fnic->config.wq_enet_desc_count,
258 sizeof(struct wq_enet_desc));
259 if (err)
260 goto err_out_cleanup;
263 /* Allocate Copy WQs used for SCSI IOs */
264 for (i = 0; i < fnic->wq_copy_count; i++) {
265 err = vnic_wq_copy_alloc(fnic->vdev, &fnic->wq_copy[i],
266 (fnic->raw_wq_count + i),
267 fnic->config.wq_copy_desc_count,
268 sizeof(struct fcpio_host_req));
269 if (err)
270 goto err_out_cleanup;
273 /* RQ for receiving FCS frames */
274 for (i = 0; i < fnic->rq_count; i++) {
275 err = vnic_rq_alloc(fnic->vdev, &fnic->rq[i], i,
276 fnic->config.rq_desc_count,
277 sizeof(struct rq_enet_desc));
278 if (err)
279 goto err_out_cleanup;
282 /* CQ for each RQ */
283 for (i = 0; i < fnic->rq_count; i++) {
284 cq_index = i;
285 err = vnic_cq_alloc(fnic->vdev,
286 &fnic->cq[cq_index], cq_index,
287 fnic->config.rq_desc_count,
288 sizeof(struct cq_enet_rq_desc));
289 if (err)
290 goto err_out_cleanup;
293 /* CQ for each WQ */
294 for (i = 0; i < fnic->raw_wq_count; i++) {
295 cq_index = fnic->rq_count + i;
296 err = vnic_cq_alloc(fnic->vdev, &fnic->cq[cq_index], cq_index,
297 fnic->config.wq_enet_desc_count,
298 sizeof(struct cq_enet_wq_desc));
299 if (err)
300 goto err_out_cleanup;
303 /* CQ for each COPY WQ */
304 wq_copy_cq_desc_count = (fnic->config.wq_copy_desc_count * 3);
305 for (i = 0; i < fnic->wq_copy_count; i++) {
306 cq_index = fnic->raw_wq_count + fnic->rq_count + i;
307 err = vnic_cq_alloc(fnic->vdev, &fnic->cq[cq_index],
308 cq_index,
309 wq_copy_cq_desc_count,
310 sizeof(struct fcpio_fw_req));
311 if (err)
312 goto err_out_cleanup;
315 for (i = 0; i < fnic->intr_count; i++) {
316 err = vnic_intr_alloc(fnic->vdev, &fnic->intr[i], i);
317 if (err)
318 goto err_out_cleanup;
321 fnic->legacy_pba = vnic_dev_get_res(fnic->vdev,
322 RES_TYPE_INTR_PBA_LEGACY, 0);
324 if (!fnic->legacy_pba && intr_mode == VNIC_DEV_INTR_MODE_INTX) {
325 shost_printk(KERN_ERR, fnic->lport->host,
326 "Failed to hook legacy pba resource\n");
327 err = -ENODEV;
328 goto err_out_cleanup;
332 * Init RQ/WQ resources.
334 * RQ[0 to n-1] point to CQ[0 to n-1]
335 * WQ[0 to m-1] point to CQ[n to n+m-1]
336 * WQ_COPY[0 to k-1] points to CQ[n+m to n+m+k-1]
338 * Note for copy wq we always initialize with cq_index = 0
340 * Error interrupt is not enabled for MSI.
343 switch (intr_mode) {
344 case VNIC_DEV_INTR_MODE_INTX:
345 case VNIC_DEV_INTR_MODE_MSIX:
346 error_interrupt_enable = 1;
347 error_interrupt_offset = fnic->err_intr_offset;
348 break;
349 default:
350 error_interrupt_enable = 0;
351 error_interrupt_offset = 0;
352 break;
355 for (i = 0; i < fnic->rq_count; i++) {
356 cq_index = i;
357 vnic_rq_init(&fnic->rq[i],
358 cq_index,
359 error_interrupt_enable,
360 error_interrupt_offset);
363 for (i = 0; i < fnic->raw_wq_count; i++) {
364 cq_index = i + fnic->rq_count;
365 vnic_wq_init(&fnic->wq[i],
366 cq_index,
367 error_interrupt_enable,
368 error_interrupt_offset);
371 for (i = 0; i < fnic->wq_copy_count; i++) {
372 vnic_wq_copy_init(&fnic->wq_copy[i],
373 0 /* cq_index 0 - always */,
374 error_interrupt_enable,
375 error_interrupt_offset);
378 for (i = 0; i < fnic->cq_count; i++) {
380 switch (intr_mode) {
381 case VNIC_DEV_INTR_MODE_MSIX:
382 interrupt_offset = i;
383 break;
384 default:
385 interrupt_offset = 0;
386 break;
389 vnic_cq_init(&fnic->cq[i],
390 0 /* flow_control_enable */,
391 1 /* color_enable */,
392 0 /* cq_head */,
393 0 /* cq_tail */,
394 1 /* cq_tail_color */,
395 1 /* interrupt_enable */,
396 1 /* cq_entry_enable */,
397 0 /* cq_message_enable */,
398 interrupt_offset,
399 0 /* cq_message_addr */);
403 * Init INTR resources
405 * mask_on_assertion is not used for INTx due to the level-
406 * triggered nature of INTx
409 switch (intr_mode) {
410 case VNIC_DEV_INTR_MODE_MSI:
411 case VNIC_DEV_INTR_MODE_MSIX:
412 mask_on_assertion = 1;
413 break;
414 default:
415 mask_on_assertion = 0;
416 break;
419 for (i = 0; i < fnic->intr_count; i++) {
420 vnic_intr_init(&fnic->intr[i],
421 fnic->config.intr_timer,
422 fnic->config.intr_timer_type,
423 mask_on_assertion);
426 /* init the stats memory by making the first call here */
427 err = vnic_dev_stats_dump(fnic->vdev, &fnic->stats);
428 if (err) {
429 shost_printk(KERN_ERR, fnic->lport->host,
430 "vnic_dev_stats_dump failed - x%x\n", err);
431 goto err_out_cleanup;
434 /* Clear LIF stats */
435 vnic_dev_stats_clear(fnic->vdev);
437 return 0;
439 err_out_cleanup:
440 fnic_free_vnic_resources(fnic);
442 return err;