Merge tag 'aa-3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmo...
[firefly-linux-kernel-4.4.55.git] / drivers / scsi / csiostor / csio_mb.c
1 /*
2  * This file is part of the Chelsio FCoE driver for Linux.
3  *
4  * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved.
5  *
6  * This software is available to you under a choice of one of two
7  * licenses.  You may choose to be licensed under the terms of the GNU
8  * General Public License (GPL) Version 2, available from the file
9  * COPYING in the main directory of this source tree, or the
10  * OpenIB.org BSD license below:
11  *
12  *     Redistribution and use in source and binary forms, with or
13  *     without modification, are permitted provided that the following
14  *     conditions are met:
15  *
16  *      - Redistributions of source code must retain the above
17  *        copyright notice, this list of conditions and the following
18  *        disclaimer.
19  *
20  *      - Redistributions in binary form must reproduce the above
21  *        copyright notice, this list of conditions and the following
22  *        disclaimer in the documentation and/or other materials
23  *        provided with the distribution.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32  * SOFTWARE.
33  */
34
35 #include <linux/delay.h>
36 #include <linux/jiffies.h>
37 #include <linux/string.h>
38 #include <scsi/scsi_device.h>
39 #include <scsi/scsi_transport_fc.h>
40
41 #include "csio_hw.h"
42 #include "csio_lnode.h"
43 #include "csio_rnode.h"
44 #include "csio_mb.h"
45 #include "csio_wr.h"
46
47 #define csio_mb_is_host_owner(__owner)          ((__owner) == CSIO_MBOWNER_PL)
48
49 /* MB Command/Response Helpers */
50 /*
51  * csio_mb_fw_retval - FW return value from a mailbox response.
52  * @mbp: Mailbox structure
53  *
54  */
55 enum fw_retval
56 csio_mb_fw_retval(struct csio_mb *mbp)
57 {
58         struct fw_cmd_hdr *hdr;
59
60         hdr = (struct fw_cmd_hdr *)(mbp->mb);
61
62         return FW_CMD_RETVAL_GET(ntohl(hdr->lo));
63 }
64
65 /*
66  * csio_mb_hello - FW HELLO command helper
67  * @hw: The HW structure
68  * @mbp: Mailbox structure
69  * @m_mbox: Master mailbox number, if any.
70  * @a_mbox: Mailbox number for asycn notifications.
71  * @master: Device mastership.
72  * @cbfn: Callback, if any.
73  *
74  */
75 void
76 csio_mb_hello(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
77               uint32_t m_mbox, uint32_t a_mbox, enum csio_dev_master master,
78               void (*cbfn) (struct csio_hw *, struct csio_mb *))
79 {
80         struct fw_hello_cmd *cmdp = (struct fw_hello_cmd *)(mbp->mb);
81
82         CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
83
84         cmdp->op_to_write = htonl(FW_CMD_OP(FW_HELLO_CMD) |
85                                        FW_CMD_REQUEST | FW_CMD_WRITE);
86         cmdp->retval_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
87         cmdp->err_to_clearinit = htonl(
88                 FW_HELLO_CMD_MASTERDIS(master == CSIO_MASTER_CANT)      |
89                 FW_HELLO_CMD_MASTERFORCE(master == CSIO_MASTER_MUST)    |
90                 FW_HELLO_CMD_MBMASTER(master == CSIO_MASTER_MUST ?
91                                 m_mbox : FW_HELLO_CMD_MBMASTER_MASK)    |
92                 FW_HELLO_CMD_MBASYNCNOT(a_mbox) |
93                 FW_HELLO_CMD_STAGE(fw_hello_cmd_stage_os) |
94                 FW_HELLO_CMD_CLEARINIT);
95
96 }
97
98 /*
99  * csio_mb_process_hello_rsp - FW HELLO response processing helper
100  * @hw: The HW structure
101  * @mbp: Mailbox structure
102  * @retval: Mailbox return value from Firmware
103  * @state: State that the function is in.
104  * @mpfn: Master pfn
105  *
106  */
107 void
108 csio_mb_process_hello_rsp(struct csio_hw *hw, struct csio_mb *mbp,
109                           enum fw_retval *retval, enum csio_dev_state *state,
110                           uint8_t *mpfn)
111 {
112         struct fw_hello_cmd *rsp = (struct fw_hello_cmd *)(mbp->mb);
113         uint32_t value;
114
115         *retval = FW_CMD_RETVAL_GET(ntohl(rsp->retval_len16));
116
117         if (*retval == FW_SUCCESS) {
118                 hw->fwrev = ntohl(rsp->fwrev);
119
120                 value = ntohl(rsp->err_to_clearinit);
121                 *mpfn = FW_HELLO_CMD_MBMASTER_GET(value);
122
123                 if (value & FW_HELLO_CMD_INIT)
124                         *state = CSIO_DEV_STATE_INIT;
125                 else if (value & FW_HELLO_CMD_ERR)
126                         *state = CSIO_DEV_STATE_ERR;
127                 else
128                         *state = CSIO_DEV_STATE_UNINIT;
129         }
130 }
131
132 /*
133  * csio_mb_bye - FW BYE command helper
134  * @hw: The HW structure
135  * @mbp: Mailbox structure
136  * @cbfn: Callback, if any.
137  *
138  */
139 void
140 csio_mb_bye(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
141             void (*cbfn) (struct csio_hw *, struct csio_mb *))
142 {
143         struct fw_bye_cmd *cmdp = (struct fw_bye_cmd *)(mbp->mb);
144
145         CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
146
147         cmdp->op_to_write = htonl(FW_CMD_OP(FW_BYE_CMD) |
148                                        FW_CMD_REQUEST | FW_CMD_WRITE);
149         cmdp->retval_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
150
151 }
152
153 /*
154  * csio_mb_reset - FW RESET command helper
155  * @hw: The HW structure
156  * @mbp: Mailbox structure
157  * @reset: Type of reset.
158  * @cbfn: Callback, if any.
159  *
160  */
161 void
162 csio_mb_reset(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
163               int reset, int halt,
164               void (*cbfn) (struct csio_hw *, struct csio_mb *))
165 {
166         struct fw_reset_cmd *cmdp = (struct fw_reset_cmd *)(mbp->mb);
167
168         CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
169
170         cmdp->op_to_write = htonl(FW_CMD_OP(FW_RESET_CMD) |
171                                   FW_CMD_REQUEST | FW_CMD_WRITE);
172         cmdp->retval_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
173         cmdp->val = htonl(reset);
174         cmdp->halt_pkd = htonl(halt);
175
176 }
177
178 /*
179  * csio_mb_params - FW PARAMS command helper
180  * @hw: The HW structure
181  * @mbp: Mailbox structure
182  * @tmo: Command timeout.
183  * @pf: PF number.
184  * @vf: VF number.
185  * @nparams: Number of parameters
186  * @params: Parameter mnemonic array.
187  * @val: Parameter value array.
188  * @wr: Write/Read PARAMS.
189  * @cbfn: Callback, if any.
190  *
191  */
192 void
193 csio_mb_params(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
194                unsigned int pf, unsigned int vf, unsigned int nparams,
195                const u32 *params, u32 *val, bool wr,
196                void (*cbfn)(struct csio_hw *, struct csio_mb *))
197 {
198         uint32_t i;
199         uint32_t temp_params = 0, temp_val = 0;
200         struct fw_params_cmd *cmdp = (struct fw_params_cmd *)(mbp->mb);
201         __be32 *p = &cmdp->param[0].mnem;
202
203         CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
204
205         cmdp->op_to_vfn = htonl(FW_CMD_OP(FW_PARAMS_CMD)                |
206                                 FW_CMD_REQUEST                          |
207                                 (wr ? FW_CMD_WRITE : FW_CMD_READ)       |
208                                 FW_PARAMS_CMD_PFN(pf)                   |
209                                 FW_PARAMS_CMD_VFN(vf));
210         cmdp->retval_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
211
212         /* Write Params */
213         if (wr) {
214                 while (nparams--) {
215                         temp_params = *params++;
216                         temp_val = *val++;
217
218                         *p++ = htonl(temp_params);
219                         *p++ = htonl(temp_val);
220                 }
221         } else {
222                 for (i = 0; i < nparams; i++, p += 2) {
223                         temp_params = *params++;
224                         *p = htonl(temp_params);
225                 }
226         }
227
228 }
229
230 /*
231  * csio_mb_process_read_params_rsp - FW PARAMS response processing helper
232  * @hw: The HW structure
233  * @mbp: Mailbox structure
234  * @retval: Mailbox return value from Firmware
235  * @nparams: Number of parameters
236  * @val: Parameter value array.
237  *
238  */
239 void
240 csio_mb_process_read_params_rsp(struct csio_hw *hw, struct csio_mb *mbp,
241                            enum fw_retval *retval, unsigned int nparams,
242                            u32 *val)
243 {
244         struct fw_params_cmd *rsp = (struct fw_params_cmd *)(mbp->mb);
245         uint32_t i;
246         __be32 *p = &rsp->param[0].val;
247
248         *retval = FW_CMD_RETVAL_GET(ntohl(rsp->retval_len16));
249
250         if (*retval == FW_SUCCESS)
251                 for (i = 0; i < nparams; i++, p += 2)
252                         *val++ = ntohl(*p);
253 }
254
255 /*
256  * csio_mb_ldst - FW LDST command
257  * @hw: The HW structure
258  * @mbp: Mailbox structure
259  * @tmo: timeout
260  * @reg: register
261  *
262  */
263 void
264 csio_mb_ldst(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo, int reg)
265 {
266         struct fw_ldst_cmd *ldst_cmd = (struct fw_ldst_cmd *)(mbp->mb);
267         CSIO_INIT_MBP(mbp, ldst_cmd, tmo, hw, NULL, 1);
268
269         /*
270          * Construct and send the Firmware LDST Command to retrieve the
271          * specified PCI-E Configuration Space register.
272          */
273         ldst_cmd->op_to_addrspace =
274                         htonl(FW_CMD_OP(FW_LDST_CMD)    |
275                         FW_CMD_REQUEST                  |
276                         FW_CMD_READ                     |
277                         FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_FUNC_PCIE));
278         ldst_cmd->cycles_to_len16 = htonl(FW_LEN16(struct fw_ldst_cmd));
279         ldst_cmd->u.pcie.select_naccess = FW_LDST_CMD_NACCESS(1);
280         ldst_cmd->u.pcie.ctrl_to_fn =
281                 (FW_LDST_CMD_LC | FW_LDST_CMD_FN(hw->pfn));
282         ldst_cmd->u.pcie.r = (uint8_t)reg;
283 }
284
285 /*
286  *
287  * csio_mb_caps_config - FW Read/Write Capabilities command helper
288  * @hw: The HW structure
289  * @mbp: Mailbox structure
290  * @wr: Write if 1, Read if 0
291  * @init: Turn on initiator mode.
292  * @tgt: Turn on target mode.
293  * @cofld:  If 1, Control Offload for FCoE
294  * @cbfn: Callback, if any.
295  *
296  * This helper assumes that cmdp has MB payload from a previous CAPS
297  * read command.
298  */
299 void
300 csio_mb_caps_config(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
301                     bool wr, bool init, bool tgt, bool cofld,
302                     void (*cbfn) (struct csio_hw *, struct csio_mb *))
303 {
304         struct fw_caps_config_cmd *cmdp =
305                                 (struct fw_caps_config_cmd *)(mbp->mb);
306
307         CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, wr ? 0 : 1);
308
309         cmdp->op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
310                                   FW_CMD_REQUEST                |
311                                   (wr ? FW_CMD_WRITE : FW_CMD_READ));
312         cmdp->cfvalid_to_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
313
314         /* Read config */
315         if (!wr)
316                 return;
317
318         /* Write config */
319         cmdp->fcoecaps = 0;
320
321         if (cofld)
322                 cmdp->fcoecaps |= htons(FW_CAPS_CONFIG_FCOE_CTRL_OFLD);
323         if (init)
324                 cmdp->fcoecaps |= htons(FW_CAPS_CONFIG_FCOE_INITIATOR);
325         if (tgt)
326                 cmdp->fcoecaps |= htons(FW_CAPS_CONFIG_FCOE_TARGET);
327 }
328
329 void
330 csio_rss_glb_config(struct csio_hw *hw, struct csio_mb *mbp,
331                     uint32_t tmo, uint8_t mode, unsigned int flags,
332                     void (*cbfn)(struct csio_hw *, struct csio_mb *))
333 {
334         struct fw_rss_glb_config_cmd *cmdp =
335                                 (struct fw_rss_glb_config_cmd *)(mbp->mb);
336
337         CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
338
339         cmdp->op_to_write = htonl(FW_CMD_OP(FW_RSS_GLB_CONFIG_CMD) |
340                                   FW_CMD_REQUEST | FW_CMD_WRITE);
341         cmdp->retval_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
342
343         if (mode == FW_RSS_GLB_CONFIG_CMD_MODE_MANUAL) {
344                 cmdp->u.manual.mode_pkd =
345                         htonl(FW_RSS_GLB_CONFIG_CMD_MODE(mode));
346         } else if (mode == FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL) {
347                 cmdp->u.basicvirtual.mode_pkd =
348                         htonl(FW_RSS_GLB_CONFIG_CMD_MODE(mode));
349                 cmdp->u.basicvirtual.synmapen_to_hashtoeplitz = htonl(flags);
350         }
351 }
352
353
354 /*
355  * csio_mb_pfvf - FW Write PF/VF capabilities command helper.
356  * @hw: The HW structure
357  * @mbp: Mailbox structure
358  * @pf:
359  * @vf:
360  * @txq:
361  * @txq_eht_ctrl:
362  * @rxqi:
363  * @rxq:
364  * @tc:
365  * @vi:
366  * @pmask:
367  * @rcaps:
368  * @wxcaps:
369  * @cbfn: Callback, if any.
370  *
371  */
372 void
373 csio_mb_pfvf(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
374              unsigned int pf, unsigned int vf, unsigned int txq,
375              unsigned int txq_eth_ctrl, unsigned int rxqi,
376              unsigned int rxq, unsigned int tc, unsigned int vi,
377              unsigned int cmask, unsigned int pmask, unsigned int nexactf,
378              unsigned int rcaps, unsigned int wxcaps,
379              void (*cbfn) (struct csio_hw *, struct csio_mb *))
380 {
381         struct fw_pfvf_cmd *cmdp = (struct fw_pfvf_cmd *)(mbp->mb);
382
383         CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
384
385         cmdp->op_to_vfn = htonl(FW_CMD_OP(FW_PFVF_CMD)                  |
386                                 FW_CMD_REQUEST                          |
387                                 FW_CMD_WRITE                            |
388                                 FW_PFVF_CMD_PFN(pf)                     |
389                                 FW_PFVF_CMD_VFN(vf));
390         cmdp->retval_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
391         cmdp->niqflint_niq = htonl(FW_PFVF_CMD_NIQFLINT(rxqi)           |
392                                              FW_PFVF_CMD_NIQ(rxq));
393
394         cmdp->type_to_neq = htonl(FW_PFVF_CMD_TYPE                      |
395                                   FW_PFVF_CMD_CMASK(cmask)              |
396                                   FW_PFVF_CMD_PMASK(pmask)              |
397                                   FW_PFVF_CMD_NEQ(txq));
398         cmdp->tc_to_nexactf = htonl(FW_PFVF_CMD_TC(tc)                  |
399                                     FW_PFVF_CMD_NVI(vi)                 |
400                                     FW_PFVF_CMD_NEXACTF(nexactf));
401         cmdp->r_caps_to_nethctrl = htonl(FW_PFVF_CMD_R_CAPS(rcaps)      |
402                                          FW_PFVF_CMD_WX_CAPS(wxcaps)    |
403                                          FW_PFVF_CMD_NETHCTRL(txq_eth_ctrl));
404 }
405
406 #define CSIO_ADVERT_MASK     (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\
407                               FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_ANEG)
408
409 /*
410  * csio_mb_port- FW PORT command helper
411  * @hw: The HW structure
412  * @mbp: Mailbox structure
413  * @tmo: COmmand timeout
414  * @portid: Port ID to get/set info
415  * @wr: Write/Read PORT information.
416  * @fc: Flow control
417  * @caps: Port capabilites to set.
418  * @cbfn: Callback, if any.
419  *
420  */
421 void
422 csio_mb_port(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
423              uint8_t portid, bool wr, uint32_t fc, uint16_t caps,
424              void (*cbfn) (struct csio_hw *, struct csio_mb *))
425 {
426         struct fw_port_cmd *cmdp = (struct fw_port_cmd *)(mbp->mb);
427         unsigned int lfc = 0, mdi = FW_PORT_MDI(FW_PORT_MDI_AUTO);
428
429         CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn,  1);
430
431         cmdp->op_to_portid = htonl(FW_CMD_OP(FW_PORT_CMD)               |
432                                    FW_CMD_REQUEST                       |
433                                    (wr ? FW_CMD_EXEC : FW_CMD_READ)     |
434                                    FW_PORT_CMD_PORTID(portid));
435         if (!wr) {
436                 cmdp->action_to_len16 = htonl(
437                         FW_PORT_CMD_ACTION(FW_PORT_ACTION_GET_PORT_INFO) |
438                         FW_CMD_LEN16(sizeof(*cmdp) / 16));
439                 return;
440         }
441
442         /* Set port */
443         cmdp->action_to_len16 = htonl(
444                         FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) |
445                         FW_CMD_LEN16(sizeof(*cmdp) / 16));
446
447         if (fc & PAUSE_RX)
448                 lfc |= FW_PORT_CAP_FC_RX;
449         if (fc & PAUSE_TX)
450                 lfc |= FW_PORT_CAP_FC_TX;
451
452         if (!(caps & FW_PORT_CAP_ANEG))
453                 cmdp->u.l1cfg.rcap = htonl((caps & CSIO_ADVERT_MASK) | lfc);
454         else
455                 cmdp->u.l1cfg.rcap = htonl((caps & CSIO_ADVERT_MASK) |
456                                                                 lfc | mdi);
457 }
458
459 /*
460  * csio_mb_process_read_port_rsp - FW PORT command response processing helper
461  * @hw: The HW structure
462  * @mbp: Mailbox structure
463  * @retval: Mailbox return value from Firmware
464  * @caps: port capabilities
465  *
466  */
467 void
468 csio_mb_process_read_port_rsp(struct csio_hw *hw, struct csio_mb *mbp,
469                          enum fw_retval *retval, uint16_t *caps)
470 {
471         struct fw_port_cmd *rsp = (struct fw_port_cmd *)(mbp->mb);
472
473         *retval = FW_CMD_RETVAL_GET(ntohl(rsp->action_to_len16));
474
475         if (*retval == FW_SUCCESS)
476                 *caps = ntohs(rsp->u.info.pcap);
477 }
478
479 /*
480  * csio_mb_initialize - FW INITIALIZE command helper
481  * @hw: The HW structure
482  * @mbp: Mailbox structure
483  * @tmo: COmmand timeout
484  * @cbfn: Callback, if any.
485  *
486  */
487 void
488 csio_mb_initialize(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
489                    void (*cbfn) (struct csio_hw *, struct csio_mb *))
490 {
491         struct fw_initialize_cmd *cmdp = (struct fw_initialize_cmd *)(mbp->mb);
492
493         CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
494
495         cmdp->op_to_write = htonl(FW_CMD_OP(FW_INITIALIZE_CMD)  |
496                                   FW_CMD_REQUEST | FW_CMD_WRITE);
497         cmdp->retval_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
498
499 }
500
501 /*
502  * csio_mb_iq_alloc - Initializes the mailbox to allocate an
503  *                              Ingress DMA queue in the firmware.
504  *
505  * @hw: The hw structure
506  * @mbp: Mailbox structure to initialize
507  * @priv: Private object
508  * @mb_tmo: Mailbox time-out period (in ms).
509  * @iq_params: Ingress queue params needed for allocation.
510  * @cbfn: The call-back function
511  *
512  *
513  */
514 static void
515 csio_mb_iq_alloc(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
516                  uint32_t mb_tmo, struct csio_iq_params *iq_params,
517                  void (*cbfn) (struct csio_hw *, struct csio_mb *))
518 {
519         struct fw_iq_cmd *cmdp = (struct fw_iq_cmd *)(mbp->mb);
520
521         CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
522
523         cmdp->op_to_vfn = htonl(FW_CMD_OP(FW_IQ_CMD)            |
524                                 FW_CMD_REQUEST | FW_CMD_EXEC    |
525                                 FW_IQ_CMD_PFN(iq_params->pfn)   |
526                                 FW_IQ_CMD_VFN(iq_params->vfn));
527
528         cmdp->alloc_to_len16 = htonl(FW_IQ_CMD_ALLOC            |
529                                 FW_CMD_LEN16(sizeof(*cmdp) / 16));
530
531         cmdp->type_to_iqandstindex = htonl(
532                                 FW_IQ_CMD_VIID(iq_params->viid) |
533                                 FW_IQ_CMD_TYPE(iq_params->type) |
534                                 FW_IQ_CMD_IQASYNCH(iq_params->iqasynch));
535
536         cmdp->fl0size = htons(iq_params->fl0size);
537         cmdp->fl0size = htons(iq_params->fl1size);
538
539 } /* csio_mb_iq_alloc */
540
541 /*
542  * csio_mb_iq_write - Initializes the mailbox for writing into an
543  *                              Ingress DMA Queue.
544  *
545  * @hw: The HW structure
546  * @mbp: Mailbox structure to initialize
547  * @priv: Private object
548  * @mb_tmo: Mailbox time-out period (in ms).
549  * @cascaded_req: TRUE - if this request is cascased with iq-alloc request.
550  * @iq_params: Ingress queue params needed for writing.
551  * @cbfn: The call-back function
552  *
553  * NOTE: We OR relevant bits with cmdp->XXX, instead of just equating,
554  * because this IQ write request can be cascaded with a previous
555  * IQ alloc request, and we dont want to over-write the bits set by
556  * that request. This logic will work even in a non-cascaded case, since the
557  * cmdp structure is zeroed out by CSIO_INIT_MBP.
558  */
559 static void
560 csio_mb_iq_write(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
561                  uint32_t mb_tmo, bool cascaded_req,
562                  struct csio_iq_params *iq_params,
563                  void (*cbfn) (struct csio_hw *, struct csio_mb *))
564 {
565         struct fw_iq_cmd *cmdp = (struct fw_iq_cmd *)(mbp->mb);
566
567         uint32_t iq_start_stop = (iq_params->iq_start)  ?
568                                         FW_IQ_CMD_IQSTART(1) :
569                                         FW_IQ_CMD_IQSTOP(1);
570
571         /*
572          * If this IQ write is cascaded with IQ alloc request, do not
573          * re-initialize with 0's.
574          *
575          */
576         if (!cascaded_req)
577                 CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
578
579         cmdp->op_to_vfn |= htonl(FW_CMD_OP(FW_IQ_CMD)           |
580                                 FW_CMD_REQUEST | FW_CMD_WRITE   |
581                                 FW_IQ_CMD_PFN(iq_params->pfn)   |
582                                 FW_IQ_CMD_VFN(iq_params->vfn));
583         cmdp->alloc_to_len16 |= htonl(iq_start_stop |
584                                 FW_CMD_LEN16(sizeof(*cmdp) / 16));
585         cmdp->iqid |= htons(iq_params->iqid);
586         cmdp->fl0id |= htons(iq_params->fl0id);
587         cmdp->fl1id |= htons(iq_params->fl1id);
588         cmdp->type_to_iqandstindex |= htonl(
589                         FW_IQ_CMD_IQANDST(iq_params->iqandst)   |
590                         FW_IQ_CMD_IQANUS(iq_params->iqanus)     |
591                         FW_IQ_CMD_IQANUD(iq_params->iqanud)     |
592                         FW_IQ_CMD_IQANDSTINDEX(iq_params->iqandstindex));
593         cmdp->iqdroprss_to_iqesize |= htons(
594                         FW_IQ_CMD_IQPCIECH(iq_params->iqpciech)         |
595                         FW_IQ_CMD_IQDCAEN(iq_params->iqdcaen)           |
596                         FW_IQ_CMD_IQDCACPU(iq_params->iqdcacpu)         |
597                         FW_IQ_CMD_IQINTCNTTHRESH(iq_params->iqintcntthresh) |
598                         FW_IQ_CMD_IQCPRIO(iq_params->iqcprio)           |
599                         FW_IQ_CMD_IQESIZE(iq_params->iqesize));
600
601         cmdp->iqsize |= htons(iq_params->iqsize);
602         cmdp->iqaddr |= cpu_to_be64(iq_params->iqaddr);
603
604         if (iq_params->type == 0) {
605                 cmdp->iqns_to_fl0congen |= htonl(
606                         FW_IQ_CMD_IQFLINTIQHSEN(iq_params->iqflintiqhsen)|
607                         FW_IQ_CMD_IQFLINTCONGEN(iq_params->iqflintcongen));
608         }
609
610         if (iq_params->fl0size && iq_params->fl0addr &&
611             (iq_params->fl0id != 0xFFFF)) {
612
613                 cmdp->iqns_to_fl0congen |= htonl(
614                         FW_IQ_CMD_FL0HOSTFCMODE(iq_params->fl0hostfcmode)|
615                         FW_IQ_CMD_FL0CPRIO(iq_params->fl0cprio)         |
616                         FW_IQ_CMD_FL0PADEN(iq_params->fl0paden)         |
617                         FW_IQ_CMD_FL0PACKEN(iq_params->fl0packen));
618                 cmdp->fl0dcaen_to_fl0cidxfthresh |= htons(
619                         FW_IQ_CMD_FL0DCAEN(iq_params->fl0dcaen)         |
620                         FW_IQ_CMD_FL0DCACPU(iq_params->fl0dcacpu)       |
621                         FW_IQ_CMD_FL0FBMIN(iq_params->fl0fbmin)         |
622                         FW_IQ_CMD_FL0FBMAX(iq_params->fl0fbmax)         |
623                         FW_IQ_CMD_FL0CIDXFTHRESH(iq_params->fl0cidxfthresh));
624                 cmdp->fl0size |= htons(iq_params->fl0size);
625                 cmdp->fl0addr |= cpu_to_be64(iq_params->fl0addr);
626         }
627 } /* csio_mb_iq_write */
628
629 /*
630  * csio_mb_iq_alloc_write - Initializes the mailbox for allocating an
631  *                              Ingress DMA Queue.
632  *
633  * @hw: The HW structure
634  * @mbp: Mailbox structure to initialize
635  * @priv: Private data.
636  * @mb_tmo: Mailbox time-out period (in ms).
637  * @iq_params: Ingress queue params needed for allocation & writing.
638  * @cbfn: The call-back function
639  *
640  *
641  */
642 void
643 csio_mb_iq_alloc_write(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
644                        uint32_t mb_tmo, struct csio_iq_params *iq_params,
645                        void (*cbfn) (struct csio_hw *, struct csio_mb *))
646 {
647         csio_mb_iq_alloc(hw, mbp, priv, mb_tmo, iq_params, cbfn);
648         csio_mb_iq_write(hw, mbp, priv, mb_tmo, true, iq_params, cbfn);
649 } /* csio_mb_iq_alloc_write */
650
651 /*
652  * csio_mb_iq_alloc_write_rsp - Process the allocation & writing
653  *                              of ingress DMA queue mailbox's response.
654  *
655  * @hw: The HW structure.
656  * @mbp: Mailbox structure to initialize.
657  * @retval: Firmware return value.
658  * @iq_params: Ingress queue parameters, after allocation and write.
659  *
660  */
661 void
662 csio_mb_iq_alloc_write_rsp(struct csio_hw *hw, struct csio_mb *mbp,
663                            enum fw_retval *ret_val,
664                            struct csio_iq_params *iq_params)
665 {
666         struct fw_iq_cmd *rsp = (struct fw_iq_cmd *)(mbp->mb);
667
668         *ret_val = FW_CMD_RETVAL_GET(ntohl(rsp->alloc_to_len16));
669         if (*ret_val == FW_SUCCESS) {
670                 iq_params->physiqid = ntohs(rsp->physiqid);
671                 iq_params->iqid = ntohs(rsp->iqid);
672                 iq_params->fl0id = ntohs(rsp->fl0id);
673                 iq_params->fl1id = ntohs(rsp->fl1id);
674         } else {
675                 iq_params->physiqid = iq_params->iqid =
676                 iq_params->fl0id = iq_params->fl1id = 0;
677         }
678 } /* csio_mb_iq_alloc_write_rsp */
679
680 /*
681  * csio_mb_iq_free - Initializes the mailbox for freeing a
682  *                              specified Ingress DMA Queue.
683  *
684  * @hw: The HW structure
685  * @mbp: Mailbox structure to initialize
686  * @priv: Private data
687  * @mb_tmo: Mailbox time-out period (in ms).
688  * @iq_params: Parameters of ingress queue, that is to be freed.
689  * @cbfn: The call-back function
690  *
691  *
692  */
693 void
694 csio_mb_iq_free(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
695                 uint32_t mb_tmo, struct csio_iq_params *iq_params,
696                 void (*cbfn) (struct csio_hw *, struct csio_mb *))
697 {
698         struct fw_iq_cmd *cmdp = (struct fw_iq_cmd *)(mbp->mb);
699
700         CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
701
702         cmdp->op_to_vfn = htonl(FW_CMD_OP(FW_IQ_CMD)            |
703                                 FW_CMD_REQUEST | FW_CMD_EXEC    |
704                                 FW_IQ_CMD_PFN(iq_params->pfn)   |
705                                 FW_IQ_CMD_VFN(iq_params->vfn));
706         cmdp->alloc_to_len16 = htonl(FW_IQ_CMD_FREE             |
707                                 FW_CMD_LEN16(sizeof(*cmdp) / 16));
708         cmdp->type_to_iqandstindex = htonl(FW_IQ_CMD_TYPE(iq_params->type));
709
710         cmdp->iqid = htons(iq_params->iqid);
711         cmdp->fl0id = htons(iq_params->fl0id);
712         cmdp->fl1id = htons(iq_params->fl1id);
713
714 } /* csio_mb_iq_free */
715
716 /*
717  * csio_mb_eq_ofld_alloc - Initializes the mailbox for allocating
718  *                              an offload-egress queue.
719  *
720  * @hw: The HW  structure
721  * @mbp: Mailbox structure to initialize
722  * @priv: Private data
723  * @mb_tmo: Mailbox time-out period (in ms).
724  * @eq_ofld_params: (Offload) Egress queue parameters.
725  * @cbfn: The call-back function
726  *
727  *
728  */
729 static void
730 csio_mb_eq_ofld_alloc(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
731                 uint32_t mb_tmo, struct csio_eq_params *eq_ofld_params,
732                 void (*cbfn) (struct csio_hw *, struct csio_mb *))
733 {
734         struct fw_eq_ofld_cmd *cmdp = (struct fw_eq_ofld_cmd *)(mbp->mb);
735
736         CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
737         cmdp->op_to_vfn = htonl(FW_CMD_OP(FW_EQ_OFLD_CMD)               |
738                                 FW_CMD_REQUEST | FW_CMD_EXEC            |
739                                 FW_EQ_OFLD_CMD_PFN(eq_ofld_params->pfn) |
740                                 FW_EQ_OFLD_CMD_VFN(eq_ofld_params->vfn));
741         cmdp->alloc_to_len16 = htonl(FW_EQ_OFLD_CMD_ALLOC       |
742                                 FW_CMD_LEN16(sizeof(*cmdp) / 16));
743
744 } /* csio_mb_eq_ofld_alloc */
745
746 /*
747  * csio_mb_eq_ofld_write - Initializes the mailbox for writing
748  *                              an alloacted offload-egress queue.
749  *
750  * @hw: The HW structure
751  * @mbp: Mailbox structure to initialize
752  * @priv: Private data
753  * @mb_tmo: Mailbox time-out period (in ms).
754  * @cascaded_req: TRUE - if this request is cascased with Eq-alloc request.
755  * @eq_ofld_params: (Offload) Egress queue parameters.
756  * @cbfn: The call-back function
757  *
758  *
759  * NOTE: We OR relevant bits with cmdp->XXX, instead of just equating,
760  * because this EQ write request can be cascaded with a previous
761  * EQ alloc request, and we dont want to over-write the bits set by
762  * that request. This logic will work even in a non-cascaded case, since the
763  * cmdp structure is zeroed out by CSIO_INIT_MBP.
764  */
765 static void
766 csio_mb_eq_ofld_write(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
767                       uint32_t mb_tmo, bool cascaded_req,
768                       struct csio_eq_params *eq_ofld_params,
769                       void (*cbfn) (struct csio_hw *, struct csio_mb *))
770 {
771         struct fw_eq_ofld_cmd *cmdp = (struct fw_eq_ofld_cmd *)(mbp->mb);
772
773         uint32_t eq_start_stop = (eq_ofld_params->eqstart)      ?
774                                 FW_EQ_OFLD_CMD_EQSTART  : FW_EQ_OFLD_CMD_EQSTOP;
775
776         /*
777          * If this EQ write is cascaded with EQ alloc request, do not
778          * re-initialize with 0's.
779          *
780          */
781         if (!cascaded_req)
782                 CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
783
784         cmdp->op_to_vfn |= htonl(FW_CMD_OP(FW_EQ_OFLD_CMD)      |
785                                 FW_CMD_REQUEST | FW_CMD_WRITE   |
786                                 FW_EQ_OFLD_CMD_PFN(eq_ofld_params->pfn) |
787                                 FW_EQ_OFLD_CMD_VFN(eq_ofld_params->vfn));
788         cmdp->alloc_to_len16 |= htonl(eq_start_stop             |
789                                       FW_CMD_LEN16(sizeof(*cmdp) / 16));
790
791         cmdp->eqid_pkd |= htonl(FW_EQ_OFLD_CMD_EQID(eq_ofld_params->eqid));
792
793         cmdp->fetchszm_to_iqid |= htonl(
794                 FW_EQ_OFLD_CMD_HOSTFCMODE(eq_ofld_params->hostfcmode)   |
795                 FW_EQ_OFLD_CMD_CPRIO(eq_ofld_params->cprio)             |
796                 FW_EQ_OFLD_CMD_PCIECHN(eq_ofld_params->pciechn)         |
797                 FW_EQ_OFLD_CMD_IQID(eq_ofld_params->iqid));
798
799         cmdp->dcaen_to_eqsize |= htonl(
800                 FW_EQ_OFLD_CMD_DCAEN(eq_ofld_params->dcaen)             |
801                 FW_EQ_OFLD_CMD_DCACPU(eq_ofld_params->dcacpu)           |
802                 FW_EQ_OFLD_CMD_FBMIN(eq_ofld_params->fbmin)             |
803                 FW_EQ_OFLD_CMD_FBMAX(eq_ofld_params->fbmax)             |
804                 FW_EQ_OFLD_CMD_CIDXFTHRESHO(eq_ofld_params->cidxfthresho) |
805                 FW_EQ_OFLD_CMD_CIDXFTHRESH(eq_ofld_params->cidxfthresh) |
806                 FW_EQ_OFLD_CMD_EQSIZE(eq_ofld_params->eqsize));
807
808         cmdp->eqaddr |= cpu_to_be64(eq_ofld_params->eqaddr);
809
810 } /* csio_mb_eq_ofld_write */
811
812 /*
813  * csio_mb_eq_ofld_alloc_write - Initializes the mailbox for allocation
814  *                              writing into an Engress DMA Queue.
815  *
816  * @hw: The HW structure
817  * @mbp: Mailbox structure to initialize
818  * @priv: Private data.
819  * @mb_tmo: Mailbox time-out period (in ms).
820  * @eq_ofld_params: (Offload) Egress queue parameters.
821  * @cbfn: The call-back function
822  *
823  *
824  */
825 void
826 csio_mb_eq_ofld_alloc_write(struct csio_hw *hw, struct csio_mb *mbp,
827                             void *priv, uint32_t mb_tmo,
828                             struct csio_eq_params *eq_ofld_params,
829                             void (*cbfn) (struct csio_hw *, struct csio_mb *))
830 {
831         csio_mb_eq_ofld_alloc(hw, mbp, priv, mb_tmo, eq_ofld_params, cbfn);
832         csio_mb_eq_ofld_write(hw, mbp, priv, mb_tmo, true,
833                               eq_ofld_params, cbfn);
834 } /* csio_mb_eq_ofld_alloc_write */
835
836 /*
837  * csio_mb_eq_ofld_alloc_write_rsp - Process the allocation
838  *                              & write egress DMA queue mailbox's response.
839  *
840  * @hw: The HW structure.
841  * @mbp: Mailbox structure to initialize.
842  * @retval: Firmware return value.
843  * @eq_ofld_params: (Offload) Egress queue parameters.
844  *
845  */
846 void
847 csio_mb_eq_ofld_alloc_write_rsp(struct csio_hw *hw,
848                                 struct csio_mb *mbp, enum fw_retval *ret_val,
849                                 struct csio_eq_params *eq_ofld_params)
850 {
851         struct fw_eq_ofld_cmd *rsp = (struct fw_eq_ofld_cmd *)(mbp->mb);
852
853         *ret_val = FW_CMD_RETVAL_GET(ntohl(rsp->alloc_to_len16));
854
855         if (*ret_val == FW_SUCCESS) {
856                 eq_ofld_params->eqid = FW_EQ_OFLD_CMD_EQID_GET(
857                                                 ntohl(rsp->eqid_pkd));
858                 eq_ofld_params->physeqid = FW_EQ_OFLD_CMD_PHYSEQID_GET(
859                                                 ntohl(rsp->physeqid_pkd));
860         } else
861                 eq_ofld_params->eqid = 0;
862
863 } /* csio_mb_eq_ofld_alloc_write_rsp */
864
865 /*
866  * csio_mb_eq_ofld_free - Initializes the mailbox for freeing a
867  *                              specified Engress DMA Queue.
868  *
869  * @hw: The HW structure
870  * @mbp: Mailbox structure to initialize
871  * @priv: Private data area.
872  * @mb_tmo: Mailbox time-out period (in ms).
873  * @eq_ofld_params: (Offload) Egress queue parameters, that is to be freed.
874  * @cbfn: The call-back function
875  *
876  *
877  */
878 void
879 csio_mb_eq_ofld_free(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
880                      uint32_t mb_tmo, struct csio_eq_params *eq_ofld_params,
881                      void (*cbfn) (struct csio_hw *, struct csio_mb *))
882 {
883         struct fw_eq_ofld_cmd *cmdp = (struct fw_eq_ofld_cmd *)(mbp->mb);
884
885         CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
886
887         cmdp->op_to_vfn = htonl(FW_CMD_OP(FW_EQ_OFLD_CMD)       |
888                                 FW_CMD_REQUEST | FW_CMD_EXEC    |
889                                 FW_EQ_OFLD_CMD_PFN(eq_ofld_params->pfn) |
890                                 FW_EQ_OFLD_CMD_VFN(eq_ofld_params->vfn));
891         cmdp->alloc_to_len16 = htonl(FW_EQ_OFLD_CMD_FREE |
892                                 FW_CMD_LEN16(sizeof(*cmdp) / 16));
893         cmdp->eqid_pkd = htonl(FW_EQ_OFLD_CMD_EQID(eq_ofld_params->eqid));
894
895 } /* csio_mb_eq_ofld_free */
896
897 /*
898  * csio_write_fcoe_link_cond_init_mb - Initialize Mailbox to write FCoE link
899  *                               condition.
900  *
901  * @ln: The Lnode structure
902  * @mbp: Mailbox structure to initialize
903  * @mb_tmo: Mailbox time-out period (in ms).
904  * @cbfn: The call back function.
905  *
906  *
907  */
908 void
909 csio_write_fcoe_link_cond_init_mb(struct csio_lnode *ln, struct csio_mb *mbp,
910                         uint32_t mb_tmo, uint8_t port_id, uint32_t sub_opcode,
911                         uint8_t cos, bool link_status, uint32_t fcfi,
912                         void (*cbfn) (struct csio_hw *, struct csio_mb *))
913 {
914         struct fw_fcoe_link_cmd *cmdp =
915                                 (struct fw_fcoe_link_cmd *)(mbp->mb);
916
917         CSIO_INIT_MBP(mbp, cmdp, mb_tmo, ln, cbfn, 1);
918
919         cmdp->op_to_portid = htonl((
920                         FW_CMD_OP(FW_FCOE_LINK_CMD)             |
921                         FW_CMD_REQUEST                          |
922                         FW_CMD_WRITE                            |
923                         FW_FCOE_LINK_CMD_PORTID(port_id)));
924         cmdp->sub_opcode_fcfi = htonl(
925                         FW_FCOE_LINK_CMD_SUB_OPCODE(sub_opcode) |
926                         FW_FCOE_LINK_CMD_FCFI(fcfi));
927         cmdp->lstatus = link_status;
928         cmdp->retval_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
929
930 } /* csio_write_fcoe_link_cond_init_mb */
931
932 /*
933  * csio_fcoe_read_res_info_init_mb - Initializes the mailbox for reading FCoE
934  *                              resource information(FW_GET_RES_INFO_CMD).
935  *
936  * @hw: The HW structure
937  * @mbp: Mailbox structure to initialize
938  * @mb_tmo: Mailbox time-out period (in ms).
939  * @cbfn: The call-back function
940  *
941  *
942  */
943 void
944 csio_fcoe_read_res_info_init_mb(struct csio_hw *hw, struct csio_mb *mbp,
945                         uint32_t mb_tmo,
946                         void (*cbfn) (struct csio_hw *, struct csio_mb *))
947 {
948         struct fw_fcoe_res_info_cmd *cmdp =
949                         (struct fw_fcoe_res_info_cmd *)(mbp->mb);
950
951         CSIO_INIT_MBP(mbp, cmdp, mb_tmo, hw, cbfn, 1);
952
953         cmdp->op_to_read = htonl((FW_CMD_OP(FW_FCOE_RES_INFO_CMD)       |
954                                   FW_CMD_REQUEST                        |
955                                   FW_CMD_READ));
956
957         cmdp->retval_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
958
959 } /* csio_fcoe_read_res_info_init_mb */
960
961 /*
962  * csio_fcoe_vnp_alloc_init_mb - Initializes the mailbox for allocating VNP
963  *                              in the firmware (FW_FCOE_VNP_CMD).
964  *
965  * @ln: The Lnode structure.
966  * @mbp: Mailbox structure to initialize.
967  * @mb_tmo: Mailbox time-out period (in ms).
968  * @fcfi: FCF Index.
969  * @vnpi: vnpi
970  * @iqid: iqid
971  * @vnport_wwnn: vnport WWNN
972  * @vnport_wwpn: vnport WWPN
973  * @cbfn: The call-back function.
974  *
975  *
976  */
977 void
978 csio_fcoe_vnp_alloc_init_mb(struct csio_lnode *ln, struct csio_mb *mbp,
979                 uint32_t mb_tmo, uint32_t fcfi, uint32_t vnpi, uint16_t iqid,
980                 uint8_t vnport_wwnn[8], uint8_t vnport_wwpn[8],
981                 void (*cbfn) (struct csio_hw *, struct csio_mb *))
982 {
983         struct fw_fcoe_vnp_cmd *cmdp =
984                         (struct fw_fcoe_vnp_cmd *)(mbp->mb);
985
986         CSIO_INIT_MBP(mbp, cmdp, mb_tmo, ln, cbfn, 1);
987
988         cmdp->op_to_fcfi = htonl((FW_CMD_OP(FW_FCOE_VNP_CMD)            |
989                                   FW_CMD_REQUEST                        |
990                                   FW_CMD_EXEC                           |
991                                   FW_FCOE_VNP_CMD_FCFI(fcfi)));
992
993         cmdp->alloc_to_len16 = htonl(FW_FCOE_VNP_CMD_ALLOC              |
994                                      FW_CMD_LEN16(sizeof(*cmdp) / 16));
995
996         cmdp->gen_wwn_to_vnpi = htonl(FW_FCOE_VNP_CMD_VNPI(vnpi));
997
998         cmdp->iqid = htons(iqid);
999
1000         if (!wwn_to_u64(vnport_wwnn) && !wwn_to_u64(vnport_wwpn))
1001                 cmdp->gen_wwn_to_vnpi |= htonl(FW_FCOE_VNP_CMD_GEN_WWN);
1002
1003         if (vnport_wwnn)
1004                 memcpy(cmdp->vnport_wwnn, vnport_wwnn, 8);
1005         if (vnport_wwpn)
1006                 memcpy(cmdp->vnport_wwpn, vnport_wwpn, 8);
1007
1008 } /* csio_fcoe_vnp_alloc_init_mb */
1009
1010 /*
1011  * csio_fcoe_vnp_read_init_mb - Prepares VNP read cmd.
1012  * @ln: The Lnode structure.
1013  * @mbp: Mailbox structure to initialize.
1014  * @mb_tmo: Mailbox time-out period (in ms).
1015  * @fcfi: FCF Index.
1016  * @vnpi: vnpi
1017  * @cbfn: The call-back handler.
1018  */
1019 void
1020 csio_fcoe_vnp_read_init_mb(struct csio_lnode *ln, struct csio_mb *mbp,
1021                 uint32_t mb_tmo, uint32_t fcfi, uint32_t vnpi,
1022                 void (*cbfn) (struct csio_hw *, struct csio_mb *))
1023 {
1024         struct fw_fcoe_vnp_cmd *cmdp =
1025                         (struct fw_fcoe_vnp_cmd *)(mbp->mb);
1026
1027         CSIO_INIT_MBP(mbp, cmdp, mb_tmo, ln, cbfn, 1);
1028         cmdp->op_to_fcfi = htonl(FW_CMD_OP(FW_FCOE_VNP_CMD)     |
1029                                  FW_CMD_REQUEST                 |
1030                                  FW_CMD_READ                    |
1031                                  FW_FCOE_VNP_CMD_FCFI(fcfi));
1032         cmdp->alloc_to_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
1033         cmdp->gen_wwn_to_vnpi = htonl(FW_FCOE_VNP_CMD_VNPI(vnpi));
1034 }
1035
1036 /*
1037  * csio_fcoe_vnp_free_init_mb - Initializes the mailbox for freeing an
1038  *                      alloacted VNP in the firmware (FW_FCOE_VNP_CMD).
1039  *
1040  * @ln: The Lnode structure.
1041  * @mbp: Mailbox structure to initialize.
1042  * @mb_tmo: Mailbox time-out period (in ms).
1043  * @fcfi: FCF flow id
1044  * @vnpi: VNP flow id
1045  * @cbfn: The call-back function.
1046  * Return: None
1047  */
1048 void
1049 csio_fcoe_vnp_free_init_mb(struct csio_lnode *ln, struct csio_mb *mbp,
1050                 uint32_t mb_tmo, uint32_t fcfi, uint32_t vnpi,
1051                 void (*cbfn) (struct csio_hw *, struct csio_mb *))
1052 {
1053         struct fw_fcoe_vnp_cmd *cmdp =
1054                         (struct fw_fcoe_vnp_cmd *)(mbp->mb);
1055
1056         CSIO_INIT_MBP(mbp, cmdp, mb_tmo, ln, cbfn, 1);
1057
1058         cmdp->op_to_fcfi = htonl(FW_CMD_OP(FW_FCOE_VNP_CMD)     |
1059                                  FW_CMD_REQUEST                 |
1060                                  FW_CMD_EXEC                    |
1061                                  FW_FCOE_VNP_CMD_FCFI(fcfi));
1062         cmdp->alloc_to_len16 = htonl(FW_FCOE_VNP_CMD_FREE       |
1063                                      FW_CMD_LEN16(sizeof(*cmdp) / 16));
1064         cmdp->gen_wwn_to_vnpi = htonl(FW_FCOE_VNP_CMD_VNPI(vnpi));
1065 }
1066
1067 /*
1068  * csio_fcoe_read_fcf_init_mb - Initializes the mailbox to read the
1069  *                              FCF records.
1070  *
1071  * @ln: The Lnode structure
1072  * @mbp: Mailbox structure to initialize
1073  * @mb_tmo: Mailbox time-out period (in ms).
1074  * @fcf_params: FC-Forwarder parameters.
1075  * @cbfn: The call-back function
1076  *
1077  *
1078  */
1079 void
1080 csio_fcoe_read_fcf_init_mb(struct csio_lnode *ln, struct csio_mb *mbp,
1081                 uint32_t mb_tmo, uint32_t portid, uint32_t fcfi,
1082                 void (*cbfn) (struct csio_hw *, struct csio_mb *))
1083 {
1084         struct fw_fcoe_fcf_cmd *cmdp =
1085                         (struct fw_fcoe_fcf_cmd *)(mbp->mb);
1086
1087         CSIO_INIT_MBP(mbp, cmdp, mb_tmo, ln, cbfn, 1);
1088
1089         cmdp->op_to_fcfi = htonl(FW_CMD_OP(FW_FCOE_FCF_CMD)     |
1090                                  FW_CMD_REQUEST                 |
1091                                  FW_CMD_READ                    |
1092                                  FW_FCOE_FCF_CMD_FCFI(fcfi));
1093         cmdp->retval_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
1094
1095 } /* csio_fcoe_read_fcf_init_mb */
1096
1097 void
1098 csio_fcoe_read_portparams_init_mb(struct csio_hw *hw, struct csio_mb *mbp,
1099                                 uint32_t mb_tmo,
1100                                 struct fw_fcoe_port_cmd_params *portparams,
1101                                 void (*cbfn)(struct csio_hw *,
1102                                              struct csio_mb *))
1103 {
1104         struct fw_fcoe_stats_cmd *cmdp = (struct fw_fcoe_stats_cmd *)(mbp->mb);
1105
1106         CSIO_INIT_MBP(mbp, cmdp, mb_tmo, hw, cbfn, 1);
1107         mbp->mb_size = 64;
1108
1109         cmdp->op_to_flowid = htonl(FW_CMD_OP(FW_FCOE_STATS_CMD)         |
1110                                    FW_CMD_REQUEST | FW_CMD_READ);
1111         cmdp->free_to_len16 = htonl(FW_CMD_LEN16(CSIO_MAX_MB_SIZE/16));
1112
1113         cmdp->u.ctl.nstats_port = FW_FCOE_STATS_CMD_NSTATS(portparams->nstats) |
1114                                   FW_FCOE_STATS_CMD_PORT(portparams->portid);
1115
1116         cmdp->u.ctl.port_valid_ix = FW_FCOE_STATS_CMD_IX(portparams->idx)    |
1117                                     FW_FCOE_STATS_CMD_PORT_VALID;
1118
1119 } /* csio_fcoe_read_portparams_init_mb */
1120
1121 void
1122 csio_mb_process_portparams_rsp(struct csio_hw *hw,
1123                                 struct csio_mb *mbp,
1124                                 enum fw_retval *retval,
1125                                 struct fw_fcoe_port_cmd_params *portparams,
1126                                 struct fw_fcoe_port_stats *portstats)
1127 {
1128         struct fw_fcoe_stats_cmd *rsp = (struct fw_fcoe_stats_cmd *)(mbp->mb);
1129         struct fw_fcoe_port_stats stats;
1130         uint8_t *src;
1131         uint8_t *dst;
1132
1133         *retval = FW_CMD_RETVAL_GET(ntohl(rsp->free_to_len16));
1134
1135         memset(&stats, 0, sizeof(struct fw_fcoe_port_stats));
1136
1137         if (*retval == FW_SUCCESS) {
1138                 dst = (uint8_t *)(&stats) + ((portparams->idx - 1) * 8);
1139                 src = (uint8_t *)rsp + (CSIO_STATS_OFFSET * 8);
1140                 memcpy(dst, src, (portparams->nstats * 8));
1141                 if (portparams->idx == 1) {
1142                         /* Get the first 6 flits from the Mailbox */
1143                         portstats->tx_bcast_bytes = stats.tx_bcast_bytes;
1144                         portstats->tx_bcast_frames = stats.tx_bcast_frames;
1145                         portstats->tx_mcast_bytes = stats.tx_mcast_bytes;
1146                         portstats->tx_mcast_frames = stats.tx_mcast_frames;
1147                         portstats->tx_ucast_bytes = stats.tx_ucast_bytes;
1148                         portstats->tx_ucast_frames = stats.tx_ucast_frames;
1149                 }
1150                 if (portparams->idx == 7) {
1151                         /* Get the second 6 flits from the Mailbox */
1152                         portstats->tx_drop_frames = stats.tx_drop_frames;
1153                         portstats->tx_offload_bytes = stats.tx_offload_bytes;
1154                         portstats->tx_offload_frames = stats.tx_offload_frames;
1155 #if 0
1156                         portstats->rx_pf_bytes = stats.rx_pf_bytes;
1157                         portstats->rx_pf_frames = stats.rx_pf_frames;
1158 #endif
1159                         portstats->rx_bcast_bytes = stats.rx_bcast_bytes;
1160                         portstats->rx_bcast_frames = stats.rx_bcast_frames;
1161                         portstats->rx_mcast_bytes = stats.rx_mcast_bytes;
1162                 }
1163                 if (portparams->idx == 13) {
1164                         /* Get the last 4 flits from the Mailbox */
1165                         portstats->rx_mcast_frames = stats.rx_mcast_frames;
1166                         portstats->rx_ucast_bytes = stats.rx_ucast_bytes;
1167                         portstats->rx_ucast_frames = stats.rx_ucast_frames;
1168                         portstats->rx_err_frames = stats.rx_err_frames;
1169                 }
1170         }
1171 }
1172
1173 /* Entry points/APIs for MB module                                           */
1174 /*
1175  * csio_mb_intr_enable - Enable Interrupts from mailboxes.
1176  * @hw: The HW structure
1177  *
1178  * Enables CIM interrupt bit in appropriate INT_ENABLE registers.
1179  */
1180 void
1181 csio_mb_intr_enable(struct csio_hw *hw)
1182 {
1183         csio_wr_reg32(hw, MBMSGRDYINTEN(1), MYPF_REG(CIM_PF_HOST_INT_ENABLE));
1184         csio_rd_reg32(hw, MYPF_REG(CIM_PF_HOST_INT_ENABLE));
1185 }
1186
1187 /*
1188  * csio_mb_intr_disable - Disable Interrupts from mailboxes.
1189  * @hw: The HW structure
1190  *
1191  * Disable bit in HostInterruptEnable CIM register.
1192  */
1193 void
1194 csio_mb_intr_disable(struct csio_hw *hw)
1195 {
1196         csio_wr_reg32(hw, MBMSGRDYINTEN(0), MYPF_REG(CIM_PF_HOST_INT_ENABLE));
1197         csio_rd_reg32(hw, MYPF_REG(CIM_PF_HOST_INT_ENABLE));
1198 }
1199
1200 static void
1201 csio_mb_dump_fw_dbg(struct csio_hw *hw, __be64 *cmd)
1202 {
1203         struct fw_debug_cmd *dbg = (struct fw_debug_cmd *)cmd;
1204
1205         if ((FW_DEBUG_CMD_TYPE_GET(ntohl(dbg->op_type))) == 1) {
1206                 csio_info(hw, "FW print message:\n");
1207                 csio_info(hw, "\tdebug->dprtstridx = %d\n",
1208                             ntohs(dbg->u.prt.dprtstridx));
1209                 csio_info(hw, "\tdebug->dprtstrparam0 = 0x%x\n",
1210                             ntohl(dbg->u.prt.dprtstrparam0));
1211                 csio_info(hw, "\tdebug->dprtstrparam1 = 0x%x\n",
1212                             ntohl(dbg->u.prt.dprtstrparam1));
1213                 csio_info(hw, "\tdebug->dprtstrparam2 = 0x%x\n",
1214                             ntohl(dbg->u.prt.dprtstrparam2));
1215                 csio_info(hw, "\tdebug->dprtstrparam3 = 0x%x\n",
1216                             ntohl(dbg->u.prt.dprtstrparam3));
1217         } else {
1218                 /* This is a FW assertion */
1219                 csio_fatal(hw, "FW assertion at %.16s:%u, val0 %#x, val1 %#x\n",
1220                             dbg->u.assert.filename_0_7,
1221                             ntohl(dbg->u.assert.line),
1222                             ntohl(dbg->u.assert.x),
1223                             ntohl(dbg->u.assert.y));
1224         }
1225 }
1226
1227 static void
1228 csio_mb_debug_cmd_handler(struct csio_hw *hw)
1229 {
1230         int i;
1231         __be64 cmd[CSIO_MB_MAX_REGS];
1232         uint32_t ctl_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_CTRL);
1233         uint32_t data_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_DATA);
1234         int size = sizeof(struct fw_debug_cmd);
1235
1236         /* Copy mailbox data */
1237         for (i = 0; i < size; i += 8)
1238                 cmd[i / 8] = cpu_to_be64(csio_rd_reg64(hw, data_reg + i));
1239
1240         csio_mb_dump_fw_dbg(hw, cmd);
1241
1242         /* Notify FW of mailbox by setting owner as UP */
1243         csio_wr_reg32(hw, MBMSGVALID | MBINTREQ | MBOWNER(CSIO_MBOWNER_FW),
1244                       ctl_reg);
1245
1246         csio_rd_reg32(hw, ctl_reg);
1247         wmb();
1248 }
1249
1250 /*
1251  * csio_mb_issue - generic routine for issuing Mailbox commands.
1252  * @hw: The HW structure
1253  * @mbp: Mailbox command to issue
1254  *
1255  *  Caller should hold hw lock across this call.
1256  */
1257 int
1258 csio_mb_issue(struct csio_hw *hw, struct csio_mb *mbp)
1259 {
1260         uint32_t owner, ctl;
1261         int i;
1262         uint32_t ii;
1263         __be64 *cmd = mbp->mb;
1264         __be64 hdr;
1265         struct csio_mbm *mbm = &hw->mbm;
1266         uint32_t ctl_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_CTRL);
1267         uint32_t data_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_DATA);
1268         int size = mbp->mb_size;
1269         int rv = -EINVAL;
1270         struct fw_cmd_hdr *fw_hdr;
1271
1272         /* Determine mode */
1273         if (mbp->mb_cbfn == NULL) {
1274                 /* Need to issue/get results in the same context */
1275                 if (mbp->tmo < CSIO_MB_POLL_FREQ) {
1276                         csio_err(hw, "Invalid tmo: 0x%x\n", mbp->tmo);
1277                         goto error_out;
1278                 }
1279         } else if (!csio_is_host_intr_enabled(hw) ||
1280                    !csio_is_hw_intr_enabled(hw)) {
1281                 csio_err(hw, "Cannot issue mailbox in interrupt mode 0x%x\n",
1282                          *((uint8_t *)mbp->mb));
1283                         goto error_out;
1284         }
1285
1286         if (mbm->mcurrent != NULL) {
1287                 /* Queue mbox cmd, if another mbox cmd is active */
1288                 if (mbp->mb_cbfn == NULL) {
1289                         rv = -EBUSY;
1290                         csio_dbg(hw, "Couldnt own Mailbox %x op:0x%x\n",
1291                                     hw->pfn, *((uint8_t *)mbp->mb));
1292
1293                         goto error_out;
1294                 } else {
1295                         list_add_tail(&mbp->list, &mbm->req_q);
1296                         CSIO_INC_STATS(mbm, n_activeq);
1297
1298                         return 0;
1299                 }
1300         }
1301
1302         /* Now get ownership of mailbox */
1303         owner = MBOWNER_GET(csio_rd_reg32(hw, ctl_reg));
1304
1305         if (!csio_mb_is_host_owner(owner)) {
1306
1307                 for (i = 0; (owner == CSIO_MBOWNER_NONE) && (i < 3); i++)
1308                         owner = MBOWNER_GET(csio_rd_reg32(hw, ctl_reg));
1309                 /*
1310                  * Mailbox unavailable. In immediate mode, fail the command.
1311                  * In other modes, enqueue the request.
1312                  */
1313                 if (!csio_mb_is_host_owner(owner)) {
1314                         if (mbp->mb_cbfn == NULL) {
1315                                 rv = owner ? -EBUSY : -ETIMEDOUT;
1316
1317                                 csio_dbg(hw,
1318                                          "Couldnt own Mailbox %x op:0x%x "
1319                                          "owner:%x\n",
1320                                          hw->pfn, *((uint8_t *)mbp->mb), owner);
1321                                 goto error_out;
1322                         } else {
1323                                 if (mbm->mcurrent == NULL) {
1324                                         csio_err(hw,
1325                                                  "Couldnt own Mailbox %x "
1326                                                  "op:0x%x owner:%x\n",
1327                                                  hw->pfn, *((uint8_t *)mbp->mb),
1328                                                  owner);
1329                                         csio_err(hw,
1330                                                  "No outstanding driver"
1331                                                  " mailbox as well\n");
1332                                         goto error_out;
1333                                 }
1334                         }
1335                 }
1336         }
1337
1338         /* Mailbox is available, copy mailbox data into it */
1339         for (i = 0; i < size; i += 8) {
1340                 csio_wr_reg64(hw, be64_to_cpu(*cmd), data_reg + i);
1341                 cmd++;
1342         }
1343
1344         CSIO_DUMP_MB(hw, hw->pfn, data_reg);
1345
1346         /* Start completion timers in non-immediate modes and notify FW */
1347         if (mbp->mb_cbfn != NULL) {
1348                 mbm->mcurrent = mbp;
1349                 mod_timer(&mbm->timer, jiffies + msecs_to_jiffies(mbp->tmo));
1350                 csio_wr_reg32(hw, MBMSGVALID | MBINTREQ |
1351                               MBOWNER(CSIO_MBOWNER_FW), ctl_reg);
1352         } else
1353                 csio_wr_reg32(hw, MBMSGVALID | MBOWNER(CSIO_MBOWNER_FW),
1354                               ctl_reg);
1355
1356         /* Flush posted writes */
1357         csio_rd_reg32(hw, ctl_reg);
1358         wmb();
1359
1360         CSIO_INC_STATS(mbm, n_req);
1361
1362         if (mbp->mb_cbfn)
1363                 return 0;
1364
1365         /* Poll for completion in immediate mode */
1366         cmd = mbp->mb;
1367
1368         for (ii = 0; ii < mbp->tmo; ii += CSIO_MB_POLL_FREQ) {
1369                 mdelay(CSIO_MB_POLL_FREQ);
1370
1371                 /* Check for response */
1372                 ctl = csio_rd_reg32(hw, ctl_reg);
1373                 if (csio_mb_is_host_owner(MBOWNER_GET(ctl))) {
1374
1375                         if (!(ctl & MBMSGVALID)) {
1376                                 csio_wr_reg32(hw, 0, ctl_reg);
1377                                 continue;
1378                         }
1379
1380                         CSIO_DUMP_MB(hw, hw->pfn, data_reg);
1381
1382                         hdr = cpu_to_be64(csio_rd_reg64(hw, data_reg));
1383                         fw_hdr = (struct fw_cmd_hdr *)&hdr;
1384
1385                         switch (FW_CMD_OP_GET(ntohl(fw_hdr->hi))) {
1386                         case FW_DEBUG_CMD:
1387                                 csio_mb_debug_cmd_handler(hw);
1388                                 continue;
1389                         }
1390
1391                         /* Copy response */
1392                         for (i = 0; i < size; i += 8)
1393                                 *cmd++ = cpu_to_be64(csio_rd_reg64
1394                                                           (hw, data_reg + i));
1395                         csio_wr_reg32(hw, 0, ctl_reg);
1396
1397                         if (csio_mb_fw_retval(mbp) != FW_SUCCESS)
1398                                 CSIO_INC_STATS(mbm, n_err);
1399
1400                         CSIO_INC_STATS(mbm, n_rsp);
1401                         return 0;
1402                 }
1403         }
1404
1405         CSIO_INC_STATS(mbm, n_tmo);
1406
1407         csio_err(hw, "Mailbox %x op:0x%x timed out!\n",
1408                  hw->pfn, *((uint8_t *)cmd));
1409
1410         return -ETIMEDOUT;
1411
1412 error_out:
1413         CSIO_INC_STATS(mbm, n_err);
1414         return rv;
1415 }
1416
1417 /*
1418  * csio_mb_completions - Completion handler for Mailbox commands
1419  * @hw: The HW structure
1420  * @cbfn_q: Completion queue.
1421  *
1422  */
1423 void
1424 csio_mb_completions(struct csio_hw *hw, struct list_head *cbfn_q)
1425 {
1426         struct csio_mb *mbp;
1427         struct csio_mbm *mbm = &hw->mbm;
1428         enum fw_retval rv;
1429
1430         while (!list_empty(cbfn_q)) {
1431                 mbp = list_first_entry(cbfn_q, struct csio_mb, list);
1432                 list_del_init(&mbp->list);
1433
1434                 rv = csio_mb_fw_retval(mbp);
1435                 if ((rv != FW_SUCCESS) && (rv != FW_HOSTERROR))
1436                         CSIO_INC_STATS(mbm, n_err);
1437                 else if (rv != FW_HOSTERROR)
1438                         CSIO_INC_STATS(mbm, n_rsp);
1439
1440                 if (mbp->mb_cbfn)
1441                         mbp->mb_cbfn(hw, mbp);
1442         }
1443 }
1444
1445 static void
1446 csio_mb_portmod_changed(struct csio_hw *hw, uint8_t port_id)
1447 {
1448         static char *mod_str[] = {
1449                 NULL, "LR", "SR", "ER", "TWINAX", "active TWINAX", "LRM"
1450         };
1451
1452         struct csio_pport *port = &hw->pport[port_id];
1453
1454         if (port->mod_type == FW_PORT_MOD_TYPE_NONE)
1455                 csio_info(hw, "Port:%d - port module unplugged\n", port_id);
1456         else if (port->mod_type < ARRAY_SIZE(mod_str))
1457                 csio_info(hw, "Port:%d - %s port module inserted\n", port_id,
1458                           mod_str[port->mod_type]);
1459         else if (port->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED)
1460                 csio_info(hw,
1461                           "Port:%d - unsupported optical port module "
1462                           "inserted\n", port_id);
1463         else if (port->mod_type == FW_PORT_MOD_TYPE_UNKNOWN)
1464                 csio_info(hw,
1465                           "Port:%d - unknown port module inserted, forcing "
1466                           "TWINAX\n", port_id);
1467         else if (port->mod_type == FW_PORT_MOD_TYPE_ERROR)
1468                 csio_info(hw, "Port:%d - transceiver module error\n", port_id);
1469         else
1470                 csio_info(hw, "Port:%d - unknown module type %d inserted\n",
1471                           port_id, port->mod_type);
1472 }
1473
1474 int
1475 csio_mb_fwevt_handler(struct csio_hw *hw, __be64 *cmd)
1476 {
1477         uint8_t opcode = *(uint8_t *)cmd;
1478         struct fw_port_cmd *pcmd;
1479         uint8_t port_id;
1480         uint32_t link_status;
1481         uint16_t action;
1482         uint8_t mod_type;
1483
1484         if (opcode == FW_PORT_CMD) {
1485                 pcmd = (struct fw_port_cmd *)cmd;
1486                 port_id = FW_PORT_CMD_PORTID_GET(
1487                                 ntohl(pcmd->op_to_portid));
1488                 action = FW_PORT_CMD_ACTION_GET(
1489                                 ntohl(pcmd->action_to_len16));
1490                 if (action != FW_PORT_ACTION_GET_PORT_INFO) {
1491                         csio_err(hw, "Unhandled FW_PORT_CMD action: %u\n",
1492                                 action);
1493                         return -EINVAL;
1494                 }
1495
1496                 link_status = ntohl(pcmd->u.info.lstatus_to_modtype);
1497                 mod_type = FW_PORT_CMD_MODTYPE_GET(link_status);
1498
1499                 hw->pport[port_id].link_status =
1500                         FW_PORT_CMD_LSTATUS_GET(link_status);
1501                 hw->pport[port_id].link_speed =
1502                         FW_PORT_CMD_LSPEED_GET(link_status);
1503
1504                 csio_info(hw, "Port:%x - LINK %s\n", port_id,
1505                         FW_PORT_CMD_LSTATUS_GET(link_status) ? "UP" : "DOWN");
1506
1507                 if (mod_type != hw->pport[port_id].mod_type) {
1508                         hw->pport[port_id].mod_type = mod_type;
1509                         csio_mb_portmod_changed(hw, port_id);
1510                 }
1511         } else if (opcode == FW_DEBUG_CMD) {
1512                 csio_mb_dump_fw_dbg(hw, cmd);
1513         } else {
1514                 csio_dbg(hw, "Gen MB can't handle op:0x%x on evtq.\n", opcode);
1515                 return -EINVAL;
1516         }
1517
1518         return 0;
1519 }
1520
1521 /*
1522  * csio_mb_isr_handler - Handle mailboxes related interrupts.
1523  * @hw: The HW structure
1524  *
1525  * Called from the ISR to handle Mailbox related interrupts.
1526  * HW Lock should be held across this call.
1527  */
1528 int
1529 csio_mb_isr_handler(struct csio_hw *hw)
1530 {
1531         struct csio_mbm         *mbm = &hw->mbm;
1532         struct csio_mb          *mbp =  mbm->mcurrent;
1533         __be64                  *cmd;
1534         uint32_t                ctl, cim_cause, pl_cause;
1535         int                     i;
1536         uint32_t                ctl_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_CTRL);
1537         uint32_t                data_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_DATA);
1538         int                     size;
1539         __be64                  hdr;
1540         struct fw_cmd_hdr       *fw_hdr;
1541
1542         pl_cause = csio_rd_reg32(hw, MYPF_REG(PL_PF_INT_CAUSE));
1543         cim_cause = csio_rd_reg32(hw, MYPF_REG(CIM_PF_HOST_INT_CAUSE));
1544
1545         if (!(pl_cause & PFCIM) || !(cim_cause & MBMSGRDYINT)) {
1546                 CSIO_INC_STATS(hw, n_mbint_unexp);
1547                 return -EINVAL;
1548         }
1549
1550         /*
1551          * The cause registers below HAVE to be cleared in the SAME
1552          * order as below: The low level cause register followed by
1553          * the upper level cause register. In other words, CIM-cause
1554          * first followed by PL-Cause next.
1555          */
1556         csio_wr_reg32(hw, MBMSGRDYINT, MYPF_REG(CIM_PF_HOST_INT_CAUSE));
1557         csio_wr_reg32(hw, PFCIM, MYPF_REG(PL_PF_INT_CAUSE));
1558
1559         ctl = csio_rd_reg32(hw, ctl_reg);
1560
1561         if (csio_mb_is_host_owner(MBOWNER_GET(ctl))) {
1562
1563                 CSIO_DUMP_MB(hw, hw->pfn, data_reg);
1564
1565                 if (!(ctl & MBMSGVALID)) {
1566                         csio_warn(hw,
1567                                   "Stray mailbox interrupt recvd,"
1568                                   " mailbox data not valid\n");
1569                         csio_wr_reg32(hw, 0, ctl_reg);
1570                         /* Flush */
1571                         csio_rd_reg32(hw, ctl_reg);
1572                         return -EINVAL;
1573                 }
1574
1575                 hdr = cpu_to_be64(csio_rd_reg64(hw, data_reg));
1576                 fw_hdr = (struct fw_cmd_hdr *)&hdr;
1577
1578                 switch (FW_CMD_OP_GET(ntohl(fw_hdr->hi))) {
1579                 case FW_DEBUG_CMD:
1580                         csio_mb_debug_cmd_handler(hw);
1581                         return -EINVAL;
1582 #if 0
1583                 case FW_ERROR_CMD:
1584                 case FW_INITIALIZE_CMD: /* When we are not master */
1585 #endif
1586                 }
1587
1588                 CSIO_ASSERT(mbp != NULL);
1589
1590                 cmd = mbp->mb;
1591                 size = mbp->mb_size;
1592                 /* Get response */
1593                 for (i = 0; i < size; i += 8)
1594                         *cmd++ = cpu_to_be64(csio_rd_reg64
1595                                                   (hw, data_reg + i));
1596
1597                 csio_wr_reg32(hw, 0, ctl_reg);
1598                 /* Flush */
1599                 csio_rd_reg32(hw, ctl_reg);
1600
1601                 mbm->mcurrent = NULL;
1602
1603                 /* Add completion to tail of cbfn queue */
1604                 list_add_tail(&mbp->list, &mbm->cbfn_q);
1605                 CSIO_INC_STATS(mbm, n_cbfnq);
1606
1607                 /*
1608                  * Enqueue event to EventQ. Events processing happens
1609                  * in Event worker thread context
1610                  */
1611                 if (csio_enqueue_evt(hw, CSIO_EVT_MBX, mbp, sizeof(mbp)))
1612                         CSIO_INC_STATS(hw, n_evt_drop);
1613
1614                 return 0;
1615
1616         } else {
1617                 /*
1618                  * We can get here if mailbox MSIX vector is shared,
1619                  * or in INTx case. Or a stray interrupt.
1620                  */
1621                 csio_dbg(hw, "Host not owner, no mailbox interrupt\n");
1622                 CSIO_INC_STATS(hw, n_int_stray);
1623                 return -EINVAL;
1624         }
1625 }
1626
1627 /*
1628  * csio_mb_tmo_handler - Timeout handler
1629  * @hw: The HW structure
1630  *
1631  */
1632 struct csio_mb *
1633 csio_mb_tmo_handler(struct csio_hw *hw)
1634 {
1635         struct csio_mbm *mbm = &hw->mbm;
1636         struct csio_mb *mbp =  mbm->mcurrent;
1637         struct fw_cmd_hdr *fw_hdr;
1638
1639         /*
1640          * Could be a race b/w the completion handler and the timer
1641          * and the completion handler won that race.
1642          */
1643         if (mbp == NULL) {
1644                 CSIO_DB_ASSERT(0);
1645                 return NULL;
1646         }
1647
1648         fw_hdr = (struct fw_cmd_hdr *)(mbp->mb);
1649
1650         csio_dbg(hw, "Mailbox num:%x op:0x%x timed out\n", hw->pfn,
1651                     FW_CMD_OP_GET(ntohl(fw_hdr->hi)));
1652
1653         mbm->mcurrent = NULL;
1654         CSIO_INC_STATS(mbm, n_tmo);
1655         fw_hdr->lo = htonl(FW_CMD_RETVAL(FW_ETIMEDOUT));
1656
1657         return mbp;
1658 }
1659
1660 /*
1661  * csio_mb_cancel_all - Cancel all waiting commands.
1662  * @hw: The HW structure
1663  * @cbfn_q: The callback queue.
1664  *
1665  * Caller should hold hw lock across this call.
1666  */
1667 void
1668 csio_mb_cancel_all(struct csio_hw *hw, struct list_head *cbfn_q)
1669 {
1670         struct csio_mb *mbp;
1671         struct csio_mbm *mbm = &hw->mbm;
1672         struct fw_cmd_hdr *hdr;
1673         struct list_head *tmp;
1674
1675         if (mbm->mcurrent) {
1676                 mbp = mbm->mcurrent;
1677
1678                 /* Stop mailbox completion timer */
1679                 del_timer_sync(&mbm->timer);
1680
1681                 /* Add completion to tail of cbfn queue */
1682                 list_add_tail(&mbp->list, cbfn_q);
1683                 mbm->mcurrent = NULL;
1684         }
1685
1686         if (!list_empty(&mbm->req_q)) {
1687                 list_splice_tail_init(&mbm->req_q, cbfn_q);
1688                 mbm->stats.n_activeq = 0;
1689         }
1690
1691         if (!list_empty(&mbm->cbfn_q)) {
1692                 list_splice_tail_init(&mbm->cbfn_q, cbfn_q);
1693                 mbm->stats.n_cbfnq = 0;
1694         }
1695
1696         if (list_empty(cbfn_q))
1697                 return;
1698
1699         list_for_each(tmp, cbfn_q) {
1700                 mbp = (struct csio_mb *)tmp;
1701                 hdr = (struct fw_cmd_hdr *)(mbp->mb);
1702
1703                 csio_dbg(hw, "Cancelling pending mailbox num %x op:%x\n",
1704                             hw->pfn, FW_CMD_OP_GET(ntohl(hdr->hi)));
1705
1706                 CSIO_INC_STATS(mbm, n_cancel);
1707                 hdr->lo = htonl(FW_CMD_RETVAL(FW_HOSTERROR));
1708         }
1709 }
1710
1711 /*
1712  * csio_mbm_init - Initialize Mailbox module
1713  * @mbm: Mailbox module
1714  * @hw: The HW structure
1715  * @timer: Timing function for interrupting mailboxes
1716  *
1717  * Initialize timer and the request/response queues.
1718  */
1719 int
1720 csio_mbm_init(struct csio_mbm *mbm, struct csio_hw *hw,
1721               void (*timer_fn)(uintptr_t))
1722 {
1723         struct timer_list *timer = &mbm->timer;
1724
1725         init_timer(timer);
1726         timer->function = timer_fn;
1727         timer->data = (unsigned long)hw;
1728
1729         INIT_LIST_HEAD(&mbm->req_q);
1730         INIT_LIST_HEAD(&mbm->cbfn_q);
1731         csio_set_mb_intr_idx(mbm, -1);
1732
1733         return 0;
1734 }
1735
1736 /*
1737  * csio_mbm_exit - Uninitialize mailbox module
1738  * @mbm: Mailbox module
1739  *
1740  * Stop timer.
1741  */
1742 void
1743 csio_mbm_exit(struct csio_mbm *mbm)
1744 {
1745         del_timer_sync(&mbm->timer);
1746
1747         CSIO_DB_ASSERT(mbm->mcurrent == NULL);
1748         CSIO_DB_ASSERT(list_empty(&mbm->req_q));
1749         CSIO_DB_ASSERT(list_empty(&mbm->cbfn_q));
1750 }