xref: /freebsd/sys/dev/smartpqi/smartpqi_helper.c (revision c697fb7f)
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 
154 	DBG_FUNC("IN\n");
155 
156 	int ret = PQI_STATUS_SUCCESS;
157 	uint32_t loop_cnt = 0;
158 
159 	while (rcb->req_pending == true) {
160 		OS_SLEEP(500); /* Micro sec */
161 
162 		/*Polling needed for FreeBSD : since ithread routine is not scheduled
163                 during bootup, we could use polling until interrupts are
164                 enabled (using 'if (cold)'to check for the boot time before
165                 interrupts are enabled). */
166 		IS_POLLING_REQUIRED(softs);
167 
168 		if (loop_cnt++ == PQISRC_CMD_TIMEOUT_CNT) {
169 			DBG_ERR("ERR: Requested cmd timed out !!!\n");
170 			ret = PQI_STATUS_TIMEOUT;
171 			break;
172 		}
173 
174 		if (pqisrc_ctrl_offline(softs)) {
175 			DBG_ERR("Controller is Offline");
176 			ret = PQI_STATUS_FAILURE;
177 			break;
178 		}
179 
180 	}
181 	rcb->req_pending = true;
182 
183 	DBG_FUNC("OUT\n");
184 
185 	return ret;
186 }
187 
188 /* Function used to validate the device wwid. */
189 boolean_t pqisrc_device_equal(pqi_scsi_dev_t *dev1,
190 	pqi_scsi_dev_t *dev2)
191 {
192 	return dev1->wwid == dev2->wwid;
193 }
194 
195 /* Function used to validate the device scsi3addr. */
196 boolean_t pqisrc_scsi3addr_equal(uint8_t *scsi3addr1, uint8_t *scsi3addr2)
197 {
198 	return memcmp(scsi3addr1, scsi3addr2, 8) == 0;
199 }
200 
201 /* Function used to validate hba_lunid */
202 boolean_t pqisrc_is_hba_lunid(uint8_t *scsi3addr)
203 {
204 	return pqisrc_scsi3addr_equal(scsi3addr, (uint8_t*)RAID_CTLR_LUNID);
205 }
206 
207 /* Function used to validate type of device */
208 boolean_t pqisrc_is_logical_device(pqi_scsi_dev_t *device)
209 {
210 	return !device->is_physical_device;
211 }
212 
213 /* Function used to sanitize inquiry string */
214 void pqisrc_sanitize_inquiry_string(unsigned char *s, int len)
215 {
216 	boolean_t terminated = false;
217 
218 	DBG_FUNC("IN\n");
219 
220 	for (; len > 0; (--len, ++s)) {
221 		if (*s == 0)
222 			terminated = true;
223 		if (terminated || *s < 0x20 || *s > 0x7e)
224 			*s = ' ';
225 	}
226 
227 	DBG_FUNC("OUT\n");
228 }
229 
230 static char *raid_levels[] = {
231 	"RAID 0",
232 	"RAID 4",
233 	"RAID 1(1+0)",
234 	"RAID 5",
235 	"RAID 5+1",
236 	"RAID ADG",
237 	"RAID 1(ADM)",
238 };
239 
240 /* Get the RAID level from the index */
241 char *pqisrc_raidlevel_to_string(uint8_t raid_level)
242 {
243 	DBG_FUNC("IN\n");
244 	if (raid_level < ARRAY_SIZE(raid_levels))
245 		return raid_levels[raid_level];
246 	DBG_FUNC("OUT\n");
247 
248 	return " ";
249 }
250 
251 /* Debug routine for displaying device info */
252 void pqisrc_display_device_info(pqisrc_softstate_t *softs,
253 	char *action, pqi_scsi_dev_t *device)
254 {
255 	DBG_INFO( "%s scsi BTL %d:%d:%d:  %.8s %.16s %-12s SSDSmartPathCap%c En%c Exp%c qd=%d\n",
256 		action,
257 		device->bus,
258 		device->target,
259 		device->lun,
260 		device->vendor,
261 		device->model,
262 		pqisrc_raidlevel_to_string(device->raid_level),
263 		device->offload_config ? '+' : '-',
264 		device->offload_enabled_pending ? '+' : '-',
265 		device->expose_device ? '+' : '-',
266 		device->queue_depth);
267 	pqisrc_raidlevel_to_string(device->raid_level); /* To use this function */
268 }
269 
270 /* validate the structure sizes */
271 void check_struct_sizes()
272 {
273 
274     ASSERT(sizeof(SCSI3Addr_struct)== 2);
275     ASSERT(sizeof(PhysDevAddr_struct) == 8);
276     ASSERT(sizeof(LogDevAddr_struct)== 8);
277     ASSERT(sizeof(LUNAddr_struct)==8);
278     ASSERT(sizeof(RequestBlock_struct) == 20);
279     ASSERT(sizeof(MoreErrInfo_struct)== 8);
280     ASSERT(sizeof(ErrorInfo_struct)== 48);
281     ASSERT(sizeof(IOCTL_Command_struct)== 86);
282     ASSERT(sizeof(struct bmic_host_wellness_driver_version)== 42);
283     ASSERT(sizeof(struct bmic_host_wellness_time)== 20);
284     ASSERT(sizeof(struct pqi_dev_adminq_cap)== 8);
285     ASSERT(sizeof(struct admin_q_param)== 4);
286     ASSERT(sizeof(struct pqi_registers)== 256);
287     ASSERT(sizeof(struct ioa_registers)== 4128);
288     ASSERT(sizeof(struct pqi_pref_settings)==4);
289     ASSERT(sizeof(struct pqi_cap)== 20);
290     ASSERT(sizeof(iu_header_t)== 4);
291     ASSERT(sizeof(gen_adm_req_iu_t)== 64);
292     ASSERT(sizeof(gen_adm_resp_iu_t)== 64);
293     ASSERT(sizeof(op_q_params) == 9);
294     ASSERT(sizeof(raid_path_error_info_elem_t)== 276);
295     ASSERT(sizeof(aio_path_error_info_elem_t)== 276);
296     ASSERT(sizeof(struct init_base_struct)== 24);
297     ASSERT(sizeof(pqi_iu_layer_desc_t)== 16);
298     ASSERT(sizeof(pqi_dev_cap_t)== 576);
299     ASSERT(sizeof(pqi_aio_req_t)== 128);
300     ASSERT(sizeof(pqisrc_raid_req_t)== 128);
301     ASSERT(sizeof(pqi_tmf_req_t)== 32);
302     ASSERT(sizeof(struct pqi_io_response)== 16);
303     ASSERT(sizeof(struct sense_header_scsi)== 8);
304     ASSERT(sizeof(reportlun_header_t)==8);
305     ASSERT(sizeof(reportlun_ext_entry_t)== 24);
306     ASSERT(sizeof(reportlun_data_ext_t)== 32);
307     ASSERT(sizeof(raidmap_data_t)==8);
308     ASSERT(sizeof(pqisrc_raid_map_t)== 8256);
309     ASSERT(sizeof(bmic_ident_ctrl_t)== 325);
310     ASSERT(sizeof(bmic_ident_physdev_t)==2048);
311 
312 }
313