1*1e66f787SSean Bruno /*- 2*1e66f787SSean Bruno * Copyright (c) 2018 Microsemi Corporation. 3*1e66f787SSean Bruno * All rights reserved. 4*1e66f787SSean Bruno * 5*1e66f787SSean Bruno * Redistribution and use in source and binary forms, with or without 6*1e66f787SSean Bruno * modification, are permitted provided that the following conditions 7*1e66f787SSean Bruno * are met: 8*1e66f787SSean Bruno * 1. Redistributions of source code must retain the above copyright 9*1e66f787SSean Bruno * notice, this list of conditions and the following disclaimer. 10*1e66f787SSean Bruno * 2. Redistributions in binary form must reproduce the above copyright 11*1e66f787SSean Bruno * notice, this list of conditions and the following disclaimer in the 12*1e66f787SSean Bruno * documentation and/or other materials provided with the distribution. 13*1e66f787SSean Bruno * 14*1e66f787SSean Bruno * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*1e66f787SSean Bruno * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*1e66f787SSean Bruno * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*1e66f787SSean Bruno * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18*1e66f787SSean Bruno * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*1e66f787SSean Bruno * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*1e66f787SSean Bruno * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*1e66f787SSean Bruno * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*1e66f787SSean Bruno * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*1e66f787SSean Bruno * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*1e66f787SSean Bruno * SUCH DAMAGE. 25*1e66f787SSean Bruno */ 26*1e66f787SSean Bruno 27*1e66f787SSean Bruno /* $FreeBSD$ */ 28*1e66f787SSean Bruno 29*1e66f787SSean Bruno #include "smartpqi_includes.h" 30*1e66f787SSean Bruno 31*1e66f787SSean Bruno /* 32*1e66f787SSean Bruno * Function used to validate the adapter health. 33*1e66f787SSean Bruno */ 34*1e66f787SSean Bruno boolean_t pqisrc_ctrl_offline(pqisrc_softstate_t *softs) 35*1e66f787SSean Bruno { 36*1e66f787SSean Bruno DBG_FUNC("IN\n"); 37*1e66f787SSean Bruno 38*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 39*1e66f787SSean Bruno 40*1e66f787SSean Bruno return !softs->ctrl_online; 41*1e66f787SSean Bruno } 42*1e66f787SSean Bruno 43*1e66f787SSean Bruno /* 44*1e66f787SSean Bruno * Function used to take exposed devices to OS as offline. 45*1e66f787SSean Bruno */ 46*1e66f787SSean Bruno void pqisrc_take_devices_offline(pqisrc_softstate_t *softs) 47*1e66f787SSean Bruno { 48*1e66f787SSean Bruno pqi_scsi_dev_t *device = NULL; 49*1e66f787SSean Bruno int i,j; 50*1e66f787SSean Bruno 51*1e66f787SSean Bruno DBG_FUNC("IN\n"); 52*1e66f787SSean Bruno for(i = 0; i < PQI_MAX_DEVICES; i++) { 53*1e66f787SSean Bruno for(j = 0; j < PQI_MAX_MULTILUN; j++) { 54*1e66f787SSean Bruno if(softs->device_list[i][j] == NULL) 55*1e66f787SSean Bruno continue; 56*1e66f787SSean Bruno device = softs->device_list[i][j]; 57*1e66f787SSean Bruno pqisrc_remove_device(softs, device); 58*1e66f787SSean Bruno } 59*1e66f787SSean Bruno } 60*1e66f787SSean Bruno 61*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 62*1e66f787SSean Bruno } 63*1e66f787SSean Bruno 64*1e66f787SSean Bruno /* 65*1e66f787SSean Bruno * Function used to take adapter offline. 66*1e66f787SSean Bruno */ 67*1e66f787SSean Bruno void pqisrc_take_ctrl_offline(pqisrc_softstate_t *softs) 68*1e66f787SSean Bruno { 69*1e66f787SSean Bruno 70*1e66f787SSean Bruno DBG_FUNC("IN\n"); 71*1e66f787SSean Bruno 72*1e66f787SSean Bruno softs->ctrl_online = false; 73*1e66f787SSean Bruno pqisrc_trigger_nmi_sis(softs); 74*1e66f787SSean Bruno os_complete_outstanding_cmds_nodevice(softs); 75*1e66f787SSean Bruno pqisrc_take_devices_offline(softs); 76*1e66f787SSean Bruno 77*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 78*1e66f787SSean Bruno } 79*1e66f787SSean Bruno 80*1e66f787SSean Bruno /* 81*1e66f787SSean Bruno * Timer handler for the adapter heart-beat. 82*1e66f787SSean Bruno */ 83*1e66f787SSean Bruno void pqisrc_heartbeat_timer_handler(pqisrc_softstate_t *softs) 84*1e66f787SSean Bruno { 85*1e66f787SSean Bruno uint64_t num_intrs; 86*1e66f787SSean Bruno uint8_t take_offline = false; 87*1e66f787SSean Bruno 88*1e66f787SSean Bruno DBG_FUNC("IN\n"); 89*1e66f787SSean Bruno 90*1e66f787SSean Bruno num_intrs = OS_ATOMIC64_READ(softs, num_intrs); 91*1e66f787SSean Bruno 92*1e66f787SSean Bruno if (PQI_NEW_HEARTBEAT_MECHANISM(softs)) { 93*1e66f787SSean Bruno if (CTRLR_HEARTBEAT_CNT(softs) == softs->prev_heartbeat_count) { 94*1e66f787SSean Bruno take_offline = true; 95*1e66f787SSean Bruno goto take_ctrl_offline; 96*1e66f787SSean Bruno } 97*1e66f787SSean Bruno softs->prev_heartbeat_count = CTRLR_HEARTBEAT_CNT(softs); 98*1e66f787SSean Bruno DBG_INFO("CTRLR_HEARTBEAT_CNT(softs) = %lx \ 99*1e66f787SSean Bruno softs->prev_heartbeat_count = %lx\n", 100*1e66f787SSean Bruno CTRLR_HEARTBEAT_CNT(softs), softs->prev_heartbeat_count); 101*1e66f787SSean Bruno } else { 102*1e66f787SSean Bruno if (num_intrs == softs->prev_num_intrs) { 103*1e66f787SSean Bruno softs->num_heartbeats_requested++; 104*1e66f787SSean Bruno if (softs->num_heartbeats_requested > PQI_MAX_HEARTBEAT_REQUESTS) { 105*1e66f787SSean Bruno take_offline = true; 106*1e66f787SSean Bruno goto take_ctrl_offline; 107*1e66f787SSean Bruno } 108*1e66f787SSean Bruno softs->pending_events[PQI_EVENT_HEARTBEAT].pending = true; 109*1e66f787SSean Bruno 110*1e66f787SSean Bruno pqisrc_ack_all_events((void*)softs); 111*1e66f787SSean Bruno 112*1e66f787SSean Bruno } else { 113*1e66f787SSean Bruno softs->num_heartbeats_requested = 0; 114*1e66f787SSean Bruno } 115*1e66f787SSean Bruno softs->prev_num_intrs = num_intrs; 116*1e66f787SSean Bruno } 117*1e66f787SSean Bruno 118*1e66f787SSean Bruno take_ctrl_offline: 119*1e66f787SSean Bruno if (take_offline){ 120*1e66f787SSean Bruno DBG_ERR("controller is offline\n"); 121*1e66f787SSean Bruno pqisrc_take_ctrl_offline(softs); 122*1e66f787SSean Bruno os_stop_heartbeat_timer(softs); 123*1e66f787SSean Bruno } 124*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 125*1e66f787SSean Bruno } 126*1e66f787SSean Bruno 127*1e66f787SSean Bruno /* 128*1e66f787SSean Bruno * Conditional variable management routine for internal commands. 129*1e66f787SSean Bruno */ 130*1e66f787SSean Bruno int pqisrc_wait_on_condition(pqisrc_softstate_t *softs, rcb_t *rcb){ 131*1e66f787SSean Bruno 132*1e66f787SSean Bruno DBG_FUNC("IN\n"); 133*1e66f787SSean Bruno 134*1e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS; 135*1e66f787SSean Bruno uint32_t loop_cnt = 0; 136*1e66f787SSean Bruno 137*1e66f787SSean Bruno while (rcb->req_pending == true) { 138*1e66f787SSean Bruno OS_SLEEP(500); /* Micro sec */ 139*1e66f787SSean Bruno 140*1e66f787SSean Bruno /*Polling needed for FreeBSD : since ithread routine is not scheduled 141*1e66f787SSean Bruno during bootup, we could use polling until interrupts are 142*1e66f787SSean Bruno enabled (using 'if (cold)'to check for the boot time before 143*1e66f787SSean Bruno interrupts are enabled). */ 144*1e66f787SSean Bruno IS_POLLING_REQUIRED(softs); 145*1e66f787SSean Bruno 146*1e66f787SSean Bruno if (loop_cnt++ == PQISRC_CMD_TIMEOUT_CNT) { 147*1e66f787SSean Bruno DBG_ERR("ERR: Requested cmd timed out !!!\n"); 148*1e66f787SSean Bruno ret = PQI_STATUS_TIMEOUT; 149*1e66f787SSean Bruno break; 150*1e66f787SSean Bruno } 151*1e66f787SSean Bruno 152*1e66f787SSean Bruno if (pqisrc_ctrl_offline(softs)) { 153*1e66f787SSean Bruno DBG_ERR("Controller is Offline"); 154*1e66f787SSean Bruno ret = PQI_STATUS_FAILURE; 155*1e66f787SSean Bruno break; 156*1e66f787SSean Bruno } 157*1e66f787SSean Bruno 158*1e66f787SSean Bruno } 159*1e66f787SSean Bruno rcb->req_pending = true; 160*1e66f787SSean Bruno 161*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 162*1e66f787SSean Bruno 163*1e66f787SSean Bruno return ret; 164*1e66f787SSean Bruno } 165*1e66f787SSean Bruno 166*1e66f787SSean Bruno /* Function used to validate the device wwid. */ 167*1e66f787SSean Bruno boolean_t pqisrc_device_equal(pqi_scsi_dev_t *dev1, 168*1e66f787SSean Bruno pqi_scsi_dev_t *dev2) 169*1e66f787SSean Bruno { 170*1e66f787SSean Bruno return dev1->wwid == dev2->wwid; 171*1e66f787SSean Bruno } 172*1e66f787SSean Bruno 173*1e66f787SSean Bruno /* Function used to validate the device scsi3addr. */ 174*1e66f787SSean Bruno boolean_t pqisrc_scsi3addr_equal(uint8_t *scsi3addr1, uint8_t *scsi3addr2) 175*1e66f787SSean Bruno { 176*1e66f787SSean Bruno return memcmp(scsi3addr1, scsi3addr2, 8) == 0; 177*1e66f787SSean Bruno } 178*1e66f787SSean Bruno 179*1e66f787SSean Bruno /* Function used to validate hba_lunid */ 180*1e66f787SSean Bruno boolean_t pqisrc_is_hba_lunid(uint8_t *scsi3addr) 181*1e66f787SSean Bruno { 182*1e66f787SSean Bruno return pqisrc_scsi3addr_equal(scsi3addr, (uint8_t*)RAID_CTLR_LUNID); 183*1e66f787SSean Bruno } 184*1e66f787SSean Bruno 185*1e66f787SSean Bruno /* Function used to validate type of device */ 186*1e66f787SSean Bruno boolean_t pqisrc_is_logical_device(pqi_scsi_dev_t *device) 187*1e66f787SSean Bruno { 188*1e66f787SSean Bruno return !device->is_physical_device; 189*1e66f787SSean Bruno } 190*1e66f787SSean Bruno 191*1e66f787SSean Bruno /* Function used to sanitize inquiry string */ 192*1e66f787SSean Bruno void pqisrc_sanitize_inquiry_string(unsigned char *s, int len) 193*1e66f787SSean Bruno { 194*1e66f787SSean Bruno boolean_t terminated = false; 195*1e66f787SSean Bruno 196*1e66f787SSean Bruno DBG_FUNC("IN\n"); 197*1e66f787SSean Bruno 198*1e66f787SSean Bruno for (; len > 0; (--len, ++s)) { 199*1e66f787SSean Bruno if (*s == 0) 200*1e66f787SSean Bruno terminated = true; 201*1e66f787SSean Bruno if (terminated || *s < 0x20 || *s > 0x7e) 202*1e66f787SSean Bruno *s = ' '; 203*1e66f787SSean Bruno } 204*1e66f787SSean Bruno 205*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 206*1e66f787SSean Bruno } 207*1e66f787SSean Bruno 208*1e66f787SSean Bruno static char *raid_levels[] = { 209*1e66f787SSean Bruno "RAID 0", 210*1e66f787SSean Bruno "RAID 4", 211*1e66f787SSean Bruno "RAID 1(1+0)", 212*1e66f787SSean Bruno "RAID 5", 213*1e66f787SSean Bruno "RAID 5+1", 214*1e66f787SSean Bruno "RAID ADG", 215*1e66f787SSean Bruno "RAID 1(ADM)", 216*1e66f787SSean Bruno "RAID 6", 217*1e66f787SSean Bruno }; 218*1e66f787SSean Bruno 219*1e66f787SSean Bruno /* Get the RAID level from the index */ 220*1e66f787SSean Bruno char *pqisrc_raidlevel_to_string(uint8_t raid_level) 221*1e66f787SSean Bruno { 222*1e66f787SSean Bruno DBG_FUNC("IN\n"); 223*1e66f787SSean Bruno if (raid_level < ARRAY_SIZE(raid_levels)) 224*1e66f787SSean Bruno return raid_levels[raid_level]; 225*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 226*1e66f787SSean Bruno 227*1e66f787SSean Bruno return " "; 228*1e66f787SSean Bruno } 229*1e66f787SSean Bruno 230*1e66f787SSean Bruno /* Debug routine for displaying device info */ 231*1e66f787SSean Bruno void pqisrc_display_device_info(pqisrc_softstate_t *softs, 232*1e66f787SSean Bruno char *action, pqi_scsi_dev_t *device) 233*1e66f787SSean Bruno { 234*1e66f787SSean Bruno DBG_INFO( "%s scsi BTL %d:%d:%d: %.8s %.16s %-12s SSDSmartPathCap%c En%c Exp%c qd=%d\n", 235*1e66f787SSean Bruno action, 236*1e66f787SSean Bruno device->bus, 237*1e66f787SSean Bruno device->target, 238*1e66f787SSean Bruno device->lun, 239*1e66f787SSean Bruno device->vendor, 240*1e66f787SSean Bruno device->model, 241*1e66f787SSean Bruno pqisrc_raidlevel_to_string(device->raid_level), 242*1e66f787SSean Bruno device->offload_config ? '+' : '-', 243*1e66f787SSean Bruno device->offload_enabled_pending ? '+' : '-', 244*1e66f787SSean Bruno device->expose_device ? '+' : '-', 245*1e66f787SSean Bruno device->queue_depth); 246*1e66f787SSean Bruno pqisrc_raidlevel_to_string(device->raid_level); /* To use this function */ 247*1e66f787SSean Bruno } 248*1e66f787SSean Bruno 249*1e66f787SSean Bruno /* validate the structure sizes */ 250*1e66f787SSean Bruno void check_struct_sizes() 251*1e66f787SSean Bruno { 252*1e66f787SSean Bruno 253*1e66f787SSean Bruno ASSERT(sizeof(SCSI3Addr_struct)== 2); 254*1e66f787SSean Bruno ASSERT(sizeof(PhysDevAddr_struct) == 8); 255*1e66f787SSean Bruno ASSERT(sizeof(LogDevAddr_struct)== 8); 256*1e66f787SSean Bruno ASSERT(sizeof(LUNAddr_struct)==8); 257*1e66f787SSean Bruno ASSERT(sizeof(RequestBlock_struct) == 20); 258*1e66f787SSean Bruno ASSERT(sizeof(MoreErrInfo_struct)== 8); 259*1e66f787SSean Bruno ASSERT(sizeof(ErrorInfo_struct)== 48); 260*1e66f787SSean Bruno ASSERT(sizeof(IOCTL_Command_struct)== 86); 261*1e66f787SSean Bruno ASSERT(sizeof(struct bmic_host_wellness_driver_version)== 42); 262*1e66f787SSean Bruno ASSERT(sizeof(struct bmic_host_wellness_time)== 20); 263*1e66f787SSean Bruno ASSERT(sizeof(struct pqi_dev_adminq_cap)== 8); 264*1e66f787SSean Bruno ASSERT(sizeof(struct admin_q_param)== 4); 265*1e66f787SSean Bruno ASSERT(sizeof(struct pqi_registers)== 256); 266*1e66f787SSean Bruno ASSERT(sizeof(struct ioa_registers)== 4128); 267*1e66f787SSean Bruno ASSERT(sizeof(struct pqi_pref_settings)==4); 268*1e66f787SSean Bruno ASSERT(sizeof(struct pqi_cap)== 20); 269*1e66f787SSean Bruno ASSERT(sizeof(iu_header_t)== 4); 270*1e66f787SSean Bruno ASSERT(sizeof(gen_adm_req_iu_t)== 64); 271*1e66f787SSean Bruno ASSERT(sizeof(gen_adm_resp_iu_t)== 64); 272*1e66f787SSean Bruno ASSERT(sizeof(op_q_params) == 9); 273*1e66f787SSean Bruno ASSERT(sizeof(raid_path_error_info_elem_t)== 276); 274*1e66f787SSean Bruno ASSERT(sizeof(aio_path_error_info_elem_t)== 276); 275*1e66f787SSean Bruno ASSERT(sizeof(struct init_base_struct)== 24); 276*1e66f787SSean Bruno ASSERT(sizeof(pqi_iu_layer_desc_t)== 16); 277*1e66f787SSean Bruno ASSERT(sizeof(pqi_dev_cap_t)== 576); 278*1e66f787SSean Bruno ASSERT(sizeof(pqi_aio_req_t)== 128); 279*1e66f787SSean Bruno ASSERT(sizeof(pqisrc_raid_req_t)== 128); 280*1e66f787SSean Bruno ASSERT(sizeof(pqi_tmf_req_t)== 32); 281*1e66f787SSean Bruno ASSERT(sizeof(struct pqi_io_response)== 16); 282*1e66f787SSean Bruno ASSERT(sizeof(struct sense_header_scsi)== 8); 283*1e66f787SSean Bruno ASSERT(sizeof(reportlun_header_t)==8); 284*1e66f787SSean Bruno ASSERT(sizeof(reportlun_ext_entry_t)== 24); 285*1e66f787SSean Bruno ASSERT(sizeof(reportlun_data_ext_t)== 32); 286*1e66f787SSean Bruno ASSERT(sizeof(raidmap_data_t)==8); 287*1e66f787SSean Bruno ASSERT(sizeof(pqisrc_raid_map_t)== 8256); 288*1e66f787SSean Bruno ASSERT(sizeof(bmic_ident_ctrl_t)== 325); 289*1e66f787SSean Bruno ASSERT(sizeof(bmic_ident_physdev_t)==2048); 290*1e66f787SSean Bruno 291*1e66f787SSean Bruno } 292