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 } 313