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