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 * Function used to validate the adapter health.
31 */
32 boolean_t
pqisrc_ctrl_offline(pqisrc_softstate_t * softs)33 pqisrc_ctrl_offline(pqisrc_softstate_t *softs)
34 {
35 DBG_FUNC("IN\n");
36
37 DBG_FUNC("OUT\n");
38
39 return !softs->ctrl_online;
40 }
41 /* Function used set/clear legacy INTx bit in Legacy Interrupt INTx
42 * mask clear pqi register
43 */
44 void
pqisrc_configure_legacy_intx(pqisrc_softstate_t * softs,boolean_t enable_intx)45 pqisrc_configure_legacy_intx(pqisrc_softstate_t *softs, boolean_t enable_intx)
46 {
47 uint32_t intx_mask;
48
49 DBG_FUNC("IN\n");
50
51 intx_mask = PCI_MEM_GET32(softs, 0, PQI_LEGACY_INTR_MASK_CLR);
52 intx_mask |= PQISRC_LEGACY_INTX_MASK;
53 PCI_MEM_PUT32(softs, 0, PQI_LEGACY_INTR_MASK_CLR ,intx_mask);
54
55 DBG_FUNC("OUT\n");
56 }
57
58 /*
59 * Function used to take exposed devices to OS as offline.
60 */
61 void
pqisrc_take_devices_offline(pqisrc_softstate_t * softs)62 pqisrc_take_devices_offline(pqisrc_softstate_t *softs)
63 {
64 pqi_scsi_dev_t *device = NULL;
65 int i;
66
67 DBG_FUNC("IN\n");
68 for(i = 0; i < PQI_MAX_DEVICES; i++) {
69 device = softs->dev_list[i];
70 if(device == NULL)
71 continue;
72 pqisrc_remove_device(softs, device);
73 }
74
75 DBG_FUNC("OUT\n");
76 }
77
78 /*
79 * Function used to take adapter offline.
80 */
81 void
pqisrc_take_ctrl_offline(pqisrc_softstate_t * softs)82 pqisrc_take_ctrl_offline(pqisrc_softstate_t *softs)
83 {
84 DBG_FUNC("IN\n");
85
86 int lockupcode = 0;
87
88 softs->ctrl_online = false;
89
90 if (SIS_IS_KERNEL_PANIC(softs)) {
91 lockupcode = PCI_MEM_GET32(softs, &softs->ioa_reg->mb[7], LEGACY_SIS_SRCV_OFFSET_MAILBOX_7);
92 DBG_ERR("Controller FW is not running, Lockup code = %x\n", lockupcode);
93 }
94 else {
95 pqisrc_trigger_nmi_sis(softs);
96 }
97
98 os_complete_outstanding_cmds_nodevice(softs);
99 pqisrc_wait_for_rescan_complete(softs);
100 pqisrc_take_devices_offline(softs);
101
102 DBG_FUNC("OUT\n");
103 }
104
105 /*
106 * Timer handler for the adapter heart-beat.
107 */
108 void
pqisrc_heartbeat_timer_handler(pqisrc_softstate_t * softs)109 pqisrc_heartbeat_timer_handler(pqisrc_softstate_t *softs)
110 {
111 uint8_t take_offline = false;
112 uint64_t new_heartbeat;
113 static uint32_t running_ping_cnt = 0;
114
115 DBG_FUNC("IN\n");
116
117 new_heartbeat = CTRLR_HEARTBEAT_CNT(softs);
118 DBG_IO("heartbeat old=%lx new=%lx\n", softs->prev_heartbeat_count, new_heartbeat);
119
120 if (new_heartbeat == softs->prev_heartbeat_count) {
121 take_offline = true;
122 goto take_ctrl_offline;
123 }
124
125 #if 1
126 /* print every 30 calls (should print once/minute) */
127 running_ping_cnt++;
128
129 if ((running_ping_cnt % 30) == 0)
130 print_all_counters(softs, COUNTER_FLAG_ONLY_NON_ZERO);
131 #endif
132
133 softs->prev_heartbeat_count = new_heartbeat;
134
135 take_ctrl_offline:
136 if (take_offline){
137 DBG_ERR("controller is offline\n");
138 os_stop_heartbeat_timer(softs);
139 pqisrc_take_ctrl_offline(softs);
140 }
141 DBG_FUNC("OUT\n");
142 }
143
144 /*
145 * Conditional variable management routine for internal commands.
146 */
147 int
pqisrc_wait_on_condition(pqisrc_softstate_t * softs,rcb_t * rcb,uint32_t timeout_in_msec)148 pqisrc_wait_on_condition(pqisrc_softstate_t *softs, rcb_t *rcb,
149 uint32_t timeout_in_msec)
150 {
151 DBG_FUNC("IN\n");
152
153 int ret = PQI_STATUS_SUCCESS;
154
155 /* 1 msec = 500 usec * 2 */
156 uint32_t loop_cnt = timeout_in_msec * 2;
157 uint32_t i = 0;
158
159 while (rcb->req_pending == true) {
160 OS_SLEEP(500); /* Micro sec */
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 ((timeout_in_msec != TIMEOUT_INFINITE) && (i++ == loop_cnt)) {
168 DBG_ERR("ERR: Requested cmd timed out !!!\n");
169 ret = PQI_STATUS_TIMEOUT;
170 rcb->timedout = true;
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,pqi_scsi_dev_t * dev2)190 pqisrc_device_equal(pqi_scsi_dev_t *dev1,
191 pqi_scsi_dev_t *dev2)
192 {
193 return dev1->wwid == dev2->wwid;
194 }
195
196 /* Function used to validate the device scsi3addr. */
197 boolean_t
pqisrc_scsi3addr_equal(uint8_t * scsi3addr1,uint8_t * scsi3addr2)198 pqisrc_scsi3addr_equal(uint8_t *scsi3addr1, uint8_t *scsi3addr2)
199 {
200 return memcmp(scsi3addr1, scsi3addr2, 8) == 0;
201 }
202
203 /* Function used to validate hba_lunid */
204 boolean_t
pqisrc_is_hba_lunid(uint8_t * scsi3addr)205 pqisrc_is_hba_lunid(uint8_t *scsi3addr)
206 {
207 return pqisrc_scsi3addr_equal(scsi3addr, RAID_CTLR_LUNID);
208 }
209
210 /* Function used to validate type of device */
211 boolean_t
pqisrc_is_logical_device(pqi_scsi_dev_t * device)212 pqisrc_is_logical_device(pqi_scsi_dev_t *device)
213 {
214 return !device->is_physical_device;
215 }
216
217 /* Function used to sanitize inquiry string */
218 void
pqisrc_sanitize_inquiry_string(unsigned char * s,int len)219 pqisrc_sanitize_inquiry_string(unsigned char *s, int len)
220 {
221 boolean_t terminated = false;
222
223 DBG_FUNC("IN\n");
224
225 for (; len > 0; (--len, ++s)) {
226 if (*s == 0)
227 terminated = true;
228 if (terminated || *s < 0x20 || *s > 0x7e)
229 *s = ' ';
230 }
231
232 DBG_FUNC("OUT\n");
233 }
234
235 static char *raid_levels[] = {
236 "RAID 0",
237 "RAID 4",
238 "RAID 1(1+0)",
239 "RAID 5",
240 "RAID 5+1",
241 "RAID 6",
242 "RAID 1(Triple)",
243 };
244
245 /* Get the RAID level from the index */
246 char *
pqisrc_raidlevel_to_string(uint8_t raid_level)247 pqisrc_raidlevel_to_string(uint8_t raid_level)
248 {
249 DBG_FUNC("IN\n");
250 if (raid_level < ARRAY_SIZE(raid_levels))
251 return raid_levels[raid_level];
252 DBG_FUNC("OUT\n");
253
254 return " ";
255 }
256
257 /* Debug routine for displaying device info */
pqisrc_display_device_info(pqisrc_softstate_t * softs,char * action,pqi_scsi_dev_t * device)258 void pqisrc_display_device_info(pqisrc_softstate_t *softs,
259 char *action, pqi_scsi_dev_t *device)
260 {
261 if (device->is_physical_device) {
262 DBG_NOTE("%s scsi BTL %d:%d:%d: %.8s %.16s %-12s "
263 "SSDSmartPathCap%c En%c Exp%c qd=%d\n",
264 action,
265 device->bus,
266 device->target,
267 device->lun,
268 device->vendor,
269 device->model,
270 "Physical",
271 device->offload_config ? '+' : '-',
272 device->offload_enabled_pending ? '+' : '-',
273 device->expose_device ? '+' : '-',
274 device->queue_depth);
275 } else if (device->devtype == RAID_DEVICE) {
276 DBG_NOTE("%s scsi BTL %d:%d:%d: %.8s %.16s %-12s "
277 "SSDSmartPathCap%c En%c Exp%c qd=%d\n",
278 action,
279 device->bus,
280 device->target,
281 device->lun,
282 device->vendor,
283 device->model,
284 "Controller",
285 device->offload_config ? '+' : '-',
286 device->offload_enabled_pending ? '+' : '-',
287 device->expose_device ? '+' : '-',
288 device->queue_depth);
289 } else if (device->devtype == CONTROLLER_DEVICE) {
290 DBG_NOTE("%s scsi BTL %d:%d:%d: %.8s %.16s %-12s "
291 "SSDSmartPathCap%c En%c Exp%c qd=%d\n",
292 action,
293 device->bus,
294 device->target,
295 device->lun,
296 device->vendor,
297 device->model,
298 "External",
299 device->offload_config ? '+' : '-',
300 device->offload_enabled_pending ? '+' : '-',
301 device->expose_device ? '+' : '-',
302 device->queue_depth);
303 } else {
304 DBG_NOTE("%s scsi BTL %d:%d:%d: %.8s %.16s %-12s "
305 "SSDSmartPathCap%c En%c Exp%c qd=%d devtype=%d\n",
306 action,
307 device->bus,
308 device->target,
309 device->lun,
310 device->vendor,
311 device->model,
312 pqisrc_raidlevel_to_string(device->raid_level),
313 device->offload_config ? '+' : '-',
314 device->offload_enabled_pending ? '+' : '-',
315 device->expose_device ? '+' : '-',
316 device->queue_depth,
317 device->devtype);
318 pqisrc_raidlevel_to_string(device->raid_level); /* To use this function */
319 }
320 }
321
322 /* validate the structure sizes */
323 void
check_struct_sizes(void)324 check_struct_sizes(void)
325 {
326
327 ASSERT(sizeof(SCSI3Addr_struct)== 2);
328 ASSERT(sizeof(PhysDevAddr_struct) == 8);
329 ASSERT(sizeof(LogDevAddr_struct)== 8);
330 ASSERT(sizeof(LUNAddr_struct)==8);
331 ASSERT(sizeof(RequestBlock_struct) == 20);
332 ASSERT(sizeof(MoreErrInfo_struct)== 8);
333 ASSERT(sizeof(ErrorInfo_struct)== 48);
334 /* Checking the size of IOCTL_Command_struct for both
335 64 bit and 32 bit system*/
336 ASSERT(sizeof(IOCTL_Command_struct)== 86 ||
337 sizeof(IOCTL_Command_struct)== 82);
338 ASSERT(sizeof(struct bmic_host_wellness_driver_version)== 42);
339 ASSERT(sizeof(struct bmic_host_wellness_time)== 20);
340 ASSERT(sizeof(struct pqi_dev_adminq_cap)== 8);
341 ASSERT(sizeof(struct admin_q_param)== 4);
342 ASSERT(sizeof(struct pqi_registers)== 256);
343 ASSERT(sizeof(struct ioa_registers)== 4128);
344 ASSERT(sizeof(struct pqi_pref_settings)==4);
345 ASSERT(sizeof(struct pqi_cap)== 20);
346 ASSERT(sizeof(iu_header_t)== 4);
347 ASSERT(sizeof(gen_adm_req_iu_t)== 64);
348 ASSERT(sizeof(gen_adm_resp_iu_t)== 64);
349 ASSERT(sizeof(op_q_params) == 9);
350 ASSERT(sizeof(raid_path_error_info_elem_t)== 276);
351 ASSERT(sizeof(aio_path_error_info_elem_t)== 276);
352 ASSERT(sizeof(struct init_base_struct)== 24);
353 ASSERT(sizeof(pqi_iu_layer_desc_t)== 16);
354 ASSERT(sizeof(pqi_dev_cap_t)== 576);
355 ASSERT(sizeof(pqi_aio_req_t)== 128);
356 ASSERT(sizeof(pqisrc_raid_req_t)== 128);
357 ASSERT(sizeof(pqi_raid_tmf_req_t)== 32);
358 ASSERT(sizeof(pqi_aio_tmf_req_t)== 32);
359 ASSERT(sizeof(struct pqi_io_response)== 16);
360 ASSERT(sizeof(struct sense_header_scsi)== 8);
361 ASSERT(sizeof(reportlun_header_t)==8);
362 ASSERT(sizeof(reportlun_ext_entry_t)== 24);
363 ASSERT(sizeof(reportlun_data_ext_t)== 32);
364 ASSERT(sizeof(raidmap_data_t)==8);
365 ASSERT(sizeof(pqisrc_raid_map_t)== 8256);
366 ASSERT(sizeof(bmic_ident_ctrl_t)== 325);
367 ASSERT(sizeof(bmic_ident_physdev_t)==2048);
368
369 }
370
371 #if 0
372 uint32_t
373 pqisrc_count_num_scsi_active_requests_on_dev(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
374 {
375 uint32_t i, active_io = 0;
376 rcb_t* rcb;
377
378 for(i = 1; i <= softs->max_outstanding_io; i++) {
379 rcb = &softs->rcb[i];
380 if(rcb && IS_OS_SCSICMD(rcb) && (rcb->dvp == device) && rcb->req_pending) {
381 active_io++;
382 }
383 }
384 return active_io;
385 }
386
387 void
388 check_device_pending_commands_to_complete(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
389 {
390 uint32_t tag = softs->max_outstanding_io, active_requests;
391 uint64_t timeout = 0, delay_in_usec = 1000; /* In micro Seconds */
392 rcb_t* rcb;
393
394 DBG_FUNC("IN\n");
395
396 active_requests = pqisrc_count_num_scsi_active_requests_on_dev(softs, device);
397
398 DBG_WARN("Device Outstanding IO count = %u\n", active_requests);
399
400 if(!active_requests)
401 return;
402
403 do {
404 rcb = &softs->rcb[tag];
405 if(rcb && IS_OS_SCSICMD(rcb) && (rcb->dvp == device) && rcb->req_pending) {
406 OS_SLEEP(delay_in_usec);
407 timeout += delay_in_usec;
408 }
409 else
410 tag--;
411 if(timeout >= PQISRC_PENDING_IO_TIMEOUT_USEC) {
412 DBG_WARN("timed out waiting for pending IO\n");
413 return;
414 }
415 } while(tag);
416 }
417 #endif
418
419 void
pqisrc_wait_for_device_commands_to_complete(pqisrc_softstate_t * softs,pqi_scsi_dev_t * device)420 pqisrc_wait_for_device_commands_to_complete(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
421 {
422 uint64_t timeout_in_usec = 0, delay_in_usec = 1000; /* In microseconds */
423
424 DBG_FUNC("IN\n");
425
426 if(!softs->ctrl_online)
427 return;
428
429 #if PQISRC_DEVICE_IO_COUNTER
430 DBG_WARN_BTL(device,"Device Outstanding IO count = %lu\n", pqisrc_read_device_active_io(softs, device));
431
432 while(pqisrc_read_device_active_io(softs, device)) {
433 OS_BUSYWAIT(delay_in_usec); /* In microseconds */
434 if(!softs->ctrl_online) {
435 DBG_WARN("Controller Offline was detected.\n");
436 }
437 timeout_in_usec += delay_in_usec;
438 if(timeout_in_usec >= PQISRC_PENDING_IO_TIMEOUT_USEC) {
439 DBG_WARN_BTL(device,"timed out waiting for pending IO. DeviceOutStandingIo's=%lu\n",
440 pqisrc_read_device_active_io(softs, device));
441 return;
442 }
443 }
444 #else
445 check_device_pending_commands_to_complete(softs, device);
446 #endif
447 }
448