a87a22319237661e9fbfa6692fbbb509f0a438b3
[dpdk.git] / drivers / net / sfc / base / efx_mcdi.c
1 /*
2  * Copyright (c) 2008-2016 Solarflare Communications Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * The views and conclusions contained in the software and documentation are
27  * those of the authors and should not be interpreted as representing official
28  * policies, either expressed or implied, of the FreeBSD Project.
29  */
30
31 #include "efx.h"
32 #include "efx_impl.h"
33
34 #if EFSYS_OPT_MCDI
35
36 /*
37  * There are three versions of the MCDI interface:
38  *  - MCDIv0: Siena BootROM. Transport uses MCDIv1 headers.
39  *  - MCDIv1: Siena firmware and Huntington BootROM.
40  *  - MCDIv2: EF10 firmware (Huntington/Medford) and Medford BootROM.
41  *            Transport uses MCDIv2 headers.
42  *
43  * MCDIv2 Header NOT_EPOCH flag
44  * ----------------------------
45  * A new epoch begins at initial startup or after an MC reboot, and defines when
46  * the MC should reject stale MCDI requests.
47  *
48  * The first MCDI request sent by the host should contain NOT_EPOCH=0, and all
49  * subsequent requests (until the next MC reboot) should contain NOT_EPOCH=1.
50  *
51  * After rebooting the MC will fail all requests with NOT_EPOCH=1 by writing a
52  * response with ERROR=1 and DATALEN=0 until a request is seen with NOT_EPOCH=0.
53  */
54
55
56
57         __checkReturn   efx_rc_t
58 efx_mcdi_init(
59         __in            efx_nic_t *enp,
60         __in            const efx_mcdi_transport_t *emtp)
61 {
62         const efx_mcdi_ops_t *emcop;
63         efx_rc_t rc;
64
65         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
66         EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0);
67
68         switch (enp->en_family) {
69
70         default:
71                 EFSYS_ASSERT(0);
72                 rc = ENOTSUP;
73                 goto fail1;
74         }
75
76         if (enp->en_features & EFX_FEATURE_MCDI_DMA) {
77                 /* MCDI requires a DMA buffer in host memory */
78                 if ((emtp == NULL) || (emtp->emt_dma_mem) == NULL) {
79                         rc = EINVAL;
80                         goto fail2;
81                 }
82         }
83         enp->en_mcdi.em_emtp = emtp;
84
85         if (emcop != NULL && emcop->emco_init != NULL) {
86                 if ((rc = emcop->emco_init(enp, emtp)) != 0)
87                         goto fail3;
88         }
89
90         enp->en_mcdi.em_emcop = emcop;
91         enp->en_mod_flags |= EFX_MOD_MCDI;
92
93         return (0);
94
95 fail3:
96         EFSYS_PROBE(fail3);
97 fail2:
98         EFSYS_PROBE(fail2);
99 fail1:
100         EFSYS_PROBE1(fail1, efx_rc_t, rc);
101
102         enp->en_mcdi.em_emcop = NULL;
103         enp->en_mcdi.em_emtp = NULL;
104         enp->en_mod_flags &= ~EFX_MOD_MCDI;
105
106         return (rc);
107 }
108
109                         void
110 efx_mcdi_fini(
111         __in            efx_nic_t *enp)
112 {
113         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
114         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
115
116         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
117         EFSYS_ASSERT3U(enp->en_mod_flags, ==, EFX_MOD_MCDI);
118
119         if (emcop != NULL && emcop->emco_fini != NULL)
120                 emcop->emco_fini(enp);
121
122         emip->emi_port = 0;
123         emip->emi_aborted = 0;
124
125         enp->en_mcdi.em_emcop = NULL;
126         enp->en_mod_flags &= ~EFX_MOD_MCDI;
127 }
128
129                         void
130 efx_mcdi_new_epoch(
131         __in            efx_nic_t *enp)
132 {
133         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
134         efsys_lock_state_t state;
135
136         /* Start a new epoch (allow fresh MCDI requests to succeed) */
137         EFSYS_LOCK(enp->en_eslp, state);
138         emip->emi_new_epoch = B_TRUE;
139         EFSYS_UNLOCK(enp->en_eslp, state);
140 }
141
142 static                  void
143 efx_mcdi_send_request(
144         __in            efx_nic_t *enp,
145         __in            void *hdrp,
146         __in            size_t hdr_len,
147         __in            void *sdup,
148         __in            size_t sdu_len)
149 {
150         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
151
152         emcop->emco_send_request(enp, hdrp, hdr_len, sdup, sdu_len);
153 }
154
155 static                  efx_rc_t
156 efx_mcdi_poll_reboot(
157         __in            efx_nic_t *enp)
158 {
159         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
160         efx_rc_t rc;
161
162         rc = emcop->emco_poll_reboot(enp);
163         return (rc);
164 }
165
166 static                  boolean_t
167 efx_mcdi_poll_response(
168         __in            efx_nic_t *enp)
169 {
170         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
171         boolean_t available;
172
173         available = emcop->emco_poll_response(enp);
174         return (available);
175 }
176
177 static                  void
178 efx_mcdi_read_response(
179         __in            efx_nic_t *enp,
180         __out           void *bufferp,
181         __in            size_t offset,
182         __in            size_t length)
183 {
184         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
185
186         emcop->emco_read_response(enp, bufferp, offset, length);
187 }
188
189                         void
190 efx_mcdi_request_start(
191         __in            efx_nic_t *enp,
192         __in            efx_mcdi_req_t *emrp,
193         __in            boolean_t ev_cpl)
194 {
195 #if EFSYS_OPT_MCDI_LOGGING
196         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
197 #endif
198         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
199         efx_dword_t hdr[2];
200         size_t hdr_len;
201         unsigned int max_version;
202         unsigned int seq;
203         unsigned int xflags;
204         boolean_t new_epoch;
205         efsys_lock_state_t state;
206
207         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
208         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
209         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
210
211         /*
212          * efx_mcdi_request_start() is naturally serialised against both
213          * efx_mcdi_request_poll() and efx_mcdi_ev_cpl()/efx_mcdi_ev_death(),
214          * by virtue of there only being one outstanding MCDI request.
215          * Unfortunately, upper layers may also call efx_mcdi_request_abort()
216          * at any time, to timeout a pending mcdi request, That request may
217          * then subsequently complete, meaning efx_mcdi_ev_cpl() or
218          * efx_mcdi_ev_death() may end up running in parallel with
219          * efx_mcdi_request_start(). This race is handled by ensuring that
220          * %emi_pending_req, %emi_ev_cpl and %emi_seq are protected by the
221          * en_eslp lock.
222          */
223         EFSYS_LOCK(enp->en_eslp, state);
224         EFSYS_ASSERT(emip->emi_pending_req == NULL);
225         emip->emi_pending_req = emrp;
226         emip->emi_ev_cpl = ev_cpl;
227         emip->emi_poll_cnt = 0;
228         seq = emip->emi_seq++ & EFX_MASK32(MCDI_HEADER_SEQ);
229         new_epoch = emip->emi_new_epoch;
230         max_version = emip->emi_max_version;
231         EFSYS_UNLOCK(enp->en_eslp, state);
232
233         xflags = 0;
234         if (ev_cpl)
235                 xflags |= MCDI_HEADER_XFLAGS_EVREQ;
236
237         /*
238          * Huntington firmware supports MCDIv2, but the Huntington BootROM only
239          * supports MCDIv1. Use MCDIv1 headers for MCDIv1 commands where
240          * possible to support this.
241          */
242         if ((max_version >= 2) &&
243             ((emrp->emr_cmd > MC_CMD_CMD_SPACE_ESCAPE_7) ||
244             (emrp->emr_in_length > MCDI_CTL_SDU_LEN_MAX_V1))) {
245                 /* Construct MCDI v2 header */
246                 hdr_len = sizeof (hdr);
247                 EFX_POPULATE_DWORD_8(hdr[0],
248                     MCDI_HEADER_CODE, MC_CMD_V2_EXTN,
249                     MCDI_HEADER_RESYNC, 1,
250                     MCDI_HEADER_DATALEN, 0,
251                     MCDI_HEADER_SEQ, seq,
252                     MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1,
253                     MCDI_HEADER_ERROR, 0,
254                     MCDI_HEADER_RESPONSE, 0,
255                     MCDI_HEADER_XFLAGS, xflags);
256
257                 EFX_POPULATE_DWORD_2(hdr[1],
258                     MC_CMD_V2_EXTN_IN_EXTENDED_CMD, emrp->emr_cmd,
259                     MC_CMD_V2_EXTN_IN_ACTUAL_LEN, emrp->emr_in_length);
260         } else {
261                 /* Construct MCDI v1 header */
262                 hdr_len = sizeof (hdr[0]);
263                 EFX_POPULATE_DWORD_8(hdr[0],
264                     MCDI_HEADER_CODE, emrp->emr_cmd,
265                     MCDI_HEADER_RESYNC, 1,
266                     MCDI_HEADER_DATALEN, emrp->emr_in_length,
267                     MCDI_HEADER_SEQ, seq,
268                     MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1,
269                     MCDI_HEADER_ERROR, 0,
270                     MCDI_HEADER_RESPONSE, 0,
271                     MCDI_HEADER_XFLAGS, xflags);
272         }
273
274 #if EFSYS_OPT_MCDI_LOGGING
275         if (emtp->emt_logger != NULL) {
276                 emtp->emt_logger(emtp->emt_context, EFX_LOG_MCDI_REQUEST,
277                     &hdr[0], hdr_len,
278                     emrp->emr_in_buf, emrp->emr_in_length);
279         }
280 #endif /* EFSYS_OPT_MCDI_LOGGING */
281
282         efx_mcdi_send_request(enp, &hdr[0], hdr_len,
283             emrp->emr_in_buf, emrp->emr_in_length);
284 }
285
286
287 static                  void
288 efx_mcdi_read_response_header(
289         __in            efx_nic_t *enp,
290         __inout         efx_mcdi_req_t *emrp)
291 {
292 #if EFSYS_OPT_MCDI_LOGGING
293         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
294 #endif /* EFSYS_OPT_MCDI_LOGGING */
295         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
296         efx_dword_t hdr[2];
297         unsigned int hdr_len;
298         unsigned int data_len;
299         unsigned int seq;
300         unsigned int cmd;
301         unsigned int error;
302         efx_rc_t rc;
303
304         EFSYS_ASSERT(emrp != NULL);
305
306         efx_mcdi_read_response(enp, &hdr[0], 0, sizeof (hdr[0]));
307         hdr_len = sizeof (hdr[0]);
308
309         cmd = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE);
310         seq = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_SEQ);
311         error = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_ERROR);
312
313         if (cmd != MC_CMD_V2_EXTN) {
314                 data_len = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_DATALEN);
315         } else {
316                 efx_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1]));
317                 hdr_len += sizeof (hdr[1]);
318
319                 cmd = EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_EXTENDED_CMD);
320                 data_len =
321                     EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
322         }
323
324         if (error && (data_len == 0)) {
325                 /* The MC has rebooted since the request was sent. */
326                 EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US);
327                 efx_mcdi_poll_reboot(enp);
328                 rc = EIO;
329                 goto fail1;
330         }
331         if ((cmd != emrp->emr_cmd) ||
332             (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) {
333                 /* Response is for a different request */
334                 rc = EIO;
335                 goto fail2;
336         }
337         if (error) {
338                 efx_dword_t err[2];
339                 unsigned int err_len = MIN(data_len, sizeof (err));
340                 int err_code = MC_CMD_ERR_EPROTO;
341                 int err_arg = 0;
342
343                 /* Read error code (and arg num for MCDI v2 commands) */
344                 efx_mcdi_read_response(enp, &err, hdr_len, err_len);
345
346                 if (err_len >= (MC_CMD_ERR_CODE_OFST + sizeof (efx_dword_t)))
347                         err_code = EFX_DWORD_FIELD(err[0], EFX_DWORD_0);
348 #ifdef WITH_MCDI_V2
349                 if (err_len >= (MC_CMD_ERR_ARG_OFST + sizeof (efx_dword_t)))
350                         err_arg = EFX_DWORD_FIELD(err[1], EFX_DWORD_0);
351 #endif
352                 emrp->emr_err_code = err_code;
353                 emrp->emr_err_arg = err_arg;
354
355 #if EFSYS_OPT_MCDI_LOGGING
356                 if (emtp->emt_logger != NULL) {
357                         emtp->emt_logger(emtp->emt_context,
358                             EFX_LOG_MCDI_RESPONSE,
359                             &hdr[0], hdr_len,
360                             &err[0], err_len);
361                 }
362 #endif /* EFSYS_OPT_MCDI_LOGGING */
363
364                 if (!emrp->emr_quiet) {
365                         EFSYS_PROBE3(mcdi_err_arg, int, emrp->emr_cmd,
366                             int, err_code, int, err_arg);
367                 }
368
369                 rc = efx_mcdi_request_errcode(err_code);
370                 goto fail3;
371         }
372
373         emrp->emr_rc = 0;
374         emrp->emr_out_length_used = data_len;
375         return;
376
377 fail3:
378 fail2:
379 fail1:
380         emrp->emr_rc = rc;
381         emrp->emr_out_length_used = 0;
382 }
383
384 static                  void
385 efx_mcdi_finish_response(
386         __in            efx_nic_t *enp,
387         __in            efx_mcdi_req_t *emrp)
388 {
389 #if EFSYS_OPT_MCDI_LOGGING
390         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
391 #endif /* EFSYS_OPT_MCDI_LOGGING */
392         efx_dword_t hdr[2];
393         unsigned int hdr_len;
394         size_t bytes;
395
396         if (emrp->emr_out_buf == NULL)
397                 return;
398
399         /* Read the command header to detect MCDI response format */
400         hdr_len = sizeof (hdr[0]);
401         efx_mcdi_read_response(enp, &hdr[0], 0, hdr_len);
402         if (EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE) == MC_CMD_V2_EXTN) {
403                 /*
404                  * Read the actual payload length. The length given in the event
405                  * is only correct for responses with the V1 format.
406                  */
407                 efx_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1]));
408                 hdr_len += sizeof (hdr[1]);
409
410                 emrp->emr_out_length_used = EFX_DWORD_FIELD(hdr[1],
411                                             MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
412         }
413
414         /* Copy payload out into caller supplied buffer */
415         bytes = MIN(emrp->emr_out_length_used, emrp->emr_out_length);
416         efx_mcdi_read_response(enp, emrp->emr_out_buf, hdr_len, bytes);
417
418 #if EFSYS_OPT_MCDI_LOGGING
419         if (emtp->emt_logger != NULL) {
420                 emtp->emt_logger(emtp->emt_context,
421                     EFX_LOG_MCDI_RESPONSE,
422                     &hdr[0], hdr_len,
423                     emrp->emr_out_buf, bytes);
424         }
425 #endif /* EFSYS_OPT_MCDI_LOGGING */
426 }
427
428
429         __checkReturn   boolean_t
430 efx_mcdi_request_poll(
431         __in            efx_nic_t *enp)
432 {
433         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
434         efx_mcdi_req_t *emrp;
435         efsys_lock_state_t state;
436         efx_rc_t rc;
437
438         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
439         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
440         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
441
442         /* Serialise against post-watchdog efx_mcdi_ev* */
443         EFSYS_LOCK(enp->en_eslp, state);
444
445         EFSYS_ASSERT(emip->emi_pending_req != NULL);
446         EFSYS_ASSERT(!emip->emi_ev_cpl);
447         emrp = emip->emi_pending_req;
448
449         /* Check for reboot atomically w.r.t efx_mcdi_request_start */
450         if (emip->emi_poll_cnt++ == 0) {
451                 if ((rc = efx_mcdi_poll_reboot(enp)) != 0) {
452                         emip->emi_pending_req = NULL;
453                         EFSYS_UNLOCK(enp->en_eslp, state);
454
455                         /* Reboot/Assertion */
456                         if (rc == EIO || rc == EINTR)
457                                 efx_mcdi_raise_exception(enp, emrp, rc);
458
459                         goto fail1;
460                 }
461         }
462
463         /* Check if a response is available */
464         if (efx_mcdi_poll_response(enp) == B_FALSE) {
465                 EFSYS_UNLOCK(enp->en_eslp, state);
466                 return (B_FALSE);
467         }
468
469         /* Read the response header */
470         efx_mcdi_read_response_header(enp, emrp);
471
472         /* Request complete */
473         emip->emi_pending_req = NULL;
474
475         /* Ensure stale MCDI requests fail after an MC reboot. */
476         emip->emi_new_epoch = B_FALSE;
477
478         EFSYS_UNLOCK(enp->en_eslp, state);
479
480         if ((rc = emrp->emr_rc) != 0)
481                 goto fail2;
482
483         efx_mcdi_finish_response(enp, emrp);
484         return (B_TRUE);
485
486 fail2:
487         if (!emrp->emr_quiet)
488                 EFSYS_PROBE(fail2);
489 fail1:
490         if (!emrp->emr_quiet)
491                 EFSYS_PROBE1(fail1, efx_rc_t, rc);
492
493         return (B_TRUE);
494 }
495
496         __checkReturn   boolean_t
497 efx_mcdi_request_abort(
498         __in            efx_nic_t *enp)
499 {
500         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
501         efx_mcdi_req_t *emrp;
502         boolean_t aborted;
503         efsys_lock_state_t state;
504
505         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
506         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
507         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
508
509         /*
510          * efx_mcdi_ev_* may have already completed this event, and be
511          * spinning/blocked on the upper layer lock. So it *is* legitimate
512          * to for emi_pending_req to be NULL. If there is a pending event
513          * completed request, then provide a "credit" to allow
514          * efx_mcdi_ev_cpl() to accept a single spurious completion.
515          */
516         EFSYS_LOCK(enp->en_eslp, state);
517         emrp = emip->emi_pending_req;
518         aborted = (emrp != NULL);
519         if (aborted) {
520                 emip->emi_pending_req = NULL;
521
522                 /* Error the request */
523                 emrp->emr_out_length_used = 0;
524                 emrp->emr_rc = ETIMEDOUT;
525
526                 /* Provide a credit for seqno/emr_pending_req mismatches */
527                 if (emip->emi_ev_cpl)
528                         ++emip->emi_aborted;
529
530                 /*
531                  * The upper layer has called us, so we don't
532                  * need to complete the request.
533                  */
534         }
535         EFSYS_UNLOCK(enp->en_eslp, state);
536
537         return (aborted);
538 }
539
540                         void
541 efx_mcdi_get_timeout(
542         __in            efx_nic_t *enp,
543         __in            efx_mcdi_req_t *emrp,
544         __out           uint32_t *timeoutp)
545 {
546         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
547
548         emcop->emco_get_timeout(enp, emrp, timeoutp);
549 }
550
551         __checkReturn   efx_rc_t
552 efx_mcdi_request_errcode(
553         __in            unsigned int err)
554 {
555
556         switch (err) {
557                 /* MCDI v1 */
558         case MC_CMD_ERR_EPERM:
559                 return (EACCES);
560         case MC_CMD_ERR_ENOENT:
561                 return (ENOENT);
562         case MC_CMD_ERR_EINTR:
563                 return (EINTR);
564         case MC_CMD_ERR_EACCES:
565                 return (EACCES);
566         case MC_CMD_ERR_EBUSY:
567                 return (EBUSY);
568         case MC_CMD_ERR_EINVAL:
569                 return (EINVAL);
570         case MC_CMD_ERR_EDEADLK:
571                 return (EDEADLK);
572         case MC_CMD_ERR_ENOSYS:
573                 return (ENOTSUP);
574         case MC_CMD_ERR_ETIME:
575                 return (ETIMEDOUT);
576         case MC_CMD_ERR_ENOTSUP:
577                 return (ENOTSUP);
578         case MC_CMD_ERR_EALREADY:
579                 return (EALREADY);
580
581                 /* MCDI v2 */
582         case MC_CMD_ERR_EEXIST:
583                 return (EEXIST);
584 #ifdef MC_CMD_ERR_EAGAIN
585         case MC_CMD_ERR_EAGAIN:
586                 return (EAGAIN);
587 #endif
588 #ifdef MC_CMD_ERR_ENOSPC
589         case MC_CMD_ERR_ENOSPC:
590                 return (ENOSPC);
591 #endif
592         case MC_CMD_ERR_ERANGE:
593                 return (ERANGE);
594
595         case MC_CMD_ERR_ALLOC_FAIL:
596                 return (ENOMEM);
597         case MC_CMD_ERR_NO_VADAPTOR:
598                 return (ENOENT);
599         case MC_CMD_ERR_NO_EVB_PORT:
600                 return (ENOENT);
601         case MC_CMD_ERR_NO_VSWITCH:
602                 return (ENODEV);
603         case MC_CMD_ERR_VLAN_LIMIT:
604                 return (EINVAL);
605         case MC_CMD_ERR_BAD_PCI_FUNC:
606                 return (ENODEV);
607         case MC_CMD_ERR_BAD_VLAN_MODE:
608                 return (EINVAL);
609         case MC_CMD_ERR_BAD_VSWITCH_TYPE:
610                 return (EINVAL);
611         case MC_CMD_ERR_BAD_VPORT_TYPE:
612                 return (EINVAL);
613         case MC_CMD_ERR_MAC_EXIST:
614                 return (EEXIST);
615
616         case MC_CMD_ERR_PROXY_PENDING:
617                 return (EAGAIN);
618
619         default:
620                 EFSYS_PROBE1(mc_pcol_error, int, err);
621                 return (EIO);
622         }
623 }
624
625                         void
626 efx_mcdi_raise_exception(
627         __in            efx_nic_t *enp,
628         __in_opt        efx_mcdi_req_t *emrp,
629         __in            int rc)
630 {
631         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
632         efx_mcdi_exception_t exception;
633
634         /* Reboot or Assertion failure only */
635         EFSYS_ASSERT(rc == EIO || rc == EINTR);
636
637         /*
638          * If MC_CMD_REBOOT causes a reboot (dependent on parameters),
639          * then the EIO is not worthy of an exception.
640          */
641         if (emrp != NULL && emrp->emr_cmd == MC_CMD_REBOOT && rc == EIO)
642                 return;
643
644         exception = (rc == EIO)
645                 ? EFX_MCDI_EXCEPTION_MC_REBOOT
646                 : EFX_MCDI_EXCEPTION_MC_BADASSERT;
647
648         emtp->emt_exception(emtp->emt_context, exception);
649 }
650
651                         void
652 efx_mcdi_execute(
653         __in            efx_nic_t *enp,
654         __inout         efx_mcdi_req_t *emrp)
655 {
656         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
657
658         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
659         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
660
661         emrp->emr_quiet = B_FALSE;
662         emtp->emt_execute(emtp->emt_context, emrp);
663 }
664
665                         void
666 efx_mcdi_execute_quiet(
667         __in            efx_nic_t *enp,
668         __inout         efx_mcdi_req_t *emrp)
669 {
670         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
671
672         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
673         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
674
675         emrp->emr_quiet = B_TRUE;
676         emtp->emt_execute(emtp->emt_context, emrp);
677 }
678
679                         void
680 efx_mcdi_ev_cpl(
681         __in            efx_nic_t *enp,
682         __in            unsigned int seq,
683         __in            unsigned int outlen,
684         __in            int errcode)
685 {
686         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
687         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
688         efx_mcdi_req_t *emrp;
689         efsys_lock_state_t state;
690
691         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
692         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
693
694         /*
695          * Serialise against efx_mcdi_request_poll()/efx_mcdi_request_start()
696          * when we're completing an aborted request.
697          */
698         EFSYS_LOCK(enp->en_eslp, state);
699         if (emip->emi_pending_req == NULL || !emip->emi_ev_cpl ||
700             (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) {
701                 EFSYS_ASSERT(emip->emi_aborted > 0);
702                 if (emip->emi_aborted > 0)
703                         --emip->emi_aborted;
704                 EFSYS_UNLOCK(enp->en_eslp, state);
705                 return;
706         }
707
708         emrp = emip->emi_pending_req;
709         emip->emi_pending_req = NULL;
710         EFSYS_UNLOCK(enp->en_eslp, state);
711
712         if (emip->emi_max_version >= 2) {
713                 /* MCDIv2 response details do not fit into an event. */
714                 efx_mcdi_read_response_header(enp, emrp);
715         } else {
716                 if (errcode != 0) {
717                         if (!emrp->emr_quiet) {
718                                 EFSYS_PROBE2(mcdi_err, int, emrp->emr_cmd,
719                                     int, errcode);
720                         }
721                         emrp->emr_out_length_used = 0;
722                         emrp->emr_rc = efx_mcdi_request_errcode(errcode);
723                 } else {
724                         emrp->emr_out_length_used = outlen;
725                         emrp->emr_rc = 0;
726                 }
727         }
728         if (errcode == 0) {
729                 efx_mcdi_finish_response(enp, emrp);
730         }
731
732         emtp->emt_ev_cpl(emtp->emt_context);
733 }
734
735                         void
736 efx_mcdi_ev_death(
737         __in            efx_nic_t *enp,
738         __in            int rc)
739 {
740         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
741         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
742         efx_mcdi_req_t *emrp = NULL;
743         boolean_t ev_cpl;
744         efsys_lock_state_t state;
745
746         /*
747          * The MCDI request (if there is one) has been terminated, either
748          * by a BADASSERT or REBOOT event.
749          *
750          * If there is an outstanding event-completed MCDI operation, then we
751          * will never receive the completion event (because both MCDI
752          * completions and BADASSERT events are sent to the same evq). So
753          * complete this MCDI op.
754          *
755          * This function might run in parallel with efx_mcdi_request_poll()
756          * for poll completed mcdi requests, and also with
757          * efx_mcdi_request_start() for post-watchdog completions.
758          */
759         EFSYS_LOCK(enp->en_eslp, state);
760         emrp = emip->emi_pending_req;
761         ev_cpl = emip->emi_ev_cpl;
762         if (emrp != NULL && emip->emi_ev_cpl) {
763                 emip->emi_pending_req = NULL;
764
765                 emrp->emr_out_length_used = 0;
766                 emrp->emr_rc = rc;
767                 ++emip->emi_aborted;
768         }
769
770         /*
771          * Since we're running in parallel with a request, consume the
772          * status word before dropping the lock.
773          */
774         if (rc == EIO || rc == EINTR) {
775                 EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US);
776                 (void) efx_mcdi_poll_reboot(enp);
777                 emip->emi_new_epoch = B_TRUE;
778         }
779
780         EFSYS_UNLOCK(enp->en_eslp, state);
781
782         efx_mcdi_raise_exception(enp, emrp, rc);
783
784         if (emrp != NULL && ev_cpl)
785                 emtp->emt_ev_cpl(emtp->emt_context);
786 }
787
788         __checkReturn           efx_rc_t
789 efx_mcdi_version(
790         __in                    efx_nic_t *enp,
791         __out_ecount_opt(4)     uint16_t versionp[4],
792         __out_opt               uint32_t *buildp,
793         __out_opt               efx_mcdi_boot_t *statusp)
794 {
795         efx_mcdi_req_t req;
796         uint8_t payload[MAX(MAX(MC_CMD_GET_VERSION_IN_LEN,
797                                 MC_CMD_GET_VERSION_OUT_LEN),
798                             MAX(MC_CMD_GET_BOOT_STATUS_IN_LEN,
799                                 MC_CMD_GET_BOOT_STATUS_OUT_LEN))];
800         efx_word_t *ver_words;
801         uint16_t version[4];
802         uint32_t build;
803         efx_mcdi_boot_t status;
804         efx_rc_t rc;
805
806         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
807
808         (void) memset(payload, 0, sizeof (payload));
809         req.emr_cmd = MC_CMD_GET_VERSION;
810         req.emr_in_buf = payload;
811         req.emr_in_length = MC_CMD_GET_VERSION_IN_LEN;
812         req.emr_out_buf = payload;
813         req.emr_out_length = MC_CMD_GET_VERSION_OUT_LEN;
814
815         efx_mcdi_execute(enp, &req);
816
817         if (req.emr_rc != 0) {
818                 rc = req.emr_rc;
819                 goto fail1;
820         }
821
822         /* bootrom support */
823         if (req.emr_out_length_used == MC_CMD_GET_VERSION_V0_OUT_LEN) {
824                 version[0] = version[1] = version[2] = version[3] = 0;
825                 build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE);
826
827                 goto version;
828         }
829
830         if (req.emr_out_length_used < MC_CMD_GET_VERSION_OUT_LEN) {
831                 rc = EMSGSIZE;
832                 goto fail2;
833         }
834
835         ver_words = MCDI_OUT2(req, efx_word_t, GET_VERSION_OUT_VERSION);
836         version[0] = EFX_WORD_FIELD(ver_words[0], EFX_WORD_0);
837         version[1] = EFX_WORD_FIELD(ver_words[1], EFX_WORD_0);
838         version[2] = EFX_WORD_FIELD(ver_words[2], EFX_WORD_0);
839         version[3] = EFX_WORD_FIELD(ver_words[3], EFX_WORD_0);
840         build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE);
841
842 version:
843         /* The bootrom doesn't understand BOOT_STATUS */
844         if (MC_FW_VERSION_IS_BOOTLOADER(build)) {
845                 status = EFX_MCDI_BOOT_ROM;
846                 goto out;
847         }
848
849         (void) memset(payload, 0, sizeof (payload));
850         req.emr_cmd = MC_CMD_GET_BOOT_STATUS;
851         req.emr_in_buf = payload;
852         req.emr_in_length = MC_CMD_GET_BOOT_STATUS_IN_LEN;
853         req.emr_out_buf = payload;
854         req.emr_out_length = MC_CMD_GET_BOOT_STATUS_OUT_LEN;
855
856         efx_mcdi_execute_quiet(enp, &req);
857
858         if (req.emr_rc == EACCES) {
859                 /* Unprivileged functions cannot access BOOT_STATUS */
860                 status = EFX_MCDI_BOOT_PRIMARY;
861                 version[0] = version[1] = version[2] = version[3] = 0;
862                 build = 0;
863                 goto out;
864         }
865
866         if (req.emr_rc != 0) {
867                 rc = req.emr_rc;
868                 goto fail3;
869         }
870
871         if (req.emr_out_length_used < MC_CMD_GET_BOOT_STATUS_OUT_LEN) {
872                 rc = EMSGSIZE;
873                 goto fail4;
874         }
875
876         if (MCDI_OUT_DWORD_FIELD(req, GET_BOOT_STATUS_OUT_FLAGS,
877             GET_BOOT_STATUS_OUT_FLAGS_PRIMARY))
878                 status = EFX_MCDI_BOOT_PRIMARY;
879         else
880                 status = EFX_MCDI_BOOT_SECONDARY;
881
882 out:
883         if (versionp != NULL)
884                 memcpy(versionp, version, sizeof (version));
885         if (buildp != NULL)
886                 *buildp = build;
887         if (statusp != NULL)
888                 *statusp = status;
889
890         return (0);
891
892 fail4:
893         EFSYS_PROBE(fail4);
894 fail3:
895         EFSYS_PROBE(fail3);
896 fail2:
897         EFSYS_PROBE(fail2);
898 fail1:
899         EFSYS_PROBE1(fail1, efx_rc_t, rc);
900
901         return (rc);
902 }
903
904 static  __checkReturn   efx_rc_t
905 efx_mcdi_do_reboot(
906         __in            efx_nic_t *enp,
907         __in            boolean_t after_assertion)
908 {
909         uint8_t payload[MAX(MC_CMD_REBOOT_IN_LEN, MC_CMD_REBOOT_OUT_LEN)];
910         efx_mcdi_req_t req;
911         efx_rc_t rc;
912
913         /*
914          * We could require the caller to have caused en_mod_flags=0 to
915          * call this function. This doesn't help the other port though,
916          * who's about to get the MC ripped out from underneath them.
917          * Since they have to cope with the subsequent fallout of MCDI
918          * failures, we should as well.
919          */
920         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
921
922         (void) memset(payload, 0, sizeof (payload));
923         req.emr_cmd = MC_CMD_REBOOT;
924         req.emr_in_buf = payload;
925         req.emr_in_length = MC_CMD_REBOOT_IN_LEN;
926         req.emr_out_buf = payload;
927         req.emr_out_length = MC_CMD_REBOOT_OUT_LEN;
928
929         MCDI_IN_SET_DWORD(req, REBOOT_IN_FLAGS,
930             (after_assertion ? MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION : 0));
931
932         efx_mcdi_execute_quiet(enp, &req);
933
934         if (req.emr_rc == EACCES) {
935                 /* Unprivileged functions cannot reboot the MC. */
936                 goto out;
937         }
938
939         /* A successful reboot request returns EIO. */
940         if (req.emr_rc != 0 && req.emr_rc != EIO) {
941                 rc = req.emr_rc;
942                 goto fail1;
943         }
944
945 out:
946         return (0);
947
948 fail1:
949         EFSYS_PROBE1(fail1, efx_rc_t, rc);
950
951         return (rc);
952 }
953
954         __checkReturn   efx_rc_t
955 efx_mcdi_reboot(
956         __in            efx_nic_t *enp)
957 {
958         return (efx_mcdi_do_reboot(enp, B_FALSE));
959 }
960
961         __checkReturn   efx_rc_t
962 efx_mcdi_exit_assertion_handler(
963         __in            efx_nic_t *enp)
964 {
965         return (efx_mcdi_do_reboot(enp, B_TRUE));
966 }
967
968         __checkReturn   efx_rc_t
969 efx_mcdi_read_assertion(
970         __in            efx_nic_t *enp)
971 {
972         efx_mcdi_req_t req;
973         uint8_t payload[MAX(MC_CMD_GET_ASSERTS_IN_LEN,
974                             MC_CMD_GET_ASSERTS_OUT_LEN)];
975         const char *reason;
976         unsigned int flags;
977         unsigned int index;
978         unsigned int ofst;
979         int retry;
980         efx_rc_t rc;
981
982         /*
983          * Before we attempt to chat to the MC, we should verify that the MC
984          * isn't in it's assertion handler, either due to a previous reboot,
985          * or because we're reinitializing due to an eec_exception().
986          *
987          * Use GET_ASSERTS to read any assertion state that may be present.
988          * Retry this command twice. Once because a boot-time assertion failure
989          * might cause the 1st MCDI request to fail. And once again because
990          * we might race with efx_mcdi_exit_assertion_handler() running on
991          * partner port(s) on the same NIC.
992          */
993         retry = 2;
994         do {
995                 (void) memset(payload, 0, sizeof (payload));
996                 req.emr_cmd = MC_CMD_GET_ASSERTS;
997                 req.emr_in_buf = payload;
998                 req.emr_in_length = MC_CMD_GET_ASSERTS_IN_LEN;
999                 req.emr_out_buf = payload;
1000                 req.emr_out_length = MC_CMD_GET_ASSERTS_OUT_LEN;
1001
1002                 MCDI_IN_SET_DWORD(req, GET_ASSERTS_IN_CLEAR, 1);
1003                 efx_mcdi_execute_quiet(enp, &req);
1004
1005         } while ((req.emr_rc == EINTR || req.emr_rc == EIO) && retry-- > 0);
1006
1007         if (req.emr_rc != 0) {
1008                 if (req.emr_rc == EACCES) {
1009                         /* Unprivileged functions cannot clear assertions. */
1010                         goto out;
1011                 }
1012                 rc = req.emr_rc;
1013                 goto fail1;
1014         }
1015
1016         if (req.emr_out_length_used < MC_CMD_GET_ASSERTS_OUT_LEN) {
1017                 rc = EMSGSIZE;
1018                 goto fail2;
1019         }
1020
1021         /* Print out any assertion state recorded */
1022         flags = MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_GLOBAL_FLAGS);
1023         if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS)
1024                 return (0);
1025
1026         reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL)
1027                 ? "system-level assertion"
1028                 : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL)
1029                 ? "thread-level assertion"
1030                 : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED)
1031                 ? "watchdog reset"
1032                 : (flags == MC_CMD_GET_ASSERTS_FLAGS_ADDR_TRAP)
1033                 ? "illegal address trap"
1034                 : "unknown assertion";
1035         EFSYS_PROBE3(mcpu_assertion,
1036             const char *, reason, unsigned int,
1037             MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_SAVED_PC_OFFS),
1038             unsigned int,
1039             MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_THREAD_OFFS));
1040
1041         /* Print out the registers (r1 ... r31) */
1042         ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST;
1043         for (index = 1;
1044                 index < 1 + MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM;
1045                 index++) {
1046                 EFSYS_PROBE2(mcpu_register, unsigned int, index, unsigned int,
1047                             EFX_DWORD_FIELD(*MCDI_OUT(req, efx_dword_t, ofst),
1048                                             EFX_DWORD_0));
1049                 ofst += sizeof (efx_dword_t);
1050         }
1051         EFSYS_ASSERT(ofst <= MC_CMD_GET_ASSERTS_OUT_LEN);
1052
1053 out:
1054         return (0);
1055
1056 fail2:
1057         EFSYS_PROBE(fail2);
1058 fail1:
1059         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1060
1061         return (rc);
1062 }
1063
1064
1065 /*
1066  * Internal routines for for specific MCDI requests.
1067  */
1068
1069         __checkReturn   efx_rc_t
1070 efx_mcdi_drv_attach(
1071         __in            efx_nic_t *enp,
1072         __in            boolean_t attach)
1073 {
1074         efx_mcdi_req_t req;
1075         uint8_t payload[MAX(MC_CMD_DRV_ATTACH_IN_LEN,
1076                             MC_CMD_DRV_ATTACH_EXT_OUT_LEN)];
1077         efx_rc_t rc;
1078
1079         (void) memset(payload, 0, sizeof (payload));
1080         req.emr_cmd = MC_CMD_DRV_ATTACH;
1081         req.emr_in_buf = payload;
1082         req.emr_in_length = MC_CMD_DRV_ATTACH_IN_LEN;
1083         req.emr_out_buf = payload;
1084         req.emr_out_length = MC_CMD_DRV_ATTACH_EXT_OUT_LEN;
1085
1086         /*
1087          * Use DONT_CARE for the datapath firmware type to ensure that the
1088          * driver can attach to an unprivileged function. The datapath firmware
1089          * type to use is controlled by the 'sfboot' utility.
1090          */
1091         MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_NEW_STATE, attach ? 1 : 0);
1092         MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_UPDATE, 1);
1093         MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_FIRMWARE_ID, MC_CMD_FW_DONT_CARE);
1094
1095         efx_mcdi_execute(enp, &req);
1096
1097         if (req.emr_rc != 0) {
1098                 rc = req.emr_rc;
1099                 goto fail1;
1100         }
1101
1102         if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_OUT_LEN) {
1103                 rc = EMSGSIZE;
1104                 goto fail2;
1105         }
1106
1107         return (0);
1108
1109 fail2:
1110         EFSYS_PROBE(fail2);
1111 fail1:
1112         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1113
1114         return (rc);
1115 }
1116
1117         __checkReturn           efx_rc_t
1118 efx_mcdi_get_board_cfg(
1119         __in                    efx_nic_t *enp,
1120         __out_opt               uint32_t *board_typep,
1121         __out_opt               efx_dword_t *capabilitiesp,
1122         __out_ecount_opt(6)     uint8_t mac_addrp[6])
1123 {
1124         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
1125         efx_mcdi_req_t req;
1126         uint8_t payload[MAX(MC_CMD_GET_BOARD_CFG_IN_LEN,
1127                             MC_CMD_GET_BOARD_CFG_OUT_LENMIN)];
1128         efx_rc_t rc;
1129
1130         (void) memset(payload, 0, sizeof (payload));
1131         req.emr_cmd = MC_CMD_GET_BOARD_CFG;
1132         req.emr_in_buf = payload;
1133         req.emr_in_length = MC_CMD_GET_BOARD_CFG_IN_LEN;
1134         req.emr_out_buf = payload;
1135         req.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMIN;
1136
1137         efx_mcdi_execute(enp, &req);
1138
1139         if (req.emr_rc != 0) {
1140                 rc = req.emr_rc;
1141                 goto fail1;
1142         }
1143
1144         if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) {
1145                 rc = EMSGSIZE;
1146                 goto fail2;
1147         }
1148
1149         if (mac_addrp != NULL) {
1150                 uint8_t *addrp;
1151
1152                 if (emip->emi_port == 1) {
1153                         addrp = MCDI_OUT2(req, uint8_t,
1154                             GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0);
1155                 } else if (emip->emi_port == 2) {
1156                         addrp = MCDI_OUT2(req, uint8_t,
1157                             GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1);
1158                 } else {
1159                         rc = EINVAL;
1160                         goto fail3;
1161                 }
1162
1163                 EFX_MAC_ADDR_COPY(mac_addrp, addrp);
1164         }
1165
1166         if (capabilitiesp != NULL) {
1167                 if (emip->emi_port == 1) {
1168                         *capabilitiesp = *MCDI_OUT2(req, efx_dword_t,
1169                             GET_BOARD_CFG_OUT_CAPABILITIES_PORT0);
1170                 } else if (emip->emi_port == 2) {
1171                         *capabilitiesp = *MCDI_OUT2(req, efx_dword_t,
1172                             GET_BOARD_CFG_OUT_CAPABILITIES_PORT1);
1173                 } else {
1174                         rc = EINVAL;
1175                         goto fail4;
1176                 }
1177         }
1178
1179         if (board_typep != NULL) {
1180                 *board_typep = MCDI_OUT_DWORD(req,
1181                     GET_BOARD_CFG_OUT_BOARD_TYPE);
1182         }
1183
1184         return (0);
1185
1186 fail4:
1187         EFSYS_PROBE(fail4);
1188 fail3:
1189         EFSYS_PROBE(fail3);
1190 fail2:
1191         EFSYS_PROBE(fail2);
1192 fail1:
1193         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1194
1195         return (rc);
1196 }
1197
1198         __checkReturn   efx_rc_t
1199 efx_mcdi_get_resource_limits(
1200         __in            efx_nic_t *enp,
1201         __out_opt       uint32_t *nevqp,
1202         __out_opt       uint32_t *nrxqp,
1203         __out_opt       uint32_t *ntxqp)
1204 {
1205         efx_mcdi_req_t req;
1206         uint8_t payload[MAX(MC_CMD_GET_RESOURCE_LIMITS_IN_LEN,
1207                             MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN)];
1208         efx_rc_t rc;
1209
1210         (void) memset(payload, 0, sizeof (payload));
1211         req.emr_cmd = MC_CMD_GET_RESOURCE_LIMITS;
1212         req.emr_in_buf = payload;
1213         req.emr_in_length = MC_CMD_GET_RESOURCE_LIMITS_IN_LEN;
1214         req.emr_out_buf = payload;
1215         req.emr_out_length = MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN;
1216
1217         efx_mcdi_execute(enp, &req);
1218
1219         if (req.emr_rc != 0) {
1220                 rc = req.emr_rc;
1221                 goto fail1;
1222         }
1223
1224         if (req.emr_out_length_used < MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN) {
1225                 rc = EMSGSIZE;
1226                 goto fail2;
1227         }
1228
1229         if (nevqp != NULL)
1230                 *nevqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_EVQ);
1231         if (nrxqp != NULL)
1232                 *nrxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_RXQ);
1233         if (ntxqp != NULL)
1234                 *ntxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_TXQ);
1235
1236         return (0);
1237
1238 fail2:
1239         EFSYS_PROBE(fail2);
1240 fail1:
1241         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1242
1243         return (rc);
1244 }
1245
1246         __checkReturn   efx_rc_t
1247 efx_mcdi_get_phy_cfg(
1248         __in            efx_nic_t *enp)
1249 {
1250         efx_port_t *epp = &(enp->en_port);
1251         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1252         efx_mcdi_req_t req;
1253         uint8_t payload[MAX(MC_CMD_GET_PHY_CFG_IN_LEN,
1254                             MC_CMD_GET_PHY_CFG_OUT_LEN)];
1255         efx_rc_t rc;
1256
1257         (void) memset(payload, 0, sizeof (payload));
1258         req.emr_cmd = MC_CMD_GET_PHY_CFG;
1259         req.emr_in_buf = payload;
1260         req.emr_in_length = MC_CMD_GET_PHY_CFG_IN_LEN;
1261         req.emr_out_buf = payload;
1262         req.emr_out_length = MC_CMD_GET_PHY_CFG_OUT_LEN;
1263
1264         efx_mcdi_execute(enp, &req);
1265
1266         if (req.emr_rc != 0) {
1267                 rc = req.emr_rc;
1268                 goto fail1;
1269         }
1270
1271         if (req.emr_out_length_used < MC_CMD_GET_PHY_CFG_OUT_LEN) {
1272                 rc = EMSGSIZE;
1273                 goto fail2;
1274         }
1275
1276         encp->enc_phy_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_TYPE);
1277 #if EFSYS_OPT_NAMES
1278         (void) strncpy(encp->enc_phy_name,
1279                 MCDI_OUT2(req, char, GET_PHY_CFG_OUT_NAME),
1280                 MIN(sizeof (encp->enc_phy_name) - 1,
1281                     MC_CMD_GET_PHY_CFG_OUT_NAME_LEN));
1282 #endif  /* EFSYS_OPT_NAMES */
1283         (void) memset(encp->enc_phy_revision, 0,
1284             sizeof (encp->enc_phy_revision));
1285         memcpy(encp->enc_phy_revision,
1286                 MCDI_OUT2(req, char, GET_PHY_CFG_OUT_REVISION),
1287                 MIN(sizeof (encp->enc_phy_revision) - 1,
1288                     MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN));
1289
1290         /* Get the media type of the fixed port, if recognised. */
1291         EFX_STATIC_ASSERT(MC_CMD_MEDIA_XAUI == EFX_PHY_MEDIA_XAUI);
1292         EFX_STATIC_ASSERT(MC_CMD_MEDIA_CX4 == EFX_PHY_MEDIA_CX4);
1293         EFX_STATIC_ASSERT(MC_CMD_MEDIA_KX4 == EFX_PHY_MEDIA_KX4);
1294         EFX_STATIC_ASSERT(MC_CMD_MEDIA_XFP == EFX_PHY_MEDIA_XFP);
1295         EFX_STATIC_ASSERT(MC_CMD_MEDIA_SFP_PLUS == EFX_PHY_MEDIA_SFP_PLUS);
1296         EFX_STATIC_ASSERT(MC_CMD_MEDIA_BASE_T == EFX_PHY_MEDIA_BASE_T);
1297         EFX_STATIC_ASSERT(MC_CMD_MEDIA_QSFP_PLUS == EFX_PHY_MEDIA_QSFP_PLUS);
1298         epp->ep_fixed_port_type =
1299                 (efx_phy_media_type_t) MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_MEDIA_TYPE);
1300         if (epp->ep_fixed_port_type >= EFX_PHY_MEDIA_NTYPES)
1301                 epp->ep_fixed_port_type = EFX_PHY_MEDIA_INVALID;
1302
1303         epp->ep_phy_cap_mask =
1304                 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_SUPPORTED_CAP);
1305
1306         encp->enc_port = (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_PRT);
1307
1308         /* Populate internal state */
1309         encp->enc_mcdi_mdio_channel =
1310                 (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_CHANNEL);
1311
1312         return (0);
1313
1314 fail2:
1315         EFSYS_PROBE(fail2);
1316 fail1:
1317         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1318
1319         return (rc);
1320 }
1321
1322         __checkReturn           efx_rc_t
1323 efx_mcdi_firmware_update_supported(
1324         __in                    efx_nic_t *enp,
1325         __out                   boolean_t *supportedp)
1326 {
1327         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1328         efx_rc_t rc;
1329
1330         if (emcop != NULL) {
1331                 if ((rc = emcop->emco_feature_supported(enp,
1332                             EFX_MCDI_FEATURE_FW_UPDATE, supportedp)) != 0)
1333                         goto fail1;
1334         } else {
1335                 /* Earlier devices always supported updates */
1336                 *supportedp = B_TRUE;
1337         }
1338
1339         return (0);
1340
1341 fail1:
1342         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1343
1344         return (rc);
1345 }
1346
1347         __checkReturn           efx_rc_t
1348 efx_mcdi_macaddr_change_supported(
1349         __in                    efx_nic_t *enp,
1350         __out                   boolean_t *supportedp)
1351 {
1352         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1353         efx_rc_t rc;
1354
1355         if (emcop != NULL) {
1356                 if ((rc = emcop->emco_feature_supported(enp,
1357                             EFX_MCDI_FEATURE_MACADDR_CHANGE, supportedp)) != 0)
1358                         goto fail1;
1359         } else {
1360                 /* Earlier devices always supported MAC changes */
1361                 *supportedp = B_TRUE;
1362         }
1363
1364         return (0);
1365
1366 fail1:
1367         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1368
1369         return (rc);
1370 }
1371
1372         __checkReturn           efx_rc_t
1373 efx_mcdi_link_control_supported(
1374         __in                    efx_nic_t *enp,
1375         __out                   boolean_t *supportedp)
1376 {
1377         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1378         efx_rc_t rc;
1379
1380         if (emcop != NULL) {
1381                 if ((rc = emcop->emco_feature_supported(enp,
1382                             EFX_MCDI_FEATURE_LINK_CONTROL, supportedp)) != 0)
1383                         goto fail1;
1384         } else {
1385                 /* Earlier devices always supported link control */
1386                 *supportedp = B_TRUE;
1387         }
1388
1389         return (0);
1390
1391 fail1:
1392         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1393
1394         return (rc);
1395 }
1396
1397         __checkReturn           efx_rc_t
1398 efx_mcdi_mac_spoofing_supported(
1399         __in                    efx_nic_t *enp,
1400         __out                   boolean_t *supportedp)
1401 {
1402         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1403         efx_rc_t rc;
1404
1405         if (emcop != NULL) {
1406                 if ((rc = emcop->emco_feature_supported(enp,
1407                             EFX_MCDI_FEATURE_MAC_SPOOFING, supportedp)) != 0)
1408                         goto fail1;
1409         } else {
1410                 /* Earlier devices always supported MAC spoofing */
1411                 *supportedp = B_TRUE;
1412         }
1413
1414         return (0);
1415
1416 fail1:
1417         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1418
1419         return (rc);
1420 }
1421
1422
1423 /* Enable logging of some events (e.g. link state changes) */
1424         __checkReturn   efx_rc_t
1425 efx_mcdi_log_ctrl(
1426         __in            efx_nic_t *enp)
1427 {
1428         efx_mcdi_req_t req;
1429         uint8_t payload[MAX(MC_CMD_LOG_CTRL_IN_LEN,
1430                             MC_CMD_LOG_CTRL_OUT_LEN)];
1431         efx_rc_t rc;
1432
1433         (void) memset(payload, 0, sizeof (payload));
1434         req.emr_cmd = MC_CMD_LOG_CTRL;
1435         req.emr_in_buf = payload;
1436         req.emr_in_length = MC_CMD_LOG_CTRL_IN_LEN;
1437         req.emr_out_buf = payload;
1438         req.emr_out_length = MC_CMD_LOG_CTRL_OUT_LEN;
1439
1440         MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST,
1441                     MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ);
1442         MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST_EVQ, 0);
1443
1444         efx_mcdi_execute(enp, &req);
1445
1446         if (req.emr_rc != 0) {
1447                 rc = req.emr_rc;
1448                 goto fail1;
1449         }
1450
1451         return (0);
1452
1453 fail1:
1454         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1455
1456         return (rc);
1457 }
1458
1459
1460         __checkReturn           efx_rc_t
1461 efx_mcdi_set_workaround(
1462         __in                    efx_nic_t *enp,
1463         __in                    uint32_t type,
1464         __in                    boolean_t enabled,
1465         __out_opt               uint32_t *flagsp)
1466 {
1467         efx_mcdi_req_t req;
1468         uint8_t payload[MAX(MC_CMD_WORKAROUND_IN_LEN,
1469                             MC_CMD_WORKAROUND_EXT_OUT_LEN)];
1470         efx_rc_t rc;
1471
1472         (void) memset(payload, 0, sizeof (payload));
1473         req.emr_cmd = MC_CMD_WORKAROUND;
1474         req.emr_in_buf = payload;
1475         req.emr_in_length = MC_CMD_WORKAROUND_IN_LEN;
1476         req.emr_out_buf = payload;
1477         req.emr_out_length = MC_CMD_WORKAROUND_OUT_LEN;
1478
1479         MCDI_IN_SET_DWORD(req, WORKAROUND_IN_TYPE, type);
1480         MCDI_IN_SET_DWORD(req, WORKAROUND_IN_ENABLED, enabled ? 1 : 0);
1481
1482         efx_mcdi_execute_quiet(enp, &req);
1483
1484         if (req.emr_rc != 0) {
1485                 rc = req.emr_rc;
1486                 goto fail1;
1487         }
1488
1489         if (flagsp != NULL) {
1490                 if (req.emr_out_length_used >= MC_CMD_WORKAROUND_EXT_OUT_LEN)
1491                         *flagsp = MCDI_OUT_DWORD(req, WORKAROUND_EXT_OUT_FLAGS);
1492                 else
1493                         *flagsp = 0;
1494         }
1495
1496         return (0);
1497
1498 fail1:
1499         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1500
1501         return (rc);
1502 }
1503
1504
1505         __checkReturn           efx_rc_t
1506 efx_mcdi_get_workarounds(
1507         __in                    efx_nic_t *enp,
1508         __out_opt               uint32_t *implementedp,
1509         __out_opt               uint32_t *enabledp)
1510 {
1511         efx_mcdi_req_t req;
1512         uint8_t payload[MC_CMD_GET_WORKAROUNDS_OUT_LEN];
1513         efx_rc_t rc;
1514
1515         (void) memset(payload, 0, sizeof (payload));
1516         req.emr_cmd = MC_CMD_GET_WORKAROUNDS;
1517         req.emr_in_buf = NULL;
1518         req.emr_in_length = 0;
1519         req.emr_out_buf = payload;
1520         req.emr_out_length = MC_CMD_GET_WORKAROUNDS_OUT_LEN;
1521
1522         efx_mcdi_execute(enp, &req);
1523
1524         if (req.emr_rc != 0) {
1525                 rc = req.emr_rc;
1526                 goto fail1;
1527         }
1528
1529         if (implementedp != NULL) {
1530                 *implementedp =
1531                     MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_IMPLEMENTED);
1532         }
1533
1534         if (enabledp != NULL) {
1535                 *enabledp = MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_ENABLED);
1536         }
1537
1538         return (0);
1539
1540 fail1:
1541         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1542
1543         return (rc);
1544 }
1545
1546 /*
1547  * Size of media information page in accordance with SFF-8472 and SFF-8436.
1548  * It is used in MCDI interface as well.
1549  */
1550 #define EFX_PHY_MEDIA_INFO_PAGE_SIZE            0x80
1551
1552 static  __checkReturn           efx_rc_t
1553 efx_mcdi_get_phy_media_info(
1554         __in                    efx_nic_t *enp,
1555         __in                    uint32_t mcdi_page,
1556         __in                    uint8_t offset,
1557         __in                    uint8_t len,
1558         __out_bcount(len)       uint8_t *data)
1559 {
1560         efx_mcdi_req_t req;
1561         uint8_t payload[MAX(MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN,
1562                             MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(
1563                                 EFX_PHY_MEDIA_INFO_PAGE_SIZE))];
1564         efx_rc_t rc;
1565
1566         EFSYS_ASSERT((uint32_t)offset + len <= EFX_PHY_MEDIA_INFO_PAGE_SIZE);
1567
1568         (void) memset(payload, 0, sizeof (payload));
1569         req.emr_cmd = MC_CMD_GET_PHY_MEDIA_INFO;
1570         req.emr_in_buf = payload;
1571         req.emr_in_length = MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN;
1572         req.emr_out_buf = payload;
1573         req.emr_out_length =
1574             MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE);
1575
1576         MCDI_IN_SET_DWORD(req, GET_PHY_MEDIA_INFO_IN_PAGE, mcdi_page);
1577
1578         efx_mcdi_execute(enp, &req);
1579
1580         if (req.emr_rc != 0) {
1581                 rc = req.emr_rc;
1582                 goto fail1;
1583         }
1584
1585         if (req.emr_out_length_used !=
1586             MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE)) {
1587                 rc = EMSGSIZE;
1588                 goto fail2;
1589         }
1590
1591         if (MCDI_OUT_DWORD(req, GET_PHY_MEDIA_INFO_OUT_DATALEN) !=
1592             EFX_PHY_MEDIA_INFO_PAGE_SIZE) {
1593                 rc = EIO;
1594                 goto fail3;
1595         }
1596
1597         memcpy(data,
1598             MCDI_OUT2(req, uint8_t, GET_PHY_MEDIA_INFO_OUT_DATA) + offset,
1599             len);
1600
1601         return (0);
1602
1603 fail3:
1604         EFSYS_PROBE(fail3);
1605 fail2:
1606         EFSYS_PROBE(fail2);
1607 fail1:
1608         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1609
1610         return (rc);
1611 }
1612
1613 /*
1614  * 2-wire device address of the base information in accordance with SFF-8472
1615  * Diagnostic Monitoring Interface for Optical Transceivers section
1616  * 4 Memory Organization.
1617  */
1618 #define EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_BASE    0xA0
1619
1620 /*
1621  * 2-wire device address of the digital diagnostics monitoring interface
1622  * in accordance with SFF-8472 Diagnostic Monitoring Interface for Optical
1623  * Transceivers section 4 Memory Organization.
1624  */
1625 #define EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_DDM     0xA2
1626
1627 /*
1628  * Hard wired 2-wire device address for QSFP+ in accordance with SFF-8436
1629  * QSFP+ 10 Gbs 4X PLUGGABLE TRANSCEIVER section 7.4 Device Addressing and
1630  * Operation.
1631  */
1632 #define EFX_PHY_MEDIA_INFO_DEV_ADDR_QSFP        0xA0
1633
1634         __checkReturn           efx_rc_t
1635 efx_mcdi_phy_module_get_info(
1636         __in                    efx_nic_t *enp,
1637         __in                    uint8_t dev_addr,
1638         __in                    uint8_t offset,
1639         __in                    uint8_t len,
1640         __out_bcount(len)       uint8_t *data)
1641 {
1642         efx_port_t *epp = &(enp->en_port);
1643         efx_rc_t rc;
1644         uint32_t mcdi_lower_page;
1645         uint32_t mcdi_upper_page;
1646
1647         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1648
1649         /*
1650          * Map device address to MC_CMD_GET_PHY_MEDIA_INFO pages.
1651          * Offset plus length interface allows to access page 0 only.
1652          * I.e. non-zero upper pages are not accessible.
1653          * See SFF-8472 section 4 Memory Organization and SFF-8436 section 7.6
1654          * QSFP+ Memory Map for details on how information is structured
1655          * and accessible.
1656          */
1657         switch (epp->ep_fixed_port_type) {
1658         case EFX_PHY_MEDIA_SFP_PLUS:
1659                 /*
1660                  * In accordance with SFF-8472 Diagnostic Monitoring
1661                  * Interface for Optical Transceivers section 4 Memory
1662                  * Organization two 2-wire addresses are defined.
1663                  */
1664                 switch (dev_addr) {
1665                 /* Base information */
1666                 case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_BASE:
1667                         /*
1668                          * MCDI page 0 should be used to access lower
1669                          * page 0 (0x00 - 0x7f) at the device address 0xA0.
1670                          */
1671                         mcdi_lower_page = 0;
1672                         /*
1673                          * MCDI page 1 should be used to access  upper
1674                          * page 0 (0x80 - 0xff) at the device address 0xA0.
1675                          */
1676                         mcdi_upper_page = 1;
1677                         break;
1678                 /* Diagnostics */
1679                 case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_DDM:
1680                         /*
1681                          * MCDI page 2 should be used to access lower
1682                          * page 0 (0x00 - 0x7f) at the device address 0xA2.
1683                          */
1684                         mcdi_lower_page = 2;
1685                         /*
1686                          * MCDI page 3 should be used to access upper
1687                          * page 0 (0x80 - 0xff) at the device address 0xA2.
1688                          */
1689                         mcdi_upper_page = 3;
1690                         break;
1691                 default:
1692                         rc = ENOTSUP;
1693                         goto fail1;
1694                 }
1695                 break;
1696         case EFX_PHY_MEDIA_QSFP_PLUS:
1697                 switch (dev_addr) {
1698                 case EFX_PHY_MEDIA_INFO_DEV_ADDR_QSFP:
1699                         /*
1700                          * MCDI page -1 should be used to access lower page 0
1701                          * (0x00 - 0x7f).
1702                          */
1703                         mcdi_lower_page = (uint32_t)-1;
1704                         /*
1705                          * MCDI page 0 should be used to access upper page 0
1706                          * (0x80h - 0xff).
1707                          */
1708                         mcdi_upper_page = 0;
1709                         break;
1710                 default:
1711                         rc = ENOTSUP;
1712                         goto fail1;
1713                 }
1714                 break;
1715         default:
1716                 rc = ENOTSUP;
1717                 goto fail1;
1718         }
1719
1720         if (offset < EFX_PHY_MEDIA_INFO_PAGE_SIZE) {
1721                 uint8_t read_len =
1722                     MIN(len, EFX_PHY_MEDIA_INFO_PAGE_SIZE - offset);
1723
1724                 rc = efx_mcdi_get_phy_media_info(enp,
1725                     mcdi_lower_page, offset, read_len, data);
1726                 if (rc != 0)
1727                         goto fail2;
1728
1729                 data += read_len;
1730                 len -= read_len;
1731
1732                 offset = 0;
1733         } else {
1734                 offset -= EFX_PHY_MEDIA_INFO_PAGE_SIZE;
1735         }
1736
1737         if (len > 0) {
1738                 EFSYS_ASSERT3U(len, <=, EFX_PHY_MEDIA_INFO_PAGE_SIZE);
1739                 EFSYS_ASSERT3U(offset, <, EFX_PHY_MEDIA_INFO_PAGE_SIZE);
1740
1741                 rc = efx_mcdi_get_phy_media_info(enp,
1742                     mcdi_upper_page, offset, len, data);
1743                 if (rc != 0)
1744                         goto fail3;
1745         }
1746
1747         return (0);
1748
1749 fail3:
1750         EFSYS_PROBE(fail3);
1751 fail2:
1752         EFSYS_PROBE(fail2);
1753 fail1:
1754         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1755
1756         return (rc);
1757 }
1758
1759 #endif  /* EFSYS_OPT_MCDI */