Linux-libre 5.4.48-gnu
[librecmc/linux-libre.git] / drivers / scsi / snic / snic_res.c
1 /*
2  * Copyright 2014 Cisco Systems, Inc.  All rights reserved.
3  *
4  * This program is free software; you may redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
9  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
10  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
11  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
12  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
13  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
15  * SOFTWARE.
16  */
17
18 #include <linux/errno.h>
19 #include <linux/types.h>
20 #include <linux/pci.h>
21
22 #include "wq_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_cq.h"
28 #include "vnic_intr.h"
29 #include "vnic_stats.h"
30 #include "snic.h"
31
32 int
33 snic_get_vnic_config(struct snic *snic)
34 {
35         struct vnic_snic_config *c = &snic->config;
36         int ret;
37
38 #define GET_CONFIG(m) \
39         do { \
40                 ret = svnic_dev_spec(snic->vdev, \
41                                      offsetof(struct vnic_snic_config, m), \
42                                      sizeof(c->m), \
43                                      &c->m); \
44                 if (ret) { \
45                         SNIC_HOST_ERR(snic->shost, \
46                                       "Error getting %s, %d\n", #m, ret); \
47                         return ret; \
48                 } \
49         } while (0)
50
51         GET_CONFIG(wq_enet_desc_count);
52         GET_CONFIG(maxdatafieldsize);
53         GET_CONFIG(intr_timer);
54         GET_CONFIG(intr_timer_type);
55         GET_CONFIG(flags);
56         GET_CONFIG(io_throttle_count);
57         GET_CONFIG(port_down_timeout);
58         GET_CONFIG(port_down_io_retries);
59         GET_CONFIG(luns_per_tgt);
60         GET_CONFIG(xpt_type);
61         GET_CONFIG(hid);
62
63         c->wq_enet_desc_count = min_t(u32,
64                                       VNIC_SNIC_WQ_DESCS_MAX,
65                                       max_t(u32,
66                                             VNIC_SNIC_WQ_DESCS_MIN,
67                                             c->wq_enet_desc_count));
68
69         c->wq_enet_desc_count = ALIGN(c->wq_enet_desc_count, 16);
70
71         c->maxdatafieldsize = min_t(u32,
72                                     VNIC_SNIC_MAXDATAFIELDSIZE_MAX,
73                                     max_t(u32,
74                                           VNIC_SNIC_MAXDATAFIELDSIZE_MIN,
75                                           c->maxdatafieldsize));
76
77         c->io_throttle_count = min_t(u32,
78                                      VNIC_SNIC_IO_THROTTLE_COUNT_MAX,
79                                      max_t(u32,
80                                            VNIC_SNIC_IO_THROTTLE_COUNT_MIN,
81                                            c->io_throttle_count));
82
83         c->port_down_timeout = min_t(u32,
84                                      VNIC_SNIC_PORT_DOWN_TIMEOUT_MAX,
85                                      c->port_down_timeout);
86
87         c->port_down_io_retries = min_t(u32,
88                                      VNIC_SNIC_PORT_DOWN_IO_RETRIES_MAX,
89                                      c->port_down_io_retries);
90
91         c->luns_per_tgt = min_t(u32,
92                                 VNIC_SNIC_LUNS_PER_TARGET_MAX,
93                                 max_t(u32,
94                                       VNIC_SNIC_LUNS_PER_TARGET_MIN,
95                                       c->luns_per_tgt));
96
97         c->intr_timer = min_t(u32, VNIC_INTR_TIMER_MAX, c->intr_timer);
98
99         SNIC_INFO("vNIC resources wq %d\n", c->wq_enet_desc_count);
100         SNIC_INFO("vNIC mtu %d intr timer %d\n",
101                   c->maxdatafieldsize,
102                   c->intr_timer);
103
104         SNIC_INFO("vNIC flags 0x%x luns per tgt %d\n",
105                   c->flags,
106                   c->luns_per_tgt);
107
108         SNIC_INFO("vNIC io throttle count %d\n", c->io_throttle_count);
109         SNIC_INFO("vNIC port down timeout %d port down io retries %d\n",
110                   c->port_down_timeout,
111                   c->port_down_io_retries);
112
113         SNIC_INFO("vNIC back end type = %d\n", c->xpt_type);
114         SNIC_INFO("vNIC hid = %d\n", c->hid);
115
116         return 0;
117 }
118
119 void
120 snic_get_res_counts(struct snic *snic)
121 {
122         snic->wq_count = svnic_dev_get_res_count(snic->vdev, RES_TYPE_WQ);
123         SNIC_BUG_ON(snic->wq_count == 0);
124         snic->cq_count = svnic_dev_get_res_count(snic->vdev, RES_TYPE_CQ);
125         SNIC_BUG_ON(snic->cq_count == 0);
126         snic->intr_count = svnic_dev_get_res_count(snic->vdev,
127                                                   RES_TYPE_INTR_CTRL);
128         SNIC_BUG_ON(snic->intr_count == 0);
129 }
130
131 void
132 snic_free_vnic_res(struct snic *snic)
133 {
134         unsigned int i;
135
136         for (i = 0; i < snic->wq_count; i++)
137                 svnic_wq_free(&snic->wq[i]);
138
139         for (i = 0; i < snic->cq_count; i++)
140                 svnic_cq_free(&snic->cq[i]);
141
142         for (i = 0; i < snic->intr_count; i++)
143                 svnic_intr_free(&snic->intr[i]);
144 }
145
146 int
147 snic_alloc_vnic_res(struct snic *snic)
148 {
149         enum vnic_dev_intr_mode intr_mode;
150         unsigned int mask_on_assertion;
151         unsigned int intr_offset;
152         unsigned int err_intr_enable;
153         unsigned int err_intr_offset;
154         unsigned int i;
155         int ret;
156
157         intr_mode = svnic_dev_get_intr_mode(snic->vdev);
158
159         SNIC_INFO("vNIC interrupt mode: %s\n",
160                   ((intr_mode == VNIC_DEV_INTR_MODE_INTX) ?
161                    "Legacy PCI INTx" :
162                    ((intr_mode == VNIC_DEV_INTR_MODE_MSI) ?
163                     "MSI" :
164                     ((intr_mode == VNIC_DEV_INTR_MODE_MSIX) ?
165                      "MSI-X" : "Unknown"))));
166
167         /* only MSI-X is supported */
168         SNIC_BUG_ON(intr_mode != VNIC_DEV_INTR_MODE_MSIX);
169
170         SNIC_INFO("wq %d cq %d intr %d\n", snic->wq_count,
171                   snic->cq_count,
172                   snic->intr_count);
173
174
175         /* Allocate WQs used for SCSI IOs */
176         for (i = 0; i < snic->wq_count; i++) {
177                 ret = svnic_wq_alloc(snic->vdev,
178                                      &snic->wq[i],
179                                      i,
180                                      snic->config.wq_enet_desc_count,
181                                      sizeof(struct wq_enet_desc));
182                 if (ret)
183                         goto error_cleanup;
184         }
185
186         /* CQ for each WQ */
187         for (i = 0; i < snic->wq_count; i++) {
188                 ret = svnic_cq_alloc(snic->vdev,
189                                      &snic->cq[i],
190                                      i,
191                                      snic->config.wq_enet_desc_count,
192                                      sizeof(struct cq_enet_wq_desc));
193                 if (ret)
194                         goto error_cleanup;
195         }
196
197         SNIC_BUG_ON(snic->cq_count != 2 * snic->wq_count);
198         /* CQ for FW TO host */
199         for (i = snic->wq_count; i < snic->cq_count; i++) {
200                 ret = svnic_cq_alloc(snic->vdev,
201                                      &snic->cq[i],
202                                      i,
203                                      (snic->config.wq_enet_desc_count * 3),
204                                      sizeof(struct snic_fw_req));
205                 if (ret)
206                         goto error_cleanup;
207         }
208
209         for (i = 0; i < snic->intr_count; i++) {
210                 ret = svnic_intr_alloc(snic->vdev, &snic->intr[i], i);
211                 if (ret)
212                         goto error_cleanup;
213         }
214
215         /*
216          * Init WQ Resources.
217          * WQ[0 to n] points to CQ[0 to n-1]
218          * firmware to host comm points to CQ[n to m+1]
219          */
220         err_intr_enable = 1;
221         err_intr_offset = snic->err_intr_offset;
222
223         for (i = 0; i < snic->wq_count; i++) {
224                 svnic_wq_init(&snic->wq[i],
225                               i,
226                               err_intr_enable,
227                               err_intr_offset);
228         }
229
230         for (i = 0; i < snic->cq_count; i++) {
231                 intr_offset = i;
232
233                 svnic_cq_init(&snic->cq[i],
234                               0 /* flow_control_enable */,
235                               1 /* color_enable */,
236                               0 /* cq_head */,
237                               0 /* cq_tail */,
238                               1 /* cq_tail_color */,
239                               1 /* interrupt_enable */,
240                               1 /* cq_entry_enable */,
241                               0 /* cq_message_enable */,
242                               intr_offset,
243                               0 /* cq_message_addr */);
244         }
245
246         /*
247          * Init INTR resources
248          * Assumption : snic is always in MSI-X mode
249          */
250         SNIC_BUG_ON(intr_mode != VNIC_DEV_INTR_MODE_MSIX);
251         mask_on_assertion = 1;
252
253         for (i = 0; i < snic->intr_count; i++) {
254                 svnic_intr_init(&snic->intr[i],
255                                 snic->config.intr_timer,
256                                 snic->config.intr_timer_type,
257                                 mask_on_assertion);
258         }
259
260         /* init the stats memory by making the first call here */
261         ret = svnic_dev_stats_dump(snic->vdev, &snic->stats);
262         if (ret) {
263                 SNIC_HOST_ERR(snic->shost,
264                               "svnic_dev_stats_dump failed - x%x\n",
265                               ret);
266                 goto error_cleanup;
267         }
268
269         /* Clear LIF stats */
270         svnic_dev_stats_clear(snic->vdev);
271         ret = 0;
272
273         return ret;
274
275 error_cleanup:
276         snic_free_vnic_res(snic);
277
278         return ret;
279 }
280
281 void
282 snic_log_q_error(struct snic *snic)
283 {
284         unsigned int i;
285         u32 err_status;
286
287         for (i = 0; i < snic->wq_count; i++) {
288                 err_status = ioread32(&snic->wq[i].ctrl->error_status);
289                 if (err_status)
290                         SNIC_HOST_ERR(snic->shost,
291                                       "WQ[%d] error status %d\n",
292                                       i,
293                                       err_status);
294         }
295 } /* end of snic_log_q_error */