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 /* Validate the scsi sense response code */ 32*1e66f787SSean Bruno static inline boolean_t pqisrc_scsi_sense_valid(const struct sense_header_scsi *sshdr) 33*1e66f787SSean Bruno { 34*1e66f787SSean Bruno DBG_FUNC("IN\n"); 35*1e66f787SSean Bruno 36*1e66f787SSean Bruno if (!sshdr) 37*1e66f787SSean Bruno return false; 38*1e66f787SSean Bruno 39*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 40*1e66f787SSean Bruno 41*1e66f787SSean Bruno return (sshdr->response_code & 0x70) == 0x70; 42*1e66f787SSean Bruno } 43*1e66f787SSean Bruno 44*1e66f787SSean Bruno /* Update scsi sense info to a local buffer*/ 45*1e66f787SSean Bruno boolean_t pqisrc_update_scsi_sense(const uint8_t *buff, int len, 46*1e66f787SSean Bruno struct sense_header_scsi *header) 47*1e66f787SSean Bruno { 48*1e66f787SSean Bruno 49*1e66f787SSean Bruno DBG_FUNC("IN\n"); 50*1e66f787SSean Bruno 51*1e66f787SSean Bruno if (!buff || !len) 52*1e66f787SSean Bruno return false; 53*1e66f787SSean Bruno 54*1e66f787SSean Bruno memset(header, 0, sizeof(struct sense_header_scsi)); 55*1e66f787SSean Bruno 56*1e66f787SSean Bruno header->response_code = (buff[0] & 0x7f); 57*1e66f787SSean Bruno 58*1e66f787SSean Bruno if (!pqisrc_scsi_sense_valid(header)) 59*1e66f787SSean Bruno return false; 60*1e66f787SSean Bruno 61*1e66f787SSean Bruno if (header->response_code >= 0x72) { 62*1e66f787SSean Bruno /* descriptor format */ 63*1e66f787SSean Bruno if (len > 1) 64*1e66f787SSean Bruno header->sense_key = (buff[1] & 0xf); 65*1e66f787SSean Bruno if (len > 2) 66*1e66f787SSean Bruno header->asc = buff[2]; 67*1e66f787SSean Bruno if (len > 3) 68*1e66f787SSean Bruno header->ascq = buff[3]; 69*1e66f787SSean Bruno if (len > 7) 70*1e66f787SSean Bruno header->additional_length = buff[7]; 71*1e66f787SSean Bruno } else { 72*1e66f787SSean Bruno /* fixed format */ 73*1e66f787SSean Bruno if (len > 2) 74*1e66f787SSean Bruno header->sense_key = (buff[2] & 0xf); 75*1e66f787SSean Bruno if (len > 7) { 76*1e66f787SSean Bruno len = (len < (buff[7] + 8)) ? 77*1e66f787SSean Bruno len : (buff[7] + 8); 78*1e66f787SSean Bruno if (len > 12) 79*1e66f787SSean Bruno header->asc = buff[12]; 80*1e66f787SSean Bruno if (len > 13) 81*1e66f787SSean Bruno header->ascq = buff[13]; 82*1e66f787SSean Bruno } 83*1e66f787SSean Bruno } 84*1e66f787SSean Bruno 85*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 86*1e66f787SSean Bruno 87*1e66f787SSean Bruno return true; 88*1e66f787SSean Bruno } 89*1e66f787SSean Bruno 90*1e66f787SSean Bruno /* 91*1e66f787SSean Bruno * Function used to build the internal raid request and analyze the response 92*1e66f787SSean Bruno */ 93*1e66f787SSean Bruno int pqisrc_build_send_raid_request(pqisrc_softstate_t *softs, pqisrc_raid_req_t *request, 94*1e66f787SSean Bruno void *buff, size_t datasize, uint8_t cmd, uint16_t vpd_page, uint8_t *scsi3addr, 95*1e66f787SSean Bruno raid_path_error_info_elem_t *error_info) 96*1e66f787SSean Bruno { 97*1e66f787SSean Bruno 98*1e66f787SSean Bruno uint8_t *cdb; 99*1e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS; 100*1e66f787SSean Bruno uint32_t tag = 0; 101*1e66f787SSean Bruno struct dma_mem device_mem; 102*1e66f787SSean Bruno sgt_t *sgd; 103*1e66f787SSean Bruno 104*1e66f787SSean Bruno ib_queue_t *ib_q = &softs->op_raid_ib_q[PQI_DEFAULT_IB_QUEUE]; 105*1e66f787SSean Bruno ob_queue_t *ob_q = &softs->op_ob_q[PQI_DEFAULT_IB_QUEUE]; 106*1e66f787SSean Bruno 107*1e66f787SSean Bruno rcb_t *rcb = NULL; 108*1e66f787SSean Bruno 109*1e66f787SSean Bruno DBG_FUNC("IN\n"); 110*1e66f787SSean Bruno 111*1e66f787SSean Bruno memset(&device_mem, 0, sizeof(struct dma_mem)); 112*1e66f787SSean Bruno 113*1e66f787SSean Bruno /* for TUR datasize: 0 buff: NULL */ 114*1e66f787SSean Bruno if (datasize) { 115*1e66f787SSean Bruno device_mem.tag = "device_mem"; 116*1e66f787SSean Bruno device_mem.size = datasize; 117*1e66f787SSean Bruno device_mem.align = PQISRC_DEFAULT_DMA_ALIGN; 118*1e66f787SSean Bruno 119*1e66f787SSean Bruno ret = os_dma_mem_alloc(softs, &device_mem); 120*1e66f787SSean Bruno 121*1e66f787SSean Bruno if (ret) { 122*1e66f787SSean Bruno DBG_ERR("failed to allocate dma memory for device_mem return code %d\n", ret); 123*1e66f787SSean Bruno return ret; 124*1e66f787SSean Bruno } 125*1e66f787SSean Bruno 126*1e66f787SSean Bruno sgd = (sgt_t *)&request->sg_descriptors[0]; 127*1e66f787SSean Bruno 128*1e66f787SSean Bruno sgd->addr = device_mem.dma_addr; 129*1e66f787SSean Bruno sgd->len = datasize; 130*1e66f787SSean Bruno sgd->flags = SG_FLAG_LAST; 131*1e66f787SSean Bruno 132*1e66f787SSean Bruno } 133*1e66f787SSean Bruno 134*1e66f787SSean Bruno /* Build raid path request */ 135*1e66f787SSean Bruno request->header.iu_type = PQI_IU_TYPE_RAID_PATH_IO_REQUEST; 136*1e66f787SSean Bruno 137*1e66f787SSean Bruno request->header.iu_length = LE_16(offsetof(pqisrc_raid_req_t, 138*1e66f787SSean Bruno sg_descriptors[1]) - PQI_REQUEST_HEADER_LENGTH); 139*1e66f787SSean Bruno request->buffer_length = LE_32(datasize); 140*1e66f787SSean Bruno memcpy(request->lun_number, scsi3addr, sizeof(request->lun_number)); 141*1e66f787SSean Bruno request->task_attribute = SOP_TASK_ATTRIBUTE_SIMPLE; 142*1e66f787SSean Bruno request->additional_cdb_bytes_usage = PQI_ADDITIONAL_CDB_BYTES_0; 143*1e66f787SSean Bruno 144*1e66f787SSean Bruno cdb = request->cdb; 145*1e66f787SSean Bruno 146*1e66f787SSean Bruno switch (cmd) { 147*1e66f787SSean Bruno case SA_INQUIRY: 148*1e66f787SSean Bruno request->data_direction = SOP_DATA_DIR_TO_DEVICE; 149*1e66f787SSean Bruno cdb[0] = SA_INQUIRY; 150*1e66f787SSean Bruno if (vpd_page & VPD_PAGE) { 151*1e66f787SSean Bruno cdb[1] = 0x1; 152*1e66f787SSean Bruno cdb[2] = (uint8_t)vpd_page; 153*1e66f787SSean Bruno } 154*1e66f787SSean Bruno cdb[4] = (uint8_t)datasize; 155*1e66f787SSean Bruno break; 156*1e66f787SSean Bruno case SA_REPORT_LOG: 157*1e66f787SSean Bruno case SA_REPORT_PHYS: 158*1e66f787SSean Bruno request->data_direction = SOP_DATA_DIR_TO_DEVICE; 159*1e66f787SSean Bruno cdb[0] = cmd; 160*1e66f787SSean Bruno if (cmd == SA_REPORT_PHYS) 161*1e66f787SSean Bruno cdb[1] = SA_REPORT_PHYS_EXTENDED; 162*1e66f787SSean Bruno else 163*1e66f787SSean Bruno cdb[1] = SA_REPORT_LOG_EXTENDED; 164*1e66f787SSean Bruno cdb[8] = (uint8_t)((datasize) >> 8); 165*1e66f787SSean Bruno cdb[9] = (uint8_t)datasize; 166*1e66f787SSean Bruno break; 167*1e66f787SSean Bruno case TEST_UNIT_READY: 168*1e66f787SSean Bruno request->data_direction = SOP_DATA_DIR_NONE; 169*1e66f787SSean Bruno break; 170*1e66f787SSean Bruno case SA_GET_RAID_MAP: 171*1e66f787SSean Bruno request->data_direction = SOP_DATA_DIR_TO_DEVICE; 172*1e66f787SSean Bruno cdb[0] = SA_CISS_READ; 173*1e66f787SSean Bruno cdb[1] = cmd; 174*1e66f787SSean Bruno cdb[8] = (uint8_t)((datasize) >> 8); 175*1e66f787SSean Bruno cdb[9] = (uint8_t)datasize; 176*1e66f787SSean Bruno break; 177*1e66f787SSean Bruno case SA_CACHE_FLUSH: 178*1e66f787SSean Bruno request->data_direction = SOP_DATA_DIR_FROM_DEVICE; 179*1e66f787SSean Bruno cdb[0] = BMIC_WRITE; 180*1e66f787SSean Bruno cdb[6] = BMIC_CACHE_FLUSH; 181*1e66f787SSean Bruno cdb[7] = (uint8_t)((datasize) << 8); 182*1e66f787SSean Bruno cdb[8] = (uint8_t)((datasize) >> 8); 183*1e66f787SSean Bruno break; 184*1e66f787SSean Bruno case BMIC_IDENTIFY_CONTROLLER: 185*1e66f787SSean Bruno case BMIC_IDENTIFY_PHYSICAL_DEVICE: 186*1e66f787SSean Bruno request->data_direction = SOP_DATA_DIR_TO_DEVICE; 187*1e66f787SSean Bruno cdb[0] = BMIC_READ; 188*1e66f787SSean Bruno cdb[6] = cmd; 189*1e66f787SSean Bruno cdb[7] = (uint8_t)((datasize) << 8); 190*1e66f787SSean Bruno cdb[8] = (uint8_t)((datasize) >> 8); 191*1e66f787SSean Bruno break; 192*1e66f787SSean Bruno case BMIC_WRITE_HOST_WELLNESS: 193*1e66f787SSean Bruno request->data_direction = SOP_DATA_DIR_FROM_DEVICE; 194*1e66f787SSean Bruno memcpy(device_mem.virt_addr, buff, datasize); 195*1e66f787SSean Bruno cdb[0] = BMIC_WRITE; 196*1e66f787SSean Bruno cdb[6] = cmd; 197*1e66f787SSean Bruno cdb[7] = (uint8_t)((datasize) << 8); 198*1e66f787SSean Bruno cdb[8] = (uint8_t)((datasize) >> 8); 199*1e66f787SSean Bruno break; 200*1e66f787SSean Bruno case BMIC_SENSE_SUBSYSTEM_INFORMATION: 201*1e66f787SSean Bruno request->data_direction = SOP_DATA_DIR_TO_DEVICE; 202*1e66f787SSean Bruno cdb[0] = BMIC_READ; 203*1e66f787SSean Bruno cdb[6] = cmd; 204*1e66f787SSean Bruno cdb[7] = (uint8_t)((datasize) << 8); 205*1e66f787SSean Bruno cdb[8] = (uint8_t)((datasize) >> 8); 206*1e66f787SSean Bruno break; 207*1e66f787SSean Bruno default: 208*1e66f787SSean Bruno DBG_ERR("unknown command 0x%x", cmd); 209*1e66f787SSean Bruno break; 210*1e66f787SSean Bruno } 211*1e66f787SSean Bruno 212*1e66f787SSean Bruno tag = pqisrc_get_tag(&softs->taglist); 213*1e66f787SSean Bruno if (INVALID_ELEM == tag) { 214*1e66f787SSean Bruno DBG_ERR("Tag not available\n"); 215*1e66f787SSean Bruno ret = PQI_STATUS_FAILURE; 216*1e66f787SSean Bruno goto err_notag; 217*1e66f787SSean Bruno } 218*1e66f787SSean Bruno 219*1e66f787SSean Bruno ((pqisrc_raid_req_t *)request)->request_id = tag; 220*1e66f787SSean Bruno ((pqisrc_raid_req_t *)request)->error_index = ((pqisrc_raid_req_t *)request)->request_id; 221*1e66f787SSean Bruno ((pqisrc_raid_req_t *)request)->response_queue_id = ob_q->q_id; 222*1e66f787SSean Bruno rcb = &softs->rcb[tag]; 223*1e66f787SSean Bruno rcb->success_cmp_callback = pqisrc_process_internal_raid_response_success; 224*1e66f787SSean Bruno rcb->error_cmp_callback = pqisrc_process_internal_raid_response_error; 225*1e66f787SSean Bruno 226*1e66f787SSean Bruno rcb->req_pending = true; 227*1e66f787SSean Bruno rcb->tag = tag; 228*1e66f787SSean Bruno /* Submit Command */ 229*1e66f787SSean Bruno ret = pqisrc_submit_cmnd(softs, ib_q, request); 230*1e66f787SSean Bruno 231*1e66f787SSean Bruno if (ret != PQI_STATUS_SUCCESS) { 232*1e66f787SSean Bruno DBG_ERR("Unable to submit command\n"); 233*1e66f787SSean Bruno goto err_out; 234*1e66f787SSean Bruno } 235*1e66f787SSean Bruno 236*1e66f787SSean Bruno ret = pqisrc_wait_on_condition(softs, rcb); 237*1e66f787SSean Bruno if (ret != PQI_STATUS_SUCCESS) { 238*1e66f787SSean Bruno DBG_ERR("Internal RAID request timed out: cmd : 0x%c\n", cmd); 239*1e66f787SSean Bruno goto err_out; 240*1e66f787SSean Bruno } 241*1e66f787SSean Bruno 242*1e66f787SSean Bruno if (datasize) { 243*1e66f787SSean Bruno if (buff) { 244*1e66f787SSean Bruno memcpy(buff, device_mem.virt_addr, datasize); 245*1e66f787SSean Bruno } 246*1e66f787SSean Bruno os_dma_mem_free(softs, &device_mem); 247*1e66f787SSean Bruno } 248*1e66f787SSean Bruno 249*1e66f787SSean Bruno ret = rcb->status; 250*1e66f787SSean Bruno if (ret) { 251*1e66f787SSean Bruno if(error_info) { 252*1e66f787SSean Bruno memcpy(error_info, 253*1e66f787SSean Bruno rcb->error_info, 254*1e66f787SSean Bruno sizeof(*error_info)); 255*1e66f787SSean Bruno 256*1e66f787SSean Bruno if (error_info->data_out_result == 257*1e66f787SSean Bruno PQI_RAID_DATA_IN_OUT_UNDERFLOW) { 258*1e66f787SSean Bruno ret = PQI_STATUS_SUCCESS; 259*1e66f787SSean Bruno } 260*1e66f787SSean Bruno else{ 261*1e66f787SSean Bruno DBG_INFO("Error!! Bus=%u Target=%u, Cmd=0x%x," 262*1e66f787SSean Bruno "Ret=%d\n", BMIC_GET_LEVEL_2_BUS(scsi3addr), 263*1e66f787SSean Bruno BMIC_GET_LEVEL_TWO_TARGET(scsi3addr), 264*1e66f787SSean Bruno cmd, ret); 265*1e66f787SSean Bruno ret = PQI_STATUS_FAILURE; 266*1e66f787SSean Bruno } 267*1e66f787SSean Bruno } 268*1e66f787SSean Bruno } else { 269*1e66f787SSean Bruno if(error_info) { 270*1e66f787SSean Bruno ret = PQI_STATUS_SUCCESS; 271*1e66f787SSean Bruno memset(error_info, 0, sizeof(*error_info)); 272*1e66f787SSean Bruno } 273*1e66f787SSean Bruno } 274*1e66f787SSean Bruno 275*1e66f787SSean Bruno os_reset_rcb(rcb); 276*1e66f787SSean Bruno pqisrc_put_tag(&softs->taglist, ((pqisrc_raid_req_t *)request)->request_id); 277*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 278*1e66f787SSean Bruno return ret; 279*1e66f787SSean Bruno 280*1e66f787SSean Bruno err_out: 281*1e66f787SSean Bruno DBG_ERR("Error!! Bus=%u Target=%u, Cmd=0x%x, Ret=%d\n", 282*1e66f787SSean Bruno BMIC_GET_LEVEL_2_BUS(scsi3addr), BMIC_GET_LEVEL_TWO_TARGET(scsi3addr), 283*1e66f787SSean Bruno cmd, ret); 284*1e66f787SSean Bruno os_reset_rcb(rcb); 285*1e66f787SSean Bruno pqisrc_put_tag(&softs->taglist, ((pqisrc_raid_req_t *)request)->request_id); 286*1e66f787SSean Bruno err_notag: 287*1e66f787SSean Bruno if (datasize) 288*1e66f787SSean Bruno os_dma_mem_free(softs, &device_mem); 289*1e66f787SSean Bruno DBG_FUNC("FAILED \n"); 290*1e66f787SSean Bruno return ret; 291*1e66f787SSean Bruno } 292*1e66f787SSean Bruno 293*1e66f787SSean Bruno /* common function used to send report physical and logical luns cmnds*/ 294*1e66f787SSean Bruno static int pqisrc_report_luns(pqisrc_softstate_t *softs, uint8_t cmd, 295*1e66f787SSean Bruno void *buff, size_t buf_len) 296*1e66f787SSean Bruno { 297*1e66f787SSean Bruno int ret; 298*1e66f787SSean Bruno pqisrc_raid_req_t request; 299*1e66f787SSean Bruno 300*1e66f787SSean Bruno DBG_FUNC("IN\n"); 301*1e66f787SSean Bruno 302*1e66f787SSean Bruno memset(&request, 0, sizeof(request)); 303*1e66f787SSean Bruno ret = pqisrc_build_send_raid_request(softs, &request, buff, 304*1e66f787SSean Bruno buf_len, cmd, 0, (uint8_t *)RAID_CTLR_LUNID, NULL); 305*1e66f787SSean Bruno 306*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 307*1e66f787SSean Bruno 308*1e66f787SSean Bruno return ret; 309*1e66f787SSean Bruno } 310*1e66f787SSean Bruno 311*1e66f787SSean Bruno /* subroutine used to get physical and logical luns of the device */ 312*1e66f787SSean Bruno static int pqisrc_get_physical_logical_luns(pqisrc_softstate_t *softs, uint8_t cmd, 313*1e66f787SSean Bruno reportlun_data_ext_t **buff, size_t *data_length) 314*1e66f787SSean Bruno { 315*1e66f787SSean Bruno int ret; 316*1e66f787SSean Bruno size_t list_len; 317*1e66f787SSean Bruno size_t data_len; 318*1e66f787SSean Bruno size_t new_lun_list_length; 319*1e66f787SSean Bruno reportlun_data_ext_t *lun_data; 320*1e66f787SSean Bruno reportlun_header_t report_lun_header; 321*1e66f787SSean Bruno 322*1e66f787SSean Bruno DBG_FUNC("IN\n"); 323*1e66f787SSean Bruno 324*1e66f787SSean Bruno ret = pqisrc_report_luns(softs, cmd, &report_lun_header, 325*1e66f787SSean Bruno sizeof(report_lun_header)); 326*1e66f787SSean Bruno 327*1e66f787SSean Bruno if (ret) { 328*1e66f787SSean Bruno DBG_ERR("failed return code: %d\n", ret); 329*1e66f787SSean Bruno return ret; 330*1e66f787SSean Bruno } 331*1e66f787SSean Bruno list_len = BE_32(report_lun_header.list_length); 332*1e66f787SSean Bruno 333*1e66f787SSean Bruno retry: 334*1e66f787SSean Bruno data_len = sizeof(reportlun_header_t) + list_len; 335*1e66f787SSean Bruno *data_length = data_len; 336*1e66f787SSean Bruno 337*1e66f787SSean Bruno lun_data = os_mem_alloc(softs, data_len); 338*1e66f787SSean Bruno 339*1e66f787SSean Bruno if (!lun_data) { 340*1e66f787SSean Bruno DBG_ERR("failed to allocate memory for lun_data\n"); 341*1e66f787SSean Bruno return PQI_STATUS_FAILURE; 342*1e66f787SSean Bruno } 343*1e66f787SSean Bruno 344*1e66f787SSean Bruno if (list_len == 0) { 345*1e66f787SSean Bruno DBG_INFO("list_len is 0\n"); 346*1e66f787SSean Bruno memcpy(lun_data, &report_lun_header, sizeof(report_lun_header)); 347*1e66f787SSean Bruno goto out; 348*1e66f787SSean Bruno } 349*1e66f787SSean Bruno 350*1e66f787SSean Bruno ret = pqisrc_report_luns(softs, cmd, lun_data, data_len); 351*1e66f787SSean Bruno 352*1e66f787SSean Bruno if (ret) { 353*1e66f787SSean Bruno DBG_ERR("error\n"); 354*1e66f787SSean Bruno goto error; 355*1e66f787SSean Bruno } 356*1e66f787SSean Bruno 357*1e66f787SSean Bruno new_lun_list_length = BE_32(lun_data->header.list_length); 358*1e66f787SSean Bruno 359*1e66f787SSean Bruno if (new_lun_list_length > list_len) { 360*1e66f787SSean Bruno list_len = new_lun_list_length; 361*1e66f787SSean Bruno os_mem_free(softs, (void *)lun_data, data_len); 362*1e66f787SSean Bruno goto retry; 363*1e66f787SSean Bruno } 364*1e66f787SSean Bruno 365*1e66f787SSean Bruno out: 366*1e66f787SSean Bruno *buff = lun_data; 367*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 368*1e66f787SSean Bruno return 0; 369*1e66f787SSean Bruno 370*1e66f787SSean Bruno error: 371*1e66f787SSean Bruno os_mem_free(softs, (void *)lun_data, data_len); 372*1e66f787SSean Bruno DBG_ERR("FAILED\n"); 373*1e66f787SSean Bruno return ret; 374*1e66f787SSean Bruno } 375*1e66f787SSean Bruno 376*1e66f787SSean Bruno /* 377*1e66f787SSean Bruno * Function used to get physical and logical device list 378*1e66f787SSean Bruno */ 379*1e66f787SSean Bruno static int pqisrc_get_phys_log_device_list(pqisrc_softstate_t *softs, 380*1e66f787SSean Bruno reportlun_data_ext_t **physical_dev_list, 381*1e66f787SSean Bruno reportlun_data_ext_t **logical_dev_list, 382*1e66f787SSean Bruno size_t *phys_data_length, 383*1e66f787SSean Bruno size_t *log_data_length) 384*1e66f787SSean Bruno { 385*1e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS; 386*1e66f787SSean Bruno size_t logical_list_length; 387*1e66f787SSean Bruno size_t logdev_data_length; 388*1e66f787SSean Bruno size_t data_length; 389*1e66f787SSean Bruno reportlun_data_ext_t *local_logdev_list; 390*1e66f787SSean Bruno reportlun_data_ext_t *logdev_data; 391*1e66f787SSean Bruno reportlun_header_t report_lun_header; 392*1e66f787SSean Bruno 393*1e66f787SSean Bruno 394*1e66f787SSean Bruno DBG_FUNC("IN\n"); 395*1e66f787SSean Bruno 396*1e66f787SSean Bruno ret = pqisrc_get_physical_logical_luns(softs, SA_REPORT_PHYS, physical_dev_list, phys_data_length); 397*1e66f787SSean Bruno if (ret) { 398*1e66f787SSean Bruno DBG_ERR("report physical LUNs failed"); 399*1e66f787SSean Bruno return ret; 400*1e66f787SSean Bruno } 401*1e66f787SSean Bruno 402*1e66f787SSean Bruno ret = pqisrc_get_physical_logical_luns(softs, SA_REPORT_LOG, logical_dev_list, log_data_length); 403*1e66f787SSean Bruno if (ret) { 404*1e66f787SSean Bruno DBG_ERR("report logical LUNs failed"); 405*1e66f787SSean Bruno return ret; 406*1e66f787SSean Bruno } 407*1e66f787SSean Bruno 408*1e66f787SSean Bruno 409*1e66f787SSean Bruno logdev_data = *logical_dev_list; 410*1e66f787SSean Bruno 411*1e66f787SSean Bruno if (logdev_data) { 412*1e66f787SSean Bruno logical_list_length = 413*1e66f787SSean Bruno BE_32(logdev_data->header.list_length); 414*1e66f787SSean Bruno } else { 415*1e66f787SSean Bruno memset(&report_lun_header, 0, sizeof(report_lun_header)); 416*1e66f787SSean Bruno logdev_data = 417*1e66f787SSean Bruno (reportlun_data_ext_t *)&report_lun_header; 418*1e66f787SSean Bruno logical_list_length = 0; 419*1e66f787SSean Bruno } 420*1e66f787SSean Bruno 421*1e66f787SSean Bruno logdev_data_length = sizeof(reportlun_header_t) + 422*1e66f787SSean Bruno logical_list_length; 423*1e66f787SSean Bruno 424*1e66f787SSean Bruno /* Adding LOGICAL device entry for controller */ 425*1e66f787SSean Bruno local_logdev_list = os_mem_alloc(softs, 426*1e66f787SSean Bruno logdev_data_length + sizeof(reportlun_ext_entry_t)); 427*1e66f787SSean Bruno if (!local_logdev_list) { 428*1e66f787SSean Bruno data_length = *log_data_length; 429*1e66f787SSean Bruno os_mem_free(softs, (char *)*logical_dev_list, data_length); 430*1e66f787SSean Bruno *logical_dev_list = NULL; 431*1e66f787SSean Bruno return PQI_STATUS_FAILURE; 432*1e66f787SSean Bruno } 433*1e66f787SSean Bruno 434*1e66f787SSean Bruno memcpy(local_logdev_list, logdev_data, logdev_data_length); 435*1e66f787SSean Bruno memset((uint8_t *)local_logdev_list + logdev_data_length, 0, 436*1e66f787SSean Bruno sizeof(reportlun_ext_entry_t)); 437*1e66f787SSean Bruno local_logdev_list->header.list_length = BE_32(logical_list_length + 438*1e66f787SSean Bruno sizeof(reportlun_ext_entry_t)); 439*1e66f787SSean Bruno data_length = *log_data_length; 440*1e66f787SSean Bruno os_mem_free(softs, (char *)*logical_dev_list, data_length); 441*1e66f787SSean Bruno *log_data_length = logdev_data_length + sizeof(reportlun_ext_entry_t); 442*1e66f787SSean Bruno *logical_dev_list = local_logdev_list; 443*1e66f787SSean Bruno 444*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 445*1e66f787SSean Bruno 446*1e66f787SSean Bruno return ret; 447*1e66f787SSean Bruno } 448*1e66f787SSean Bruno 449*1e66f787SSean Bruno /* Subroutine used to set Bus-Target-Lun for the requested device */ 450*1e66f787SSean Bruno static inline void pqisrc_set_btl(pqi_scsi_dev_t *device, 451*1e66f787SSean Bruno int bus, int target, int lun) 452*1e66f787SSean Bruno { 453*1e66f787SSean Bruno DBG_FUNC("IN\n"); 454*1e66f787SSean Bruno 455*1e66f787SSean Bruno device->bus = bus; 456*1e66f787SSean Bruno device->target = target; 457*1e66f787SSean Bruno device->lun = lun; 458*1e66f787SSean Bruno 459*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 460*1e66f787SSean Bruno } 461*1e66f787SSean Bruno 462*1e66f787SSean Bruno inline boolean_t pqisrc_is_external_raid_device(pqi_scsi_dev_t *device) 463*1e66f787SSean Bruno { 464*1e66f787SSean Bruno return device->is_external_raid_device; 465*1e66f787SSean Bruno } 466*1e66f787SSean Bruno 467*1e66f787SSean Bruno static inline boolean_t pqisrc_is_external_raid_addr(uint8_t *scsi3addr) 468*1e66f787SSean Bruno { 469*1e66f787SSean Bruno return scsi3addr[2] != 0; 470*1e66f787SSean Bruno } 471*1e66f787SSean Bruno 472*1e66f787SSean Bruno /* Function used to assign Bus-Target-Lun for the requested device */ 473*1e66f787SSean Bruno static void pqisrc_assign_btl(pqi_scsi_dev_t *device) 474*1e66f787SSean Bruno { 475*1e66f787SSean Bruno uint8_t *scsi3addr; 476*1e66f787SSean Bruno uint32_t lunid; 477*1e66f787SSean Bruno uint32_t bus; 478*1e66f787SSean Bruno uint32_t target; 479*1e66f787SSean Bruno uint32_t lun; 480*1e66f787SSean Bruno DBG_FUNC("IN\n"); 481*1e66f787SSean Bruno 482*1e66f787SSean Bruno scsi3addr = device->scsi3addr; 483*1e66f787SSean Bruno lunid = GET_LE32(scsi3addr); 484*1e66f787SSean Bruno 485*1e66f787SSean Bruno if (pqisrc_is_hba_lunid(scsi3addr)) { 486*1e66f787SSean Bruno /* The specified device is the controller. */ 487*1e66f787SSean Bruno pqisrc_set_btl(device, PQI_HBA_BUS, PQI_CTLR_INDEX, lunid & 0x3fff); 488*1e66f787SSean Bruno device->target_lun_valid = true; 489*1e66f787SSean Bruno return; 490*1e66f787SSean Bruno } 491*1e66f787SSean Bruno 492*1e66f787SSean Bruno if (pqisrc_is_logical_device(device)) { 493*1e66f787SSean Bruno if (pqisrc_is_external_raid_device(device)) { 494*1e66f787SSean Bruno DBG_INFO("External Raid Device!!!"); 495*1e66f787SSean Bruno bus = PQI_EXTERNAL_RAID_VOLUME_BUS; 496*1e66f787SSean Bruno target = (lunid >> 16) & 0x3fff; 497*1e66f787SSean Bruno lun = lunid & 0xff; 498*1e66f787SSean Bruno } else { 499*1e66f787SSean Bruno bus = PQI_RAID_VOLUME_BUS; 500*1e66f787SSean Bruno lun = 0; 501*1e66f787SSean Bruno target = lunid & 0x3fff; 502*1e66f787SSean Bruno } 503*1e66f787SSean Bruno pqisrc_set_btl(device, bus, target, lun); 504*1e66f787SSean Bruno device->target_lun_valid = true; 505*1e66f787SSean Bruno return; 506*1e66f787SSean Bruno } 507*1e66f787SSean Bruno 508*1e66f787SSean Bruno /* physical device */ 509*1e66f787SSean Bruno pqisrc_set_btl(device, PQI_PHYSICAL_DEVICE_BUS, PQI_PD_INDEX(scsi3addr[6]), 0); 510*1e66f787SSean Bruno 511*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 512*1e66f787SSean Bruno } 513*1e66f787SSean Bruno 514*1e66f787SSean Bruno /* Build and send the internal INQUIRY command to particular device */ 515*1e66f787SSean Bruno static int pqisrc_send_scsi_inquiry(pqisrc_softstate_t *softs, 516*1e66f787SSean Bruno uint8_t *scsi3addr, uint16_t vpd_page, uint8_t *buff, int buf_len) 517*1e66f787SSean Bruno { 518*1e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS; 519*1e66f787SSean Bruno pqisrc_raid_req_t request; 520*1e66f787SSean Bruno raid_path_error_info_elem_t error_info; 521*1e66f787SSean Bruno 522*1e66f787SSean Bruno DBG_FUNC("IN\n"); 523*1e66f787SSean Bruno 524*1e66f787SSean Bruno memset(&request, 0, sizeof(request)); 525*1e66f787SSean Bruno ret = pqisrc_build_send_raid_request(softs, &request, buff, buf_len, 526*1e66f787SSean Bruno SA_INQUIRY, vpd_page, scsi3addr, &error_info); 527*1e66f787SSean Bruno 528*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 529*1e66f787SSean Bruno return ret; 530*1e66f787SSean Bruno } 531*1e66f787SSean Bruno 532*1e66f787SSean Bruno /* Function used to parse the sense information from response */ 533*1e66f787SSean Bruno static void pqisrc_fetch_sense_info(const uint8_t *sense_data, 534*1e66f787SSean Bruno unsigned sense_data_length, uint8_t *sense_key, uint8_t *asc, uint8_t *ascq) 535*1e66f787SSean Bruno { 536*1e66f787SSean Bruno struct sense_header_scsi header; 537*1e66f787SSean Bruno 538*1e66f787SSean Bruno DBG_FUNC("IN\n"); 539*1e66f787SSean Bruno 540*1e66f787SSean Bruno *sense_key = 0; 541*1e66f787SSean Bruno *ascq = 0; 542*1e66f787SSean Bruno *asc = 0; 543*1e66f787SSean Bruno 544*1e66f787SSean Bruno if (pqisrc_update_scsi_sense(sense_data, sense_data_length, &header)) { 545*1e66f787SSean Bruno *sense_key = header.sense_key; 546*1e66f787SSean Bruno *asc = header.asc; 547*1e66f787SSean Bruno *ascq = header.ascq; 548*1e66f787SSean Bruno } 549*1e66f787SSean Bruno 550*1e66f787SSean Bruno DBG_INFO("sense_key: %x asc: %x ascq: %x\n", *sense_key, *asc, *ascq); 551*1e66f787SSean Bruno 552*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 553*1e66f787SSean Bruno } 554*1e66f787SSean Bruno 555*1e66f787SSean Bruno /* Function used to validate volume offline status */ 556*1e66f787SSean Bruno static uint8_t pqisrc_get_volume_offline_status(pqisrc_softstate_t *softs, 557*1e66f787SSean Bruno uint8_t *scsi3addr) 558*1e66f787SSean Bruno { 559*1e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS; 560*1e66f787SSean Bruno uint8_t status = SA_LV_STATUS_VPD_UNSUPPORTED; 561*1e66f787SSean Bruno uint8_t size; 562*1e66f787SSean Bruno uint8_t *buff = NULL; 563*1e66f787SSean Bruno 564*1e66f787SSean Bruno DBG_FUNC("IN\n"); 565*1e66f787SSean Bruno 566*1e66f787SSean Bruno buff = os_mem_alloc(softs, 64); 567*1e66f787SSean Bruno if (!buff) 568*1e66f787SSean Bruno return PQI_STATUS_FAILURE; 569*1e66f787SSean Bruno 570*1e66f787SSean Bruno /* Get the size of the VPD return buff. */ 571*1e66f787SSean Bruno ret = pqisrc_send_scsi_inquiry(softs, scsi3addr, VPD_PAGE | SA_VPD_LV_STATUS, 572*1e66f787SSean Bruno buff, SCSI_VPD_HEADER_LENGTH); 573*1e66f787SSean Bruno 574*1e66f787SSean Bruno if (ret) 575*1e66f787SSean Bruno goto out; 576*1e66f787SSean Bruno 577*1e66f787SSean Bruno size = buff[3]; 578*1e66f787SSean Bruno 579*1e66f787SSean Bruno /* Now get the whole VPD buff. */ 580*1e66f787SSean Bruno ret = pqisrc_send_scsi_inquiry(softs, scsi3addr, VPD_PAGE | SA_VPD_LV_STATUS, 581*1e66f787SSean Bruno buff, size + SCSI_VPD_HEADER_LENGTH); 582*1e66f787SSean Bruno if (ret) 583*1e66f787SSean Bruno goto out; 584*1e66f787SSean Bruno 585*1e66f787SSean Bruno status = buff[4]; 586*1e66f787SSean Bruno 587*1e66f787SSean Bruno out: 588*1e66f787SSean Bruno os_mem_free(softs, (char *)buff, 64); 589*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 590*1e66f787SSean Bruno 591*1e66f787SSean Bruno return status; 592*1e66f787SSean Bruno } 593*1e66f787SSean Bruno 594*1e66f787SSean Bruno 595*1e66f787SSean Bruno /* Determine offline status of a volume. Returns appropriate SA_LV_* status.*/ 596*1e66f787SSean Bruno static uint8_t pqisrc_get_dev_vol_status(pqisrc_softstate_t *softs, 597*1e66f787SSean Bruno uint8_t *scsi3addr) 598*1e66f787SSean Bruno { 599*1e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS; 600*1e66f787SSean Bruno uint8_t *sense_data; 601*1e66f787SSean Bruno unsigned sense_data_len; 602*1e66f787SSean Bruno uint8_t sense_key; 603*1e66f787SSean Bruno uint8_t asc; 604*1e66f787SSean Bruno uint8_t ascq; 605*1e66f787SSean Bruno uint8_t off_status; 606*1e66f787SSean Bruno uint8_t scsi_status; 607*1e66f787SSean Bruno pqisrc_raid_req_t request; 608*1e66f787SSean Bruno raid_path_error_info_elem_t error_info; 609*1e66f787SSean Bruno 610*1e66f787SSean Bruno DBG_FUNC("IN\n"); 611*1e66f787SSean Bruno 612*1e66f787SSean Bruno memset(&request, 0, sizeof(request)); 613*1e66f787SSean Bruno ret = pqisrc_build_send_raid_request(softs, &request, NULL, 0, 614*1e66f787SSean Bruno TEST_UNIT_READY, 0, scsi3addr, &error_info); 615*1e66f787SSean Bruno 616*1e66f787SSean Bruno if (ret) 617*1e66f787SSean Bruno goto error; 618*1e66f787SSean Bruno sense_data = error_info.data; 619*1e66f787SSean Bruno sense_data_len = LE_16(error_info.sense_data_len); 620*1e66f787SSean Bruno 621*1e66f787SSean Bruno if (sense_data_len > sizeof(error_info.data)) 622*1e66f787SSean Bruno sense_data_len = sizeof(error_info.data); 623*1e66f787SSean Bruno 624*1e66f787SSean Bruno pqisrc_fetch_sense_info(sense_data, sense_data_len, &sense_key, &asc, 625*1e66f787SSean Bruno &ascq); 626*1e66f787SSean Bruno 627*1e66f787SSean Bruno scsi_status = error_info.status; 628*1e66f787SSean Bruno 629*1e66f787SSean Bruno /* scsi status: "CHECK CONDN" / SK: "not ready" ? */ 630*1e66f787SSean Bruno if (scsi_status != 2 || 631*1e66f787SSean Bruno sense_key != 2 || 632*1e66f787SSean Bruno asc != ASC_LUN_NOT_READY) { 633*1e66f787SSean Bruno return SA_LV_OK; 634*1e66f787SSean Bruno } 635*1e66f787SSean Bruno 636*1e66f787SSean Bruno /* Determine the reason for not ready state. */ 637*1e66f787SSean Bruno off_status = pqisrc_get_volume_offline_status(softs, scsi3addr); 638*1e66f787SSean Bruno 639*1e66f787SSean Bruno DBG_INFO("offline_status 0x%x\n", off_status); 640*1e66f787SSean Bruno 641*1e66f787SSean Bruno /* Keep volume offline in certain cases. */ 642*1e66f787SSean Bruno switch (off_status) { 643*1e66f787SSean Bruno case SA_LV_UNDERGOING_ERASE: 644*1e66f787SSean Bruno case SA_LV_NOT_AVAILABLE: 645*1e66f787SSean Bruno case SA_LV_UNDERGOING_RPI: 646*1e66f787SSean Bruno case SA_LV_PENDING_RPI: 647*1e66f787SSean Bruno case SA_LV_ENCRYPTED_NO_KEY: 648*1e66f787SSean Bruno case SA_LV_PLAINTEXT_IN_ENCRYPT_ONLY_CONTROLLER: 649*1e66f787SSean Bruno case SA_LV_UNDERGOING_ENCRYPTION: 650*1e66f787SSean Bruno case SA_LV_UNDERGOING_ENCRYPTION_REKEYING: 651*1e66f787SSean Bruno case SA_LV_ENCRYPTED_IN_NON_ENCRYPTED_CONTROLLER: 652*1e66f787SSean Bruno return off_status; 653*1e66f787SSean Bruno case SA_LV_STATUS_VPD_UNSUPPORTED: 654*1e66f787SSean Bruno /* 655*1e66f787SSean Bruno * If the VPD status page isn't available, 656*1e66f787SSean Bruno * use ASC/ASCQ to determine state. 657*1e66f787SSean Bruno */ 658*1e66f787SSean Bruno if (ascq == ASCQ_LUN_NOT_READY_FORMAT_IN_PROGRESS || 659*1e66f787SSean Bruno ascq == ASCQ_LUN_NOT_READY_INITIALIZING_CMD_REQ) 660*1e66f787SSean Bruno return off_status; 661*1e66f787SSean Bruno break; 662*1e66f787SSean Bruno } 663*1e66f787SSean Bruno 664*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 665*1e66f787SSean Bruno 666*1e66f787SSean Bruno return SA_LV_OK; 667*1e66f787SSean Bruno 668*1e66f787SSean Bruno error: 669*1e66f787SSean Bruno return SA_LV_STATUS_VPD_UNSUPPORTED; 670*1e66f787SSean Bruno } 671*1e66f787SSean Bruno 672*1e66f787SSean Bruno /* Validate the RAID map parameters */ 673*1e66f787SSean Bruno static int pqisrc_raid_map_validation(pqisrc_softstate_t *softs, 674*1e66f787SSean Bruno pqi_scsi_dev_t *device, pqisrc_raid_map_t *raid_map) 675*1e66f787SSean Bruno { 676*1e66f787SSean Bruno char *error_msg; 677*1e66f787SSean Bruno uint32_t raidmap_size; 678*1e66f787SSean Bruno uint32_t r5or6_blocks_per_row; 679*1e66f787SSean Bruno unsigned phys_dev_num; 680*1e66f787SSean Bruno unsigned num_raidmap_entries; 681*1e66f787SSean Bruno 682*1e66f787SSean Bruno DBG_FUNC("IN\n"); 683*1e66f787SSean Bruno 684*1e66f787SSean Bruno raidmap_size = LE_32(raid_map->structure_size); 685*1e66f787SSean Bruno if (raidmap_size < offsetof(pqisrc_raid_map_t, dev_data)) { 686*1e66f787SSean Bruno error_msg = "RAID map too small\n"; 687*1e66f787SSean Bruno goto error; 688*1e66f787SSean Bruno } 689*1e66f787SSean Bruno 690*1e66f787SSean Bruno if (raidmap_size > sizeof(*raid_map)) { 691*1e66f787SSean Bruno error_msg = "RAID map too large\n"; 692*1e66f787SSean Bruno goto error; 693*1e66f787SSean Bruno } 694*1e66f787SSean Bruno 695*1e66f787SSean Bruno phys_dev_num = LE_16(raid_map->layout_map_count) * 696*1e66f787SSean Bruno (LE_16(raid_map->data_disks_per_row) + 697*1e66f787SSean Bruno LE_16(raid_map->metadata_disks_per_row)); 698*1e66f787SSean Bruno num_raidmap_entries = phys_dev_num * 699*1e66f787SSean Bruno LE_16(raid_map->row_cnt); 700*1e66f787SSean Bruno 701*1e66f787SSean Bruno if (num_raidmap_entries > RAID_MAP_MAX_ENTRIES) { 702*1e66f787SSean Bruno error_msg = "invalid number of map entries in RAID map\n"; 703*1e66f787SSean Bruno goto error; 704*1e66f787SSean Bruno } 705*1e66f787SSean Bruno 706*1e66f787SSean Bruno if (device->raid_level == SA_RAID_1) { 707*1e66f787SSean Bruno if (LE_16(raid_map->layout_map_count) != 2) { 708*1e66f787SSean Bruno error_msg = "invalid RAID-1 map\n"; 709*1e66f787SSean Bruno goto error; 710*1e66f787SSean Bruno } 711*1e66f787SSean Bruno } else if (device->raid_level == SA_RAID_ADM) { 712*1e66f787SSean Bruno if (LE_16(raid_map->layout_map_count) != 3) { 713*1e66f787SSean Bruno error_msg = "invalid RAID-1(ADM) map\n"; 714*1e66f787SSean Bruno goto error; 715*1e66f787SSean Bruno } 716*1e66f787SSean Bruno } else if ((device->raid_level == SA_RAID_5 || 717*1e66f787SSean Bruno device->raid_level == SA_RAID_6) && 718*1e66f787SSean Bruno LE_16(raid_map->layout_map_count) > 1) { 719*1e66f787SSean Bruno /* RAID 50/60 */ 720*1e66f787SSean Bruno r5or6_blocks_per_row = 721*1e66f787SSean Bruno LE_16(raid_map->strip_size) * 722*1e66f787SSean Bruno LE_16(raid_map->data_disks_per_row); 723*1e66f787SSean Bruno if (r5or6_blocks_per_row == 0) { 724*1e66f787SSean Bruno error_msg = "invalid RAID-5 or RAID-6 map\n"; 725*1e66f787SSean Bruno goto error; 726*1e66f787SSean Bruno } 727*1e66f787SSean Bruno } 728*1e66f787SSean Bruno 729*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 730*1e66f787SSean Bruno 731*1e66f787SSean Bruno return 0; 732*1e66f787SSean Bruno 733*1e66f787SSean Bruno error: 734*1e66f787SSean Bruno DBG_ERR("%s\n", error_msg); 735*1e66f787SSean Bruno return PQI_STATUS_FAILURE; 736*1e66f787SSean Bruno } 737*1e66f787SSean Bruno 738*1e66f787SSean Bruno /* Get device raidmap for the requested device */ 739*1e66f787SSean Bruno static int pqisrc_get_device_raidmap(pqisrc_softstate_t *softs, 740*1e66f787SSean Bruno pqi_scsi_dev_t *device) 741*1e66f787SSean Bruno { 742*1e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS; 743*1e66f787SSean Bruno pqisrc_raid_req_t request; 744*1e66f787SSean Bruno pqisrc_raid_map_t *raid_map; 745*1e66f787SSean Bruno 746*1e66f787SSean Bruno DBG_FUNC("IN\n"); 747*1e66f787SSean Bruno 748*1e66f787SSean Bruno raid_map = os_mem_alloc(softs, sizeof(*raid_map)); 749*1e66f787SSean Bruno if (!raid_map) 750*1e66f787SSean Bruno return PQI_STATUS_FAILURE; 751*1e66f787SSean Bruno 752*1e66f787SSean Bruno memset(&request, 0, sizeof(request)); 753*1e66f787SSean Bruno ret = pqisrc_build_send_raid_request(softs, &request, raid_map, sizeof(*raid_map), 754*1e66f787SSean Bruno SA_GET_RAID_MAP, 0, device->scsi3addr, NULL); 755*1e66f787SSean Bruno 756*1e66f787SSean Bruno if (ret) { 757*1e66f787SSean Bruno DBG_ERR("error in build send raid req ret=%d\n", ret); 758*1e66f787SSean Bruno goto err_out; 759*1e66f787SSean Bruno } 760*1e66f787SSean Bruno 761*1e66f787SSean Bruno ret = pqisrc_raid_map_validation(softs, device, raid_map); 762*1e66f787SSean Bruno if (ret) { 763*1e66f787SSean Bruno DBG_ERR("error in raid map validation ret=%d\n", ret); 764*1e66f787SSean Bruno goto err_out; 765*1e66f787SSean Bruno } 766*1e66f787SSean Bruno 767*1e66f787SSean Bruno device->raid_map = raid_map; 768*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 769*1e66f787SSean Bruno return 0; 770*1e66f787SSean Bruno 771*1e66f787SSean Bruno err_out: 772*1e66f787SSean Bruno os_mem_free(softs, (char*)raid_map, sizeof(*raid_map)); 773*1e66f787SSean Bruno DBG_FUNC("FAILED \n"); 774*1e66f787SSean Bruno return ret; 775*1e66f787SSean Bruno } 776*1e66f787SSean Bruno 777*1e66f787SSean Bruno /* Get device ioaccel_status to validate the type of device */ 778*1e66f787SSean Bruno static void pqisrc_get_dev_ioaccel_status(pqisrc_softstate_t *softs, 779*1e66f787SSean Bruno pqi_scsi_dev_t *device) 780*1e66f787SSean Bruno { 781*1e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS; 782*1e66f787SSean Bruno uint8_t *buff; 783*1e66f787SSean Bruno uint8_t ioaccel_status; 784*1e66f787SSean Bruno 785*1e66f787SSean Bruno DBG_FUNC("IN\n"); 786*1e66f787SSean Bruno 787*1e66f787SSean Bruno buff = os_mem_alloc(softs, 64); 788*1e66f787SSean Bruno if (!buff) 789*1e66f787SSean Bruno return; 790*1e66f787SSean Bruno 791*1e66f787SSean Bruno ret = pqisrc_send_scsi_inquiry(softs, device->scsi3addr, 792*1e66f787SSean Bruno VPD_PAGE | SA_VPD_LV_IOACCEL_STATUS, buff, 64); 793*1e66f787SSean Bruno if (ret) { 794*1e66f787SSean Bruno DBG_ERR("error in send scsi inquiry ret=%d\n", ret); 795*1e66f787SSean Bruno goto err_out; 796*1e66f787SSean Bruno } 797*1e66f787SSean Bruno 798*1e66f787SSean Bruno ioaccel_status = buff[IOACCEL_STATUS_BYTE]; 799*1e66f787SSean Bruno device->offload_config = 800*1e66f787SSean Bruno !!(ioaccel_status & OFFLOAD_CONFIGURED_BIT); 801*1e66f787SSean Bruno 802*1e66f787SSean Bruno if (device->offload_config) { 803*1e66f787SSean Bruno device->offload_enabled_pending = 804*1e66f787SSean Bruno !!(ioaccel_status & OFFLOAD_ENABLED_BIT); 805*1e66f787SSean Bruno if (pqisrc_get_device_raidmap(softs, device)) 806*1e66f787SSean Bruno device->offload_enabled_pending = false; 807*1e66f787SSean Bruno } 808*1e66f787SSean Bruno 809*1e66f787SSean Bruno DBG_INFO("offload_config: 0x%x offload_enabled_pending: 0x%x \n", 810*1e66f787SSean Bruno device->offload_config, device->offload_enabled_pending); 811*1e66f787SSean Bruno 812*1e66f787SSean Bruno err_out: 813*1e66f787SSean Bruno os_mem_free(softs, (char*)buff, 64); 814*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 815*1e66f787SSean Bruno } 816*1e66f787SSean Bruno 817*1e66f787SSean Bruno /* Get RAID level of requested device */ 818*1e66f787SSean Bruno static void pqisrc_get_dev_raid_level(pqisrc_softstate_t *softs, 819*1e66f787SSean Bruno pqi_scsi_dev_t *device) 820*1e66f787SSean Bruno { 821*1e66f787SSean Bruno uint8_t raid_level; 822*1e66f787SSean Bruno uint8_t *buff; 823*1e66f787SSean Bruno 824*1e66f787SSean Bruno DBG_FUNC("IN\n"); 825*1e66f787SSean Bruno 826*1e66f787SSean Bruno raid_level = SA_RAID_UNKNOWN; 827*1e66f787SSean Bruno 828*1e66f787SSean Bruno buff = os_mem_alloc(softs, 64); 829*1e66f787SSean Bruno if (buff) { 830*1e66f787SSean Bruno int ret; 831*1e66f787SSean Bruno ret = pqisrc_send_scsi_inquiry(softs, device->scsi3addr, 832*1e66f787SSean Bruno VPD_PAGE | SA_VPD_LV_DEVICE_GEOMETRY, buff, 64); 833*1e66f787SSean Bruno if (ret == 0) { 834*1e66f787SSean Bruno raid_level = buff[8]; 835*1e66f787SSean Bruno if (raid_level > SA_RAID_MAX) 836*1e66f787SSean Bruno raid_level = SA_RAID_UNKNOWN; 837*1e66f787SSean Bruno } 838*1e66f787SSean Bruno os_mem_free(softs, (char*)buff, 64); 839*1e66f787SSean Bruno } 840*1e66f787SSean Bruno 841*1e66f787SSean Bruno device->raid_level = raid_level; 842*1e66f787SSean Bruno DBG_INFO("RAID LEVEL: %x \n", raid_level); 843*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 844*1e66f787SSean Bruno } 845*1e66f787SSean Bruno 846*1e66f787SSean Bruno /* Parse the inquiry response and determine the type of device */ 847*1e66f787SSean Bruno static int pqisrc_get_dev_data(pqisrc_softstate_t *softs, 848*1e66f787SSean Bruno pqi_scsi_dev_t *device) 849*1e66f787SSean Bruno { 850*1e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS; 851*1e66f787SSean Bruno uint8_t *inq_buff; 852*1e66f787SSean Bruno 853*1e66f787SSean Bruno DBG_FUNC("IN\n"); 854*1e66f787SSean Bruno 855*1e66f787SSean Bruno inq_buff = os_mem_alloc(softs, OBDR_TAPE_INQ_SIZE); 856*1e66f787SSean Bruno if (!inq_buff) 857*1e66f787SSean Bruno return PQI_STATUS_FAILURE; 858*1e66f787SSean Bruno 859*1e66f787SSean Bruno /* Send an inquiry to the device to see what it is. */ 860*1e66f787SSean Bruno ret = pqisrc_send_scsi_inquiry(softs, device->scsi3addr, 0, inq_buff, 861*1e66f787SSean Bruno OBDR_TAPE_INQ_SIZE); 862*1e66f787SSean Bruno if (ret) 863*1e66f787SSean Bruno goto err_out; 864*1e66f787SSean Bruno pqisrc_sanitize_inquiry_string(&inq_buff[8], 8); 865*1e66f787SSean Bruno pqisrc_sanitize_inquiry_string(&inq_buff[16], 16); 866*1e66f787SSean Bruno 867*1e66f787SSean Bruno device->devtype = inq_buff[0] & 0x1f; 868*1e66f787SSean Bruno memcpy(device->vendor, &inq_buff[8], 869*1e66f787SSean Bruno sizeof(device->vendor)); 870*1e66f787SSean Bruno memcpy(device->model, &inq_buff[16], 871*1e66f787SSean Bruno sizeof(device->model)); 872*1e66f787SSean Bruno DBG_INFO("DEV_TYPE: %x VENDOR: %s MODEL: %s\n", device->devtype, device->vendor, device->model); 873*1e66f787SSean Bruno 874*1e66f787SSean Bruno if (pqisrc_is_logical_device(device) && device->devtype == DISK_DEVICE) { 875*1e66f787SSean Bruno if (pqisrc_is_external_raid_device(device)) { 876*1e66f787SSean Bruno device->raid_level = SA_RAID_UNKNOWN; 877*1e66f787SSean Bruno device->volume_status = SA_LV_OK; 878*1e66f787SSean Bruno device->volume_offline = false; 879*1e66f787SSean Bruno } 880*1e66f787SSean Bruno else { 881*1e66f787SSean Bruno pqisrc_get_dev_raid_level(softs, device); 882*1e66f787SSean Bruno pqisrc_get_dev_ioaccel_status(softs, device); 883*1e66f787SSean Bruno device->volume_status = pqisrc_get_dev_vol_status(softs, 884*1e66f787SSean Bruno device->scsi3addr); 885*1e66f787SSean Bruno device->volume_offline = device->volume_status != SA_LV_OK; 886*1e66f787SSean Bruno } 887*1e66f787SSean Bruno } 888*1e66f787SSean Bruno 889*1e66f787SSean Bruno /* 890*1e66f787SSean Bruno * Check if this is a One-Button-Disaster-Recovery device 891*1e66f787SSean Bruno * by looking for "$DR-10" at offset 43 in the inquiry data. 892*1e66f787SSean Bruno */ 893*1e66f787SSean Bruno device->is_obdr_device = (device->devtype == ROM_DEVICE && 894*1e66f787SSean Bruno memcmp(&inq_buff[OBDR_SIG_OFFSET], OBDR_TAPE_SIG, 895*1e66f787SSean Bruno OBDR_SIG_LEN) == 0); 896*1e66f787SSean Bruno err_out: 897*1e66f787SSean Bruno os_mem_free(softs, (char*)inq_buff, OBDR_TAPE_INQ_SIZE); 898*1e66f787SSean Bruno 899*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 900*1e66f787SSean Bruno return ret; 901*1e66f787SSean Bruno } 902*1e66f787SSean Bruno 903*1e66f787SSean Bruno /* 904*1e66f787SSean Bruno * BMIC (Basic Management And Interface Commands) command 905*1e66f787SSean Bruno * to get the controller identify params 906*1e66f787SSean Bruno */ 907*1e66f787SSean Bruno static int pqisrc_identify_ctrl(pqisrc_softstate_t *softs, 908*1e66f787SSean Bruno bmic_ident_ctrl_t *buff) 909*1e66f787SSean Bruno { 910*1e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS; 911*1e66f787SSean Bruno pqisrc_raid_req_t request; 912*1e66f787SSean Bruno 913*1e66f787SSean Bruno DBG_FUNC("IN\n"); 914*1e66f787SSean Bruno 915*1e66f787SSean Bruno memset(&request, 0, sizeof(request)); 916*1e66f787SSean Bruno ret = pqisrc_build_send_raid_request(softs, &request, buff, sizeof(*buff), 917*1e66f787SSean Bruno BMIC_IDENTIFY_CONTROLLER, 0, (uint8_t *)RAID_CTLR_LUNID, NULL); 918*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 919*1e66f787SSean Bruno 920*1e66f787SSean Bruno return ret; 921*1e66f787SSean Bruno } 922*1e66f787SSean Bruno 923*1e66f787SSean Bruno /* Get the adapter FW version using BMIC_IDENTIFY_CONTROLLER */ 924*1e66f787SSean Bruno int pqisrc_get_ctrl_fw_version(pqisrc_softstate_t *softs) 925*1e66f787SSean Bruno { 926*1e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS; 927*1e66f787SSean Bruno bmic_ident_ctrl_t *identify_ctrl; 928*1e66f787SSean Bruno 929*1e66f787SSean Bruno DBG_FUNC("IN\n"); 930*1e66f787SSean Bruno 931*1e66f787SSean Bruno identify_ctrl = os_mem_alloc(softs, sizeof(*identify_ctrl)); 932*1e66f787SSean Bruno if (!identify_ctrl) { 933*1e66f787SSean Bruno DBG_ERR("failed to allocate memory for identify_ctrl\n"); 934*1e66f787SSean Bruno return PQI_STATUS_FAILURE; 935*1e66f787SSean Bruno } 936*1e66f787SSean Bruno 937*1e66f787SSean Bruno memset(identify_ctrl, 0, sizeof(*identify_ctrl)); 938*1e66f787SSean Bruno 939*1e66f787SSean Bruno ret = pqisrc_identify_ctrl(softs, identify_ctrl); 940*1e66f787SSean Bruno if (ret) 941*1e66f787SSean Bruno goto out; 942*1e66f787SSean Bruno 943*1e66f787SSean Bruno softs->fw_build_number = identify_ctrl->fw_build_number; 944*1e66f787SSean Bruno memcpy(softs->fw_version, identify_ctrl->fw_version, 945*1e66f787SSean Bruno sizeof(identify_ctrl->fw_version)); 946*1e66f787SSean Bruno softs->fw_version[sizeof(identify_ctrl->fw_version)] = '\0'; 947*1e66f787SSean Bruno snprintf(softs->fw_version + 948*1e66f787SSean Bruno strlen(softs->fw_version), 949*1e66f787SSean Bruno sizeof(softs->fw_version), 950*1e66f787SSean Bruno "-%u", identify_ctrl->fw_build_number); 951*1e66f787SSean Bruno out: 952*1e66f787SSean Bruno os_mem_free(softs, (char *)identify_ctrl, sizeof(*identify_ctrl)); 953*1e66f787SSean Bruno DBG_INFO("Firmware version: %s Firmware build number: %d\n", softs->fw_version, softs->fw_build_number); 954*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 955*1e66f787SSean Bruno return ret; 956*1e66f787SSean Bruno } 957*1e66f787SSean Bruno 958*1e66f787SSean Bruno /* BMIC command to determine scsi device identify params */ 959*1e66f787SSean Bruno static int pqisrc_identify_physical_disk(pqisrc_softstate_t *softs, 960*1e66f787SSean Bruno pqi_scsi_dev_t *device, 961*1e66f787SSean Bruno bmic_ident_physdev_t *buff, 962*1e66f787SSean Bruno int buf_len) 963*1e66f787SSean Bruno { 964*1e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS; 965*1e66f787SSean Bruno uint16_t bmic_device_index; 966*1e66f787SSean Bruno pqisrc_raid_req_t request; 967*1e66f787SSean Bruno 968*1e66f787SSean Bruno 969*1e66f787SSean Bruno DBG_FUNC("IN\n"); 970*1e66f787SSean Bruno 971*1e66f787SSean Bruno memset(&request, 0, sizeof(request)); 972*1e66f787SSean Bruno bmic_device_index = BMIC_GET_DRIVE_NUMBER(device->scsi3addr); 973*1e66f787SSean Bruno request.cdb[2] = (uint8_t)bmic_device_index; 974*1e66f787SSean Bruno request.cdb[9] = (uint8_t)(bmic_device_index >> 8); 975*1e66f787SSean Bruno 976*1e66f787SSean Bruno ret = pqisrc_build_send_raid_request(softs, &request, buff, buf_len, 977*1e66f787SSean Bruno BMIC_IDENTIFY_PHYSICAL_DEVICE, 0, (uint8_t *)RAID_CTLR_LUNID, NULL); 978*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 979*1e66f787SSean Bruno return ret; 980*1e66f787SSean Bruno } 981*1e66f787SSean Bruno 982*1e66f787SSean Bruno /* 983*1e66f787SSean Bruno * Function used to get the scsi device information using one of BMIC 984*1e66f787SSean Bruno * BMIC_IDENTIFY_PHYSICAL_DEVICE 985*1e66f787SSean Bruno */ 986*1e66f787SSean Bruno static void pqisrc_get_physical_device_info(pqisrc_softstate_t *softs, 987*1e66f787SSean Bruno pqi_scsi_dev_t *device, 988*1e66f787SSean Bruno bmic_ident_physdev_t *id_phys) 989*1e66f787SSean Bruno { 990*1e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS; 991*1e66f787SSean Bruno 992*1e66f787SSean Bruno DBG_FUNC("IN\n"); 993*1e66f787SSean Bruno memset(id_phys, 0, sizeof(*id_phys)); 994*1e66f787SSean Bruno 995*1e66f787SSean Bruno ret= pqisrc_identify_physical_disk(softs, device, 996*1e66f787SSean Bruno id_phys, sizeof(*id_phys)); 997*1e66f787SSean Bruno if (ret) { 998*1e66f787SSean Bruno device->queue_depth = PQI_PHYSICAL_DISK_DEFAULT_MAX_QUEUE_DEPTH; 999*1e66f787SSean Bruno return; 1000*1e66f787SSean Bruno } 1001*1e66f787SSean Bruno 1002*1e66f787SSean Bruno device->queue_depth = 1003*1e66f787SSean Bruno LE_16(id_phys->current_queue_depth_limit); 1004*1e66f787SSean Bruno device->device_type = id_phys->device_type; 1005*1e66f787SSean Bruno device->active_path_index = id_phys->active_path_number; 1006*1e66f787SSean Bruno device->path_map = id_phys->redundant_path_present_map; 1007*1e66f787SSean Bruno memcpy(&device->box, 1008*1e66f787SSean Bruno &id_phys->alternate_paths_phys_box_on_port, 1009*1e66f787SSean Bruno sizeof(device->box)); 1010*1e66f787SSean Bruno memcpy(&device->phys_connector, 1011*1e66f787SSean Bruno &id_phys->alternate_paths_phys_connector, 1012*1e66f787SSean Bruno sizeof(device->phys_connector)); 1013*1e66f787SSean Bruno device->bay = id_phys->phys_bay_in_box; 1014*1e66f787SSean Bruno 1015*1e66f787SSean Bruno DBG_INFO("BMIC DEV_TYPE: %x QUEUE DEPTH: 0x%x \n", device->device_type, device->queue_depth); 1016*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 1017*1e66f787SSean Bruno } 1018*1e66f787SSean Bruno 1019*1e66f787SSean Bruno 1020*1e66f787SSean Bruno /* Function used to find the entry of the device in a list */ 1021*1e66f787SSean Bruno static device_status_t pqisrc_scsi_find_entry(pqisrc_softstate_t *softs, 1022*1e66f787SSean Bruno pqi_scsi_dev_t *device_to_find, 1023*1e66f787SSean Bruno pqi_scsi_dev_t **same_device) 1024*1e66f787SSean Bruno { 1025*1e66f787SSean Bruno pqi_scsi_dev_t *device; 1026*1e66f787SSean Bruno int i,j; 1027*1e66f787SSean Bruno DBG_FUNC("IN\n"); 1028*1e66f787SSean Bruno for(i = 0; i < PQI_MAX_DEVICES; i++) { 1029*1e66f787SSean Bruno for(j = 0; j < PQI_MAX_MULTILUN; j++) { 1030*1e66f787SSean Bruno if(softs->device_list[i][j] == NULL) 1031*1e66f787SSean Bruno continue; 1032*1e66f787SSean Bruno device = softs->device_list[i][j]; 1033*1e66f787SSean Bruno if (pqisrc_scsi3addr_equal(device_to_find->scsi3addr, 1034*1e66f787SSean Bruno device->scsi3addr)) { 1035*1e66f787SSean Bruno *same_device = device; 1036*1e66f787SSean Bruno if (pqisrc_device_equal(device_to_find, device)) { 1037*1e66f787SSean Bruno if (device_to_find->volume_offline) 1038*1e66f787SSean Bruno return DEVICE_CHANGED; 1039*1e66f787SSean Bruno return DEVICE_UNCHANGED; 1040*1e66f787SSean Bruno } 1041*1e66f787SSean Bruno return DEVICE_CHANGED; 1042*1e66f787SSean Bruno } 1043*1e66f787SSean Bruno } 1044*1e66f787SSean Bruno } 1045*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 1046*1e66f787SSean Bruno 1047*1e66f787SSean Bruno return DEVICE_NOT_FOUND; 1048*1e66f787SSean Bruno } 1049*1e66f787SSean Bruno 1050*1e66f787SSean Bruno 1051*1e66f787SSean Bruno /* Update the newly added devices as existed device */ 1052*1e66f787SSean Bruno static void pqisrc_exist_device_update(pqisrc_softstate_t *softs, 1053*1e66f787SSean Bruno pqi_scsi_dev_t *device_exist, 1054*1e66f787SSean Bruno pqi_scsi_dev_t *new_device) 1055*1e66f787SSean Bruno { 1056*1e66f787SSean Bruno DBG_FUNC("IN\n"); 1057*1e66f787SSean Bruno device_exist->expose_device = new_device->expose_device; 1058*1e66f787SSean Bruno memcpy(device_exist->vendor, new_device->vendor, 1059*1e66f787SSean Bruno sizeof(device_exist->vendor)); 1060*1e66f787SSean Bruno memcpy(device_exist->model, new_device->model, 1061*1e66f787SSean Bruno sizeof(device_exist->model)); 1062*1e66f787SSean Bruno device_exist->is_physical_device = new_device->is_physical_device; 1063*1e66f787SSean Bruno device_exist->is_external_raid_device = 1064*1e66f787SSean Bruno new_device->is_external_raid_device; 1065*1e66f787SSean Bruno device_exist->sas_address = new_device->sas_address; 1066*1e66f787SSean Bruno device_exist->raid_level = new_device->raid_level; 1067*1e66f787SSean Bruno device_exist->queue_depth = new_device->queue_depth; 1068*1e66f787SSean Bruno device_exist->ioaccel_handle = new_device->ioaccel_handle; 1069*1e66f787SSean Bruno device_exist->volume_status = new_device->volume_status; 1070*1e66f787SSean Bruno device_exist->active_path_index = new_device->active_path_index; 1071*1e66f787SSean Bruno device_exist->path_map = new_device->path_map; 1072*1e66f787SSean Bruno device_exist->bay = new_device->bay; 1073*1e66f787SSean Bruno memcpy(device_exist->box, new_device->box, 1074*1e66f787SSean Bruno sizeof(device_exist->box)); 1075*1e66f787SSean Bruno memcpy(device_exist->phys_connector, new_device->phys_connector, 1076*1e66f787SSean Bruno sizeof(device_exist->phys_connector)); 1077*1e66f787SSean Bruno device_exist->offload_config = new_device->offload_config; 1078*1e66f787SSean Bruno device_exist->offload_enabled = false; 1079*1e66f787SSean Bruno device_exist->offload_enabled_pending = 1080*1e66f787SSean Bruno new_device->offload_enabled_pending; 1081*1e66f787SSean Bruno device_exist->offload_to_mirror = 0; 1082*1e66f787SSean Bruno if (device_exist->raid_map) 1083*1e66f787SSean Bruno os_mem_free(softs, 1084*1e66f787SSean Bruno (char *)device_exist->raid_map, 1085*1e66f787SSean Bruno sizeof(*device_exist->raid_map)); 1086*1e66f787SSean Bruno device_exist->raid_map = new_device->raid_map; 1087*1e66f787SSean Bruno /* To prevent this from being freed later. */ 1088*1e66f787SSean Bruno new_device->raid_map = NULL; 1089*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 1090*1e66f787SSean Bruno } 1091*1e66f787SSean Bruno 1092*1e66f787SSean Bruno /* Validate the ioaccel_handle for a newly added device */ 1093*1e66f787SSean Bruno static pqi_scsi_dev_t *pqisrc_identify_device_via_ioaccel( 1094*1e66f787SSean Bruno pqisrc_softstate_t *softs, uint32_t ioaccel_handle) 1095*1e66f787SSean Bruno { 1096*1e66f787SSean Bruno pqi_scsi_dev_t *device; 1097*1e66f787SSean Bruno int i,j; 1098*1e66f787SSean Bruno DBG_FUNC("IN\n"); 1099*1e66f787SSean Bruno for(i = 0; i < PQI_MAX_DEVICES; i++) { 1100*1e66f787SSean Bruno for(j = 0; j < PQI_MAX_MULTILUN; j++) { 1101*1e66f787SSean Bruno if(softs->device_list[i][j] == NULL) 1102*1e66f787SSean Bruno continue; 1103*1e66f787SSean Bruno device = softs->device_list[i][j]; 1104*1e66f787SSean Bruno if (device->devtype != DISK_DEVICE) 1105*1e66f787SSean Bruno continue; 1106*1e66f787SSean Bruno if (pqisrc_is_logical_device(device)) 1107*1e66f787SSean Bruno continue; 1108*1e66f787SSean Bruno if (device->ioaccel_handle == ioaccel_handle) 1109*1e66f787SSean Bruno return device; 1110*1e66f787SSean Bruno } 1111*1e66f787SSean Bruno } 1112*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 1113*1e66f787SSean Bruno 1114*1e66f787SSean Bruno return NULL; 1115*1e66f787SSean Bruno } 1116*1e66f787SSean Bruno 1117*1e66f787SSean Bruno /* Get the scsi device queue depth */ 1118*1e66f787SSean Bruno static void pqisrc_update_log_dev_qdepth(pqisrc_softstate_t *softs) 1119*1e66f787SSean Bruno { 1120*1e66f787SSean Bruno unsigned i; 1121*1e66f787SSean Bruno unsigned phys_dev_num; 1122*1e66f787SSean Bruno unsigned num_raidmap_entries; 1123*1e66f787SSean Bruno unsigned queue_depth; 1124*1e66f787SSean Bruno pqisrc_raid_map_t *raid_map; 1125*1e66f787SSean Bruno pqi_scsi_dev_t *device; 1126*1e66f787SSean Bruno raidmap_data_t *dev_data; 1127*1e66f787SSean Bruno pqi_scsi_dev_t *phys_disk; 1128*1e66f787SSean Bruno unsigned j; 1129*1e66f787SSean Bruno 1130*1e66f787SSean Bruno DBG_FUNC("IN\n"); 1131*1e66f787SSean Bruno 1132*1e66f787SSean Bruno for(i = 0; i < PQI_MAX_DEVICES; i++) { 1133*1e66f787SSean Bruno for(j = 0; j < PQI_MAX_MULTILUN; j++) { 1134*1e66f787SSean Bruno if(softs->device_list[i][j] == NULL) 1135*1e66f787SSean Bruno continue; 1136*1e66f787SSean Bruno device = softs->device_list[i][j]; 1137*1e66f787SSean Bruno if (device->devtype != DISK_DEVICE) 1138*1e66f787SSean Bruno continue; 1139*1e66f787SSean Bruno if (!pqisrc_is_logical_device(device)) 1140*1e66f787SSean Bruno continue; 1141*1e66f787SSean Bruno if (pqisrc_is_external_raid_device(device)) 1142*1e66f787SSean Bruno continue; 1143*1e66f787SSean Bruno device->queue_depth = PQI_LOGICAL_DISK_DEFAULT_MAX_QUEUE_DEPTH; 1144*1e66f787SSean Bruno raid_map = device->raid_map; 1145*1e66f787SSean Bruno if (!raid_map) 1146*1e66f787SSean Bruno return; 1147*1e66f787SSean Bruno dev_data = raid_map->dev_data; 1148*1e66f787SSean Bruno phys_dev_num = LE_16(raid_map->layout_map_count) * 1149*1e66f787SSean Bruno (LE_16(raid_map->data_disks_per_row) + 1150*1e66f787SSean Bruno LE_16(raid_map->metadata_disks_per_row)); 1151*1e66f787SSean Bruno num_raidmap_entries = phys_dev_num * 1152*1e66f787SSean Bruno LE_16(raid_map->row_cnt); 1153*1e66f787SSean Bruno 1154*1e66f787SSean Bruno queue_depth = 0; 1155*1e66f787SSean Bruno for (i = 0; i < num_raidmap_entries; i++) { 1156*1e66f787SSean Bruno phys_disk = pqisrc_identify_device_via_ioaccel(softs, 1157*1e66f787SSean Bruno dev_data[i].ioaccel_handle); 1158*1e66f787SSean Bruno 1159*1e66f787SSean Bruno if (!phys_disk) { 1160*1e66f787SSean Bruno DBG_WARN( 1161*1e66f787SSean Bruno "Failed to find physical disk handle for logical drive %016llx\n", 1162*1e66f787SSean Bruno (unsigned long long)BE_64(device->scsi3addr[0])); 1163*1e66f787SSean Bruno device->offload_enabled = false; 1164*1e66f787SSean Bruno device->offload_enabled_pending = false; 1165*1e66f787SSean Bruno if (raid_map) 1166*1e66f787SSean Bruno os_mem_free(softs, (char *)raid_map, sizeof(*raid_map)); 1167*1e66f787SSean Bruno device->raid_map = NULL; 1168*1e66f787SSean Bruno return; 1169*1e66f787SSean Bruno } 1170*1e66f787SSean Bruno 1171*1e66f787SSean Bruno queue_depth += phys_disk->queue_depth; 1172*1e66f787SSean Bruno } 1173*1e66f787SSean Bruno 1174*1e66f787SSean Bruno device->queue_depth = queue_depth; 1175*1e66f787SSean Bruno } /* end inner loop */ 1176*1e66f787SSean Bruno }/* end outer loop */ 1177*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 1178*1e66f787SSean Bruno } 1179*1e66f787SSean Bruno 1180*1e66f787SSean Bruno /* Function used to add a scsi device to OS scsi subsystem */ 1181*1e66f787SSean Bruno static int pqisrc_add_device(pqisrc_softstate_t *softs, 1182*1e66f787SSean Bruno pqi_scsi_dev_t *device) 1183*1e66f787SSean Bruno { 1184*1e66f787SSean Bruno DBG_FUNC("IN\n"); 1185*1e66f787SSean Bruno DBG_INFO("vendor: %s model: %s bus:%d target:%d lun:%d is_physical_device:0x%x expose_device:0x%x volume_offline 0x%x volume_status 0x%x \n", 1186*1e66f787SSean Bruno device->vendor, device->model, device->bus, device->target, device->lun, device->is_physical_device, device->expose_device, device->volume_offline, device->volume_status); 1187*1e66f787SSean Bruno 1188*1e66f787SSean Bruno device->invalid = false; 1189*1e66f787SSean Bruno 1190*1e66f787SSean Bruno if(device->expose_device) { 1191*1e66f787SSean Bruno /* TBD: Call OS upper layer function to add the device entry */ 1192*1e66f787SSean Bruno os_add_device(softs,device); 1193*1e66f787SSean Bruno } 1194*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 1195*1e66f787SSean Bruno return PQI_STATUS_SUCCESS; 1196*1e66f787SSean Bruno 1197*1e66f787SSean Bruno } 1198*1e66f787SSean Bruno 1199*1e66f787SSean Bruno /* Function used to remove a scsi device from OS scsi subsystem */ 1200*1e66f787SSean Bruno void pqisrc_remove_device(pqisrc_softstate_t *softs, 1201*1e66f787SSean Bruno pqi_scsi_dev_t *device) 1202*1e66f787SSean Bruno { 1203*1e66f787SSean Bruno DBG_FUNC("IN\n"); 1204*1e66f787SSean Bruno DBG_INFO("vendor: %s model: %s bus:%d target:%d lun:%d is_physical_device:0x%x expose_device:0x%x volume_offline 0x%x volume_status 0x%x \n", 1205*1e66f787SSean Bruno device->vendor, device->model, device->bus, device->target, device->lun, device->is_physical_device, device->expose_device, device->volume_offline, device->volume_status); 1206*1e66f787SSean Bruno 1207*1e66f787SSean Bruno /* TBD: Call OS upper layer function to remove the device entry */ 1208*1e66f787SSean Bruno device->invalid = true; 1209*1e66f787SSean Bruno os_remove_device(softs,device); 1210*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 1211*1e66f787SSean Bruno } 1212*1e66f787SSean Bruno 1213*1e66f787SSean Bruno 1214*1e66f787SSean Bruno /* 1215*1e66f787SSean Bruno * When exposing new device to OS fails then adjst list according to the 1216*1e66f787SSean Bruno * mid scsi list 1217*1e66f787SSean Bruno */ 1218*1e66f787SSean Bruno static void pqisrc_adjust_list(pqisrc_softstate_t *softs, 1219*1e66f787SSean Bruno pqi_scsi_dev_t *device) 1220*1e66f787SSean Bruno { 1221*1e66f787SSean Bruno DBG_FUNC("IN\n"); 1222*1e66f787SSean Bruno 1223*1e66f787SSean Bruno if (!device) { 1224*1e66f787SSean Bruno DBG_ERR("softs = %p: device is NULL !!!\n", softs); 1225*1e66f787SSean Bruno return; 1226*1e66f787SSean Bruno } 1227*1e66f787SSean Bruno 1228*1e66f787SSean Bruno OS_ACQUIRE_SPINLOCK(&softs->devlist_lock); 1229*1e66f787SSean Bruno softs->device_list[device->target][device->lun] = NULL; 1230*1e66f787SSean Bruno OS_RELEASE_SPINLOCK(&softs->devlist_lock); 1231*1e66f787SSean Bruno pqisrc_device_mem_free(softs, device); 1232*1e66f787SSean Bruno 1233*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 1234*1e66f787SSean Bruno } 1235*1e66f787SSean Bruno 1236*1e66f787SSean Bruno /* Debug routine used to display the RAID volume status of the device */ 1237*1e66f787SSean Bruno static void pqisrc_display_volume_status(pqisrc_softstate_t *softs, 1238*1e66f787SSean Bruno pqi_scsi_dev_t *device) 1239*1e66f787SSean Bruno { 1240*1e66f787SSean Bruno char *status; 1241*1e66f787SSean Bruno 1242*1e66f787SSean Bruno DBG_FUNC("IN\n"); 1243*1e66f787SSean Bruno switch (device->volume_status) { 1244*1e66f787SSean Bruno case SA_LV_OK: 1245*1e66f787SSean Bruno status = "Volume is online."; 1246*1e66f787SSean Bruno break; 1247*1e66f787SSean Bruno case SA_LV_UNDERGOING_ERASE: 1248*1e66f787SSean Bruno status = "Volume is undergoing background erase process."; 1249*1e66f787SSean Bruno break; 1250*1e66f787SSean Bruno case SA_LV_NOT_AVAILABLE: 1251*1e66f787SSean Bruno status = "Volume is waiting for transforming volume."; 1252*1e66f787SSean Bruno break; 1253*1e66f787SSean Bruno case SA_LV_UNDERGOING_RPI: 1254*1e66f787SSean Bruno status = "Volume is undergoing rapid parity initialization process."; 1255*1e66f787SSean Bruno break; 1256*1e66f787SSean Bruno case SA_LV_PENDING_RPI: 1257*1e66f787SSean Bruno status = "Volume is queued for rapid parity initialization process."; 1258*1e66f787SSean Bruno break; 1259*1e66f787SSean Bruno case SA_LV_ENCRYPTED_NO_KEY: 1260*1e66f787SSean Bruno status = "Volume is encrypted and cannot be accessed because key is not present."; 1261*1e66f787SSean Bruno break; 1262*1e66f787SSean Bruno case SA_LV_PLAINTEXT_IN_ENCRYPT_ONLY_CONTROLLER: 1263*1e66f787SSean Bruno status = "Volume is not encrypted and cannot be accessed because controller is in encryption-only mode."; 1264*1e66f787SSean Bruno break; 1265*1e66f787SSean Bruno case SA_LV_UNDERGOING_ENCRYPTION: 1266*1e66f787SSean Bruno status = "Volume is undergoing encryption process."; 1267*1e66f787SSean Bruno break; 1268*1e66f787SSean Bruno case SA_LV_UNDERGOING_ENCRYPTION_REKEYING: 1269*1e66f787SSean Bruno status = "Volume is undergoing encryption re-keying process."; 1270*1e66f787SSean Bruno break; 1271*1e66f787SSean Bruno case SA_LV_ENCRYPTED_IN_NON_ENCRYPTED_CONTROLLER: 1272*1e66f787SSean Bruno status = "Volume is encrypted and cannot be accessed because controller does not have encryption enabled."; 1273*1e66f787SSean Bruno break; 1274*1e66f787SSean Bruno case SA_LV_PENDING_ENCRYPTION: 1275*1e66f787SSean Bruno status = "Volume is pending migration to encrypted state, but process has not started."; 1276*1e66f787SSean Bruno break; 1277*1e66f787SSean Bruno case SA_LV_PENDING_ENCRYPTION_REKEYING: 1278*1e66f787SSean Bruno status = "Volume is encrypted and is pending encryption rekeying."; 1279*1e66f787SSean Bruno break; 1280*1e66f787SSean Bruno case SA_LV_STATUS_VPD_UNSUPPORTED: 1281*1e66f787SSean Bruno status = "Volume status is not available through vital product data pages."; 1282*1e66f787SSean Bruno break; 1283*1e66f787SSean Bruno default: 1284*1e66f787SSean Bruno status = "Volume is in an unknown state."; 1285*1e66f787SSean Bruno break; 1286*1e66f787SSean Bruno } 1287*1e66f787SSean Bruno 1288*1e66f787SSean Bruno DBG_INFO("scsi BTL %d:%d:%d %s\n", 1289*1e66f787SSean Bruno device->bus, device->target, device->lun, status); 1290*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 1291*1e66f787SSean Bruno } 1292*1e66f787SSean Bruno 1293*1e66f787SSean Bruno void pqisrc_device_mem_free(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) 1294*1e66f787SSean Bruno { 1295*1e66f787SSean Bruno DBG_INFO("IN\n"); 1296*1e66f787SSean Bruno if (!device) 1297*1e66f787SSean Bruno return; 1298*1e66f787SSean Bruno if (device->raid_map) { 1299*1e66f787SSean Bruno os_mem_free(softs, (char *)device->raid_map, sizeof(pqisrc_raid_map_t)); 1300*1e66f787SSean Bruno } 1301*1e66f787SSean Bruno os_mem_free(softs, (char *)device,sizeof(*device)); 1302*1e66f787SSean Bruno DBG_INFO("OUT\n"); 1303*1e66f787SSean Bruno 1304*1e66f787SSean Bruno } 1305*1e66f787SSean Bruno 1306*1e66f787SSean Bruno /* OS should call this function to free the scsi device */ 1307*1e66f787SSean Bruno void pqisrc_free_device(pqisrc_softstate_t * softs,pqi_scsi_dev_t *device) 1308*1e66f787SSean Bruno { 1309*1e66f787SSean Bruno 1310*1e66f787SSean Bruno OS_ACQUIRE_SPINLOCK(&softs->devlist_lock); 1311*1e66f787SSean Bruno pqisrc_device_mem_free(softs, device); 1312*1e66f787SSean Bruno OS_RELEASE_SPINLOCK(&softs->devlist_lock); 1313*1e66f787SSean Bruno 1314*1e66f787SSean Bruno } 1315*1e66f787SSean Bruno 1316*1e66f787SSean Bruno 1317*1e66f787SSean Bruno /* Update the newly added devices to the device list */ 1318*1e66f787SSean Bruno static void pqisrc_update_device_list(pqisrc_softstate_t *softs, 1319*1e66f787SSean Bruno pqi_scsi_dev_t *new_device_list[], int num_new_devices) 1320*1e66f787SSean Bruno { 1321*1e66f787SSean Bruno int ret; 1322*1e66f787SSean Bruno int i; 1323*1e66f787SSean Bruno device_status_t dev_status; 1324*1e66f787SSean Bruno pqi_scsi_dev_t *device; 1325*1e66f787SSean Bruno pqi_scsi_dev_t *same_device; 1326*1e66f787SSean Bruno pqi_scsi_dev_t **added = NULL; 1327*1e66f787SSean Bruno pqi_scsi_dev_t **removed = NULL; 1328*1e66f787SSean Bruno int nadded = 0, nremoved = 0; 1329*1e66f787SSean Bruno int j; 1330*1e66f787SSean Bruno DBG_INFO("IN\n"); 1331*1e66f787SSean Bruno 1332*1e66f787SSean Bruno added = os_mem_alloc(softs, sizeof(*added) * PQI_MAX_DEVICES); 1333*1e66f787SSean Bruno removed = os_mem_alloc(softs, sizeof(*removed) * PQI_MAX_DEVICES); 1334*1e66f787SSean Bruno 1335*1e66f787SSean Bruno if (!added || !removed) { 1336*1e66f787SSean Bruno DBG_WARN("Out of memory \n"); 1337*1e66f787SSean Bruno goto free_and_out; 1338*1e66f787SSean Bruno } 1339*1e66f787SSean Bruno 1340*1e66f787SSean Bruno OS_ACQUIRE_SPINLOCK(&softs->devlist_lock); 1341*1e66f787SSean Bruno 1342*1e66f787SSean Bruno for(i = 0; i < PQI_MAX_DEVICES; i++) { 1343*1e66f787SSean Bruno for(j = 0; j < PQI_MAX_MULTILUN; j++) { 1344*1e66f787SSean Bruno if(softs->device_list[i][j] == NULL) 1345*1e66f787SSean Bruno continue; 1346*1e66f787SSean Bruno device = softs->device_list[i][j]; 1347*1e66f787SSean Bruno device->device_gone = true; 1348*1e66f787SSean Bruno } 1349*1e66f787SSean Bruno } 1350*1e66f787SSean Bruno DBG_IO("Device list used an array\n"); 1351*1e66f787SSean Bruno for (i = 0; i < num_new_devices; i++) { 1352*1e66f787SSean Bruno device = new_device_list[i]; 1353*1e66f787SSean Bruno 1354*1e66f787SSean Bruno dev_status = pqisrc_scsi_find_entry(softs, device, 1355*1e66f787SSean Bruno &same_device); 1356*1e66f787SSean Bruno 1357*1e66f787SSean Bruno switch (dev_status) { 1358*1e66f787SSean Bruno case DEVICE_UNCHANGED: 1359*1e66f787SSean Bruno /* New Device present in existing device list */ 1360*1e66f787SSean Bruno device->new_device = false; 1361*1e66f787SSean Bruno same_device->device_gone = false; 1362*1e66f787SSean Bruno pqisrc_exist_device_update(softs, same_device, device); 1363*1e66f787SSean Bruno break; 1364*1e66f787SSean Bruno case DEVICE_NOT_FOUND: 1365*1e66f787SSean Bruno /* Device not found in existing list */ 1366*1e66f787SSean Bruno device->new_device = true; 1367*1e66f787SSean Bruno break; 1368*1e66f787SSean Bruno case DEVICE_CHANGED: 1369*1e66f787SSean Bruno /* Actual device gone need to add device to list*/ 1370*1e66f787SSean Bruno device->new_device = true; 1371*1e66f787SSean Bruno break; 1372*1e66f787SSean Bruno default: 1373*1e66f787SSean Bruno break; 1374*1e66f787SSean Bruno } 1375*1e66f787SSean Bruno } 1376*1e66f787SSean Bruno /* Process all devices that have gone away. */ 1377*1e66f787SSean Bruno for(i = 0, nremoved = 0; i < PQI_MAX_DEVICES; i++) { 1378*1e66f787SSean Bruno for(j = 0; j < PQI_MAX_MULTILUN; j++) { 1379*1e66f787SSean Bruno if(softs->device_list[i][j] == NULL) 1380*1e66f787SSean Bruno continue; 1381*1e66f787SSean Bruno device = softs->device_list[i][j]; 1382*1e66f787SSean Bruno if (device->device_gone) { 1383*1e66f787SSean Bruno softs->device_list[device->target][device->lun] = NULL; 1384*1e66f787SSean Bruno removed[nremoved] = device; 1385*1e66f787SSean Bruno nremoved++; 1386*1e66f787SSean Bruno } 1387*1e66f787SSean Bruno } 1388*1e66f787SSean Bruno } 1389*1e66f787SSean Bruno 1390*1e66f787SSean Bruno /* Process all new devices. */ 1391*1e66f787SSean Bruno for (i = 0, nadded = 0; i < num_new_devices; i++) { 1392*1e66f787SSean Bruno device = new_device_list[i]; 1393*1e66f787SSean Bruno if (!device->new_device) 1394*1e66f787SSean Bruno continue; 1395*1e66f787SSean Bruno if (device->volume_offline) 1396*1e66f787SSean Bruno continue; 1397*1e66f787SSean Bruno 1398*1e66f787SSean Bruno softs->device_list[device->target][device->lun] = device; 1399*1e66f787SSean Bruno DBG_INFO("Added device %p at B : %d T : %d L : %d\n",device, 1400*1e66f787SSean Bruno device->bus,device->target,device->lun); 1401*1e66f787SSean Bruno /* To prevent this entry from being freed later. */ 1402*1e66f787SSean Bruno new_device_list[i] = NULL; 1403*1e66f787SSean Bruno added[nadded] = device; 1404*1e66f787SSean Bruno nadded++; 1405*1e66f787SSean Bruno } 1406*1e66f787SSean Bruno 1407*1e66f787SSean Bruno pqisrc_update_log_dev_qdepth(softs); 1408*1e66f787SSean Bruno 1409*1e66f787SSean Bruno for(i = 0; i < PQI_MAX_DEVICES; i++) { 1410*1e66f787SSean Bruno for(j = 0; j < PQI_MAX_MULTILUN; j++) { 1411*1e66f787SSean Bruno if(softs->device_list[i][j] == NULL) 1412*1e66f787SSean Bruno continue; 1413*1e66f787SSean Bruno device = softs->device_list[i][j]; 1414*1e66f787SSean Bruno device->offload_enabled = device->offload_enabled_pending; 1415*1e66f787SSean Bruno } 1416*1e66f787SSean Bruno } 1417*1e66f787SSean Bruno 1418*1e66f787SSean Bruno OS_RELEASE_SPINLOCK(&softs->devlist_lock); 1419*1e66f787SSean Bruno 1420*1e66f787SSean Bruno for(i = 0; i < nremoved; i++) { 1421*1e66f787SSean Bruno device = removed[i]; 1422*1e66f787SSean Bruno if (device == NULL) 1423*1e66f787SSean Bruno continue; 1424*1e66f787SSean Bruno pqisrc_remove_device(softs, device); 1425*1e66f787SSean Bruno pqisrc_display_device_info(softs, "removed", device); 1426*1e66f787SSean Bruno 1427*1e66f787SSean Bruno } 1428*1e66f787SSean Bruno 1429*1e66f787SSean Bruno for(i = 0; i < PQI_MAX_DEVICES; i++) { 1430*1e66f787SSean Bruno for(j = 0; j < PQI_MAX_MULTILUN; j++) { 1431*1e66f787SSean Bruno if(softs->device_list[i][j] == NULL) 1432*1e66f787SSean Bruno continue; 1433*1e66f787SSean Bruno device = softs->device_list[i][j]; 1434*1e66f787SSean Bruno /* 1435*1e66f787SSean Bruno * Notify the OS upper layer if the queue depth of any existing device has 1436*1e66f787SSean Bruno * changed. 1437*1e66f787SSean Bruno */ 1438*1e66f787SSean Bruno if (device->queue_depth != 1439*1e66f787SSean Bruno device->advertised_queue_depth) { 1440*1e66f787SSean Bruno device->advertised_queue_depth = device->queue_depth; 1441*1e66f787SSean Bruno /* TBD: Call OS upper layer function to change device Q depth */ 1442*1e66f787SSean Bruno } 1443*1e66f787SSean Bruno } 1444*1e66f787SSean Bruno } 1445*1e66f787SSean Bruno for(i = 0; i < nadded; i++) { 1446*1e66f787SSean Bruno device = added[i]; 1447*1e66f787SSean Bruno if (device->expose_device) { 1448*1e66f787SSean Bruno ret = pqisrc_add_device(softs, device); 1449*1e66f787SSean Bruno if (ret) { 1450*1e66f787SSean Bruno DBG_WARN("scsi %d:%d:%d addition failed, device not added\n", 1451*1e66f787SSean Bruno device->bus, device->target, 1452*1e66f787SSean Bruno device->lun); 1453*1e66f787SSean Bruno pqisrc_adjust_list(softs, device); 1454*1e66f787SSean Bruno continue; 1455*1e66f787SSean Bruno } 1456*1e66f787SSean Bruno } 1457*1e66f787SSean Bruno 1458*1e66f787SSean Bruno pqisrc_display_device_info(softs, "added", device); 1459*1e66f787SSean Bruno } 1460*1e66f787SSean Bruno 1461*1e66f787SSean Bruno /* Process all volumes that are offline. */ 1462*1e66f787SSean Bruno for (i = 0; i < num_new_devices; i++) { 1463*1e66f787SSean Bruno device = new_device_list[i]; 1464*1e66f787SSean Bruno if (!device) 1465*1e66f787SSean Bruno continue; 1466*1e66f787SSean Bruno if (!device->new_device) 1467*1e66f787SSean Bruno continue; 1468*1e66f787SSean Bruno if (device->volume_offline) { 1469*1e66f787SSean Bruno pqisrc_display_volume_status(softs, device); 1470*1e66f787SSean Bruno pqisrc_display_device_info(softs, "offline", device); 1471*1e66f787SSean Bruno } 1472*1e66f787SSean Bruno } 1473*1e66f787SSean Bruno 1474*1e66f787SSean Bruno free_and_out: 1475*1e66f787SSean Bruno if (added) 1476*1e66f787SSean Bruno os_mem_free(softs, (char *)added, 1477*1e66f787SSean Bruno sizeof(*added) * PQI_MAX_DEVICES); 1478*1e66f787SSean Bruno if (removed) 1479*1e66f787SSean Bruno os_mem_free(softs, (char *)removed, 1480*1e66f787SSean Bruno sizeof(*removed) * PQI_MAX_DEVICES); 1481*1e66f787SSean Bruno 1482*1e66f787SSean Bruno DBG_INFO("OUT\n"); 1483*1e66f787SSean Bruno } 1484*1e66f787SSean Bruno 1485*1e66f787SSean Bruno /* 1486*1e66f787SSean Bruno * Let the Adapter know about driver version using one of BMIC 1487*1e66f787SSean Bruno * BMIC_WRITE_HOST_WELLNESS 1488*1e66f787SSean Bruno */ 1489*1e66f787SSean Bruno int pqisrc_write_driver_version_to_host_wellness(pqisrc_softstate_t *softs) 1490*1e66f787SSean Bruno { 1491*1e66f787SSean Bruno int rval = PQI_STATUS_SUCCESS; 1492*1e66f787SSean Bruno struct bmic_host_wellness_driver_version *host_wellness_driver_ver; 1493*1e66f787SSean Bruno size_t data_length; 1494*1e66f787SSean Bruno pqisrc_raid_req_t request; 1495*1e66f787SSean Bruno 1496*1e66f787SSean Bruno DBG_FUNC("IN\n"); 1497*1e66f787SSean Bruno 1498*1e66f787SSean Bruno memset(&request, 0, sizeof(request)); 1499*1e66f787SSean Bruno data_length = sizeof(*host_wellness_driver_ver); 1500*1e66f787SSean Bruno 1501*1e66f787SSean Bruno host_wellness_driver_ver = os_mem_alloc(softs, data_length); 1502*1e66f787SSean Bruno if (!host_wellness_driver_ver) { 1503*1e66f787SSean Bruno DBG_ERR("failed to allocate memory for host wellness driver_version\n"); 1504*1e66f787SSean Bruno return PQI_STATUS_FAILURE; 1505*1e66f787SSean Bruno } 1506*1e66f787SSean Bruno 1507*1e66f787SSean Bruno host_wellness_driver_ver->start_tag[0] = '<'; 1508*1e66f787SSean Bruno host_wellness_driver_ver->start_tag[1] = 'H'; 1509*1e66f787SSean Bruno host_wellness_driver_ver->start_tag[2] = 'W'; 1510*1e66f787SSean Bruno host_wellness_driver_ver->start_tag[3] = '>'; 1511*1e66f787SSean Bruno host_wellness_driver_ver->driver_version_tag[0] = 'D'; 1512*1e66f787SSean Bruno host_wellness_driver_ver->driver_version_tag[1] = 'V'; 1513*1e66f787SSean Bruno host_wellness_driver_ver->driver_version_length = LE_16(sizeof(host_wellness_driver_ver->driver_version)); 1514*1e66f787SSean Bruno strncpy(host_wellness_driver_ver->driver_version, softs->os_name, 1515*1e66f787SSean Bruno sizeof(host_wellness_driver_ver->driver_version)); 1516*1e66f787SSean Bruno if (strlen(softs->os_name) < sizeof(host_wellness_driver_ver->driver_version) ) { 1517*1e66f787SSean Bruno strncpy(host_wellness_driver_ver->driver_version + strlen(softs->os_name), PQISRC_DRIVER_VERSION, 1518*1e66f787SSean Bruno sizeof(host_wellness_driver_ver->driver_version) - strlen(softs->os_name)); 1519*1e66f787SSean Bruno } else { 1520*1e66f787SSean Bruno DBG_INFO("OS name length(%lu) is longer than buffer of driver_version\n", 1521*1e66f787SSean Bruno strlen(softs->os_name)); 1522*1e66f787SSean Bruno } 1523*1e66f787SSean Bruno host_wellness_driver_ver->driver_version[sizeof(host_wellness_driver_ver->driver_version) - 1] = '\0'; 1524*1e66f787SSean Bruno host_wellness_driver_ver->end_tag[0] = 'Z'; 1525*1e66f787SSean Bruno host_wellness_driver_ver->end_tag[1] = 'Z'; 1526*1e66f787SSean Bruno 1527*1e66f787SSean Bruno rval = pqisrc_build_send_raid_request(softs, &request, host_wellness_driver_ver,data_length, 1528*1e66f787SSean Bruno BMIC_WRITE_HOST_WELLNESS, 0, (uint8_t *)RAID_CTLR_LUNID, NULL); 1529*1e66f787SSean Bruno 1530*1e66f787SSean Bruno os_mem_free(softs, (char *)host_wellness_driver_ver, data_length); 1531*1e66f787SSean Bruno 1532*1e66f787SSean Bruno DBG_FUNC("OUT"); 1533*1e66f787SSean Bruno return rval; 1534*1e66f787SSean Bruno } 1535*1e66f787SSean Bruno 1536*1e66f787SSean Bruno /* 1537*1e66f787SSean Bruno * Write current RTC time from host to the adapter using 1538*1e66f787SSean Bruno * BMIC_WRITE_HOST_WELLNESS 1539*1e66f787SSean Bruno */ 1540*1e66f787SSean Bruno int pqisrc_write_current_time_to_host_wellness(pqisrc_softstate_t *softs) 1541*1e66f787SSean Bruno { 1542*1e66f787SSean Bruno int rval = PQI_STATUS_SUCCESS; 1543*1e66f787SSean Bruno struct bmic_host_wellness_time *host_wellness_time; 1544*1e66f787SSean Bruno size_t data_length; 1545*1e66f787SSean Bruno pqisrc_raid_req_t request; 1546*1e66f787SSean Bruno 1547*1e66f787SSean Bruno DBG_FUNC("IN\n"); 1548*1e66f787SSean Bruno 1549*1e66f787SSean Bruno memset(&request, 0, sizeof(request)); 1550*1e66f787SSean Bruno data_length = sizeof(*host_wellness_time); 1551*1e66f787SSean Bruno 1552*1e66f787SSean Bruno host_wellness_time = os_mem_alloc(softs, data_length); 1553*1e66f787SSean Bruno if (!host_wellness_time) { 1554*1e66f787SSean Bruno DBG_ERR("failed to allocate memory for host wellness time structure\n"); 1555*1e66f787SSean Bruno return PQI_STATUS_FAILURE; 1556*1e66f787SSean Bruno } 1557*1e66f787SSean Bruno 1558*1e66f787SSean Bruno host_wellness_time->start_tag[0] = '<'; 1559*1e66f787SSean Bruno host_wellness_time->start_tag[1] = 'H'; 1560*1e66f787SSean Bruno host_wellness_time->start_tag[2] = 'W'; 1561*1e66f787SSean Bruno host_wellness_time->start_tag[3] = '>'; 1562*1e66f787SSean Bruno host_wellness_time->time_tag[0] = 'T'; 1563*1e66f787SSean Bruno host_wellness_time->time_tag[1] = 'D'; 1564*1e66f787SSean Bruno host_wellness_time->time_length = LE_16(offsetof(struct bmic_host_wellness_time, time_length) - 1565*1e66f787SSean Bruno offsetof(struct bmic_host_wellness_time, century)); 1566*1e66f787SSean Bruno 1567*1e66f787SSean Bruno os_get_time(host_wellness_time); 1568*1e66f787SSean Bruno 1569*1e66f787SSean Bruno host_wellness_time->dont_write_tag[0] = 'D'; 1570*1e66f787SSean Bruno host_wellness_time->dont_write_tag[1] = 'W'; 1571*1e66f787SSean Bruno host_wellness_time->end_tag[0] = 'Z'; 1572*1e66f787SSean Bruno host_wellness_time->end_tag[1] = 'Z'; 1573*1e66f787SSean Bruno 1574*1e66f787SSean Bruno rval = pqisrc_build_send_raid_request(softs, &request, host_wellness_time,data_length, 1575*1e66f787SSean Bruno BMIC_WRITE_HOST_WELLNESS, 0, (uint8_t *)RAID_CTLR_LUNID, NULL); 1576*1e66f787SSean Bruno 1577*1e66f787SSean Bruno os_mem_free(softs, (char *)host_wellness_time, data_length); 1578*1e66f787SSean Bruno 1579*1e66f787SSean Bruno DBG_FUNC("OUT"); 1580*1e66f787SSean Bruno return rval; 1581*1e66f787SSean Bruno } 1582*1e66f787SSean Bruno 1583*1e66f787SSean Bruno /* 1584*1e66f787SSean Bruno * Function used to perform a rescan of scsi devices 1585*1e66f787SSean Bruno * for any config change events 1586*1e66f787SSean Bruno */ 1587*1e66f787SSean Bruno int pqisrc_scan_devices(pqisrc_softstate_t *softs) 1588*1e66f787SSean Bruno { 1589*1e66f787SSean Bruno boolean_t is_physical_device; 1590*1e66f787SSean Bruno int ret = PQI_STATUS_FAILURE; 1591*1e66f787SSean Bruno int i; 1592*1e66f787SSean Bruno int new_dev_cnt; 1593*1e66f787SSean Bruno int phy_log_dev_cnt; 1594*1e66f787SSean Bruno uint8_t *scsi3addr; 1595*1e66f787SSean Bruno uint32_t physical_cnt; 1596*1e66f787SSean Bruno uint32_t logical_cnt; 1597*1e66f787SSean Bruno uint32_t ndev_allocated = 0; 1598*1e66f787SSean Bruno size_t phys_data_length, log_data_length; 1599*1e66f787SSean Bruno reportlun_data_ext_t *physical_dev_list = NULL; 1600*1e66f787SSean Bruno reportlun_data_ext_t *logical_dev_list = NULL; 1601*1e66f787SSean Bruno reportlun_ext_entry_t *lun_ext_entry = NULL; 1602*1e66f787SSean Bruno bmic_ident_physdev_t *bmic_phy_info = NULL; 1603*1e66f787SSean Bruno pqi_scsi_dev_t **new_device_list = NULL; 1604*1e66f787SSean Bruno pqi_scsi_dev_t *device = NULL; 1605*1e66f787SSean Bruno 1606*1e66f787SSean Bruno 1607*1e66f787SSean Bruno DBG_FUNC("IN\n"); 1608*1e66f787SSean Bruno 1609*1e66f787SSean Bruno ret = pqisrc_get_phys_log_device_list(softs, &physical_dev_list, &logical_dev_list, 1610*1e66f787SSean Bruno &phys_data_length, &log_data_length); 1611*1e66f787SSean Bruno 1612*1e66f787SSean Bruno if (ret) 1613*1e66f787SSean Bruno goto err_out; 1614*1e66f787SSean Bruno 1615*1e66f787SSean Bruno physical_cnt = BE_32(physical_dev_list->header.list_length) 1616*1e66f787SSean Bruno / sizeof(physical_dev_list->lun_entries[0]); 1617*1e66f787SSean Bruno 1618*1e66f787SSean Bruno logical_cnt = BE_32(logical_dev_list->header.list_length) 1619*1e66f787SSean Bruno / sizeof(logical_dev_list->lun_entries[0]); 1620*1e66f787SSean Bruno 1621*1e66f787SSean Bruno DBG_INFO("physical_cnt %d logical_cnt %d\n", physical_cnt, logical_cnt); 1622*1e66f787SSean Bruno 1623*1e66f787SSean Bruno if (physical_cnt) { 1624*1e66f787SSean Bruno bmic_phy_info = os_mem_alloc(softs, sizeof(*bmic_phy_info)); 1625*1e66f787SSean Bruno if (bmic_phy_info == NULL) { 1626*1e66f787SSean Bruno ret = PQI_STATUS_FAILURE; 1627*1e66f787SSean Bruno DBG_ERR("failed to allocate memory for BMIC ID PHYS Device : %d\n", ret); 1628*1e66f787SSean Bruno goto err_out; 1629*1e66f787SSean Bruno } 1630*1e66f787SSean Bruno } 1631*1e66f787SSean Bruno phy_log_dev_cnt = physical_cnt + logical_cnt; 1632*1e66f787SSean Bruno new_device_list = os_mem_alloc(softs, 1633*1e66f787SSean Bruno sizeof(*new_device_list) * phy_log_dev_cnt); 1634*1e66f787SSean Bruno 1635*1e66f787SSean Bruno if (new_device_list == NULL) { 1636*1e66f787SSean Bruno ret = PQI_STATUS_FAILURE; 1637*1e66f787SSean Bruno DBG_ERR("failed to allocate memory for device list : %d\n", ret); 1638*1e66f787SSean Bruno goto err_out; 1639*1e66f787SSean Bruno } 1640*1e66f787SSean Bruno 1641*1e66f787SSean Bruno for (i = 0; i < phy_log_dev_cnt; i++) { 1642*1e66f787SSean Bruno new_device_list[i] = os_mem_alloc(softs, 1643*1e66f787SSean Bruno sizeof(*new_device_list[i])); 1644*1e66f787SSean Bruno if (new_device_list[i] == NULL) { 1645*1e66f787SSean Bruno ret = PQI_STATUS_FAILURE; 1646*1e66f787SSean Bruno DBG_ERR("failed to allocate memory for device list : %d\n", ret); 1647*1e66f787SSean Bruno ndev_allocated = i; 1648*1e66f787SSean Bruno goto err_out; 1649*1e66f787SSean Bruno } 1650*1e66f787SSean Bruno } 1651*1e66f787SSean Bruno 1652*1e66f787SSean Bruno ndev_allocated = phy_log_dev_cnt; 1653*1e66f787SSean Bruno new_dev_cnt = 0; 1654*1e66f787SSean Bruno for (i = 0; i < phy_log_dev_cnt; i++) { 1655*1e66f787SSean Bruno 1656*1e66f787SSean Bruno if (i < physical_cnt) { 1657*1e66f787SSean Bruno is_physical_device = true; 1658*1e66f787SSean Bruno lun_ext_entry = &physical_dev_list->lun_entries[i]; 1659*1e66f787SSean Bruno } else { 1660*1e66f787SSean Bruno is_physical_device = false; 1661*1e66f787SSean Bruno lun_ext_entry = 1662*1e66f787SSean Bruno &logical_dev_list->lun_entries[i - physical_cnt]; 1663*1e66f787SSean Bruno } 1664*1e66f787SSean Bruno 1665*1e66f787SSean Bruno scsi3addr = lun_ext_entry->lunid; 1666*1e66f787SSean Bruno 1667*1e66f787SSean Bruno /* Skip masked physical non-disk devices. */ 1668*1e66f787SSean Bruno if (MASKED_DEVICE(scsi3addr) && is_physical_device) 1669*1e66f787SSean Bruno continue; 1670*1e66f787SSean Bruno 1671*1e66f787SSean Bruno device = new_device_list[new_dev_cnt]; 1672*1e66f787SSean Bruno memset(device, 0, sizeof(*device)); 1673*1e66f787SSean Bruno memcpy(device->scsi3addr, scsi3addr, sizeof(device->scsi3addr)); 1674*1e66f787SSean Bruno device->wwid = lun_ext_entry->wwid; 1675*1e66f787SSean Bruno device->is_physical_device = is_physical_device; 1676*1e66f787SSean Bruno if (!is_physical_device) 1677*1e66f787SSean Bruno device->is_external_raid_device = 1678*1e66f787SSean Bruno pqisrc_is_external_raid_addr(scsi3addr); 1679*1e66f787SSean Bruno 1680*1e66f787SSean Bruno 1681*1e66f787SSean Bruno /* Get device type, vendor, model, device ID. */ 1682*1e66f787SSean Bruno ret = pqisrc_get_dev_data(softs, device); 1683*1e66f787SSean Bruno if (ret) { 1684*1e66f787SSean Bruno DBG_WARN("Inquiry failed, skipping device %016llx\n", 1685*1e66f787SSean Bruno (unsigned long long)BE_64(device->scsi3addr[0])); 1686*1e66f787SSean Bruno DBG_INFO("INQUIRY FAILED \n"); 1687*1e66f787SSean Bruno continue; 1688*1e66f787SSean Bruno } 1689*1e66f787SSean Bruno pqisrc_assign_btl(device); 1690*1e66f787SSean Bruno 1691*1e66f787SSean Bruno /* 1692*1e66f787SSean Bruno * Expose all devices except for physical devices that 1693*1e66f787SSean Bruno * are masked. 1694*1e66f787SSean Bruno */ 1695*1e66f787SSean Bruno if (device->is_physical_device && 1696*1e66f787SSean Bruno MASKED_DEVICE(scsi3addr)) 1697*1e66f787SSean Bruno device->expose_device = false; 1698*1e66f787SSean Bruno else 1699*1e66f787SSean Bruno device->expose_device = true; 1700*1e66f787SSean Bruno 1701*1e66f787SSean Bruno if (device->is_physical_device && 1702*1e66f787SSean Bruno (lun_ext_entry->device_flags & 1703*1e66f787SSean Bruno REPORT_LUN_DEV_FLAG_AIO_ENABLED) && 1704*1e66f787SSean Bruno lun_ext_entry->ioaccel_handle) { 1705*1e66f787SSean Bruno device->aio_enabled = true; 1706*1e66f787SSean Bruno } 1707*1e66f787SSean Bruno switch (device->devtype) { 1708*1e66f787SSean Bruno case ROM_DEVICE: 1709*1e66f787SSean Bruno /* 1710*1e66f787SSean Bruno * We don't *really* support actual CD-ROM devices, 1711*1e66f787SSean Bruno * but we do support the HP "One Button Disaster 1712*1e66f787SSean Bruno * Recovery" tape drive which temporarily pretends to 1713*1e66f787SSean Bruno * be a CD-ROM drive. 1714*1e66f787SSean Bruno */ 1715*1e66f787SSean Bruno if (device->is_obdr_device) 1716*1e66f787SSean Bruno new_dev_cnt++; 1717*1e66f787SSean Bruno break; 1718*1e66f787SSean Bruno case DISK_DEVICE: 1719*1e66f787SSean Bruno case ZBC_DEVICE: 1720*1e66f787SSean Bruno if (device->is_physical_device) { 1721*1e66f787SSean Bruno device->ioaccel_handle = 1722*1e66f787SSean Bruno lun_ext_entry->ioaccel_handle; 1723*1e66f787SSean Bruno device->sas_address = BE_64(lun_ext_entry->wwid); 1724*1e66f787SSean Bruno pqisrc_get_physical_device_info(softs, device, 1725*1e66f787SSean Bruno bmic_phy_info); 1726*1e66f787SSean Bruno } 1727*1e66f787SSean Bruno /* Logical device doesn't have SAS address 1728*1e66f787SSean Bruno * so requires target SAS address for MSA. 1729*1e66f787SSean Bruno */ 1730*1e66f787SSean Bruno if(device->is_external_raid_device) 1731*1e66f787SSean Bruno device->sas_address = BE_64((uint64_t)lun_ext_entry->lunid); 1732*1e66f787SSean Bruno new_dev_cnt++; 1733*1e66f787SSean Bruno break; 1734*1e66f787SSean Bruno case ENCLOSURE_DEVICE: 1735*1e66f787SSean Bruno if (device->is_physical_device) { 1736*1e66f787SSean Bruno device->sas_address = BE_64(lun_ext_entry->wwid); 1737*1e66f787SSean Bruno } 1738*1e66f787SSean Bruno new_dev_cnt++; 1739*1e66f787SSean Bruno break; 1740*1e66f787SSean Bruno case TAPE_DEVICE: 1741*1e66f787SSean Bruno case MEDIUM_CHANGER_DEVICE: 1742*1e66f787SSean Bruno new_dev_cnt++; 1743*1e66f787SSean Bruno break; 1744*1e66f787SSean Bruno case RAID_DEVICE: 1745*1e66f787SSean Bruno /* 1746*1e66f787SSean Bruno * Only present the HBA controller itself as a RAID 1747*1e66f787SSean Bruno * controller. If it's a RAID controller other than 1748*1e66f787SSean Bruno * the HBA itself (an external RAID controller, MSA500 1749*1e66f787SSean Bruno * or similar), don't present it. 1750*1e66f787SSean Bruno */ 1751*1e66f787SSean Bruno if (pqisrc_is_hba_lunid(scsi3addr)) 1752*1e66f787SSean Bruno new_dev_cnt++; 1753*1e66f787SSean Bruno break; 1754*1e66f787SSean Bruno } 1755*1e66f787SSean Bruno } 1756*1e66f787SSean Bruno DBG_INFO("new_dev_cnt %d\n", new_dev_cnt); 1757*1e66f787SSean Bruno 1758*1e66f787SSean Bruno pqisrc_update_device_list(softs, new_device_list, new_dev_cnt); 1759*1e66f787SSean Bruno 1760*1e66f787SSean Bruno err_out: 1761*1e66f787SSean Bruno if (new_device_list) { 1762*1e66f787SSean Bruno for (i = 0; i < ndev_allocated; i++) { 1763*1e66f787SSean Bruno if (new_device_list[i]) { 1764*1e66f787SSean Bruno if(new_device_list[i]->raid_map) 1765*1e66f787SSean Bruno os_mem_free(softs, (char *)new_device_list[i]->raid_map, 1766*1e66f787SSean Bruno sizeof(pqisrc_raid_map_t)); 1767*1e66f787SSean Bruno os_mem_free(softs, (char*)new_device_list[i], 1768*1e66f787SSean Bruno sizeof(*new_device_list[i])); 1769*1e66f787SSean Bruno } 1770*1e66f787SSean Bruno } 1771*1e66f787SSean Bruno os_mem_free(softs, (char *)new_device_list, 1772*1e66f787SSean Bruno sizeof(*new_device_list) * ndev_allocated); 1773*1e66f787SSean Bruno } 1774*1e66f787SSean Bruno if(physical_dev_list) 1775*1e66f787SSean Bruno os_mem_free(softs, (char *)physical_dev_list, phys_data_length); 1776*1e66f787SSean Bruno if(logical_dev_list) 1777*1e66f787SSean Bruno os_mem_free(softs, (char *)logical_dev_list, log_data_length); 1778*1e66f787SSean Bruno if (bmic_phy_info) 1779*1e66f787SSean Bruno os_mem_free(softs, (char *)bmic_phy_info, sizeof(*bmic_phy_info)); 1780*1e66f787SSean Bruno 1781*1e66f787SSean Bruno DBG_FUNC("OUT \n"); 1782*1e66f787SSean Bruno 1783*1e66f787SSean Bruno return ret; 1784*1e66f787SSean Bruno } 1785*1e66f787SSean Bruno 1786*1e66f787SSean Bruno /* 1787*1e66f787SSean Bruno * Clean up memory allocated for devices. 1788*1e66f787SSean Bruno */ 1789*1e66f787SSean Bruno void pqisrc_cleanup_devices(pqisrc_softstate_t *softs) 1790*1e66f787SSean Bruno { 1791*1e66f787SSean Bruno 1792*1e66f787SSean Bruno int i = 0,j = 0; 1793*1e66f787SSean Bruno pqi_scsi_dev_t *dvp = NULL; 1794*1e66f787SSean Bruno DBG_FUNC("IN\n"); 1795*1e66f787SSean Bruno 1796*1e66f787SSean Bruno for(i = 0; i < PQI_MAX_DEVICES; i++) { 1797*1e66f787SSean Bruno for(j = 0; j < PQI_MAX_MULTILUN; j++) { 1798*1e66f787SSean Bruno if (softs->device_list[i][j] == NULL) 1799*1e66f787SSean Bruno continue; 1800*1e66f787SSean Bruno dvp = softs->device_list[i][j]; 1801*1e66f787SSean Bruno pqisrc_device_mem_free(softs, dvp); 1802*1e66f787SSean Bruno } 1803*1e66f787SSean Bruno } 1804*1e66f787SSean Bruno DBG_FUNC("OUT\n"); 1805*1e66f787SSean Bruno } 1806*1e66f787SSean Bruno 1807