xref: /freebsd/sys/dev/smartpqi/smartpqi_helper.c (revision ae41709ab46305df80f7f35bb478a3c8ebf22ebb)
1 /*-
2  * Copyright (c) 2018 Microsemi Corporation.
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
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 /* $FreeBSD$ */
28 
29 #include "smartpqi_includes.h"
30 
31 /*
32  * Function used to validate the adapter health.
33  */
34 boolean_t pqisrc_ctrl_offline(pqisrc_softstate_t *softs)
35 {
36 	DBG_FUNC("IN\n");
37 
38 	DBG_FUNC("OUT\n");
39 
40 	return !softs->ctrl_online;
41 }
42 
43 /* Function used set/clear legacy INTx bit in Legacy Interrupt INTx
44  * mask clear pqi register
45  */
46 void pqisrc_configure_legacy_intx(pqisrc_softstate_t *softs, boolean_t enable_intx)
47 {
48 	uint32_t intx_mask;
49 	uint32_t *reg_addr = NULL;
50 
51 	DBG_FUNC("IN\n");
52 
53 	if (enable_intx)
54 		reg_addr = &softs->pqi_reg->legacy_intr_mask_clr;
55 	else
56 		reg_addr = &softs->pqi_reg->legacy_intr_mask_set;
57 
58 	intx_mask = PCI_MEM_GET32(softs, reg_addr, PQI_LEGACY_INTR_MASK_CLR);
59 	intx_mask |= PQISRC_LEGACY_INTX_MASK;
60 	PCI_MEM_PUT32(softs, reg_addr, PQI_LEGACY_INTR_MASK_CLR ,intx_mask);
61 
62 	DBG_FUNC("OUT\n");
63 }
64 
65 /*
66  * Function used to take exposed devices to OS as offline.
67  */
68 void pqisrc_take_devices_offline(pqisrc_softstate_t *softs)
69 {
70 	pqi_scsi_dev_t *device = NULL;
71 	int i,j;
72 
73 	DBG_FUNC("IN\n");
74 	for(i = 0; i < PQI_MAX_DEVICES; i++) {
75 		for(j = 0; j < PQI_MAX_MULTILUN; j++) {
76 			if(softs->device_list[i][j] == NULL)
77 				continue;
78 			device = softs->device_list[i][j];
79 			pqisrc_remove_device(softs, device);
80 		}
81 	}
82 
83 	DBG_FUNC("OUT\n");
84 }
85 
86 /*
87  * Function used to take adapter offline.
88  */
89 void pqisrc_take_ctrl_offline(pqisrc_softstate_t *softs)
90 {
91 
92 	DBG_FUNC("IN\n");
93 
94 	softs->ctrl_online = false;
95 	pqisrc_trigger_nmi_sis(softs);
96 	os_complete_outstanding_cmds_nodevice(softs);
97 	pqisrc_take_devices_offline(softs);
98 
99 	DBG_FUNC("OUT\n");
100 }
101 
102 /*
103  * Timer handler for the adapter heart-beat.
104  */
105 void pqisrc_heartbeat_timer_handler(pqisrc_softstate_t *softs)
106 {
107 	uint64_t num_intrs;
108 	uint8_t take_offline = false;
109 
110 	DBG_FUNC("IN\n");
111 
112 	num_intrs = OS_ATOMIC64_READ(softs, num_intrs);
113 
114 	if (PQI_NEW_HEARTBEAT_MECHANISM(softs)) {
115 		if (CTRLR_HEARTBEAT_CNT(softs) == softs->prev_heartbeat_count) {
116 			take_offline = true;
117 			goto take_ctrl_offline;
118 		}
119 		softs->prev_heartbeat_count = CTRLR_HEARTBEAT_CNT(softs);
120 		DBG_INFO("CTRLR_HEARTBEAT_CNT(softs)  = %lx \
121 		softs->prev_heartbeat_count = %lx\n",
122 		CTRLR_HEARTBEAT_CNT(softs), softs->prev_heartbeat_count);
123 	} else {
124 		if (num_intrs == softs->prev_num_intrs) {
125 			softs->num_heartbeats_requested++;
126 			if (softs->num_heartbeats_requested > PQI_MAX_HEARTBEAT_REQUESTS) {
127 				take_offline = true;
128 				goto take_ctrl_offline;
129 			}
130 			softs->pending_events[PQI_EVENT_HEARTBEAT].pending = true;
131 
132 			pqisrc_ack_all_events((void*)softs);
133 
134 		} else {
135 			softs->num_heartbeats_requested = 0;
136 		}
137 		softs->prev_num_intrs = num_intrs;
138 	}
139 
140 take_ctrl_offline:
141 	if (take_offline){
142 		DBG_ERR("controller is offline\n");
143 		pqisrc_take_ctrl_offline(softs);
144 		os_stop_heartbeat_timer(softs);
145 	}
146 	DBG_FUNC("OUT\n");
147 }
148 
149 /*
150  * Conditional variable management routine for internal commands.
151  */
152 int pqisrc_wait_on_condition(pqisrc_softstate_t *softs, rcb_t *rcb){
153 	DBG_FUNC("IN\n");
154 
155 	int ret = PQI_STATUS_SUCCESS;
156 	uint32_t loop_cnt = 0;
157 
158 	while (rcb->req_pending == true) {
159 		OS_SLEEP(500); /* Micro sec */
160 
161 		/*Polling needed for FreeBSD : since ithread routine is not scheduled
162                 during bootup, we could use polling until interrupts are
163                 enabled (using 'if (cold)'to check for the boot time before
164                 interrupts are enabled). */
165 		IS_POLLING_REQUIRED(softs);
166 
167 		if (loop_cnt++ == PQISRC_CMD_TIMEOUT_CNT) {
168 			DBG_ERR("ERR: Requested cmd timed out !!!\n");
169 			ret = PQI_STATUS_TIMEOUT;
170 			break;
171 		}
172 
173 		if (pqisrc_ctrl_offline(softs)) {
174 			DBG_ERR("Controller is Offline");
175 			ret = PQI_STATUS_FAILURE;
176 			break;
177 		}
178 	}
179 	rcb->req_pending = true;
180 
181 	DBG_FUNC("OUT\n");
182 
183 	return ret;
184 }
185 
186 /* Function used to validate the device wwid. */
187 boolean_t pqisrc_device_equal(pqi_scsi_dev_t *dev1,
188 	pqi_scsi_dev_t *dev2)
189 {
190 	return dev1->wwid == dev2->wwid;
191 }
192 
193 /* Function used to validate the device scsi3addr. */
194 boolean_t pqisrc_scsi3addr_equal(uint8_t *scsi3addr1, uint8_t *scsi3addr2)
195 {
196 	return memcmp(scsi3addr1, scsi3addr2, 8) == 0;
197 }
198 
199 /* Function used to validate hba_lunid */
200 boolean_t pqisrc_is_hba_lunid(uint8_t *scsi3addr)
201 {
202 	return pqisrc_scsi3addr_equal(scsi3addr, (uint8_t*)RAID_CTLR_LUNID);
203 }
204 
205 /* Function used to validate type of device */
206 boolean_t pqisrc_is_logical_device(pqi_scsi_dev_t *device)
207 {
208 	return !device->is_physical_device;
209 }
210 
211 /* Function used to sanitize inquiry string */
212 void pqisrc_sanitize_inquiry_string(unsigned char *s, int len)
213 {
214 	boolean_t terminated = false;
215 
216 	DBG_FUNC("IN\n");
217 
218 	for (; len > 0; (--len, ++s)) {
219 		if (*s == 0)
220 			terminated = true;
221 		if (terminated || *s < 0x20 || *s > 0x7e)
222 			*s = ' ';
223 	}
224 
225 	DBG_FUNC("OUT\n");
226 }
227 
228 static char *raid_levels[] = {
229 	"RAID 0",
230 	"RAID 4",
231 	"RAID 1(1+0)",
232 	"RAID 5",
233 	"RAID 5+1",
234 	"RAID ADG",
235 	"RAID 1(ADM)",
236 };
237 
238 /* Get the RAID level from the index */
239 char *pqisrc_raidlevel_to_string(uint8_t raid_level)
240 {
241 	DBG_FUNC("IN\n");
242 	if (raid_level < ARRAY_SIZE(raid_levels))
243 		return raid_levels[raid_level];
244 	DBG_FUNC("OUT\n");
245 
246 	return " ";
247 }
248 
249 /* Debug routine for displaying device info */
250 void pqisrc_display_device_info(pqisrc_softstate_t *softs,
251 	char *action, pqi_scsi_dev_t *device)
252 {
253 	DBG_INFO( "%s scsi BTL %d:%d:%d:  %.8s %.16s %-12s SSDSmartPathCap%c En%c Exp%c qd=%d\n",
254 		action,
255 		device->bus,
256 		device->target,
257 		device->lun,
258 		device->vendor,
259 		device->model,
260 		pqisrc_raidlevel_to_string(device->raid_level),
261 		device->offload_config ? '+' : '-',
262 		device->offload_enabled_pending ? '+' : '-',
263 		device->expose_device ? '+' : '-',
264 		device->queue_depth);
265 	pqisrc_raidlevel_to_string(device->raid_level); /* To use this function */
266 }
267 
268 /* validate the structure sizes */
269 void check_struct_sizes()
270 {
271 
272     ASSERT(sizeof(SCSI3Addr_struct)== 2);
273     ASSERT(sizeof(PhysDevAddr_struct) == 8);
274     ASSERT(sizeof(LogDevAddr_struct)== 8);
275     ASSERT(sizeof(LUNAddr_struct)==8);
276     ASSERT(sizeof(RequestBlock_struct) == 20);
277     ASSERT(sizeof(MoreErrInfo_struct)== 8);
278     ASSERT(sizeof(ErrorInfo_struct)== 48);
279     ASSERT(sizeof(IOCTL_Command_struct)== 86);
280     ASSERT(sizeof(struct bmic_host_wellness_driver_version)== 42);
281     ASSERT(sizeof(struct bmic_host_wellness_time)== 20);
282     ASSERT(sizeof(struct pqi_dev_adminq_cap)== 8);
283     ASSERT(sizeof(struct admin_q_param)== 4);
284     ASSERT(sizeof(struct pqi_registers)== 256);
285     ASSERT(sizeof(struct ioa_registers)== 4128);
286     ASSERT(sizeof(struct pqi_pref_settings)==4);
287     ASSERT(sizeof(struct pqi_cap)== 20);
288     ASSERT(sizeof(iu_header_t)== 4);
289     ASSERT(sizeof(gen_adm_req_iu_t)== 64);
290     ASSERT(sizeof(gen_adm_resp_iu_t)== 64);
291     ASSERT(sizeof(op_q_params) == 9);
292     ASSERT(sizeof(raid_path_error_info_elem_t)== 276);
293     ASSERT(sizeof(aio_path_error_info_elem_t)== 276);
294     ASSERT(sizeof(struct init_base_struct)== 24);
295     ASSERT(sizeof(pqi_iu_layer_desc_t)== 16);
296     ASSERT(sizeof(pqi_dev_cap_t)== 576);
297     ASSERT(sizeof(pqi_aio_req_t)== 128);
298     ASSERT(sizeof(pqisrc_raid_req_t)== 128);
299     ASSERT(sizeof(pqi_tmf_req_t)== 32);
300     ASSERT(sizeof(struct pqi_io_response)== 16);
301     ASSERT(sizeof(struct sense_header_scsi)== 8);
302     ASSERT(sizeof(reportlun_header_t)==8);
303     ASSERT(sizeof(reportlun_ext_entry_t)== 24);
304     ASSERT(sizeof(reportlun_data_ext_t)== 32);
305     ASSERT(sizeof(raidmap_data_t)==8);
306     ASSERT(sizeof(pqisrc_raid_map_t)== 8256);
307     ASSERT(sizeof(bmic_ident_ctrl_t)== 325);
308     ASSERT(sizeof(bmic_ident_physdev_t)==2048);
309 
310 }
311