[SCSI] fcoe: Out of order tx frames was causing several check condition SCSI status
[linux-2.6] / drivers / staging / benet / eth.c
1 /*
2  * Copyright (C) 2005 - 2008 ServerEngines
3  * All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License version 2
7  * as published by the Free Software Foundation.  The full GNU General
8  * Public License is included in this distribution in the file called COPYING.
9  *
10  * Contact Information:
11  * linux-drivers@serverengines.com
12  *
13  * ServerEngines
14  * 209 N. Fair Oaks Ave
15  * Sunnyvale, CA 94085
16  */
17 #include <linux/if_ether.h>
18 #include "hwlib.h"
19 #include "bestatus.h"
20
21 /*
22  *---------------------------------------------------------
23  * Function: be_eth_sq_create_ex
24  *   Creates an ethernet send ring - extended version with
25  *   additional parameters.
26  * pfob -
27  * rd             - ring address
28  * length_in_bytes -
29  * type            - The type of ring to create.
30  * ulp             - The requested ULP number for the ring.
31  *                   This should be zero based, i.e. 0,1,2. This must
32  *                   be valid NIC ULP based on the firmware config.
33  *                   All doorbells for this ring must be sent to
34  *                   this ULP. The first network ring allocated for
35  *                   each ULP are higher performance than subsequent rings.
36  * cq_object       - cq object for completions
37  * ex_parameters   - Additional parameters (that may increase in
38  *                   future revisions). These parameters are only used
39  *                   for certain ring types -- see
40  *                   struct be_eth_sq_parameters for details.
41  * eth_sq          -
42  * return status   - BE_SUCCESS (0) on success. Negative error code on failure.
43  *---------------------------------------------------------
44  */
45 int
46 be_eth_sq_create_ex(struct be_function_object *pfob, struct ring_desc *rd,
47                 u32 length, u32 type, u32 ulp, struct be_cq_object *cq_object,
48                 struct be_eth_sq_parameters *ex_parameters,
49                 struct be_ethsq_object *eth_sq)
50 {
51         struct FWCMD_COMMON_ETH_TX_CREATE *fwcmd = NULL;
52         struct MCC_WRB_AMAP *wrb = NULL;
53         int status = 0;
54         u32 n;
55         unsigned long irql;
56
57         ASSERT(rd);
58         ASSERT(eth_sq);
59         ASSERT(ex_parameters);
60
61         spin_lock_irqsave(&pfob->post_lock, irql);
62
63         memset(eth_sq, 0, sizeof(*eth_sq));
64
65         eth_sq->parent_function = pfob;
66         eth_sq->bid = 0xFFFFFFFF;
67         eth_sq->cq_object = cq_object;
68
69         /* Translate hwlib interface to arm interface. */
70         switch (type) {
71         case BE_ETH_TX_RING_TYPE_FORWARDING:
72                 type = ETH_TX_RING_TYPE_FORWARDING;
73                 break;
74         case BE_ETH_TX_RING_TYPE_STANDARD:
75                 type = ETH_TX_RING_TYPE_STANDARD;
76                 break;
77         case BE_ETH_TX_RING_TYPE_BOUND:
78                 ASSERT(ex_parameters->port < 2);
79                 type = ETH_TX_RING_TYPE_BOUND;
80                 break;
81         default:
82                 TRACE(DL_ERR, "Invalid eth tx ring type:%d", type);
83                 return BE_NOT_OK;
84                 break;
85         }
86
87         wrb = be_function_peek_mcc_wrb(pfob);
88         if (!wrb) {
89                 ASSERT(wrb);
90                 TRACE(DL_ERR, "No free MCC WRBs in create EQ.");
91                 status = BE_STATUS_NO_MCC_WRB;
92                 goto Error;
93         }
94         /* NIC must be supported by the current config. */
95         ASSERT(pfob->fw_config.nic_ulp_mask);
96
97         /*
98          * The ulp parameter must select a valid NIC ULP
99          * for the current config.
100          */
101         ASSERT((1 << ulp) & pfob->fw_config.nic_ulp_mask);
102
103         /* Prepares an embedded fwcmd, including request/response sizes. */
104         fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_ETH_TX_CREATE);
105         fwcmd->header.request.port_number = ex_parameters->port;
106
107         AMAP_SET_BITS_PTR(ETX_CONTEXT, pd_id,
108                                 &fwcmd->params.request.context, 0);
109
110         n = be_ring_length_to_encoding(length, sizeof(struct ETH_WRB_AMAP));
111         AMAP_SET_BITS_PTR(ETX_CONTEXT, tx_ring_size,
112                                         &fwcmd->params.request.context, n);
113
114         AMAP_SET_BITS_PTR(ETX_CONTEXT, cq_id_send,
115                         &fwcmd->params.request.context, cq_object->cq_id);
116
117         n = pfob->pci_function_number;
118         AMAP_SET_BITS_PTR(ETX_CONTEXT, func, &fwcmd->params.request.context, n);
119
120         fwcmd->params.request.type = type;
121         fwcmd->params.request.ulp_num  = (1 << ulp);
122         fwcmd->params.request.num_pages = DIV_ROUND_UP(length, PAGE_SIZE);
123         ASSERT(PAGES_SPANNED(rd->va, rd->length) >=
124                                 fwcmd->params.request.num_pages);
125
126         /* Create a page list for the FWCMD. */
127         be_rd_to_pa_list(rd, fwcmd->params.request.pages,
128                           ARRAY_SIZE(fwcmd->params.request.pages));
129
130         status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
131                                         NULL, NULL, fwcmd, NULL);
132         if (status != BE_SUCCESS) {
133                 TRACE(DL_ERR, "MCC to create etx queue failed.");
134                 goto Error;
135         }
136         /* save the butler ID */
137         eth_sq->bid = fwcmd->params.response.cid;
138
139         /* add a reference to the corresponding CQ */
140         atomic_inc(&cq_object->ref_count);
141
142 Error:
143         spin_unlock_irqrestore(&pfob->post_lock, irql);
144
145         if (pfob->pend_queue_driving && pfob->mcc) {
146                 pfob->pend_queue_driving = 0;
147                 be_drive_mcc_wrb_queue(pfob->mcc);
148         }
149         return status;
150 }
151
152
153 /*
154     This routine destroys an ethernet send queue
155
156     EthSq - EthSq Handle returned from EthSqCreate
157
158     This function always return BE_SUCCESS.
159
160     This function frees memory allocated by EthSqCreate for the EthSq Object.
161
162 */
163 int be_eth_sq_destroy(struct be_ethsq_object *eth_sq)
164 {
165         int status = 0;
166
167         /* Send fwcmd to destroy the queue. */
168         status = be_function_ring_destroy(eth_sq->parent_function, eth_sq->bid,
169                      FWCMD_RING_TYPE_ETH_TX, NULL, NULL, NULL, NULL);
170         ASSERT(status == 0);
171
172         /* Derefence any associated CQs. */
173         atomic_dec(&eth_sq->cq_object->ref_count);
174         return status;
175 }
176 /*
177     This routine attempts to set the transmit flow control parameters.
178
179     FunctionObject      - Handle to a function object
180
181     txfc_enable         - transmit flow control enable - true for
182                           enable, false for disable
183
184     rxfc_enable         - receive flow control enable - true for
185                                 enable, false for disable
186
187     Returns BE_SUCCESS if successfull, otherwise a useful int error
188     code is returned.
189
190     IRQL: < DISPATCH_LEVEL
191
192     This function always fails in non-privileged machine context.
193 */
194 int
195 be_eth_set_flow_control(struct be_function_object *pfob,
196                         bool txfc_enable, bool rxfc_enable)
197 {
198         struct FWCMD_COMMON_SET_FLOW_CONTROL *fwcmd = NULL;
199         struct MCC_WRB_AMAP *wrb = NULL;
200         int status = 0;
201         unsigned long irql;
202
203         spin_lock_irqsave(&pfob->post_lock, irql);
204
205         wrb = be_function_peek_mcc_wrb(pfob);
206         if (!wrb) {
207                 TRACE(DL_ERR, "MCC wrb peek failed.");
208                 status = BE_STATUS_NO_MCC_WRB;
209                 goto error;
210         }
211         /* Prepares an embedded fwcmd, including request/response sizes. */
212         fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_SET_FLOW_CONTROL);
213
214         fwcmd->params.request.rx_flow_control = rxfc_enable;
215         fwcmd->params.request.tx_flow_control = txfc_enable;
216
217         /* Post the f/w command */
218         status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
219                                         NULL, NULL, fwcmd, NULL);
220
221         if (status != 0) {
222                 TRACE(DL_ERR, "set flow control fwcmd failed.");
223                 goto error;
224         }
225
226 error:
227         spin_unlock_irqrestore(&pfob->post_lock, irql);
228
229         if (pfob->pend_queue_driving && pfob->mcc) {
230                 pfob->pend_queue_driving = 0;
231                 be_drive_mcc_wrb_queue(pfob->mcc);
232         }
233         return status;
234 }
235
236 /*
237     This routine attempts to get the transmit flow control parameters.
238
239     pfob      - Handle to a function object
240
241     txfc_enable         - transmit flow control enable - true for
242                         enable, false for disable
243
244     rxfc_enable         - receive flow control enable - true for enable,
245                         false for disable
246
247     Returns BE_SUCCESS if successfull, otherwise a useful int error code
248                         is returned.
249
250     IRQL: < DISPATCH_LEVEL
251
252     This function always fails in non-privileged machine context.
253 */
254 int
255 be_eth_get_flow_control(struct be_function_object *pfob,
256                         bool *txfc_enable, bool *rxfc_enable)
257 {
258         struct FWCMD_COMMON_GET_FLOW_CONTROL *fwcmd = NULL;
259         struct MCC_WRB_AMAP *wrb = NULL;
260         int status = 0;
261         unsigned long irql;
262
263         spin_lock_irqsave(&pfob->post_lock, irql);
264
265         wrb = be_function_peek_mcc_wrb(pfob);
266         if (!wrb) {
267                 TRACE(DL_ERR, "MCC wrb peek failed.");
268                 status = BE_STATUS_NO_MCC_WRB;
269                 goto error;
270         }
271         /* Prepares an embedded fwcmd, including request/response sizes. */
272         fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_GET_FLOW_CONTROL);
273
274         /* Post the f/w command */
275         status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
276                                                 NULL, NULL, fwcmd, NULL);
277
278         if (status != 0) {
279                 TRACE(DL_ERR, "get flow control fwcmd failed.");
280                 goto error;
281         }
282
283         *txfc_enable = fwcmd->params.response.tx_flow_control;
284         *rxfc_enable = fwcmd->params.response.rx_flow_control;
285
286 error:
287         spin_unlock_irqrestore(&pfob->post_lock, irql);
288
289         if (pfob->pend_queue_driving && pfob->mcc) {
290                 pfob->pend_queue_driving = 0;
291                 be_drive_mcc_wrb_queue(pfob->mcc);
292         }
293         return status;
294 }
295
296 /*
297  *---------------------------------------------------------
298  * Function: be_eth_set_qos
299  *   This function sets the ethernet transmit Quality of Service (QoS)
300  *   characteristics of BladeEngine for the domain. All ethernet
301  *   transmit rings of the domain will evenly share the bandwidth.
302  *   The exeception to sharing is the host primary (super) ethernet
303  *   transmit ring as well as the host ethernet forwarding ring
304  *   for missed offload data.
305  * pfob -
306  * max_bps         - the maximum bits per second in units of
307  *                      10 Mbps (valid 0-100)
308  * max_pps         - the maximum packets per second in units
309  *                      of 1 Kpps (0 indicates no limit)
310  * return status   - BE_SUCCESS (0) on success. Negative error code on failure.
311  *---------------------------------------------------------
312  */
313 int
314 be_eth_set_qos(struct be_function_object *pfob, u32 max_bps, u32 max_pps)
315 {
316         struct FWCMD_COMMON_SET_QOS *fwcmd = NULL;
317         struct MCC_WRB_AMAP *wrb = NULL;
318         int status = 0;
319         unsigned long irql;
320
321         spin_lock_irqsave(&pfob->post_lock, irql);
322
323         wrb = be_function_peek_mcc_wrb(pfob);
324         if (!wrb) {
325                 TRACE(DL_ERR, "MCC wrb peek failed.");
326                 status = BE_STATUS_NO_MCC_WRB;
327                 goto error;
328         }
329         /* Prepares an embedded fwcmd, including request/response sizes. */
330         fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_SET_QOS);
331
332         /* Set fields in fwcmd */
333         fwcmd->params.request.max_bits_per_second_NIC = max_bps;
334         fwcmd->params.request.max_packets_per_second_NIC = max_pps;
335         fwcmd->params.request.valid_flags = QOS_BITS_NIC | QOS_PKTS_NIC;
336
337         /* Post the f/w command */
338         status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
339                                         NULL, NULL, fwcmd, NULL);
340
341         if (status != 0)
342                 TRACE(DL_ERR, "network set qos fwcmd failed.");
343
344 error:
345         spin_unlock_irqrestore(&pfob->post_lock, irql);
346         if (pfob->pend_queue_driving && pfob->mcc) {
347                 pfob->pend_queue_driving = 0;
348                 be_drive_mcc_wrb_queue(pfob->mcc);
349         }
350         return status;
351 }
352
353 /*
354  *---------------------------------------------------------
355  * Function: be_eth_get_qos
356  *   This function retrieves the ethernet transmit Quality of Service (QoS)
357  *   characteristics for the domain.
358  * max_bps         - the maximum bits per second in units of
359  *                      10 Mbps (valid 0-100)
360  * max_pps         - the maximum packets per second in units of
361  *                      1 Kpps (0 indicates no limit)
362  * return status   - BE_SUCCESS (0) on success. Negative error code on failure.
363  *---------------------------------------------------------
364  */
365 int
366 be_eth_get_qos(struct be_function_object *pfob, u32 *max_bps, u32 *max_pps)
367 {
368         struct FWCMD_COMMON_GET_QOS *fwcmd = NULL;
369         struct MCC_WRB_AMAP *wrb = NULL;
370         int status = 0;
371         unsigned long irql;
372
373         spin_lock_irqsave(&pfob->post_lock, irql);
374
375         wrb = be_function_peek_mcc_wrb(pfob);
376         if (!wrb) {
377                 TRACE(DL_ERR, "MCC wrb peek failed.");
378                 status = BE_STATUS_NO_MCC_WRB;
379                 goto error;
380         }
381         /* Prepares an embedded fwcmd, including request/response sizes. */
382         fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_GET_QOS);
383
384         /* Post the f/w command */
385         status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
386                                         NULL, NULL, fwcmd, NULL);
387
388         if (status != 0) {
389                 TRACE(DL_ERR, "network get qos fwcmd failed.");
390                 goto error;
391         }
392
393         *max_bps = fwcmd->params.response.max_bits_per_second_NIC;
394         *max_pps = fwcmd->params.response.max_packets_per_second_NIC;
395
396 error:
397         spin_unlock_irqrestore(&pfob->post_lock, irql);
398         if (pfob->pend_queue_driving && pfob->mcc) {
399                 pfob->pend_queue_driving = 0;
400                 be_drive_mcc_wrb_queue(pfob->mcc);
401         }
402         return status;
403 }
404
405 /*
406  *---------------------------------------------------------
407  * Function: be_eth_set_frame_size
408  *   This function sets the ethernet maximum frame size. The previous
409  *   values are returned.
410  * pfob -
411  * tx_frame_size   - maximum transmit frame size in bytes
412  * rx_frame_size   - maximum receive frame size in bytes
413  * return status   - BE_SUCCESS (0) on success. Negative error code on failure.
414  *---------------------------------------------------------
415  */
416 int
417 be_eth_set_frame_size(struct be_function_object *pfob,
418                       u32 *tx_frame_size, u32 *rx_frame_size)
419 {
420         struct FWCMD_COMMON_SET_FRAME_SIZE *fwcmd = NULL;
421         struct MCC_WRB_AMAP *wrb = NULL;
422         int status = 0;
423         unsigned long irql;
424
425         spin_lock_irqsave(&pfob->post_lock, irql);
426
427         wrb = be_function_peek_mcc_wrb(pfob);
428         if (!wrb) {
429                 TRACE(DL_ERR, "MCC wrb peek failed.");
430                 status = BE_STATUS_NO_MCC_WRB;
431                 goto error;
432         }
433         /* Prepares an embedded fwcmd, including request/response sizes. */
434         fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_SET_FRAME_SIZE);
435         fwcmd->params.request.max_tx_frame_size = *tx_frame_size;
436         fwcmd->params.request.max_rx_frame_size = *rx_frame_size;
437
438         /* Post the f/w command */
439         status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
440                                                 NULL, NULL, fwcmd, NULL);
441
442         if (status != 0) {
443                 TRACE(DL_ERR, "network set frame size fwcmd failed.");
444                 goto error;
445         }
446
447         *tx_frame_size = fwcmd->params.response.chip_max_tx_frame_size;
448         *rx_frame_size = fwcmd->params.response.chip_max_rx_frame_size;
449
450 error:
451         spin_unlock_irqrestore(&pfob->post_lock, irql);
452         if (pfob->pend_queue_driving && pfob->mcc) {
453                 pfob->pend_queue_driving = 0;
454                 be_drive_mcc_wrb_queue(pfob->mcc);
455         }
456         return status;
457 }
458
459
460 /*
461     This routine creates a Ethernet receive ring.
462
463     pfob      - handle to a function object
464     rq_base_va            - base VA for the default receive ring. this must be
465                         exactly 8K in length and continguous physical memory.
466     cq_object            - handle to a previously created CQ to be associated
467                         with the RQ.
468     pp_eth_rq             - pointer to an opqaue handle where an eth
469                         receive object is returned.
470     Returns BE_SUCCESS if successfull, , otherwise a useful
471     int error code is returned.
472
473     IRQL: < DISPATCH_LEVEL
474     this function allocates a struct be_ethrq_object *object.
475     there must be no more than 1 of these per function object, unless the
476     function object supports RSS (is networking and on the host).
477     the rq_base_va must point to a buffer of exactly 8K.
478     the erx::host_cqid (or host_stor_cqid) register and erx::ring_page registers
479     will be updated as appropriate on return
480 */
481 int
482 be_eth_rq_create(struct be_function_object *pfob,
483                         struct ring_desc *rd, struct be_cq_object *cq_object,
484                         struct be_cq_object *bcmc_cq_object,
485                         struct be_ethrq_object *eth_rq)
486 {
487         int status = 0;
488         struct MCC_WRB_AMAP *wrb = NULL;
489         struct FWCMD_COMMON_ETH_RX_CREATE *fwcmd = NULL;
490         unsigned long irql;
491
492         /* MPU will set the  */
493         ASSERT(rd);
494         ASSERT(eth_rq);
495
496         spin_lock_irqsave(&pfob->post_lock, irql);
497
498         eth_rq->parent_function = pfob;
499         eth_rq->cq_object = cq_object;
500
501         wrb = be_function_peek_mcc_wrb(pfob);
502         if (!wrb) {
503                 TRACE(DL_ERR, "MCC wrb peek failed.");
504                 status = BE_STATUS_NO_MCC_WRB;
505                 goto Error;
506         }
507         /* Prepares an embedded fwcmd, including request/response sizes. */
508         fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_ETH_RX_CREATE);
509
510         fwcmd->params.request.num_pages = 2;    /* required length */
511         fwcmd->params.request.cq_id = cq_object->cq_id;
512
513         if (bcmc_cq_object)
514                 fwcmd->params.request.bcmc_cq_id = bcmc_cq_object->cq_id;
515         else
516                 fwcmd->params.request.bcmc_cq_id = 0xFFFF;
517
518         /* Create a page list for the FWCMD. */
519         be_rd_to_pa_list(rd, fwcmd->params.request.pages,
520                           ARRAY_SIZE(fwcmd->params.request.pages));
521
522         /* Post the f/w command */
523         status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
524                                                 NULL, NULL, fwcmd, NULL);
525         if (status != BE_SUCCESS) {
526                 TRACE(DL_ERR, "fwcmd to map eth rxq frags failed.");
527                 goto Error;
528         }
529         /* Save the ring ID for cleanup. */
530         eth_rq->rid = fwcmd->params.response.id;
531
532         atomic_inc(&cq_object->ref_count);
533
534 Error:
535         spin_unlock_irqrestore(&pfob->post_lock, irql);
536
537         if (pfob->pend_queue_driving && pfob->mcc) {
538                 pfob->pend_queue_driving = 0;
539                 be_drive_mcc_wrb_queue(pfob->mcc);
540         }
541         return status;
542 }
543
544 /*
545     This routine destroys an Ethernet receive queue
546
547     eth_rq - ethernet receive queue handle returned from eth_rq_create
548
549     Returns BE_SUCCESS on success and an appropriate int on failure.
550
551     This function frees resourcs allocated by EthRqCreate.
552     The erx::host_cqid (or host_stor_cqid) register and erx::ring_page
553     registers will be updated as appropriate on return
554     IRQL: < DISPATCH_LEVEL
555 */
556
557 static void be_eth_rq_destroy_internal_cb(void *context, int status,
558                                          struct MCC_WRB_AMAP *wrb)
559 {
560         struct be_ethrq_object *eth_rq = (struct be_ethrq_object *) context;
561
562         if (status != BE_SUCCESS) {
563                 TRACE(DL_ERR, "Destroy eth rq failed in internal callback.\n");
564         } else {
565                 /* Dereference any CQs associated with this queue. */
566                 atomic_dec(&eth_rq->cq_object->ref_count);
567         }
568
569         return;
570 }
571
572 int be_eth_rq_destroy(struct be_ethrq_object *eth_rq)
573 {
574         int status = BE_SUCCESS;
575
576         /* Send fwcmd to destroy the RQ. */
577         status = be_function_ring_destroy(eth_rq->parent_function,
578                         eth_rq->rid, FWCMD_RING_TYPE_ETH_RX, NULL, NULL,
579                         be_eth_rq_destroy_internal_cb, eth_rq);
580
581         return status;
582 }
583
584 /*
585  *---------------------------------------------------------------------------
586  * Function: be_eth_rq_destroy_options
587  *   Destroys an ethernet receive ring with finer granularity options
588  *   than the standard be_eth_rq_destroy() API function.
589  * eth_rq           -
590  * flush            - Set to 1 to flush the ring, set to 0 to bypass the flush
591  * cb               - Callback function on completion
592  * cb_context       - Callback context
593  * return status    - BE_SUCCESS (0) on success. Negative error code on failure.
594  *----------------------------------------------------------------------------
595  */
596 int
597 be_eth_rq_destroy_options(struct be_ethrq_object *eth_rq, bool flush,
598                 mcc_wrb_cqe_callback cb, void *cb_context)
599 {
600         struct FWCMD_COMMON_RING_DESTROY *fwcmd = NULL;
601         struct MCC_WRB_AMAP *wrb = NULL;
602         int status = BE_SUCCESS;
603         struct be_function_object *pfob = NULL;
604         unsigned long irql;
605
606         pfob = eth_rq->parent_function;
607
608         spin_lock_irqsave(&pfob->post_lock, irql);
609
610         TRACE(DL_INFO, "Destroy eth_rq ring id:%d, flush:%d", eth_rq->rid,
611               flush);
612
613         wrb = be_function_peek_mcc_wrb(pfob);
614         if (!wrb) {
615                 ASSERT(wrb);
616                 TRACE(DL_ERR, "No free MCC WRBs in destroy eth_rq ring.");
617                 status = BE_STATUS_NO_MCC_WRB;
618                 goto Error;
619         }
620         /* Prepares an embedded fwcmd, including request/response sizes. */
621         fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_RING_DESTROY);
622
623         fwcmd->params.request.id = eth_rq->rid;
624         fwcmd->params.request.ring_type = FWCMD_RING_TYPE_ETH_RX;
625         fwcmd->params.request.bypass_flush = ((0 == flush) ? 1 : 0);
626
627         /* Post the f/w command */
628         status = be_function_post_mcc_wrb(pfob, wrb, NULL, cb, cb_context,
629                         be_eth_rq_destroy_internal_cb, eth_rq, fwcmd, NULL);
630
631         if (status != BE_SUCCESS && status != BE_PENDING) {
632                 TRACE(DL_ERR, "eth_rq ring destroy failed. id:%d, flush:%d",
633                       eth_rq->rid, flush);
634                 goto Error;
635         }
636
637 Error:
638         spin_unlock_irqrestore(&pfob->post_lock, irql);
639
640         if (pfob->pend_queue_driving && pfob->mcc) {
641                 pfob->pend_queue_driving = 0;
642                 be_drive_mcc_wrb_queue(pfob->mcc);
643         }
644         return status;
645 }
646
647 /*
648     This routine queries the frag size for erx.
649
650     pfob      - handle to a function object
651
652     frag_size_bytes       - erx frag size in bytes that is/was set.
653
654     Returns BE_SUCCESS if successfull, otherwise a useful int error
655     code is returned.
656
657     IRQL: < DISPATCH_LEVEL
658
659 */
660 int
661 be_eth_rq_get_frag_size(struct be_function_object *pfob, u32 *frag_size_bytes)
662 {
663         struct FWCMD_ETH_GET_RX_FRAG_SIZE *fwcmd = NULL;
664         struct MCC_WRB_AMAP *wrb = NULL;
665         int status = 0;
666         unsigned long irql;
667
668         ASSERT(frag_size_bytes);
669
670         spin_lock_irqsave(&pfob->post_lock, irql);
671
672         wrb = be_function_peek_mcc_wrb(pfob);
673         if (!wrb) {
674                 TRACE(DL_ERR, "MCC wrb peek failed.");
675                 return BE_STATUS_NO_MCC_WRB;
676         }
677         /* Prepares an embedded fwcmd, including request/response sizes. */
678         fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, ETH_GET_RX_FRAG_SIZE);
679
680         /* Post the f/w command */
681         status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
682                                 NULL, NULL, fwcmd, NULL);
683
684         if (status != 0) {
685                 TRACE(DL_ERR, "get frag size fwcmd failed.");
686                 goto error;
687         }
688
689         *frag_size_bytes = 1 << fwcmd->params.response.actual_fragsize_log2;
690
691 error:
692         spin_unlock_irqrestore(&pfob->post_lock, irql);
693
694         if (pfob->pend_queue_driving && pfob->mcc) {
695                 pfob->pend_queue_driving = 0;
696                 be_drive_mcc_wrb_queue(pfob->mcc);
697         }
698         return status;
699 }
700
701 /*
702     This routine attempts to set the frag size for erx.  If the frag size is
703     already set, the attempt fails and the current frag size is returned.
704
705     pfob      - Handle to a function object
706
707     frag_size       - Erx frag size in bytes that is/was set.
708
709     current_frag_size_bytes    - Pointer to location where currrent frag
710                                  is to be rturned
711
712     Returns BE_SUCCESS if successfull, otherwise a useful int error
713     code is returned.
714
715     IRQL: < DISPATCH_LEVEL
716
717     This function always fails in non-privileged machine context.
718 */
719 int
720 be_eth_rq_set_frag_size(struct be_function_object *pfob,
721                         u32 frag_size, u32 *frag_size_bytes)
722 {
723         struct FWCMD_ETH_SET_RX_FRAG_SIZE *fwcmd = NULL;
724         struct MCC_WRB_AMAP *wrb = NULL;
725         int status = 0;
726         unsigned long irql;
727
728         ASSERT(frag_size_bytes);
729
730         spin_lock_irqsave(&pfob->post_lock, irql);
731
732         wrb = be_function_peek_mcc_wrb(pfob);
733         if (!wrb) {
734                 TRACE(DL_ERR, "MCC wrb peek failed.");
735                 status = BE_STATUS_NO_MCC_WRB;
736                 goto error;
737         }
738         /* Prepares an embedded fwcmd, including request/response sizes. */
739         fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, ETH_SET_RX_FRAG_SIZE);
740
741         ASSERT(frag_size >= 128 && frag_size <= 16 * 1024);
742
743         /* This is the log2 of the fragsize.  This is not the exact
744          * ERX encoding. */
745         fwcmd->params.request.new_fragsize_log2 = __ilog2_u32(frag_size);
746
747         /* Post the f/w command */
748         status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
749                                 NULL, NULL, fwcmd, NULL);
750
751         if (status != 0) {
752                 TRACE(DL_ERR, "set frag size fwcmd failed.");
753                 goto error;
754         }
755
756         *frag_size_bytes = 1 << fwcmd->params.response.actual_fragsize_log2;
757 error:
758         spin_unlock_irqrestore(&pfob->post_lock, irql);
759
760         if (pfob->pend_queue_driving && pfob->mcc) {
761                 pfob->pend_queue_driving = 0;
762                 be_drive_mcc_wrb_queue(pfob->mcc);
763         }
764         return status;
765 }
766
767
768 /*
769     This routine gets or sets a mac address for a domain
770     given the port and mac.
771
772     FunctionObject  - Function object handle.
773     port1           - Set to TRUE if this function will set/get the Port 1
774                         address.  Only the host may set this to TRUE.
775     mac1            - Set to TRUE if this function will set/get the
776                         MAC 1 address.  Only the host may set this to TRUE.
777     write           - Set to TRUE if this function should write the mac address.
778     mac_address      - Buffer of the mac address to read or write.
779
780     Returns BE_SUCCESS if successfull, otherwise a useful int is returned.
781
782     IRQL: < DISPATCH_LEVEL
783 */
784 int be_rxf_mac_address_read_write(struct be_function_object *pfob,
785                 bool port1,     /* VM must always set to false */
786                 bool mac1,      /* VM must always set to false */
787                 bool mgmt, bool write,
788                 bool permanent, u8 *mac_address,
789                 mcc_wrb_cqe_callback cb,        /* optional */
790                 void *cb_context)       /* optional */
791 {
792         int status = BE_SUCCESS;
793         union {
794                 struct FWCMD_COMMON_NTWK_MAC_QUERY *query;
795                 struct FWCMD_COMMON_NTWK_MAC_SET *set;
796         } fwcmd = {NULL};
797         struct MCC_WRB_AMAP *wrb = NULL;
798         u32 type = 0;
799         unsigned long irql;
800         struct be_mcc_wrb_response_copy rc;
801
802         spin_lock_irqsave(&pfob->post_lock, irql);
803
804         ASSERT(mac_address);
805
806         ASSERT(port1 == false);
807         ASSERT(mac1 == false);
808
809         wrb = be_function_peek_mcc_wrb(pfob);
810         if (!wrb) {
811                 TRACE(DL_ERR, "MCC wrb peek failed.");
812                 status = BE_STATUS_NO_MCC_WRB;
813                 goto Error;
814         }
815
816         if (mgmt) {
817                 type = MAC_ADDRESS_TYPE_MANAGEMENT;
818         } else {
819                 if (pfob->type == BE_FUNCTION_TYPE_NETWORK)
820                         type = MAC_ADDRESS_TYPE_NETWORK;
821                 else
822                         type = MAC_ADDRESS_TYPE_STORAGE;
823         }
824
825         if (write) {
826                 /* Prepares an embedded fwcmd, including
827                  * request/response sizes.
828                  */
829                 fwcmd.set = BE_PREPARE_EMBEDDED_FWCMD(pfob,
830                                                wrb, COMMON_NTWK_MAC_SET);
831
832                 fwcmd.set->params.request.invalidate = 0;
833                 fwcmd.set->params.request.mac1 = (mac1 ? 1 : 0);
834                 fwcmd.set->params.request.port = (port1 ? 1 : 0);
835                 fwcmd.set->params.request.type = type;
836
837                 /* Copy the mac address to set. */
838                 fwcmd.set->params.request.mac.SizeOfStructure =
839                             sizeof(fwcmd.set->params.request.mac);
840                 memcpy(fwcmd.set->params.request.mac.MACAddress,
841                         mac_address, ETH_ALEN);
842
843                 /* Post the f/w command */
844                 status = be_function_post_mcc_wrb(pfob, wrb, NULL,
845                                 cb, cb_context, NULL, NULL, fwcmd.set, NULL);
846
847         } else {
848
849                 /*
850                  * Prepares an embedded fwcmd, including
851                  * request/response sizes.
852                  */
853                 fwcmd.query = BE_PREPARE_EMBEDDED_FWCMD(pfob,
854                                                wrb, COMMON_NTWK_MAC_QUERY);
855
856                 fwcmd.query->params.request.mac1 = (mac1 ? 1 : 0);
857                 fwcmd.query->params.request.port = (port1 ? 1 : 0);
858                 fwcmd.query->params.request.type = type;
859                 fwcmd.query->params.request.permanent = permanent;
860
861                 rc.length = FIELD_SIZEOF(struct FWCMD_COMMON_NTWK_MAC_QUERY,
862                                                 params.response.mac.MACAddress);
863                 rc.fwcmd_offset = offsetof(struct FWCMD_COMMON_NTWK_MAC_QUERY,
864                                                 params.response.mac.MACAddress);
865                 rc.va = mac_address;
866                 /* Post the f/w command (with a copy for the response) */
867                 status = be_function_post_mcc_wrb(pfob, wrb, NULL, cb,
868                                 cb_context, NULL, NULL, fwcmd.query, &rc);
869         }
870
871         if (status < 0) {
872                 TRACE(DL_ERR, "mac set/query failed.");
873                 goto Error;
874         }
875
876 Error:
877         spin_unlock_irqrestore(&pfob->post_lock, irql);
878         if (pfob->pend_queue_driving && pfob->mcc) {
879                 pfob->pend_queue_driving = 0;
880                 be_drive_mcc_wrb_queue(pfob->mcc);
881         }
882         return status;
883 }
884
885 /*
886     This routine writes data to context memory.
887
888     pfob  - Function object handle.
889     mac_table     - Set to the 128-bit multicast address hash table.
890
891     Returns BE_SUCCESS if successfull, otherwise a useful int is returned.
892
893     IRQL: < DISPATCH_LEVEL
894 */
895
896 int be_rxf_multicast_config(struct be_function_object *pfob,
897                 bool promiscuous, u32 num, u8 *mac_table,
898                 mcc_wrb_cqe_callback cb,        /* optional */
899                 void *cb_context,
900                 struct be_multicast_q_ctxt *q_ctxt)
901 {
902         int status = BE_SUCCESS;
903         struct FWCMD_COMMON_NTWK_MULTICAST_SET *fwcmd = NULL;
904         struct MCC_WRB_AMAP *wrb = NULL;
905         struct be_generic_q_ctxt *generic_ctxt = NULL;
906         unsigned long irql;
907
908         ASSERT(num <= ARRAY_SIZE(fwcmd->params.request.mac));
909
910         if (num > ARRAY_SIZE(fwcmd->params.request.mac)) {
911                 TRACE(DL_ERR, "Too many multicast addresses. BE supports %d.",
912                       (int) ARRAY_SIZE(fwcmd->params.request.mac));
913                 return BE_NOT_OK;
914         }
915
916         spin_lock_irqsave(&pfob->post_lock, irql);
917
918         wrb = be_function_peek_mcc_wrb(pfob);
919         if (!wrb) {
920                 if (q_ctxt && cb) {
921                         wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header;
922                         generic_ctxt = (struct be_generic_q_ctxt *) q_ctxt;
923                         generic_ctxt->context.bytes = sizeof(*q_ctxt);
924                 } else {
925                         status = BE_STATUS_NO_MCC_WRB;
926                         goto Error;
927                 }
928         }
929         /* Prepares an embedded fwcmd, including request/response sizes. */
930         fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_NTWK_MULTICAST_SET);
931
932         fwcmd->params.request.promiscuous = promiscuous;
933         if (!promiscuous) {
934                 fwcmd->params.request.num_mac = num;
935                 if (num > 0) {
936                         ASSERT(mac_table);
937                         memcpy(fwcmd->params.request.mac,
938                                                 mac_table, ETH_ALEN * num);
939                 }
940         }
941
942         /* Post the f/w command */
943         status = be_function_post_mcc_wrb(pfob, wrb, generic_ctxt,
944                         cb, cb_context, NULL, NULL, fwcmd, NULL);
945         if (status < 0) {
946                 TRACE(DL_ERR, "multicast fwcmd failed.");
947                 goto Error;
948         }
949
950 Error:
951         spin_unlock_irqrestore(&pfob->post_lock, irql);
952         if (pfob->pend_queue_driving && pfob->mcc) {
953                 pfob->pend_queue_driving = 0;
954                 be_drive_mcc_wrb_queue(pfob->mcc);
955         }
956         return status;
957 }
958
959 /*
960     This routine adds or removes a vlan tag from the rxf table.
961
962     FunctionObject  - Function object handle.
963     VLanTag         - VLan tag to add or remove.
964     Add             - Set to TRUE if this will add a vlan tag
965
966     Returns BE_SUCCESS if successfull, otherwise a useful int is returned.
967
968     IRQL: < DISPATCH_LEVEL
969 */
970 int be_rxf_vlan_config(struct be_function_object *pfob,
971                 bool promiscuous, u32 num, u16 *vlan_tag_array,
972                 mcc_wrb_cqe_callback cb,        /* optional */
973                 void *cb_context,
974                 struct be_vlan_q_ctxt *q_ctxt)  /* optional */
975 {
976         int status = BE_SUCCESS;
977         struct FWCMD_COMMON_NTWK_VLAN_CONFIG *fwcmd = NULL;
978         struct MCC_WRB_AMAP *wrb = NULL;
979         struct be_generic_q_ctxt *generic_ctxt = NULL;
980         unsigned long irql;
981
982         if (num > ARRAY_SIZE(fwcmd->params.request.vlan_tag)) {
983                 TRACE(DL_ERR, "Too many VLAN tags.");
984                 return BE_NOT_OK;
985         }
986
987         spin_lock_irqsave(&pfob->post_lock, irql);
988
989         wrb = be_function_peek_mcc_wrb(pfob);
990         if (!wrb) {
991                 if (q_ctxt && cb) {
992                         wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header;
993                         generic_ctxt = (struct be_generic_q_ctxt *) q_ctxt;
994                         generic_ctxt->context.bytes = sizeof(*q_ctxt);
995                 } else {
996                         status = BE_STATUS_NO_MCC_WRB;
997                         goto Error;
998                 }
999         }
1000         /* Prepares an embedded fwcmd, including request/response sizes. */
1001         fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_NTWK_VLAN_CONFIG);
1002
1003         fwcmd->params.request.promiscuous = promiscuous;
1004         if (!promiscuous) {
1005                 fwcmd->params.request.num_vlan = num;
1006
1007                 if (num > 0) {
1008                         ASSERT(vlan_tag_array);
1009                         memcpy(fwcmd->params.request.vlan_tag, vlan_tag_array,
1010                                   num * sizeof(vlan_tag_array[0]));
1011                 }
1012         }
1013
1014         /* Post the commadn */
1015         status = be_function_post_mcc_wrb(pfob, wrb, generic_ctxt,
1016                         cb, cb_context, NULL, NULL, fwcmd, NULL);
1017         if (status < 0) {
1018                 TRACE(DL_ERR, "vlan fwcmd failed.");
1019                 goto Error;
1020         }
1021
1022 Error:
1023         spin_unlock_irqrestore(&pfob->post_lock, irql);
1024         if (pfob->pend_queue_driving && pfob->mcc) {
1025                 pfob->pend_queue_driving = 0;
1026                 be_drive_mcc_wrb_queue(pfob->mcc);
1027         }
1028         return status;
1029 }
1030
1031
1032 int be_rxf_link_status(struct be_function_object *pfob,
1033                 struct BE_LINK_STATUS *link_status,
1034                 mcc_wrb_cqe_callback cb,
1035                 void *cb_context,
1036                 struct be_link_status_q_ctxt *q_ctxt)
1037 {
1038         struct FWCMD_COMMON_NTWK_LINK_STATUS_QUERY *fwcmd = NULL;
1039         struct MCC_WRB_AMAP *wrb = NULL;
1040         int status = 0;
1041         struct be_generic_q_ctxt *generic_ctxt = NULL;
1042         unsigned long irql;
1043         struct be_mcc_wrb_response_copy rc;
1044
1045         ASSERT(link_status);
1046
1047         spin_lock_irqsave(&pfob->post_lock, irql);
1048
1049         wrb = be_function_peek_mcc_wrb(pfob);
1050
1051         if (!wrb) {
1052                 if (q_ctxt && cb) {
1053                         wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header;
1054                         generic_ctxt = (struct be_generic_q_ctxt *) q_ctxt;
1055                         generic_ctxt->context.bytes = sizeof(*q_ctxt);
1056                 } else {
1057                         status = BE_STATUS_NO_MCC_WRB;
1058                         goto Error;
1059                 }
1060         }
1061         /* Prepares an embedded fwcmd, including request/response sizes. */
1062         fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb,
1063                                                COMMON_NTWK_LINK_STATUS_QUERY);
1064
1065         rc.length = FIELD_SIZEOF(struct FWCMD_COMMON_NTWK_LINK_STATUS_QUERY,
1066                                         params.response);
1067         rc.fwcmd_offset = offsetof(struct FWCMD_COMMON_NTWK_LINK_STATUS_QUERY,
1068                                         params.response);
1069         rc.va = link_status;
1070         /* Post or queue the f/w command */
1071         status = be_function_post_mcc_wrb(pfob, wrb, generic_ctxt,
1072                         cb, cb_context, NULL, NULL, fwcmd, &rc);
1073
1074         if (status < 0) {
1075                 TRACE(DL_ERR, "link status fwcmd failed.");
1076                 goto Error;
1077         }
1078
1079 Error:
1080         spin_unlock_irqrestore(&pfob->post_lock, irql);
1081         if (pfob->pend_queue_driving && pfob->mcc) {
1082                 pfob->pend_queue_driving = 0;
1083                 be_drive_mcc_wrb_queue(pfob->mcc);
1084         }
1085         return status;
1086 }
1087
1088 int
1089 be_rxf_query_eth_statistics(struct be_function_object *pfob,
1090                     struct FWCMD_ETH_GET_STATISTICS *va_for_fwcmd,
1091                     u64 pa_for_fwcmd, mcc_wrb_cqe_callback cb,
1092                     void *cb_context,
1093                     struct be_nonembedded_q_ctxt *q_ctxt)
1094 {
1095         struct MCC_WRB_AMAP *wrb = NULL;
1096         int status = 0;
1097         struct be_generic_q_ctxt *generic_ctxt = NULL;
1098         unsigned long irql;
1099
1100         ASSERT(va_for_fwcmd);
1101         ASSERT(pa_for_fwcmd);
1102
1103         spin_lock_irqsave(&pfob->post_lock, irql);
1104
1105         wrb = be_function_peek_mcc_wrb(pfob);
1106
1107         if (!wrb) {
1108                 if (q_ctxt && cb) {
1109                         wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header;
1110                         generic_ctxt = (struct be_generic_q_ctxt *) q_ctxt;
1111                         generic_ctxt->context.bytes = sizeof(*q_ctxt);
1112                 } else {
1113                         status = BE_STATUS_NO_MCC_WRB;
1114                         goto Error;
1115                 }
1116         }
1117
1118         TRACE(DL_INFO, "Query eth stats. fwcmd va:%p pa:0x%08x_%08x",
1119               va_for_fwcmd, upper_32_bits(pa_for_fwcmd), (u32)pa_for_fwcmd);
1120
1121         /* Prepares an embedded fwcmd, including request/response sizes. */
1122         va_for_fwcmd = BE_PREPARE_NONEMBEDDED_FWCMD(pfob, wrb,
1123                           va_for_fwcmd, pa_for_fwcmd, ETH_GET_STATISTICS);
1124
1125         /* Post the f/w command */
1126         status = be_function_post_mcc_wrb(pfob, wrb, generic_ctxt,
1127                 cb, cb_context, NULL, NULL, va_for_fwcmd, NULL);
1128         if (status < 0) {
1129                 TRACE(DL_ERR, "eth stats fwcmd failed.");
1130                 goto Error;
1131         }
1132
1133 Error:
1134         spin_unlock_irqrestore(&pfob->post_lock, irql);
1135         if (pfob->pend_queue_driving && pfob->mcc) {
1136                 pfob->pend_queue_driving = 0;
1137                 be_drive_mcc_wrb_queue(pfob->mcc);
1138         }
1139         return status;
1140 }
1141
1142 int
1143 be_rxf_promiscuous(struct be_function_object *pfob,
1144                    bool enable_port0, bool enable_port1,
1145                    mcc_wrb_cqe_callback cb, void *cb_context,
1146                    struct be_promiscuous_q_ctxt *q_ctxt)
1147 {
1148         struct FWCMD_ETH_PROMISCUOUS *fwcmd = NULL;
1149         struct MCC_WRB_AMAP *wrb = NULL;
1150         int status = 0;
1151         struct be_generic_q_ctxt *generic_ctxt = NULL;
1152         unsigned long irql;
1153
1154
1155         spin_lock_irqsave(&pfob->post_lock, irql);
1156
1157         wrb = be_function_peek_mcc_wrb(pfob);
1158
1159         if (!wrb) {
1160                 if (q_ctxt && cb) {
1161                         wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header;
1162                         generic_ctxt = (struct be_generic_q_ctxt *) q_ctxt;
1163                         generic_ctxt->context.bytes = sizeof(*q_ctxt);
1164                 } else {
1165                         status = BE_STATUS_NO_MCC_WRB;
1166                         goto Error;
1167                 }
1168         }
1169         /* Prepares an embedded fwcmd, including request/response sizes. */
1170         fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, ETH_PROMISCUOUS);
1171
1172         fwcmd->params.request.port0_promiscuous = enable_port0;
1173         fwcmd->params.request.port1_promiscuous = enable_port1;
1174
1175         /* Post the f/w command */
1176         status = be_function_post_mcc_wrb(pfob, wrb, generic_ctxt,
1177                         cb, cb_context, NULL, NULL, fwcmd, NULL);
1178
1179         if (status < 0) {
1180                 TRACE(DL_ERR, "promiscuous fwcmd failed.");
1181                 goto Error;
1182         }
1183
1184 Error:
1185         spin_unlock_irqrestore(&pfob->post_lock, irql);
1186         if (pfob->pend_queue_driving && pfob->mcc) {
1187                 pfob->pend_queue_driving = 0;
1188                 be_drive_mcc_wrb_queue(pfob->mcc);
1189         }
1190         return status;
1191 }
1192
1193
1194 /*
1195  *-------------------------------------------------------------------------
1196  * Function: be_rxf_filter_config
1197  *   Configures BladeEngine ethernet receive filter settings.
1198  * pfob    -
1199  * settings           - Pointer to the requested filter settings.
1200  *                      The response from BladeEngine will be placed back
1201  *                      in this structure.
1202  * cb                 - optional
1203  * cb_context         - optional
1204  * q_ctxt             - Optional. Pointer to a previously allocated struct.
1205  *                      If the MCC WRB ring is full, this structure is
1206  *                      used to queue the operation. It will be posted
1207  *                      to the MCC ring when space becomes available. All
1208  *                      queued commands will be posted to the ring in
1209  *                      the order they are received. It is always valid
1210  *                      to pass a pointer to a generic
1211  *                      be_generic_q_ctxt. However, the specific
1212  *                      context structs are generally smaller than
1213  *                      the generic struct.
1214  * return pend_status - BE_SUCCESS (0) on success.
1215  *                      BE_PENDING (postive value) if the FWCMD
1216  *                      completion is pending. Negative error code on failure.
1217  *---------------------------------------------------------------------------
1218  */
1219 int
1220 be_rxf_filter_config(struct be_function_object *pfob,
1221                      struct NTWK_RX_FILTER_SETTINGS *settings,
1222                      mcc_wrb_cqe_callback cb, void *cb_context,
1223                      struct be_rxf_filter_q_ctxt *q_ctxt)
1224 {
1225         struct FWCMD_COMMON_NTWK_RX_FILTER *fwcmd = NULL;
1226         struct MCC_WRB_AMAP *wrb = NULL;
1227         int status = 0;
1228         struct be_generic_q_ctxt *generic_ctxt = NULL;
1229         unsigned long irql;
1230         struct be_mcc_wrb_response_copy rc;
1231
1232         ASSERT(settings);
1233
1234         spin_lock_irqsave(&pfob->post_lock, irql);
1235
1236         wrb = be_function_peek_mcc_wrb(pfob);
1237
1238         if (!wrb) {
1239                 if (q_ctxt && cb) {
1240                         wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header;
1241                         generic_ctxt = (struct be_generic_q_ctxt *) q_ctxt;
1242                         generic_ctxt->context.bytes = sizeof(*q_ctxt);
1243                 } else {
1244                         status = BE_STATUS_NO_MCC_WRB;
1245                         goto Error;
1246                 }
1247         }
1248         /* Prepares an embedded fwcmd, including request/response sizes. */
1249         fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_NTWK_RX_FILTER);
1250         memcpy(&fwcmd->params.request, settings, sizeof(*settings));
1251
1252         rc.length = FIELD_SIZEOF(struct FWCMD_COMMON_NTWK_RX_FILTER,
1253                                         params.response);
1254         rc.fwcmd_offset = offsetof(struct FWCMD_COMMON_NTWK_RX_FILTER,
1255                                         params.response);
1256         rc.va = settings;
1257         /* Post or queue the f/w command */
1258         status = be_function_post_mcc_wrb(pfob, wrb, generic_ctxt,
1259                         cb, cb_context, NULL, NULL, fwcmd, &rc);
1260
1261         if (status < 0) {
1262                 TRACE(DL_ERR, "RXF/ERX filter config fwcmd failed.");
1263                 goto Error;
1264         }
1265
1266 Error:
1267         spin_unlock_irqrestore(&pfob->post_lock, irql);
1268         if (pfob->pend_queue_driving && pfob->mcc) {
1269                 pfob->pend_queue_driving = 0;
1270                 be_drive_mcc_wrb_queue(pfob->mcc);
1271         }
1272         return status;
1273 }