]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/smartpqi/smartpqi_helper.c
MFV r333668:
[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 /*
44  * Function used to take exposed devices to OS as offline.
45  */
46 void pqisrc_take_devices_offline(pqisrc_softstate_t *softs)
47 {
48         pqi_scsi_dev_t *device = NULL;
49         int i,j;
50
51         DBG_FUNC("IN\n");
52         for(i = 0; i < PQI_MAX_DEVICES; i++) {
53                 for(j = 0; j < PQI_MAX_MULTILUN; j++) {
54                         if(softs->device_list[i][j] == NULL)
55                                 continue;
56                         device = softs->device_list[i][j];
57                         pqisrc_remove_device(softs, device);
58                 }
59         }
60
61         DBG_FUNC("OUT\n");
62 }
63
64 /*
65  * Function used to take adapter offline.
66  */
67 void pqisrc_take_ctrl_offline(pqisrc_softstate_t *softs)
68 {
69
70         DBG_FUNC("IN\n");
71
72         softs->ctrl_online = false;
73         pqisrc_trigger_nmi_sis(softs);
74         os_complete_outstanding_cmds_nodevice(softs);
75         pqisrc_take_devices_offline(softs);
76
77         DBG_FUNC("OUT\n");
78 }
79
80 /*
81  * Timer handler for the adapter heart-beat.
82  */
83 void pqisrc_heartbeat_timer_handler(pqisrc_softstate_t *softs)
84 {
85         uint64_t num_intrs;
86         uint8_t take_offline = false;
87
88         DBG_FUNC("IN\n");
89
90         num_intrs = OS_ATOMIC64_READ(softs, num_intrs);
91
92         if (PQI_NEW_HEARTBEAT_MECHANISM(softs)) {
93                 if (CTRLR_HEARTBEAT_CNT(softs) == softs->prev_heartbeat_count) {
94                         take_offline = true;
95                         goto take_ctrl_offline;
96                 }
97                 softs->prev_heartbeat_count = CTRLR_HEARTBEAT_CNT(softs);
98                 DBG_INFO("CTRLR_HEARTBEAT_CNT(softs)  = %lx \
99                 softs->prev_heartbeat_count = %lx\n",
100                 CTRLR_HEARTBEAT_CNT(softs), softs->prev_heartbeat_count);
101         } else {
102                 if (num_intrs == softs->prev_num_intrs) {
103                         softs->num_heartbeats_requested++;
104                         if (softs->num_heartbeats_requested > PQI_MAX_HEARTBEAT_REQUESTS) {
105                                 take_offline = true;
106                                 goto take_ctrl_offline;
107                         }
108                         softs->pending_events[PQI_EVENT_HEARTBEAT].pending = true;
109
110                         pqisrc_ack_all_events((void*)softs);
111
112                 } else {
113                         softs->num_heartbeats_requested = 0;
114                 }
115                 softs->prev_num_intrs = num_intrs;
116         }
117
118 take_ctrl_offline:
119         if (take_offline){
120                 DBG_ERR("controller is offline\n");
121                 pqisrc_take_ctrl_offline(softs);
122                 os_stop_heartbeat_timer(softs);
123         }
124         DBG_FUNC("OUT\n");
125 }
126
127 /*
128  * Conditional variable management routine for internal commands.
129  */
130 int pqisrc_wait_on_condition(pqisrc_softstate_t *softs, rcb_t *rcb){
131
132         DBG_FUNC("IN\n");
133
134         int ret = PQI_STATUS_SUCCESS;
135         uint32_t loop_cnt = 0;
136         
137         while (rcb->req_pending == true) {
138                 OS_SLEEP(500); /* Micro sec */
139
140                 /*Polling needed for FreeBSD : since ithread routine is not scheduled
141                 during bootup, we could use polling until interrupts are
142                 enabled (using 'if (cold)'to check for the boot time before
143                 interrupts are enabled). */
144                 IS_POLLING_REQUIRED(softs);
145
146                 if (loop_cnt++ == PQISRC_CMD_TIMEOUT_CNT) {
147                         DBG_ERR("ERR: Requested cmd timed out !!!\n");
148                         ret = PQI_STATUS_TIMEOUT;
149                         break;
150                 }
151         
152                 if (pqisrc_ctrl_offline(softs)) {
153                         DBG_ERR("Controller is Offline");
154                         ret = PQI_STATUS_FAILURE;
155                         break;
156                 }
157
158         }
159         rcb->req_pending = true;
160
161         DBG_FUNC("OUT\n");
162
163         return ret;
164 }
165
166 /* Function used to validate the device wwid. */
167 boolean_t pqisrc_device_equal(pqi_scsi_dev_t *dev1,
168         pqi_scsi_dev_t *dev2)
169 {
170         return dev1->wwid == dev2->wwid;
171 }
172
173 /* Function used to validate the device scsi3addr. */
174 boolean_t pqisrc_scsi3addr_equal(uint8_t *scsi3addr1, uint8_t *scsi3addr2)
175 {
176         return memcmp(scsi3addr1, scsi3addr2, 8) == 0;
177 }
178
179 /* Function used to validate hba_lunid */
180 boolean_t pqisrc_is_hba_lunid(uint8_t *scsi3addr)
181 {
182         return pqisrc_scsi3addr_equal(scsi3addr, (uint8_t*)RAID_CTLR_LUNID);
183 }
184
185 /* Function used to validate type of device */
186 boolean_t pqisrc_is_logical_device(pqi_scsi_dev_t *device)
187 {
188         return !device->is_physical_device;
189 }
190
191 /* Function used to sanitize inquiry string */
192 void pqisrc_sanitize_inquiry_string(unsigned char *s, int len)
193 {
194         boolean_t terminated = false;
195
196         DBG_FUNC("IN\n");
197
198         for (; len > 0; (--len, ++s)) {
199                 if (*s == 0)
200                         terminated = true;
201                 if (terminated || *s < 0x20 || *s > 0x7e)
202                         *s = ' ';
203         }
204
205         DBG_FUNC("OUT\n");
206 }
207
208 static char *raid_levels[] = {
209         "RAID 0",
210         "RAID 4",
211         "RAID 1(1+0)",
212         "RAID 5",
213         "RAID 5+1",
214         "RAID ADG",
215         "RAID 1(ADM)",
216         "RAID 6",
217 };
218
219 /* Get the RAID level from the index */
220 char *pqisrc_raidlevel_to_string(uint8_t raid_level)
221 {
222         DBG_FUNC("IN\n");
223         if (raid_level < ARRAY_SIZE(raid_levels))
224                 return raid_levels[raid_level];
225         DBG_FUNC("OUT\n");
226
227         return " ";
228 }
229
230 /* Debug routine for displaying device info */
231 void pqisrc_display_device_info(pqisrc_softstate_t *softs,
232         char *action, pqi_scsi_dev_t *device)
233 {
234         DBG_INFO( "%s scsi BTL %d:%d:%d:  %.8s %.16s %-12s SSDSmartPathCap%c En%c Exp%c qd=%d\n",
235                 action,
236                 device->bus,
237                 device->target,
238                 device->lun,
239                 device->vendor,
240                 device->model,
241                 pqisrc_raidlevel_to_string(device->raid_level),
242                 device->offload_config ? '+' : '-',
243                 device->offload_enabled_pending ? '+' : '-',
244                 device->expose_device ? '+' : '-',
245                 device->queue_depth);
246         pqisrc_raidlevel_to_string(device->raid_level); /* To use this function */
247 }
248
249 /* validate the structure sizes */
250 void check_struct_sizes()
251 {   
252     
253     ASSERT(sizeof(SCSI3Addr_struct)== 2);
254     ASSERT(sizeof(PhysDevAddr_struct) == 8);
255     ASSERT(sizeof(LogDevAddr_struct)== 8);
256     ASSERT(sizeof(LUNAddr_struct)==8);
257     ASSERT(sizeof(RequestBlock_struct) == 20);
258     ASSERT(sizeof(MoreErrInfo_struct)== 8);
259     ASSERT(sizeof(ErrorInfo_struct)== 48);
260     ASSERT(sizeof(IOCTL_Command_struct)== 86);
261     ASSERT(sizeof(struct bmic_host_wellness_driver_version)== 42);
262     ASSERT(sizeof(struct bmic_host_wellness_time)== 20);
263     ASSERT(sizeof(struct pqi_dev_adminq_cap)== 8);
264     ASSERT(sizeof(struct admin_q_param)== 4);
265     ASSERT(sizeof(struct pqi_registers)== 256);
266     ASSERT(sizeof(struct ioa_registers)== 4128);
267     ASSERT(sizeof(struct pqi_pref_settings)==4);
268     ASSERT(sizeof(struct pqi_cap)== 20);
269     ASSERT(sizeof(iu_header_t)== 4);
270     ASSERT(sizeof(gen_adm_req_iu_t)== 64);
271     ASSERT(sizeof(gen_adm_resp_iu_t)== 64);
272     ASSERT(sizeof(op_q_params) == 9);
273     ASSERT(sizeof(raid_path_error_info_elem_t)== 276);
274     ASSERT(sizeof(aio_path_error_info_elem_t)== 276);
275     ASSERT(sizeof(struct init_base_struct)== 24);
276     ASSERT(sizeof(pqi_iu_layer_desc_t)== 16);
277     ASSERT(sizeof(pqi_dev_cap_t)== 576);
278     ASSERT(sizeof(pqi_aio_req_t)== 128);
279     ASSERT(sizeof(pqisrc_raid_req_t)== 128);
280     ASSERT(sizeof(pqi_tmf_req_t)== 32);
281     ASSERT(sizeof(struct pqi_io_response)== 16);
282     ASSERT(sizeof(struct sense_header_scsi)== 8);
283     ASSERT(sizeof(reportlun_header_t)==8);
284     ASSERT(sizeof(reportlun_ext_entry_t)== 24);
285     ASSERT(sizeof(reportlun_data_ext_t)== 32);
286     ASSERT(sizeof(raidmap_data_t)==8);
287     ASSERT(sizeof(pqisrc_raid_map_t)== 8256);
288     ASSERT(sizeof(bmic_ident_ctrl_t)== 325);
289     ASSERT(sizeof(bmic_ident_physdev_t)==2048);
290   
291 }