]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/smartpqi/smartpqi_helper.c
MFV r357163:
[FreeBSD/FreeBSD.git] / sys / dev / smartpqi / smartpqi_helper.c
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 }