1 /*-
2 * Copyright 2016-2025 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 const * softs)33 pqisrc_ctrl_offline(pqisrc_softstate_t const *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 softs->ctrl_online = false;
87
88 if (SIS_IS_KERNEL_PANIC(softs)) {
89 int lockupcode = PCI_MEM_GET32(softs, &softs->ioa_reg->mb[7], LEGACY_SIS_SRCV_OFFSET_MAILBOX_7);
90 DBG_ERR("Controller FW is not running, Lockup code = %x\n", lockupcode);
91 }
92 else {
93 pqisrc_trigger_nmi_sis(softs);
94 }
95
96 os_complete_outstanding_cmds_nodevice(softs);
97 pqisrc_wait_for_rescan_complete(softs);
98 pqisrc_take_devices_offline(softs);
99
100 DBG_FUNC("OUT\n");
101 }
102
103 /*
104 * Timer handler for the adapter heart-beat.
105 */
106 void
pqisrc_heartbeat_timer_handler(pqisrc_softstate_t * softs)107 pqisrc_heartbeat_timer_handler(pqisrc_softstate_t *softs)
108 {
109 uint8_t take_offline = false;
110 uint64_t new_heartbeat;
111 static uint32_t running_ping_cnt = 0;
112
113 DBG_FUNC("IN\n");
114
115 new_heartbeat = CTRLR_HEARTBEAT_CNT(softs);
116 DBG_IO("heartbeat old=%lx new=%lx\n", softs->prev_heartbeat_count, new_heartbeat);
117
118 if (new_heartbeat == softs->prev_heartbeat_count) {
119 take_offline = true;
120 goto take_ctrl_offline;
121 }
122
123 #if 1
124 /* print every 30 calls (should print once/minute) */
125 running_ping_cnt++;
126
127 if ((running_ping_cnt % 30) == 0)
128 print_all_counters(softs, COUNTER_FLAG_ONLY_NON_ZERO);
129 #endif
130
131 softs->prev_heartbeat_count = new_heartbeat;
132
133 take_ctrl_offline:
134 if (take_offline){
135 DBG_ERR("controller is offline\n");
136 os_stop_heartbeat_timer(softs);
137 pqisrc_take_ctrl_offline(softs);
138 }
139 DBG_FUNC("OUT\n");
140 }
141
142 /*
143 * Conditional variable management routine for internal commands.
144 */
145 int
pqisrc_wait_on_condition(pqisrc_softstate_t * softs,rcb_t * rcb,uint32_t timeout_in_msec)146 pqisrc_wait_on_condition(pqisrc_softstate_t *softs, rcb_t *rcb,
147 uint32_t timeout_in_msec)
148 {
149 DBG_FUNC("IN\n");
150
151 int ret = PQI_STATUS_SUCCESS;
152
153 /* 1 msec = 500 usec * 2 */
154 uint32_t loop_cnt = timeout_in_msec * 2;
155 uint32_t i = 0;
156
157 while (rcb->req_pending == true) {
158 OS_SLEEP(500); /* Micro sec */
159 /* Polling needed for FreeBSD : since ithread routine is not scheduled
160 * during bootup, we could use polling until interrupts are
161 * enabled (using 'if (cold)'to check for the boot time before
162 * interrupts are enabled). */
163 IS_POLLING_REQUIRED(softs);
164
165 if ((timeout_in_msec != TIMEOUT_INFINITE) && (i++ == loop_cnt)) {
166 DBG_ERR("ERR: Requested cmd timed out !!!\n");
167 ret = PQI_STATUS_TIMEOUT;
168 rcb->timedout = true;
169 break;
170 }
171
172 if (pqisrc_ctrl_offline(softs)) {
173 DBG_ERR("Controller is Offline\n");
174 ret = PQI_STATUS_FAILURE;
175 break;
176 }
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 const * dev1,pqi_scsi_dev_t const * dev2)188 pqisrc_device_equal(pqi_scsi_dev_t const *dev1,
189 pqi_scsi_dev_t const *dev2)
190 {
191 return dev1->wwid == dev2->wwid;
192 }
193
194 /* Function used to validate the device scsi3addr. */
195 boolean_t
pqisrc_scsi3addr_equal(uint8_t const * scsi3addr1,uint8_t const * scsi3addr2)196 pqisrc_scsi3addr_equal(uint8_t const *scsi3addr1, uint8_t const *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 const * scsi3addr)203 pqisrc_is_hba_lunid(uint8_t const *scsi3addr)
204 {
205 return pqisrc_scsi3addr_equal(scsi3addr, RAID_CTLR_LUNID);
206 }
207
208 /* Function used to validate type of device */
209 boolean_t
pqisrc_is_logical_device(pqi_scsi_dev_t const * device)210 pqisrc_is_logical_device(pqi_scsi_dev_t const *device)
211 {
212 return !device->is_physical_device;
213 }
214
215 /* Function used to sanitize inquiry string */
216 void
pqisrc_sanitize_inquiry_string(unsigned char * s,int len)217 pqisrc_sanitize_inquiry_string(unsigned char *s, int len)
218 {
219 boolean_t terminated = false;
220
221 DBG_FUNC("IN\n");
222
223 for (; len > 0; (--len, ++s)) {
224 if (*s == 0)
225 terminated = true;
226 if (terminated || *s < 0x20 || *s > 0x7e)
227 *s = ' ';
228 }
229
230 DBG_FUNC("OUT\n");
231 }
232
233 static char *raid_levels[] = {
234 "RAID 0",
235 "RAID 4",
236 "RAID 1(1+0)",
237 "RAID 5",
238 "RAID 5+1",
239 "RAID 6",
240 "RAID 1(Triple)",
241 };
242
243 /* Get the RAID level from the index */
244 char *
pqisrc_raidlevel_to_string(uint8_t raid_level)245 pqisrc_raidlevel_to_string(uint8_t raid_level)
246 {
247 DBG_FUNC("IN\n");
248 if (raid_level < ARRAY_SIZE(raid_levels))
249 return raid_levels[raid_level];
250 DBG_FUNC("OUT\n");
251
252 return " ";
253 }
254
255 /* Debug routine for displaying device info */
pqisrc_display_device_info(pqisrc_softstate_t * softs,char const * action,pqi_scsi_dev_t * device)256 void pqisrc_display_device_info(pqisrc_softstate_t *softs,
257 char const *action, pqi_scsi_dev_t *device)
258 {
259 if (device->is_physical_device) {
260 DBG_NOTE("%s scsi B%d:T%d:L%d %.8s %.16s %-12s "
261 "SSDSmartPathCap%c En%c Exp%c qd=%d\n",
262 action,
263 device->bus,
264 device->target,
265 device->lun,
266 device->vendor,
267 device->model,
268 "Physical",
269 device->offload_config ? '+' : '-',
270 device->offload_enabled_pending ? '+' : '-',
271 device->expose_device ? '+' : '-',
272 device->queue_depth);
273 } else if (device->devtype == RAID_DEVICE) {
274 DBG_NOTE("%s scsi B%d:T%d:L%d %.8s %.16s %-12s "
275 "SSDSmartPathCap%c En%c Exp%c qd=%d\n",
276 action,
277 device->bus,
278 device->target,
279 device->lun,
280 device->vendor,
281 device->model,
282 "Controller",
283 device->offload_config ? '+' : '-',
284 device->offload_enabled_pending ? '+' : '-',
285 device->expose_device ? '+' : '-',
286 device->queue_depth);
287 } else if (device->devtype == CONTROLLER_DEVICE) {
288 DBG_NOTE("%s scsi B%d:T%d:L%d %.8s %.16s %-12s "
289 "SSDSmartPathCap%c En%c Exp%c qd=%d\n",
290 action,
291 device->bus,
292 device->target,
293 device->lun,
294 device->vendor,
295 device->model,
296 "External",
297 device->offload_config ? '+' : '-',
298 device->offload_enabled_pending ? '+' : '-',
299 device->expose_device ? '+' : '-',
300 device->queue_depth);
301 } else {
302 DBG_NOTE("%s scsi B%d:T%d:L%d %.8s %.16s %-12s "
303 "SSDSmartPathCap%c En%c Exp%c qd=%d devtype=%d\n",
304 action,
305 device->bus,
306 device->target,
307 device->lun,
308 device->vendor,
309 device->model,
310 pqisrc_raidlevel_to_string(device->raid_level),
311 device->offload_config ? '+' : '-',
312 device->offload_enabled_pending ? '+' : '-',
313 device->expose_device ? '+' : '-',
314 device->queue_depth,
315 device->devtype);
316 pqisrc_raidlevel_to_string(device->raid_level); /* To use this function */
317 }
318 }
319
320 /* validate the structure sizes */
321 void
check_struct_sizes(void)322 check_struct_sizes(void)
323 {
324
325 ASSERT(sizeof(SCSI3Addr_struct)== 2);
326 ASSERT(sizeof(PhysDevAddr_struct) == 8);
327 ASSERT(sizeof(LogDevAddr_struct)== 8);
328 ASSERT(sizeof(LUNAddr_struct)==8);
329 ASSERT(sizeof(RequestBlock_struct) == 20);
330 ASSERT(sizeof(MoreErrInfo_struct)== 8);
331 ASSERT(sizeof(ErrorInfo_struct)== 48);
332 /* Checking the size of IOCTL_Command_struct for both
333 64 bit and 32 bit system*/
334 ASSERT(sizeof(IOCTL_Command_struct)== 86 ||
335 sizeof(IOCTL_Command_struct)== 82);
336 ASSERT(sizeof(BIG_IOCTL_Command_struct)== 88 ||
337 sizeof(BIG_IOCTL_Command_struct)== 84);
338 ASSERT(sizeof(struct bmic_host_wellness_driver_version)== 44);
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 microseconds */
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