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