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