11e66f787SSean Bruno /*-
2*7ea28254SJohn Hall * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries.
31e66f787SSean Bruno *
41e66f787SSean Bruno * Redistribution and use in source and binary forms, with or without
51e66f787SSean Bruno * modification, are permitted provided that the following conditions
61e66f787SSean Bruno * are met:
71e66f787SSean Bruno * 1. Redistributions of source code must retain the above copyright
81e66f787SSean Bruno * notice, this list of conditions and the following disclaimer.
91e66f787SSean Bruno * 2. Redistributions in binary form must reproduce the above copyright
101e66f787SSean Bruno * notice, this list of conditions and the following disclaimer in the
111e66f787SSean Bruno * documentation and/or other materials provided with the distribution.
121e66f787SSean Bruno *
131e66f787SSean Bruno * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
141e66f787SSean Bruno * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
151e66f787SSean Bruno * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
161e66f787SSean Bruno * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
171e66f787SSean Bruno * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
181e66f787SSean Bruno * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
191e66f787SSean Bruno * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
201e66f787SSean Bruno * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
211e66f787SSean Bruno * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
221e66f787SSean Bruno * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
231e66f787SSean Bruno * SUCH DAMAGE.
241e66f787SSean Bruno */
251e66f787SSean Bruno
261e66f787SSean Bruno
271e66f787SSean Bruno #include "smartpqi_includes.h"
281e66f787SSean Bruno
291e66f787SSean Bruno /*
30*7ea28254SJohn Hall * Populate hostwellness time variables in bcd format from FreeBSD format.
311e66f787SSean Bruno */
329fac68fcSPAPANI SRIKANTH void
os_get_time(struct bmic_host_wellness_time * host_wellness_time)339fac68fcSPAPANI SRIKANTH os_get_time(struct bmic_host_wellness_time *host_wellness_time)
341e66f787SSean Bruno {
351e66f787SSean Bruno struct timespec ts;
36*7ea28254SJohn Hall struct clocktime ct = {0};
371e66f787SSean Bruno
381e66f787SSean Bruno getnanotime(&ts);
391e66f787SSean Bruno clock_ts_to_ct(&ts, &ct);
401e66f787SSean Bruno
411e66f787SSean Bruno /* Fill the time In BCD Format */
421e66f787SSean Bruno host_wellness_time->hour= (uint8_t)bin2bcd(ct.hour);
431e66f787SSean Bruno host_wellness_time->min = (uint8_t)bin2bcd(ct.min);
441e66f787SSean Bruno host_wellness_time->sec= (uint8_t)bin2bcd(ct.sec);
451e66f787SSean Bruno host_wellness_time->reserved = 0;
461e66f787SSean Bruno host_wellness_time->month = (uint8_t)bin2bcd(ct.mon);
471e66f787SSean Bruno host_wellness_time->day = (uint8_t)bin2bcd(ct.day);
481e66f787SSean Bruno host_wellness_time->century = (uint8_t)bin2bcd(ct.year / 100);
491e66f787SSean Bruno host_wellness_time->year = (uint8_t)bin2bcd(ct.year % 100);
501e66f787SSean Bruno
511e66f787SSean Bruno }
521e66f787SSean Bruno
531e66f787SSean Bruno /*
541e66f787SSean Bruno * Update host time to f/w every 24 hours in a periodic timer.
551e66f787SSean Bruno */
561e66f787SSean Bruno
579fac68fcSPAPANI SRIKANTH void
os_wellness_periodic(void * data)589fac68fcSPAPANI SRIKANTH os_wellness_periodic(void *data)
591e66f787SSean Bruno {
601e66f787SSean Bruno struct pqisrc_softstate *softs = (struct pqisrc_softstate *)data;
611e66f787SSean Bruno int ret = 0;
621e66f787SSean Bruno
631e66f787SSean Bruno /* update time to FW */
641e66f787SSean Bruno if (!pqisrc_ctrl_offline(softs)){
651e66f787SSean Bruno if( (ret = pqisrc_write_current_time_to_host_wellness(softs)) != 0 )
661e66f787SSean Bruno DBG_ERR("Failed to update time to FW in periodic ret = %d\n", ret);
671e66f787SSean Bruno }
681e66f787SSean Bruno
691e66f787SSean Bruno /* reschedule ourselves */
709fac68fcSPAPANI SRIKANTH callout_reset(&softs->os_specific.wellness_periodic,
719fac68fcSPAPANI SRIKANTH PQI_HOST_WELLNESS_TIMEOUT_SEC * hz, os_wellness_periodic, softs);
721e66f787SSean Bruno }
731e66f787SSean Bruno
741e66f787SSean Bruno /*
751e66f787SSean Bruno * Routine used to stop the heart-beat timer
761e66f787SSean Bruno */
779fac68fcSPAPANI SRIKANTH void
os_stop_heartbeat_timer(pqisrc_softstate_t * softs)789fac68fcSPAPANI SRIKANTH os_stop_heartbeat_timer(pqisrc_softstate_t *softs)
791e66f787SSean Bruno {
801e66f787SSean Bruno DBG_FUNC("IN\n");
811e66f787SSean Bruno
821e66f787SSean Bruno /* Kill the heart beat event */
839358ccebSJohn Baldwin callout_stop(&softs->os_specific.heartbeat_timeout_id);
841e66f787SSean Bruno
851e66f787SSean Bruno DBG_FUNC("OUT\n");
861e66f787SSean Bruno }
871e66f787SSean Bruno
881e66f787SSean Bruno /*
891e66f787SSean Bruno * Routine used to start the heart-beat timer
901e66f787SSean Bruno */
919fac68fcSPAPANI SRIKANTH void
os_start_heartbeat_timer(void * data)929fac68fcSPAPANI SRIKANTH os_start_heartbeat_timer(void *data)
931e66f787SSean Bruno {
941e66f787SSean Bruno struct pqisrc_softstate *softs = (struct pqisrc_softstate *)data;
951e66f787SSean Bruno DBG_FUNC("IN\n");
961e66f787SSean Bruno
971e66f787SSean Bruno pqisrc_heartbeat_timer_handler(softs);
981e66f787SSean Bruno if (!pqisrc_ctrl_offline(softs)) {
999358ccebSJohn Baldwin callout_reset(&softs->os_specific.heartbeat_timeout_id,
1009fac68fcSPAPANI SRIKANTH PQI_HEARTBEAT_TIMEOUT_SEC * hz,
1019358ccebSJohn Baldwin os_start_heartbeat_timer, softs);
1021e66f787SSean Bruno }
1031e66f787SSean Bruno
1041e66f787SSean Bruno DBG_FUNC("OUT\n");
1051e66f787SSean Bruno }
1061e66f787SSean Bruno
1071e66f787SSean Bruno /*
1081e66f787SSean Bruno * Mutex initialization function
1091e66f787SSean Bruno */
1109fac68fcSPAPANI SRIKANTH int
os_init_spinlock(struct pqisrc_softstate * softs,struct mtx * lock,char * lockname)1119fac68fcSPAPANI SRIKANTH os_init_spinlock(struct pqisrc_softstate *softs, struct mtx *lock,
1121e66f787SSean Bruno char *lockname)
1131e66f787SSean Bruno {
1141e66f787SSean Bruno mtx_init(lock, lockname, NULL, MTX_SPIN);
1151e66f787SSean Bruno return 0;
116*7ea28254SJohn Hall
1171e66f787SSean Bruno }
1181e66f787SSean Bruno
1191e66f787SSean Bruno /*
1201e66f787SSean Bruno * Mutex uninitialization function
1211e66f787SSean Bruno */
1229fac68fcSPAPANI SRIKANTH void
os_uninit_spinlock(struct mtx * lock)1239fac68fcSPAPANI SRIKANTH os_uninit_spinlock(struct mtx *lock)
1241e66f787SSean Bruno {
1251e66f787SSean Bruno mtx_destroy(lock);
1261e66f787SSean Bruno return;
1271e66f787SSean Bruno }
1281e66f787SSean Bruno
1291e66f787SSean Bruno /*
1301e66f787SSean Bruno * Semaphore initialization function
1311e66f787SSean Bruno */
1329fac68fcSPAPANI SRIKANTH int
os_create_semaphore(const char * name,int value,struct sema * sema)1339fac68fcSPAPANI SRIKANTH os_create_semaphore(const char *name, int value, struct sema *sema)
1341e66f787SSean Bruno {
1351e66f787SSean Bruno sema_init(sema, value, name);
1361e66f787SSean Bruno return PQI_STATUS_SUCCESS;
1371e66f787SSean Bruno }
1381e66f787SSean Bruno
1391e66f787SSean Bruno /*
1401e66f787SSean Bruno * Semaphore uninitialization function
1411e66f787SSean Bruno */
1429fac68fcSPAPANI SRIKANTH int
os_destroy_semaphore(struct sema * sema)1439fac68fcSPAPANI SRIKANTH os_destroy_semaphore(struct sema *sema)
1441e66f787SSean Bruno {
1451e66f787SSean Bruno sema_destroy(sema);
1461e66f787SSean Bruno return PQI_STATUS_SUCCESS;
1471e66f787SSean Bruno }
1481e66f787SSean Bruno
1491e66f787SSean Bruno /*
1501e66f787SSean Bruno * Semaphore grab function
1511e66f787SSean Bruno */
1529fac68fcSPAPANI SRIKANTH void inline
os_sema_lock(struct sema * sema)1539fac68fcSPAPANI SRIKANTH os_sema_lock(struct sema *sema)
1541e66f787SSean Bruno {
1551e66f787SSean Bruno sema_post(sema);
1561e66f787SSean Bruno }
1571e66f787SSean Bruno
1581e66f787SSean Bruno /*
1591e66f787SSean Bruno * Semaphore release function
1601e66f787SSean Bruno */
1619fac68fcSPAPANI SRIKANTH void inline
os_sema_unlock(struct sema * sema)1629fac68fcSPAPANI SRIKANTH os_sema_unlock(struct sema *sema)
1631e66f787SSean Bruno {
1641e66f787SSean Bruno sema_wait(sema);
1651e66f787SSean Bruno }
1661e66f787SSean Bruno
1671e66f787SSean Bruno /*
1681e66f787SSean Bruno * string copy wrapper function
1691e66f787SSean Bruno */
1709fac68fcSPAPANI SRIKANTH int
os_strlcpy(char * dst,char * src,int size)1719fac68fcSPAPANI SRIKANTH os_strlcpy(char *dst, char *src, int size)
1721e66f787SSean Bruno {
1731e66f787SSean Bruno return strlcpy(dst, src, size);
1741e66f787SSean Bruno }
1759fac68fcSPAPANI SRIKANTH
1769fac68fcSPAPANI SRIKANTH int
bsd_status_to_pqi_status(int bsd_status)1779fac68fcSPAPANI SRIKANTH bsd_status_to_pqi_status(int bsd_status)
1789fac68fcSPAPANI SRIKANTH {
1799fac68fcSPAPANI SRIKANTH if (bsd_status == BSD_SUCCESS)
1809fac68fcSPAPANI SRIKANTH return PQI_STATUS_SUCCESS;
1819fac68fcSPAPANI SRIKANTH else
1829fac68fcSPAPANI SRIKANTH return PQI_STATUS_FAILURE;
1839fac68fcSPAPANI SRIKANTH }
184*7ea28254SJohn Hall
185*7ea28254SJohn Hall /* Return true : If the feature is disabled from device hints.
186*7ea28254SJohn Hall * Return false : If the feature is enabled from device hints.
187*7ea28254SJohn Hall * Return default: The feature status is not deciding from hints.
188*7ea28254SJohn Hall * */
189*7ea28254SJohn Hall boolean_t
check_device_hint_status(struct pqisrc_softstate * softs,unsigned int feature_bit)190*7ea28254SJohn Hall check_device_hint_status(struct pqisrc_softstate *softs, unsigned int feature_bit)
191*7ea28254SJohn Hall {
192*7ea28254SJohn Hall DBG_FUNC("IN\n");
193*7ea28254SJohn Hall
194*7ea28254SJohn Hall switch(feature_bit) {
195*7ea28254SJohn Hall case PQI_FIRMWARE_FEATURE_RAID_1_WRITE_BYPASS:
196*7ea28254SJohn Hall if (!softs->hint.aio_raid1_write_status)
197*7ea28254SJohn Hall return true;
198*7ea28254SJohn Hall break;
199*7ea28254SJohn Hall case PQI_FIRMWARE_FEATURE_RAID_5_WRITE_BYPASS:
200*7ea28254SJohn Hall if (!softs->hint.aio_raid5_write_status)
201*7ea28254SJohn Hall return true;
202*7ea28254SJohn Hall break;
203*7ea28254SJohn Hall case PQI_FIRMWARE_FEATURE_RAID_6_WRITE_BYPASS:
204*7ea28254SJohn Hall if (!softs->hint.aio_raid6_write_status)
205*7ea28254SJohn Hall return true;
206*7ea28254SJohn Hall break;
207*7ea28254SJohn Hall case PQI_FIRMWARE_FEATURE_UNIQUE_SATA_WWN:
208*7ea28254SJohn Hall if (!softs->hint.sata_unique_wwn_status)
209*7ea28254SJohn Hall return true;
210*7ea28254SJohn Hall break;
211*7ea28254SJohn Hall default:
212*7ea28254SJohn Hall return false;
213*7ea28254SJohn Hall }
214*7ea28254SJohn Hall
215*7ea28254SJohn Hall DBG_FUNC("OUT\n");
216*7ea28254SJohn Hall
217*7ea28254SJohn Hall return false;
218*7ea28254SJohn Hall }
219*7ea28254SJohn Hall
220*7ea28254SJohn Hall static void
bsd_set_hint_adapter_queue_depth(struct pqisrc_softstate * softs)221*7ea28254SJohn Hall bsd_set_hint_adapter_queue_depth(struct pqisrc_softstate *softs)
222*7ea28254SJohn Hall {
223*7ea28254SJohn Hall uint32_t queue_depth = softs->pqi_cap.max_outstanding_io;
224*7ea28254SJohn Hall
225*7ea28254SJohn Hall DBG_FUNC("IN\n");
226*7ea28254SJohn Hall
227*7ea28254SJohn Hall if ((!softs->hint.queue_depth) || (softs->hint.queue_depth >
228*7ea28254SJohn Hall softs->pqi_cap.max_outstanding_io)) {
229*7ea28254SJohn Hall /* Nothing to do here. Supported queue depth
230*7ea28254SJohn Hall * is already set by controller/driver */
231*7ea28254SJohn Hall }
232*7ea28254SJohn Hall else if (softs->hint.queue_depth < PQISRC_MIN_OUTSTANDING_REQ) {
233*7ea28254SJohn Hall /* Nothing to do here. Supported queue depth
234*7ea28254SJohn Hall * is already set by controller/driver */
235*7ea28254SJohn Hall }
236*7ea28254SJohn Hall else {
237*7ea28254SJohn Hall /* Set Device.Hint queue depth here */
238*7ea28254SJohn Hall softs->pqi_cap.max_outstanding_io =
239*7ea28254SJohn Hall softs->hint.queue_depth;
240*7ea28254SJohn Hall }
241*7ea28254SJohn Hall
242*7ea28254SJohn Hall DBG_NOTE("Adapter queue depth before hint set = %u, Queue depth after hint set = %u\n",
243*7ea28254SJohn Hall queue_depth, softs->pqi_cap.max_outstanding_io);
244*7ea28254SJohn Hall
245*7ea28254SJohn Hall DBG_FUNC("OUT\n");
246*7ea28254SJohn Hall }
247*7ea28254SJohn Hall
248*7ea28254SJohn Hall static void
bsd_set_hint_scatter_gather_config(struct pqisrc_softstate * softs)249*7ea28254SJohn Hall bsd_set_hint_scatter_gather_config(struct pqisrc_softstate *softs)
250*7ea28254SJohn Hall {
251*7ea28254SJohn Hall uint32_t pqi_sg_segments = softs->pqi_cap.max_sg_elem;
252*7ea28254SJohn Hall
253*7ea28254SJohn Hall DBG_FUNC("IN\n");
254*7ea28254SJohn Hall
255*7ea28254SJohn Hall /* At least > 16 sg's required to wotk hint correctly.
256*7ea28254SJohn Hall * Default the sg count set by driver/controller. */
257*7ea28254SJohn Hall
258*7ea28254SJohn Hall if ((!softs->hint.sg_segments) || (softs->hint.sg_segments >
259*7ea28254SJohn Hall softs->pqi_cap.max_sg_elem)) {
260*7ea28254SJohn Hall /* Nothing to do here. Supported sg count
261*7ea28254SJohn Hall * is already set by controller/driver. */
262*7ea28254SJohn Hall }
263*7ea28254SJohn Hall else if (softs->hint.sg_segments < BSD_MIN_SG_SEGMENTS)
264*7ea28254SJohn Hall {
265*7ea28254SJohn Hall /* Nothing to do here. Supported sg count
266*7ea28254SJohn Hall * is already set by controller/driver. */
267*7ea28254SJohn Hall }
268*7ea28254SJohn Hall else {
269*7ea28254SJohn Hall /* Set Device.Hint sg count here */
270*7ea28254SJohn Hall softs->pqi_cap.max_sg_elem = softs->hint.sg_segments;
271*7ea28254SJohn Hall }
272*7ea28254SJohn Hall
273*7ea28254SJohn Hall DBG_NOTE("SG segments before hint set = %u, SG segments after hint set = %u\n",
274*7ea28254SJohn Hall pqi_sg_segments, softs->pqi_cap.max_sg_elem);
275*7ea28254SJohn Hall
276*7ea28254SJohn Hall DBG_FUNC("OUT\n");
277*7ea28254SJohn Hall }
278*7ea28254SJohn Hall
279*7ea28254SJohn Hall void
bsd_set_hint_adapter_cap(struct pqisrc_softstate * softs)280*7ea28254SJohn Hall bsd_set_hint_adapter_cap(struct pqisrc_softstate *softs)
281*7ea28254SJohn Hall {
282*7ea28254SJohn Hall DBG_FUNC("IN\n");
283*7ea28254SJohn Hall
284*7ea28254SJohn Hall bsd_set_hint_adapter_queue_depth(softs);
285*7ea28254SJohn Hall bsd_set_hint_scatter_gather_config(softs);
286*7ea28254SJohn Hall
287*7ea28254SJohn Hall DBG_FUNC("OUT\n");
288*7ea28254SJohn Hall }
289*7ea28254SJohn Hall
290*7ea28254SJohn Hall void
bsd_set_hint_adapter_cpu_config(struct pqisrc_softstate * softs)291*7ea28254SJohn Hall bsd_set_hint_adapter_cpu_config(struct pqisrc_softstate *softs)
292*7ea28254SJohn Hall {
293*7ea28254SJohn Hall DBG_FUNC("IN\n");
294*7ea28254SJohn Hall
295*7ea28254SJohn Hall /* online cpu count decides the no.of queues the driver can create,
296*7ea28254SJohn Hall * and msi interrupt count as well.
297*7ea28254SJohn Hall * If the cpu count is "zero" set by hint file then the driver
298*7ea28254SJohn Hall * can have "one" queue and "one" legacy interrupt. (It shares event queue for
299*7ea28254SJohn Hall * operational IB queue).
300*7ea28254SJohn Hall * Check for os_get_intr_config function for interrupt assignment.*/
301*7ea28254SJohn Hall
302*7ea28254SJohn Hall if (softs->hint.cpu_count > softs->num_cpus_online) {
303*7ea28254SJohn Hall /* Nothing to do here. Supported cpu count
304*7ea28254SJohn Hall * already fetched from hardware */
305*7ea28254SJohn Hall }
306*7ea28254SJohn Hall else {
307*7ea28254SJohn Hall /* Set Device.Hint cpu count here */
308*7ea28254SJohn Hall softs->num_cpus_online = softs->hint.cpu_count;
309*7ea28254SJohn Hall }
310*7ea28254SJohn Hall
311*7ea28254SJohn Hall DBG_FUNC("OUT\n");
312*7ea28254SJohn Hall }
313