Branch data Line data Source code
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/pci.h>
20 : : #include <linux/slab.h>
21 : :
22 : : #include <linux/interrupt.h>
23 : : #include <linux/workqueue.h>
24 : : #include <linux/spinlock.h>
25 : : #include <linux/mempool.h>
26 : : #include <scsi/scsi_tcq.h>
27 : : #include <linux/ctype.h>
28 : :
29 : : #include "snic_io.h"
30 : : #include "snic.h"
31 : : #include "cq_enet_desc.h"
32 : : #include "snic_fwint.h"
33 : :
34 : : /*
35 : : * snic_handle_link : Handles link flaps.
36 : : */
37 : : void
38 : 0 : snic_handle_link(struct work_struct *work)
39 : : {
40 : 0 : struct snic *snic = container_of(work, struct snic, link_work);
41 : :
42 [ # # ]: 0 : if (snic->config.xpt_type == SNIC_DAS)
43 : : return;
44 : :
45 : 0 : snic->link_status = svnic_dev_link_status(snic->vdev);
46 : 0 : snic->link_down_cnt = svnic_dev_link_down_cnt(snic->vdev);
47 [ # # ]: 0 : SNIC_HOST_INFO(snic->shost, "Link Event: Link %s.\n",
48 : : ((snic->link_status) ? "Up" : "Down"));
49 : :
50 : 0 : SNIC_ASSERT_NOT_IMPL(1);
51 : : }
52 : :
53 : :
54 : : /*
55 : : * snic_ver_enc : Encodes version str to int
56 : : * version string is similar to netmask string
57 : : */
58 : : static int
59 : 0 : snic_ver_enc(const char *s)
60 : : {
61 : 0 : int v[4] = {0};
62 : 0 : int i = 0, x = 0;
63 : 0 : char c;
64 : 0 : const char *p = s;
65 : :
66 : : /* validate version string */
67 [ # # # # ]: 0 : if ((strlen(s) > 15) || (strlen(s) < 7))
68 : 0 : goto end;
69 : :
70 [ # # ]: 0 : while ((c = *p++)) {
71 [ # # ]: 0 : if (c == '.') {
72 : 0 : i++;
73 : 0 : continue;
74 : : }
75 : :
76 [ # # # # ]: 0 : if (i > 3 || !isdigit(c))
77 : 0 : goto end;
78 : :
79 : 0 : v[i] = v[i] * 10 + (c - '0');
80 : : }
81 : :
82 : : /* validate sub version numbers */
83 [ # # ]: 0 : for (i = 3; i >= 0; i--)
84 [ # # ]: 0 : if (v[i] > 0xff)
85 : 0 : goto end;
86 : :
87 : 0 : x |= (v[0] << 24) | v[1] << 16 | v[2] << 8 | v[3];
88 : :
89 : : end:
90 [ # # ]: 0 : if (x == 0) {
91 : 0 : SNIC_ERR("Invalid version string [%s].\n", s);
92 : :
93 : 0 : return -1;
94 : : }
95 : :
96 : : return x;
97 : : } /* end of snic_ver_enc */
98 : :
99 : : /*
100 : : * snic_qeueue_exch_ver_req :
101 : : *
102 : : * Queues Exchange Version Request, to communicate host information
103 : : * in return, it gets firmware version details
104 : : */
105 : : int
106 : 0 : snic_queue_exch_ver_req(struct snic *snic)
107 : : {
108 : 0 : struct snic_req_info *rqi = NULL;
109 : 0 : struct snic_host_req *req = NULL;
110 : 0 : u32 ver = 0;
111 : 0 : int ret = 0;
112 : :
113 : 0 : SNIC_HOST_INFO(snic->shost, "Exch Ver Req Preparing...\n");
114 : :
115 : 0 : rqi = snic_req_init(snic, 0);
116 [ # # ]: 0 : if (!rqi) {
117 : 0 : SNIC_HOST_ERR(snic->shost,
118 : : "Queuing Exch Ver Req failed, err = %d\n",
119 : : ret);
120 : :
121 : 0 : ret = -ENOMEM;
122 : 0 : goto error;
123 : : }
124 : :
125 : 0 : req = rqi_to_req(rqi);
126 : :
127 : : /* Initialize snic_host_req */
128 : 0 : snic_io_hdr_enc(&req->hdr, SNIC_REQ_EXCH_VER, 0, SCSI_NO_TAG,
129 : 0 : snic->config.hid, 0, (ulong)rqi);
130 : 0 : ver = snic_ver_enc(SNIC_DRV_VERSION);
131 : 0 : req->u.exch_ver.drvr_ver = cpu_to_le32(ver);
132 : 0 : req->u.exch_ver.os_type = cpu_to_le32(SNIC_OS_LINUX);
133 : :
134 : 0 : snic_handle_untagged_req(snic, rqi);
135 : :
136 : 0 : ret = snic_queue_wq_desc(snic, req, sizeof(*req));
137 [ # # ]: 0 : if (ret) {
138 : 0 : snic_release_untagged_req(snic, rqi);
139 : 0 : SNIC_HOST_ERR(snic->shost,
140 : : "Queuing Exch Ver Req failed, err = %d\n",
141 : : ret);
142 : 0 : goto error;
143 : : }
144 : :
145 : 0 : SNIC_HOST_INFO(snic->shost, "Exch Ver Req is issued. ret = %d\n", ret);
146 : :
147 : 0 : error:
148 : 0 : return ret;
149 : : } /* end of snic_queue_exch_ver_req */
150 : :
151 : : /*
152 : : * snic_io_exch_ver_cmpl_handler
153 : : */
154 : : int
155 : 0 : snic_io_exch_ver_cmpl_handler(struct snic *snic, struct snic_fw_req *fwreq)
156 : : {
157 : 0 : struct snic_req_info *rqi = NULL;
158 : 0 : struct snic_exch_ver_rsp *exv_cmpl = &fwreq->u.exch_ver_cmpl;
159 : 0 : u8 typ, hdr_stat;
160 : 0 : u32 cmnd_id, hid, max_sgs;
161 : 0 : ulong ctx = 0;
162 : 0 : unsigned long flags;
163 : 0 : int ret = 0;
164 : :
165 : 0 : SNIC_HOST_INFO(snic->shost, "Exch Ver Compl Received.\n");
166 [ # # ]: 0 : snic_io_hdr_dec(&fwreq->hdr, &typ, &hdr_stat, &cmnd_id, &hid, &ctx);
167 [ # # # # ]: 0 : SNIC_BUG_ON(snic->config.hid != hid);
168 : 0 : rqi = (struct snic_req_info *) ctx;
169 : :
170 [ # # ]: 0 : if (hdr_stat) {
171 : 0 : SNIC_HOST_ERR(snic->shost,
172 : : "Exch Ver Completed w/ err status %d\n",
173 : : hdr_stat);
174 : :
175 : 0 : goto exch_cmpl_end;
176 : : }
177 : :
178 : 0 : spin_lock_irqsave(&snic->snic_lock, flags);
179 : 0 : snic->fwinfo.fw_ver = le32_to_cpu(exv_cmpl->version);
180 : 0 : snic->fwinfo.hid = le32_to_cpu(exv_cmpl->hid);
181 : 0 : snic->fwinfo.max_concur_ios = le32_to_cpu(exv_cmpl->max_concur_ios);
182 : 0 : snic->fwinfo.max_sgs_per_cmd = le32_to_cpu(exv_cmpl->max_sgs_per_cmd);
183 : 0 : snic->fwinfo.max_io_sz = le32_to_cpu(exv_cmpl->max_io_sz);
184 : 0 : snic->fwinfo.max_tgts = le32_to_cpu(exv_cmpl->max_tgts);
185 : 0 : snic->fwinfo.io_tmo = le16_to_cpu(exv_cmpl->io_timeout);
186 : :
187 : 0 : SNIC_HOST_INFO(snic->shost,
188 : : "vers %u hid %u max_concur_ios %u max_sgs_per_cmd %u max_io_sz %u max_tgts %u fw tmo %u\n",
189 : : snic->fwinfo.fw_ver,
190 : : snic->fwinfo.hid,
191 : : snic->fwinfo.max_concur_ios,
192 : : snic->fwinfo.max_sgs_per_cmd,
193 : : snic->fwinfo.max_io_sz,
194 : : snic->fwinfo.max_tgts,
195 : : snic->fwinfo.io_tmo);
196 : :
197 : 0 : SNIC_HOST_INFO(snic->shost,
198 : : "HBA Capabilities = 0x%x\n",
199 : : le32_to_cpu(exv_cmpl->hba_cap));
200 : :
201 : : /* Updating SGList size */
202 : 0 : max_sgs = snic->fwinfo.max_sgs_per_cmd;
203 [ # # ]: 0 : if (max_sgs && max_sgs < SNIC_MAX_SG_DESC_CNT) {
204 : 0 : snic->shost->sg_tablesize = max_sgs;
205 : 0 : SNIC_HOST_INFO(snic->shost, "Max SGs set to %d\n",
206 : : snic->shost->sg_tablesize);
207 [ # # ]: 0 : } else if (max_sgs > snic->shost->sg_tablesize) {
208 : 0 : SNIC_HOST_INFO(snic->shost,
209 : : "Target type %d Supports Larger Max SGList %d than driver's Max SG List %d.\n",
210 : : snic->config.xpt_type, max_sgs,
211 : : snic->shost->sg_tablesize);
212 : : }
213 : :
214 [ # # ]: 0 : if (snic->shost->can_queue > snic->fwinfo.max_concur_ios)
215 : 0 : snic->shost->can_queue = snic->fwinfo.max_concur_ios;
216 : :
217 : 0 : snic->shost->max_sectors = snic->fwinfo.max_io_sz >> 9;
218 [ # # ]: 0 : if (snic->fwinfo.wait)
219 : 0 : complete(snic->fwinfo.wait);
220 : :
221 : 0 : spin_unlock_irqrestore(&snic->snic_lock, flags);
222 : :
223 : 0 : exch_cmpl_end:
224 : 0 : snic_release_untagged_req(snic, rqi);
225 : :
226 : 0 : SNIC_HOST_INFO(snic->shost, "Exch_cmpl Done, hdr_stat %d.\n", hdr_stat);
227 : :
228 : 0 : return ret;
229 : : } /* end of snic_io_exch_ver_cmpl_handler */
230 : :
231 : : /*
232 : : * snic_get_conf
233 : : *
234 : : * Synchronous call, and Retrieves snic params.
235 : : */
236 : : int
237 : 0 : snic_get_conf(struct snic *snic)
238 : : {
239 : 0 : DECLARE_COMPLETION_ONSTACK(wait);
240 : 0 : unsigned long flags;
241 : 0 : int ret;
242 : 0 : int nr_retries = 3;
243 : :
244 : 0 : SNIC_HOST_INFO(snic->shost, "Retrieving snic params.\n");
245 : 0 : spin_lock_irqsave(&snic->snic_lock, flags);
246 : 0 : memset(&snic->fwinfo, 0, sizeof(snic->fwinfo));
247 : 0 : snic->fwinfo.wait = &wait;
248 : 0 : spin_unlock_irqrestore(&snic->snic_lock, flags);
249 : :
250 : : /* Additional delay to handle HW Resource initialization. */
251 : 0 : msleep(50);
252 : :
253 : : /*
254 : : * Exch ver req can be ignored by FW, if HW Resource initialization
255 : : * is in progress, Hence retry.
256 : : */
257 : 0 : do {
258 : 0 : ret = snic_queue_exch_ver_req(snic);
259 [ # # ]: 0 : if (ret)
260 : 0 : return ret;
261 : :
262 : 0 : wait_for_completion_timeout(&wait, msecs_to_jiffies(2000));
263 : 0 : spin_lock_irqsave(&snic->snic_lock, flags);
264 [ # # ]: 0 : ret = (snic->fwinfo.fw_ver != 0) ? 0 : -ETIMEDOUT;
265 : 0 : if (ret)
266 : 0 : SNIC_HOST_ERR(snic->shost,
267 : : "Failed to retrieve snic params,\n");
268 : :
269 : : /* Unset fwinfo.wait, on success or on last retry */
270 [ # # # # ]: 0 : if (ret == 0 || nr_retries == 1)
271 : 0 : snic->fwinfo.wait = NULL;
272 : :
273 : 0 : spin_unlock_irqrestore(&snic->snic_lock, flags);
274 [ # # # # ]: 0 : } while (ret && --nr_retries);
275 : :
276 : : return ret;
277 : : } /* end of snic_get_info */
|