]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/smartpqi/smartpqi_helper.c
one-true-awk: import 20210221 (1e4bc42c53a1) which fixes a number of bugs
[FreeBSD/FreeBSD.git] / sys / dev / smartpqi / smartpqi_helper.c
1 /*-
2  * Copyright 2016-2021 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 /* $FreeBSD$ */
27
28 #include "smartpqi_includes.h"
29
30 /* read and modify controller diagnostic option - PQI_PTRAID_UPDATE_ON_RESCAN_LUNS */
31 void
32 pqisrc_ctrl_diagnostic_options(pqisrc_softstate_t *softs)
33 {
34         int ret = PQI_STATUS_SUCCESS;
35         uint32_t diags_options = 0;
36         pqisrc_raid_req_t request;
37
38         DBG_NOTE("IN\n");
39
40         memset(&request, 0, sizeof(request));
41         /* read diags options of controller */
42         ret =  pqisrc_build_send_raid_request(softs, &request,
43                                         (void*)&diags_options,
44                                         sizeof(diags_options),
45                                         BMIC_SENSE_DIAGS_OPTIONS,
46                                         0, (uint8_t *)RAID_CTLR_LUNID, NULL);
47         if (ret != PQI_STATUS_SUCCESS) {
48                 DBG_WARN("Request failed for BMIC Sense Diags Option command."
49                         "ret:%d\n",ret);
50                 return;
51         }
52         DBG_NOTE("diags options data after read: %#x\n",diags_options);
53         diags_options |= PQI_PTRAID_UPDATE_ON_RESCAN_LUNS;
54         DBG_NOTE("diags options data to write: %#x\n",diags_options);
55         memset(&request, 0, sizeof(request));
56         /* write specified diags options to controller */
57         ret =  pqisrc_build_send_raid_request(softs, &request,
58                                         (void*)&diags_options,
59                                         sizeof(diags_options),
60                                         BMIC_SET_DIAGS_OPTIONS,
61                                         0, (uint8_t *)RAID_CTLR_LUNID, NULL);
62         if (ret != PQI_STATUS_SUCCESS)
63                 DBG_WARN("Request failed for BMIC Set Diags Option command."
64                         "ret:%d\n",ret);
65 #if 0
66         diags_options = 0;
67         memset(&request, 0, sizeof(request));
68         ret =  pqisrc_build_send_raid_request(softs, &request,
69                                         (void*)&diags_options,
70                                         sizeof(diags_options),
71                                         BMIC_SENSE_DIAGS_OPTIONS,
72                                         0, (uint8_t *)RAID_CTLR_LUNID, NULL);
73         if (ret != PQI_STATUS_SUCCESS)
74                 DBG_WARN("Request failed for BMIC Sense Diags Option command."
75                         "ret:%d\n",ret);
76         DBG_NOTE("diags options after re-read: %#x\n",diags_options);
77 #endif
78         DBG_NOTE("OUT\n");
79 }
80
81 /*
82  * Function used to validate the adapter health.
83  */
84 boolean_t
85 pqisrc_ctrl_offline(pqisrc_softstate_t *softs)
86 {
87         DBG_FUNC("IN\n");
88
89         DBG_FUNC("OUT\n");
90
91         return !softs->ctrl_online;
92 }
93
94 /* Function used set/clear legacy INTx bit in Legacy Interrupt INTx
95  * mask clear pqi register
96  */
97 void
98 pqisrc_configure_legacy_intx(pqisrc_softstate_t *softs, boolean_t enable_intx)
99 {
100         uint32_t intx_mask;
101         uint32_t *reg_addr = NULL;
102
103         DBG_FUNC("IN\n");
104
105         if (enable_intx)
106                 reg_addr = &softs->pqi_reg->legacy_intr_mask_clr;
107         else
108                 reg_addr = &softs->pqi_reg->legacy_intr_mask_set;
109
110         intx_mask = PCI_MEM_GET32(softs, reg_addr, PQI_LEGACY_INTR_MASK_CLR);
111         intx_mask |= PQISRC_LEGACY_INTX_MASK;
112         PCI_MEM_PUT32(softs, reg_addr, PQI_LEGACY_INTR_MASK_CLR ,intx_mask);
113
114         DBG_FUNC("OUT\n");
115 }
116
117 /*
118  * Function used to take exposed devices to OS as offline.
119  */
120 void
121 pqisrc_take_devices_offline(pqisrc_softstate_t *softs)
122 {
123         pqi_scsi_dev_t *device = NULL;
124         int i,j;
125
126         DBG_FUNC("IN\n");
127         for(i = 0; i < PQI_MAX_DEVICES; i++) {
128                 for(j = 0; j < PQI_MAX_MULTILUN; j++) {
129                         if(softs->device_list[i][j] == NULL)
130                                 continue;
131                         device = softs->device_list[i][j];
132                         pqisrc_remove_device(softs, device);
133                 }
134         }
135
136         DBG_FUNC("OUT\n");
137 }
138
139 /*
140  * Function used to take adapter offline.
141  */
142 void
143 pqisrc_take_ctrl_offline(pqisrc_softstate_t *softs)
144 {
145         DBG_FUNC("IN\n");
146
147         softs->ctrl_online = false;
148
149         int lockupcode = 0;
150
151         if (SIS_IS_KERNEL_PANIC(softs)) {
152                 lockupcode = PCI_MEM_GET32(softs, &softs->ioa_reg->mb[7], LEGACY_SIS_SRCV_OFFSET_MAILBOX_7);
153                 DBG_ERR("Controller FW is not runnning, Lockup code = %x\n", lockupcode);
154         }
155         else {
156                 pqisrc_trigger_nmi_sis(softs);
157         }
158
159         os_complete_outstanding_cmds_nodevice(softs);
160         pqisrc_wait_for_rescan_complete(softs);
161         pqisrc_take_devices_offline(softs);
162
163         DBG_FUNC("OUT\n");
164 }
165
166 /*
167  * Timer handler for the adapter heart-beat.
168  */
169 void
170 pqisrc_heartbeat_timer_handler(pqisrc_softstate_t *softs)
171 {
172         uint8_t take_offline = false;
173
174         DBG_FUNC("IN\n");
175
176         if (CTRLR_HEARTBEAT_CNT(softs) == softs->prev_heartbeat_count) {
177                 take_offline = true;
178                 goto take_ctrl_offline;
179         }
180         softs->prev_heartbeat_count = CTRLR_HEARTBEAT_CNT(softs);
181         DBG_INFO("CTRLR_HEARTBEAT_CNT(softs)  = %lx \
182                 softs->prev_heartbeat_count = %lx\n",
183                 CTRLR_HEARTBEAT_CNT(softs), softs->prev_heartbeat_count);
184
185 take_ctrl_offline:
186         if (take_offline){
187                 DBG_ERR("controller is offline\n");
188                 pqisrc_take_ctrl_offline(softs);
189                 os_stop_heartbeat_timer(softs);
190         }
191         DBG_FUNC("OUT\n");
192 }
193
194 /*
195  * Conditional variable management routine for internal commands.
196  */
197 int
198 pqisrc_wait_on_condition(pqisrc_softstate_t *softs, rcb_t *rcb,
199                                 uint32_t timeout_in_msec)
200 {
201         DBG_FUNC("IN\n");
202
203         int ret = PQI_STATUS_SUCCESS;
204
205         /* 1 msec = 500 usec * 2 */
206         uint32_t loop_cnt = timeout_in_msec * 2;
207         uint32_t i = 0;
208
209         while (rcb->req_pending == true) {
210                 OS_SLEEP(500); /* Micro sec */
211                 /* Polling needed for FreeBSD : since ithread routine is not scheduled
212                  * during bootup, we could use polling until interrupts are
213                  * enabled (using 'if (cold)'to check for the boot time before
214                  * interrupts are enabled). */
215                 IS_POLLING_REQUIRED(softs);
216
217                 if ((timeout_in_msec != TIMEOUT_INFINITE) && (i++ == loop_cnt)) {
218                         DBG_ERR("ERR: Requested cmd timed out !!!\n");
219                         ret = PQI_STATUS_TIMEOUT;
220                         rcb->timedout = true;
221                         break;
222                 }
223
224                 if (pqisrc_ctrl_offline(softs)) {
225                         DBG_ERR("Controller is Offline");
226                         ret = PQI_STATUS_FAILURE;
227                         break;
228                 }
229
230         }
231         rcb->req_pending = true;
232
233         DBG_FUNC("OUT\n");
234
235         return ret;
236 }
237
238 /* Function used to validate the device wwid. */
239 boolean_t
240 pqisrc_device_equal(pqi_scsi_dev_t *dev1,
241         pqi_scsi_dev_t *dev2)
242 {
243         return dev1->wwid == dev2->wwid;
244 }
245
246 /* Function used to validate the device scsi3addr. */
247 boolean_t
248 pqisrc_scsi3addr_equal(uint8_t *scsi3addr1, uint8_t *scsi3addr2)
249 {
250         return memcmp(scsi3addr1, scsi3addr2, 8) == 0;
251 }
252
253 /* Function used to validate hba_lunid */
254 boolean_t
255 pqisrc_is_hba_lunid(uint8_t *scsi3addr)
256 {
257         return pqisrc_scsi3addr_equal(scsi3addr, (uint8_t*)RAID_CTLR_LUNID);
258 }
259
260 /* Function used to validate type of device */
261 boolean_t
262 pqisrc_is_logical_device(pqi_scsi_dev_t *device)
263 {
264         return !device->is_physical_device;
265 }
266
267 /* Function used to sanitize inquiry string */
268 void
269 pqisrc_sanitize_inquiry_string(unsigned char *s, int len)
270 {
271         boolean_t terminated = false;
272
273         DBG_FUNC("IN\n");
274
275         for (; len > 0; (--len, ++s)) {
276                 if (*s == 0)
277                         terminated = true;
278                 if (terminated || *s < 0x20 || *s > 0x7e)
279                         *s = ' ';
280         }
281
282         DBG_FUNC("OUT\n");
283 }
284
285 static char *raid_levels[] = {
286         "RAID 0",
287         "RAID 4",
288         "RAID 1(1+0)",
289         "RAID 5",
290         "RAID 5+1",
291         "RAID ADG",
292         "RAID 1(ADM)",
293 };
294
295 /* Get the RAID level from the index */
296 char *
297 pqisrc_raidlevel_to_string(uint8_t raid_level)
298 {
299         DBG_FUNC("IN\n");
300         if (raid_level < ARRAY_SIZE(raid_levels))
301                 return raid_levels[raid_level];
302         DBG_FUNC("OUT\n");
303
304         return " ";
305 }
306
307 /* Debug routine for displaying device info */
308 void
309 pqisrc_display_device_info(pqisrc_softstate_t *softs,
310         char *action, pqi_scsi_dev_t *device)
311 {
312         DBG_INFO( "%s scsi BTL %d:%d:%d:  %.8s %.16s %-12s SSDSmartPathCap%c En%c Exp%c qd=%d\n",
313                 action,
314                 device->bus,
315                 device->target,
316                 device->lun,
317                 device->vendor,
318                 device->model,
319                 pqisrc_raidlevel_to_string(device->raid_level),
320                 device->offload_config ? '+' : '-',
321                 device->offload_enabled_pending ? '+' : '-',
322                 device->expose_device ? '+' : '-',
323                 device->queue_depth);
324         pqisrc_raidlevel_to_string(device->raid_level); /* To use this function */
325 }
326
327 /* validate the structure sizes */
328 void
329 check_struct_sizes()
330 {
331
332     ASSERT(sizeof(SCSI3Addr_struct)== 2);
333     ASSERT(sizeof(PhysDevAddr_struct) == 8);
334     ASSERT(sizeof(LogDevAddr_struct)== 8);
335     ASSERT(sizeof(LUNAddr_struct)==8);
336     ASSERT(sizeof(RequestBlock_struct) == 20);
337     ASSERT(sizeof(MoreErrInfo_struct)== 8);
338     ASSERT(sizeof(ErrorInfo_struct)== 48);
339     /* Checking the size of IOCTL_Command_struct for both
340        64 bit and 32 bit system*/
341     ASSERT(sizeof(IOCTL_Command_struct)== 86 ||
342            sizeof(IOCTL_Command_struct)== 82);
343     ASSERT(sizeof(struct bmic_host_wellness_driver_version)== 42);
344     ASSERT(sizeof(struct bmic_host_wellness_time)== 20);
345     ASSERT(sizeof(struct pqi_dev_adminq_cap)== 8);
346     ASSERT(sizeof(struct admin_q_param)== 4);
347     ASSERT(sizeof(struct pqi_registers)== 256);
348     ASSERT(sizeof(struct ioa_registers)== 4128);
349     ASSERT(sizeof(struct pqi_pref_settings)==4);
350     ASSERT(sizeof(struct pqi_cap)== 20);
351     ASSERT(sizeof(iu_header_t)== 4);
352     ASSERT(sizeof(gen_adm_req_iu_t)== 64);
353     ASSERT(sizeof(gen_adm_resp_iu_t)== 64);
354     ASSERT(sizeof(op_q_params) == 9);
355     ASSERT(sizeof(raid_path_error_info_elem_t)== 276);
356     ASSERT(sizeof(aio_path_error_info_elem_t)== 276);
357     ASSERT(sizeof(struct init_base_struct)== 24);
358     ASSERT(sizeof(pqi_iu_layer_desc_t)== 16);
359     ASSERT(sizeof(pqi_dev_cap_t)== 576);
360     ASSERT(sizeof(pqi_aio_req_t)== 128);
361     ASSERT(sizeof(pqisrc_raid_req_t)== 128);
362     ASSERT(sizeof(pqi_raid_tmf_req_t)== 32);
363     ASSERT(sizeof(pqi_aio_tmf_req_t)== 32);
364     ASSERT(sizeof(struct pqi_io_response)== 16);
365     ASSERT(sizeof(struct sense_header_scsi)== 8);
366     ASSERT(sizeof(reportlun_header_t)==8);
367     ASSERT(sizeof(reportlun_ext_entry_t)== 24);
368     ASSERT(sizeof(reportlun_data_ext_t)== 32);
369     ASSERT(sizeof(raidmap_data_t)==8);
370     ASSERT(sizeof(pqisrc_raid_map_t)== 8256);
371     ASSERT(sizeof(bmic_ident_ctrl_t)== 325);
372     ASSERT(sizeof(bmic_ident_physdev_t)==2048);
373
374 }
375
376 uint32_t
377 pqisrc_count_num_scsi_active_requests_on_dev(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
378 {
379         uint32_t i, active_io = 0;
380         rcb_t* rcb;
381
382         for(i = 1; i <= softs->max_outstanding_io; i++) {
383                 rcb = &softs->rcb[i];
384                 if(rcb && IS_OS_SCSICMD(rcb) && (rcb->dvp == device) && rcb->req_pending) {
385                         active_io++;
386                 }
387         }
388         return active_io;
389 }
390
391 void
392 check_device_pending_commands_to_complete(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
393 {
394         uint32_t tag = softs->max_outstanding_io, active_requests;
395         uint64_t timeout = 0, delay_in_usec = 1000; //In micro Seconds
396         rcb_t* rcb;
397
398         DBG_FUNC("IN\n");
399
400         active_requests = pqisrc_count_num_scsi_active_requests_on_dev(softs, device);
401
402         DBG_WARN("Device Outstanding IO count = %u\n", active_requests);
403
404         if(!active_requests)
405                 return;
406
407         do {
408                 rcb = &softs->rcb[tag];
409                 if(rcb && IS_OS_SCSICMD(rcb) && (rcb->dvp == device) && rcb->req_pending) {
410                         OS_BUSYWAIT(delay_in_usec);
411                         timeout += delay_in_usec;
412                 }
413                 else
414                         tag--;
415                 if(timeout >= PQISRC_PENDING_IO_TIMEOUT_USEC) {
416                         DBG_WARN("timed out waiting for pending IO\n");
417                         return;
418                 }
419         } while(tag);
420
421 }
422
423 inline uint64_t
424 pqisrc_increment_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
425 {
426 #if PQISRC_DEVICE_IO_COUNTER
427         /*Increment device active io count by one*/
428         return OS_ATOMIC64_INC(&device->active_requests);
429 #endif
430 }
431
432 inline uint64_t
433 pqisrc_decrement_device_active_io(pqisrc_softstate_t *softs,  pqi_scsi_dev_t *device)
434 {
435 #if PQISRC_DEVICE_IO_COUNTER
436         /*Decrement device active io count by one*/
437         return OS_ATOMIC64_DEC(&device->active_requests);
438 #endif
439 }
440
441 inline void
442 pqisrc_init_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
443 {
444 #if PQISRC_DEVICE_IO_COUNTER
445         /* Reset device count to Zero */
446         OS_ATOMIC64_INIT(&device->active_requests, 0);
447 #endif
448 }
449
450 inline uint64_t
451 pqisrc_read_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
452 {
453 #if PQISRC_DEVICE_IO_COUNTER
454         /* read device active count*/
455         return OS_ATOMIC64_READ(&device->active_requests);
456 #endif
457 }
458
459 void
460 pqisrc_wait_for_device_commands_to_complete(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
461 {
462         uint64_t timeout_in_usec = 0, delay_in_usec = 1000; //In microseconds
463
464         DBG_FUNC("IN\n");
465
466         if(!softs->ctrl_online)
467                 return;
468
469 #if PQISRC_DEVICE_IO_COUNTER
470         DBG_NOTE("Device Outstanding IO count = %ld\n", pqisrc_read_device_active_io(softs, device));
471
472         while(pqisrc_read_device_active_io(softs, device)) {
473                 OS_BUSYWAIT(delay_in_usec); // In microseconds
474                 if(!softs->ctrl_online) {
475                         DBG_WARN("Controller Offline was detected.\n");
476                 }
477                 timeout_in_usec += delay_in_usec;
478                 if(timeout_in_usec >= PQISRC_PENDING_IO_TIMEOUT_USEC) {
479                         DBG_WARN("timed out waiting for pending IO. DeviceOutStandingIo's=%ld\n",
480                                  pqisrc_read_device_active_io(softs, device));
481                         return;
482                 }
483         }
484 #else
485         check_device_pending_commands_to_complete(softs, device);
486 #endif
487 }