xref: /openbmc/linux/drivers/scsi/bfa/bfa_port.c (revision 565d76cb)
1 /*
2  * Copyright (c) 2005-2010 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 "bfad_drv.h"
19 #include "bfa_defs_svc.h"
20 #include "bfa_port.h"
21 #include "bfi.h"
22 #include "bfa_ioc.h"
23 
24 
25 BFA_TRC_FILE(CNA, PORT);
26 
27 #define bfa_ioc_portid(__ioc) ((__ioc)->port_id)
28 
29 static void
30 bfa_port_stats_swap(struct bfa_port_s *port, union bfa_port_stats_u *stats)
31 {
32 	u32    *dip = (u32 *) stats;
33 	__be32    t0, t1;
34 	int	    i;
35 
36 	for (i = 0; i < sizeof(union bfa_port_stats_u)/sizeof(u32);
37 		i += 2) {
38 		t0 = dip[i];
39 		t1 = dip[i + 1];
40 #ifdef __BIG_ENDIAN
41 		dip[i] = be32_to_cpu(t0);
42 		dip[i + 1] = be32_to_cpu(t1);
43 #else
44 		dip[i] = be32_to_cpu(t1);
45 		dip[i + 1] = be32_to_cpu(t0);
46 #endif
47 	}
48 }
49 
50 /*
51  * bfa_port_enable_isr()
52  *
53  *
54  * @param[in] port - Pointer to the port module
55  *            status - Return status from the f/w
56  *
57  * @return void
58  */
59 static void
60 bfa_port_enable_isr(struct bfa_port_s *port, bfa_status_t status)
61 {
62 	bfa_trc(port, status);
63 	port->endis_pending = BFA_FALSE;
64 	port->endis_cbfn(port->endis_cbarg, status);
65 }
66 
67 /*
68  * bfa_port_disable_isr()
69  *
70  *
71  * @param[in] port - Pointer to the port module
72  *            status - Return status from the f/w
73  *
74  * @return void
75  */
76 static void
77 bfa_port_disable_isr(struct bfa_port_s *port, bfa_status_t status)
78 {
79 	bfa_trc(port, status);
80 	port->endis_pending = BFA_FALSE;
81 	port->endis_cbfn(port->endis_cbarg, status);
82 }
83 
84 /*
85  * bfa_port_get_stats_isr()
86  *
87  *
88  * @param[in] port - Pointer to the Port module
89  *            status - Return status from the f/w
90  *
91  * @return void
92  */
93 static void
94 bfa_port_get_stats_isr(struct bfa_port_s *port, bfa_status_t status)
95 {
96 	port->stats_status = status;
97 	port->stats_busy = BFA_FALSE;
98 
99 	if (status == BFA_STATUS_OK) {
100 		struct timeval tv;
101 
102 		memcpy(port->stats, port->stats_dma.kva,
103 		       sizeof(union bfa_port_stats_u));
104 		bfa_port_stats_swap(port, port->stats);
105 
106 		do_gettimeofday(&tv);
107 		port->stats->fc.secs_reset = tv.tv_sec - port->stats_reset_time;
108 	}
109 
110 	if (port->stats_cbfn) {
111 		port->stats_cbfn(port->stats_cbarg, status);
112 		port->stats_cbfn = NULL;
113 	}
114 }
115 
116 /*
117  * bfa_port_clear_stats_isr()
118  *
119  *
120  * @param[in] port - Pointer to the Port module
121  *            status - Return status from the f/w
122  *
123  * @return void
124  */
125 static void
126 bfa_port_clear_stats_isr(struct bfa_port_s *port, bfa_status_t status)
127 {
128 	struct timeval tv;
129 
130 	port->stats_status = status;
131 	port->stats_busy   = BFA_FALSE;
132 
133 	/*
134 	* re-initialize time stamp for stats reset
135 	*/
136 	do_gettimeofday(&tv);
137 	port->stats_reset_time = tv.tv_sec;
138 
139 	if (port->stats_cbfn) {
140 		port->stats_cbfn(port->stats_cbarg, status);
141 		port->stats_cbfn = NULL;
142 	}
143 }
144 
145 /*
146  * bfa_port_isr()
147  *
148  *
149  * @param[in] Pointer to the Port module data structure.
150  *
151  * @return void
152  */
153 static void
154 bfa_port_isr(void *cbarg, struct bfi_mbmsg_s *m)
155 {
156 	struct bfa_port_s *port = (struct bfa_port_s *) cbarg;
157 	union bfi_port_i2h_msg_u *i2hmsg;
158 
159 	i2hmsg = (union bfi_port_i2h_msg_u *) m;
160 	bfa_trc(port, m->mh.msg_id);
161 
162 	switch (m->mh.msg_id) {
163 	case BFI_PORT_I2H_ENABLE_RSP:
164 		if (port->endis_pending == BFA_FALSE)
165 			break;
166 		bfa_port_enable_isr(port, i2hmsg->enable_rsp.status);
167 		break;
168 
169 	case BFI_PORT_I2H_DISABLE_RSP:
170 		if (port->endis_pending == BFA_FALSE)
171 			break;
172 		bfa_port_disable_isr(port, i2hmsg->disable_rsp.status);
173 		break;
174 
175 	case BFI_PORT_I2H_GET_STATS_RSP:
176 		/* Stats busy flag is still set? (may be cmd timed out) */
177 		if (port->stats_busy == BFA_FALSE)
178 			break;
179 		bfa_port_get_stats_isr(port, i2hmsg->getstats_rsp.status);
180 		break;
181 
182 	case BFI_PORT_I2H_CLEAR_STATS_RSP:
183 		if (port->stats_busy == BFA_FALSE)
184 			break;
185 		bfa_port_clear_stats_isr(port, i2hmsg->clearstats_rsp.status);
186 		break;
187 
188 	default:
189 		WARN_ON(1);
190 	}
191 }
192 
193 /*
194  * bfa_port_meminfo()
195  *
196  *
197  * @param[in] void
198  *
199  * @return Size of DMA region
200  */
201 u32
202 bfa_port_meminfo(void)
203 {
204 	return BFA_ROUNDUP(sizeof(union bfa_port_stats_u), BFA_DMA_ALIGN_SZ);
205 }
206 
207 /*
208  * bfa_port_mem_claim()
209  *
210  *
211  * @param[in] port Port module pointer
212  *	      dma_kva Kernel Virtual Address of Port DMA Memory
213  *	      dma_pa  Physical Address of Port DMA Memory
214  *
215  * @return void
216  */
217 void
218 bfa_port_mem_claim(struct bfa_port_s *port, u8 *dma_kva, u64 dma_pa)
219 {
220 	port->stats_dma.kva = dma_kva;
221 	port->stats_dma.pa  = dma_pa;
222 }
223 
224 /*
225  * bfa_port_enable()
226  *
227  *   Send the Port enable request to the f/w
228  *
229  * @param[in] Pointer to the Port module data structure.
230  *
231  * @return Status
232  */
233 bfa_status_t
234 bfa_port_enable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn,
235 		 void *cbarg)
236 {
237 	struct bfi_port_generic_req_s *m;
238 
239 	if (bfa_ioc_is_disabled(port->ioc)) {
240 		bfa_trc(port, BFA_STATUS_IOC_DISABLED);
241 		return BFA_STATUS_IOC_DISABLED;
242 	}
243 
244 	if (!bfa_ioc_is_operational(port->ioc)) {
245 		bfa_trc(port, BFA_STATUS_IOC_FAILURE);
246 		return BFA_STATUS_IOC_FAILURE;
247 	}
248 
249 	if (port->endis_pending) {
250 		bfa_trc(port, BFA_STATUS_DEVBUSY);
251 		return BFA_STATUS_DEVBUSY;
252 	}
253 
254 	m = (struct bfi_port_generic_req_s *) port->endis_mb.msg;
255 
256 	port->msgtag++;
257 	port->endis_cbfn    = cbfn;
258 	port->endis_cbarg   = cbarg;
259 	port->endis_pending = BFA_TRUE;
260 
261 	bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_ENABLE_REQ,
262 		    bfa_ioc_portid(port->ioc));
263 	bfa_ioc_mbox_queue(port->ioc, &port->endis_mb);
264 
265 	return BFA_STATUS_OK;
266 }
267 
268 /*
269  * bfa_port_disable()
270  *
271  *   Send the Port disable request to the f/w
272  *
273  * @param[in] Pointer to the Port module data structure.
274  *
275  * @return Status
276  */
277 bfa_status_t
278 bfa_port_disable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn,
279 		  void *cbarg)
280 {
281 	struct bfi_port_generic_req_s *m;
282 
283 	if (bfa_ioc_is_disabled(port->ioc)) {
284 		bfa_trc(port, BFA_STATUS_IOC_DISABLED);
285 		return BFA_STATUS_IOC_DISABLED;
286 	}
287 
288 	if (!bfa_ioc_is_operational(port->ioc)) {
289 		bfa_trc(port, BFA_STATUS_IOC_FAILURE);
290 		return BFA_STATUS_IOC_FAILURE;
291 	}
292 
293 	if (port->endis_pending) {
294 		bfa_trc(port, BFA_STATUS_DEVBUSY);
295 		return BFA_STATUS_DEVBUSY;
296 	}
297 
298 	m = (struct bfi_port_generic_req_s *) port->endis_mb.msg;
299 
300 	port->msgtag++;
301 	port->endis_cbfn    = cbfn;
302 	port->endis_cbarg   = cbarg;
303 	port->endis_pending = BFA_TRUE;
304 
305 	bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_DISABLE_REQ,
306 		    bfa_ioc_portid(port->ioc));
307 	bfa_ioc_mbox_queue(port->ioc, &port->endis_mb);
308 
309 	return BFA_STATUS_OK;
310 }
311 
312 /*
313  * bfa_port_get_stats()
314  *
315  *   Send the request to the f/w to fetch Port statistics.
316  *
317  * @param[in] Pointer to the Port module data structure.
318  *
319  * @return Status
320  */
321 bfa_status_t
322 bfa_port_get_stats(struct bfa_port_s *port, union bfa_port_stats_u *stats,
323 		    bfa_port_stats_cbfn_t cbfn, void *cbarg)
324 {
325 	struct bfi_port_get_stats_req_s *m;
326 
327 	if (!bfa_ioc_is_operational(port->ioc)) {
328 		bfa_trc(port, BFA_STATUS_IOC_FAILURE);
329 		return BFA_STATUS_IOC_FAILURE;
330 	}
331 
332 	if (port->stats_busy) {
333 		bfa_trc(port, BFA_STATUS_DEVBUSY);
334 		return BFA_STATUS_DEVBUSY;
335 	}
336 
337 	m = (struct bfi_port_get_stats_req_s *) port->stats_mb.msg;
338 
339 	port->stats	  = stats;
340 	port->stats_cbfn  = cbfn;
341 	port->stats_cbarg = cbarg;
342 	port->stats_busy  = BFA_TRUE;
343 	bfa_dma_be_addr_set(m->dma_addr, port->stats_dma.pa);
344 
345 	bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_GET_STATS_REQ,
346 		    bfa_ioc_portid(port->ioc));
347 	bfa_ioc_mbox_queue(port->ioc, &port->stats_mb);
348 
349 	return BFA_STATUS_OK;
350 }
351 
352 /*
353  * bfa_port_clear_stats()
354  *
355  *
356  * @param[in] Pointer to the Port module data structure.
357  *
358  * @return Status
359  */
360 bfa_status_t
361 bfa_port_clear_stats(struct bfa_port_s *port, bfa_port_stats_cbfn_t cbfn,
362 		      void *cbarg)
363 {
364 	struct bfi_port_generic_req_s *m;
365 
366 	if (!bfa_ioc_is_operational(port->ioc)) {
367 		bfa_trc(port, BFA_STATUS_IOC_FAILURE);
368 		return BFA_STATUS_IOC_FAILURE;
369 	}
370 
371 	if (port->stats_busy) {
372 		bfa_trc(port, BFA_STATUS_DEVBUSY);
373 		return BFA_STATUS_DEVBUSY;
374 	}
375 
376 	m = (struct bfi_port_generic_req_s *) port->stats_mb.msg;
377 
378 	port->stats_cbfn  = cbfn;
379 	port->stats_cbarg = cbarg;
380 	port->stats_busy  = BFA_TRUE;
381 
382 	bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_CLEAR_STATS_REQ,
383 		    bfa_ioc_portid(port->ioc));
384 	bfa_ioc_mbox_queue(port->ioc, &port->stats_mb);
385 
386 	return BFA_STATUS_OK;
387 }
388 
389 /*
390  * bfa_port_hbfail()
391  *
392  *
393  * @param[in] Pointer to the Port module data structure.
394  *
395  * @return void
396  */
397 void
398 bfa_port_hbfail(void *arg)
399 {
400 	struct bfa_port_s *port = (struct bfa_port_s *) arg;
401 
402 	/* Fail any pending get_stats/clear_stats requests */
403 	if (port->stats_busy) {
404 		if (port->stats_cbfn)
405 			port->stats_cbfn(port->stats_cbarg, BFA_STATUS_FAILED);
406 		port->stats_cbfn = NULL;
407 		port->stats_busy = BFA_FALSE;
408 	}
409 
410 	/* Clear any enable/disable is pending */
411 	if (port->endis_pending) {
412 		if (port->endis_cbfn)
413 			port->endis_cbfn(port->endis_cbarg, BFA_STATUS_FAILED);
414 		port->endis_cbfn = NULL;
415 		port->endis_pending = BFA_FALSE;
416 	}
417 }
418 
419 /*
420  * bfa_port_attach()
421  *
422  *
423  * @param[in] port - Pointer to the Port module data structure
424  *            ioc  - Pointer to the ioc module data structure
425  *            dev  - Pointer to the device driver module data structure
426  *                   The device driver specific mbox ISR functions have
427  *                   this pointer as one of the parameters.
428  *            trcmod -
429  *
430  * @return void
431  */
432 void
433 bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc,
434 		 void *dev, struct bfa_trc_mod_s *trcmod)
435 {
436 	struct timeval tv;
437 
438 	WARN_ON(!port);
439 
440 	port->dev    = dev;
441 	port->ioc    = ioc;
442 	port->trcmod = trcmod;
443 
444 	port->stats_busy = BFA_FALSE;
445 	port->endis_pending = BFA_FALSE;
446 	port->stats_cbfn = NULL;
447 	port->endis_cbfn = NULL;
448 
449 	bfa_ioc_mbox_regisr(port->ioc, BFI_MC_PORT, bfa_port_isr, port);
450 	bfa_ioc_hbfail_init(&port->hbfail, bfa_port_hbfail, port);
451 	list_add_tail(&port->hbfail.qe, &port->ioc->hb_notify_q);
452 
453 	/*
454 	 * initialize time stamp for stats reset
455 	 */
456 	do_gettimeofday(&tv);
457 	port->stats_reset_time = tv.tv_sec;
458 
459 	bfa_trc(port, 0);
460 }
461