1 /*- 2 * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 27 #include "smartpqi_includes.h" 28 29 /* 30 * Populate hostwellness time variables in bcd format from FreeBSD format. 31 */ 32 void 33 os_get_time(struct bmic_host_wellness_time *host_wellness_time) 34 { 35 struct timespec ts; 36 struct clocktime ct = {0}; 37 38 getnanotime(&ts); 39 clock_ts_to_ct(&ts, &ct); 40 41 /* Fill the time In BCD Format */ 42 host_wellness_time->hour= (uint8_t)bin2bcd(ct.hour); 43 host_wellness_time->min = (uint8_t)bin2bcd(ct.min); 44 host_wellness_time->sec= (uint8_t)bin2bcd(ct.sec); 45 host_wellness_time->reserved = 0; 46 host_wellness_time->month = (uint8_t)bin2bcd(ct.mon); 47 host_wellness_time->day = (uint8_t)bin2bcd(ct.day); 48 host_wellness_time->century = (uint8_t)bin2bcd(ct.year / 100); 49 host_wellness_time->year = (uint8_t)bin2bcd(ct.year % 100); 50 51 } 52 53 /* 54 * Update host time to f/w every 24 hours in a periodic timer. 55 */ 56 57 void 58 os_wellness_periodic(void *data) 59 { 60 struct pqisrc_softstate *softs = (struct pqisrc_softstate *)data; 61 int ret = 0; 62 63 /* update time to FW */ 64 if (!pqisrc_ctrl_offline(softs)){ 65 if( (ret = pqisrc_write_current_time_to_host_wellness(softs)) != 0 ) 66 DBG_ERR("Failed to update time to FW in periodic ret = %d\n", ret); 67 } 68 69 /* reschedule ourselves */ 70 callout_reset(&softs->os_specific.wellness_periodic, 71 PQI_HOST_WELLNESS_TIMEOUT_SEC * hz, os_wellness_periodic, softs); 72 } 73 74 /* 75 * Routine used to stop the heart-beat timer 76 */ 77 void 78 os_stop_heartbeat_timer(pqisrc_softstate_t *softs) 79 { 80 DBG_FUNC("IN\n"); 81 82 /* Kill the heart beat event */ 83 callout_stop(&softs->os_specific.heartbeat_timeout_id); 84 85 DBG_FUNC("OUT\n"); 86 } 87 88 /* 89 * Routine used to start the heart-beat timer 90 */ 91 void 92 os_start_heartbeat_timer(void *data) 93 { 94 struct pqisrc_softstate *softs = (struct pqisrc_softstate *)data; 95 DBG_FUNC("IN\n"); 96 97 pqisrc_heartbeat_timer_handler(softs); 98 if (!pqisrc_ctrl_offline(softs)) { 99 callout_reset(&softs->os_specific.heartbeat_timeout_id, 100 PQI_HEARTBEAT_TIMEOUT_SEC * hz, 101 os_start_heartbeat_timer, softs); 102 } 103 104 DBG_FUNC("OUT\n"); 105 } 106 107 /* 108 * Mutex initialization function 109 */ 110 int 111 os_init_spinlock(struct pqisrc_softstate *softs, struct mtx *lock, 112 char *lockname) 113 { 114 mtx_init(lock, lockname, NULL, MTX_SPIN); 115 return 0; 116 117 } 118 119 /* 120 * Mutex uninitialization function 121 */ 122 void 123 os_uninit_spinlock(struct mtx *lock) 124 { 125 mtx_destroy(lock); 126 return; 127 } 128 129 /* 130 * Semaphore initialization function 131 */ 132 int 133 os_create_semaphore(const char *name, int value, struct sema *sema) 134 { 135 sema_init(sema, value, name); 136 return PQI_STATUS_SUCCESS; 137 } 138 139 /* 140 * Semaphore uninitialization function 141 */ 142 int 143 os_destroy_semaphore(struct sema *sema) 144 { 145 sema_destroy(sema); 146 return PQI_STATUS_SUCCESS; 147 } 148 149 /* 150 * Semaphore grab function 151 */ 152 void inline 153 os_sema_lock(struct sema *sema) 154 { 155 sema_post(sema); 156 } 157 158 /* 159 * Semaphore release function 160 */ 161 void inline 162 os_sema_unlock(struct sema *sema) 163 { 164 sema_wait(sema); 165 } 166 167 /* 168 * string copy wrapper function 169 */ 170 int 171 os_strlcpy(char *dst, char *src, int size) 172 { 173 return strlcpy(dst, src, size); 174 } 175 176 int 177 bsd_status_to_pqi_status(int bsd_status) 178 { 179 if (bsd_status == BSD_SUCCESS) 180 return PQI_STATUS_SUCCESS; 181 else 182 return PQI_STATUS_FAILURE; 183 } 184 185 /* Return true : If the feature is disabled from device hints. 186 * Return false : If the feature is enabled from device hints. 187 * Return default: The feature status is not deciding from hints. 188 * */ 189 boolean_t 190 check_device_hint_status(struct pqisrc_softstate *softs, unsigned int feature_bit) 191 { 192 DBG_FUNC("IN\n"); 193 194 switch(feature_bit) { 195 case PQI_FIRMWARE_FEATURE_RAID_1_WRITE_BYPASS: 196 if (!softs->hint.aio_raid1_write_status) 197 return true; 198 break; 199 case PQI_FIRMWARE_FEATURE_RAID_5_WRITE_BYPASS: 200 if (!softs->hint.aio_raid5_write_status) 201 return true; 202 break; 203 case PQI_FIRMWARE_FEATURE_RAID_6_WRITE_BYPASS: 204 if (!softs->hint.aio_raid6_write_status) 205 return true; 206 break; 207 case PQI_FIRMWARE_FEATURE_UNIQUE_SATA_WWN: 208 if (!softs->hint.sata_unique_wwn_status) 209 return true; 210 break; 211 default: 212 return false; 213 } 214 215 DBG_FUNC("OUT\n"); 216 217 return false; 218 } 219 220 static void 221 bsd_set_hint_adapter_queue_depth(struct pqisrc_softstate *softs) 222 { 223 uint32_t queue_depth = softs->pqi_cap.max_outstanding_io; 224 225 DBG_FUNC("IN\n"); 226 227 if ((!softs->hint.queue_depth) || (softs->hint.queue_depth > 228 softs->pqi_cap.max_outstanding_io)) { 229 /* Nothing to do here. Supported queue depth 230 * is already set by controller/driver */ 231 } 232 else if (softs->hint.queue_depth < PQISRC_MIN_OUTSTANDING_REQ) { 233 /* Nothing to do here. Supported queue depth 234 * is already set by controller/driver */ 235 } 236 else { 237 /* Set Device.Hint queue depth here */ 238 softs->pqi_cap.max_outstanding_io = 239 softs->hint.queue_depth; 240 } 241 242 DBG_NOTE("Adapter queue depth before hint set = %u, Queue depth after hint set = %u\n", 243 queue_depth, softs->pqi_cap.max_outstanding_io); 244 245 DBG_FUNC("OUT\n"); 246 } 247 248 static void 249 bsd_set_hint_scatter_gather_config(struct pqisrc_softstate *softs) 250 { 251 uint32_t pqi_sg_segments = softs->pqi_cap.max_sg_elem; 252 253 DBG_FUNC("IN\n"); 254 255 /* At least > 16 sg's required to wotk hint correctly. 256 * Default the sg count set by driver/controller. */ 257 258 if ((!softs->hint.sg_segments) || (softs->hint.sg_segments > 259 softs->pqi_cap.max_sg_elem)) { 260 /* Nothing to do here. Supported sg count 261 * is already set by controller/driver. */ 262 } 263 else if (softs->hint.sg_segments < BSD_MIN_SG_SEGMENTS) 264 { 265 /* Nothing to do here. Supported sg count 266 * is already set by controller/driver. */ 267 } 268 else { 269 /* Set Device.Hint sg count here */ 270 softs->pqi_cap.max_sg_elem = softs->hint.sg_segments; 271 } 272 273 DBG_NOTE("SG segments before hint set = %u, SG segments after hint set = %u\n", 274 pqi_sg_segments, softs->pqi_cap.max_sg_elem); 275 276 DBG_FUNC("OUT\n"); 277 } 278 279 void 280 bsd_set_hint_adapter_cap(struct pqisrc_softstate *softs) 281 { 282 DBG_FUNC("IN\n"); 283 284 bsd_set_hint_adapter_queue_depth(softs); 285 bsd_set_hint_scatter_gather_config(softs); 286 287 DBG_FUNC("OUT\n"); 288 } 289 290 void 291 bsd_set_hint_adapter_cpu_config(struct pqisrc_softstate *softs) 292 { 293 DBG_FUNC("IN\n"); 294 295 /* online cpu count decides the no.of queues the driver can create, 296 * and msi interrupt count as well. 297 * If the cpu count is "zero" set by hint file then the driver 298 * can have "one" queue and "one" legacy interrupt. (It shares event queue for 299 * operational IB queue). 300 * Check for os_get_intr_config function for interrupt assignment.*/ 301 302 if (softs->hint.cpu_count > softs->num_cpus_online) { 303 /* Nothing to do here. Supported cpu count 304 * already fetched from hardware */ 305 } 306 else { 307 /* Set Device.Hint cpu count here */ 308 softs->num_cpus_online = softs->hint.cpu_count; 309 } 310 311 DBG_FUNC("OUT\n"); 312 } 313