1 /* 2 * Copyright (c) 2009-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 <sys/types.h> 32 #include <sys/kmem.h> 33 #include "sfxge.h" 34 35 36 static int 37 sfxge_vpd_get_keyword(sfxge_t *sp, sfxge_vpd_ioc_t *svip) 38 { 39 efx_nic_t *enp = sp->s_enp; 40 efx_vpd_value_t vpd; 41 size_t size; 42 void *buf; 43 int rc; 44 45 if ((rc = efx_vpd_size(enp, &size)) != 0) 46 goto fail1; 47 48 buf = kmem_zalloc(size, KM_NOSLEEP); 49 if (buf == NULL) { 50 rc = ENOMEM; 51 goto fail1; 52 } 53 54 if ((rc = efx_vpd_read(enp, buf, size)) != 0) 55 goto fail2; 56 57 if ((rc = efx_vpd_verify(enp, buf, size)) != 0) 58 goto fail3; 59 60 vpd.evv_tag = svip->svi_tag; 61 vpd.evv_keyword = svip->svi_keyword; 62 63 if ((rc = efx_vpd_get(enp, buf, size, &vpd)) != 0) 64 goto fail4; 65 66 svip->svi_len = vpd.evv_length; 67 EFX_STATIC_ASSERT(sizeof (svip->svi_payload) == sizeof (vpd.evv_value)); 68 bcopy(&vpd.evv_value[0], svip->svi_payload, sizeof (svip->svi_payload)); 69 70 kmem_free(buf, size); 71 72 return (0); 73 74 fail4: 75 DTRACE_PROBE(fail4); 76 fail3: 77 DTRACE_PROBE(fail3); 78 fail2: 79 DTRACE_PROBE(fail2); 80 kmem_free(buf, size); 81 fail1: 82 DTRACE_PROBE1(fail1, int, rc); 83 84 return (rc); 85 } 86 87 88 static int 89 sfxge_vpd_set_keyword(sfxge_t *sp, sfxge_vpd_ioc_t *svip) 90 { 91 efx_nic_t *enp = sp->s_enp; 92 efx_vpd_value_t vpd; 93 size_t size; 94 void *buf; 95 int rc; 96 97 /* restriction on writable tags is in efx_vpd_hunk_set() */ 98 99 if ((rc = efx_vpd_size(enp, &size)) != 0) 100 goto fail1; 101 102 buf = kmem_zalloc(size, KM_NOSLEEP); 103 if (buf == NULL) { 104 rc = ENOMEM; 105 goto fail1; 106 } 107 108 if ((rc = efx_vpd_read(enp, buf, size)) != 0) 109 goto fail2; 110 111 if ((rc = efx_vpd_verify(enp, buf, size)) != 0) { 112 if ((rc = efx_vpd_reinit(enp, buf, size)) != 0) 113 goto fail3; 114 if ((rc = efx_vpd_verify(enp, buf, size)) != 0) 115 goto fail4; 116 } 117 118 vpd.evv_tag = svip->svi_tag; 119 vpd.evv_keyword = svip->svi_keyword; 120 vpd.evv_length = svip->svi_len; 121 122 EFX_STATIC_ASSERT(sizeof (svip->svi_payload) == sizeof (vpd.evv_value)); 123 bcopy(svip->svi_payload, &vpd.evv_value[0], sizeof (svip->svi_payload)); 124 125 if ((rc = efx_vpd_set(enp, buf, size, &vpd)) != 0) 126 goto fail5; 127 128 if ((rc = efx_vpd_verify(enp, buf, size)) != 0) 129 goto fail6; 130 131 /* And write the VPD back to the hardware */ 132 if ((rc = efx_vpd_write(enp, buf, size)) != 0) 133 goto fail7; 134 135 kmem_free(buf, size); 136 137 return (0); 138 139 fail7: 140 DTRACE_PROBE(fail7); 141 fail6: 142 DTRACE_PROBE(fail6); 143 fail5: 144 DTRACE_PROBE(fail5); 145 fail4: 146 DTRACE_PROBE(fail4); 147 fail3: 148 DTRACE_PROBE(fail3); 149 fail2: 150 DTRACE_PROBE(fail2); 151 kmem_free(buf, size); 152 fail1: 153 DTRACE_PROBE1(fail1, int, rc); 154 155 return (rc); 156 } 157 158 159 int 160 sfxge_vpd_ioctl(sfxge_t *sp, sfxge_vpd_ioc_t *svip) 161 { 162 int rc; 163 164 switch (svip->svi_op) { 165 case SFXGE_VPD_OP_GET_KEYWORD: 166 if ((rc = sfxge_vpd_get_keyword(sp, svip)) != 0) 167 goto fail1; 168 break; 169 case SFXGE_VPD_OP_SET_KEYWORD: 170 if ((rc = sfxge_vpd_set_keyword(sp, svip)) != 0) 171 goto fail1; 172 break; 173 default: 174 rc = EINVAL; 175 goto fail2; 176 } 177 178 return (0); 179 180 fail2: 181 DTRACE_PROBE(fail2); 182 fail1: 183 DTRACE_PROBE1(fail1, int, rc); 184 185 return (rc); 186 }