xref: /freebsd/sys/dev/smartpqi/smartpqi_discovery.c (revision b17f4335d2becd4ad1a74636675e4a3d273807a2)
11e66f787SSean Bruno /*-
21e66f787SSean Bruno  * Copyright (c) 2018 Microsemi Corporation.
31e66f787SSean Bruno  * All rights reserved.
41e66f787SSean Bruno  *
51e66f787SSean Bruno  * Redistribution and use in source and binary forms, with or without
61e66f787SSean Bruno  * modification, are permitted provided that the following conditions
71e66f787SSean Bruno  * are met:
81e66f787SSean Bruno  * 1. Redistributions of source code must retain the above copyright
91e66f787SSean Bruno  *    notice, this list of conditions and the following disclaimer.
101e66f787SSean Bruno  * 2. Redistributions in binary form must reproduce the above copyright
111e66f787SSean Bruno  *    notice, this list of conditions and the following disclaimer in the
121e66f787SSean Bruno  *    documentation and/or other materials provided with the distribution.
131e66f787SSean Bruno  *
141e66f787SSean Bruno  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151e66f787SSean Bruno  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161e66f787SSean Bruno  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171e66f787SSean Bruno  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181e66f787SSean Bruno  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191e66f787SSean Bruno  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201e66f787SSean Bruno  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211e66f787SSean Bruno  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221e66f787SSean Bruno  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231e66f787SSean Bruno  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241e66f787SSean Bruno  * SUCH DAMAGE.
251e66f787SSean Bruno  */
261e66f787SSean Bruno 
271e66f787SSean Bruno /* $FreeBSD$ */
281e66f787SSean Bruno 
291e66f787SSean Bruno #include "smartpqi_includes.h"
301e66f787SSean Bruno 
311e66f787SSean Bruno /* Validate the scsi sense response code */
321e66f787SSean Bruno static inline boolean_t pqisrc_scsi_sense_valid(const struct sense_header_scsi *sshdr)
331e66f787SSean Bruno {
341e66f787SSean Bruno 	DBG_FUNC("IN\n");
351e66f787SSean Bruno 
361e66f787SSean Bruno 	if (!sshdr)
371e66f787SSean Bruno 		return false;
381e66f787SSean Bruno 
391e66f787SSean Bruno 	DBG_FUNC("OUT\n");
401e66f787SSean Bruno 
411e66f787SSean Bruno 	return (sshdr->response_code & 0x70) == 0x70;
421e66f787SSean Bruno }
431e66f787SSean Bruno 
44*b17f4335SSean Bruno /* Initialize target ID pool for HBA/PDs */
45*b17f4335SSean Bruno void  pqisrc_init_targetid_pool(pqisrc_softstate_t *softs)
46*b17f4335SSean Bruno {
47*b17f4335SSean Bruno 	int i, tid = PQI_MAX_PHYSICALS + PQI_MAX_LOGICALS - 1;
48*b17f4335SSean Bruno 
49*b17f4335SSean Bruno 	for(i = 0; i < PQI_MAX_PHYSICALS; i++) {
50*b17f4335SSean Bruno 		softs->tid_pool.tid[i] = tid--;
51*b17f4335SSean Bruno 	}
52*b17f4335SSean Bruno 	softs->tid_pool.index = i - 1;
53*b17f4335SSean Bruno }
54*b17f4335SSean Bruno 
55*b17f4335SSean Bruno int pqisrc_alloc_tid(pqisrc_softstate_t *softs)
56*b17f4335SSean Bruno {
57*b17f4335SSean Bruno 	if(softs->tid_pool.index <= -1) {
58*b17f4335SSean Bruno 		DBG_ERR("Target ID exhausted\n");
59*b17f4335SSean Bruno 		return INVALID_ELEM;
60*b17f4335SSean Bruno 	}
61*b17f4335SSean Bruno 
62*b17f4335SSean Bruno 	return  softs->tid_pool.tid[softs->tid_pool.index--];
63*b17f4335SSean Bruno }
64*b17f4335SSean Bruno 
65*b17f4335SSean Bruno void pqisrc_free_tid(pqisrc_softstate_t *softs, int tid)
66*b17f4335SSean Bruno {
67*b17f4335SSean Bruno 	if(softs->tid_pool.index >= PQI_MAX_PHYSICALS) {
68*b17f4335SSean Bruno 		DBG_ERR("Target ID queue is full\n");
69*b17f4335SSean Bruno 		return;
70*b17f4335SSean Bruno 	}
71*b17f4335SSean Bruno 
72*b17f4335SSean Bruno 	softs->tid_pool.index++;
73*b17f4335SSean Bruno 	softs->tid_pool.tid[softs->tid_pool.index] = tid;
74*b17f4335SSean Bruno }
75*b17f4335SSean Bruno 
761e66f787SSean Bruno /* Update scsi sense info to a local buffer*/
771e66f787SSean Bruno boolean_t pqisrc_update_scsi_sense(const uint8_t *buff, int len,
781e66f787SSean Bruno 			      struct sense_header_scsi *header)
791e66f787SSean Bruno {
801e66f787SSean Bruno 
811e66f787SSean Bruno 	DBG_FUNC("IN\n");
821e66f787SSean Bruno 
831e66f787SSean Bruno 	if (!buff || !len)
841e66f787SSean Bruno 		return false;
851e66f787SSean Bruno 
861e66f787SSean Bruno 	memset(header, 0, sizeof(struct sense_header_scsi));
871e66f787SSean Bruno 
881e66f787SSean Bruno 	header->response_code = (buff[0] & 0x7f);
891e66f787SSean Bruno 
901e66f787SSean Bruno 	if (!pqisrc_scsi_sense_valid(header))
911e66f787SSean Bruno 		return false;
921e66f787SSean Bruno 
931e66f787SSean Bruno 	if (header->response_code >= 0x72) {
941e66f787SSean Bruno 		/* descriptor format */
951e66f787SSean Bruno 		if (len > 1)
961e66f787SSean Bruno 			header->sense_key = (buff[1] & 0xf);
971e66f787SSean Bruno 		if (len > 2)
981e66f787SSean Bruno 			header->asc = buff[2];
991e66f787SSean Bruno 		if (len > 3)
1001e66f787SSean Bruno 			header->ascq = buff[3];
1011e66f787SSean Bruno 		if (len > 7)
1021e66f787SSean Bruno 			header->additional_length = buff[7];
1031e66f787SSean Bruno 	} else {
1041e66f787SSean Bruno 		 /* fixed format */
1051e66f787SSean Bruno 		if (len > 2)
1061e66f787SSean Bruno 			header->sense_key = (buff[2] & 0xf);
1071e66f787SSean Bruno 		if (len > 7) {
1081e66f787SSean Bruno 			len = (len < (buff[7] + 8)) ?
1091e66f787SSean Bruno 					len : (buff[7] + 8);
1101e66f787SSean Bruno 			if (len > 12)
1111e66f787SSean Bruno 				header->asc = buff[12];
1121e66f787SSean Bruno 			if (len > 13)
1131e66f787SSean Bruno 				header->ascq = buff[13];
1141e66f787SSean Bruno 		}
1151e66f787SSean Bruno 	}
1161e66f787SSean Bruno 
1171e66f787SSean Bruno 	DBG_FUNC("OUT\n");
1181e66f787SSean Bruno 
1191e66f787SSean Bruno 	return true;
1201e66f787SSean Bruno }
1211e66f787SSean Bruno 
1221e66f787SSean Bruno /*
1231e66f787SSean Bruno  * Function used to build the internal raid request and analyze the response
1241e66f787SSean Bruno  */
1251e66f787SSean Bruno int pqisrc_build_send_raid_request(pqisrc_softstate_t *softs,  pqisrc_raid_req_t *request,
1261e66f787SSean Bruno 			    void *buff, size_t datasize, uint8_t cmd, uint16_t vpd_page, uint8_t *scsi3addr,
1271e66f787SSean Bruno 			    raid_path_error_info_elem_t *error_info)
1281e66f787SSean Bruno {
1291e66f787SSean Bruno 
1301e66f787SSean Bruno 	uint8_t *cdb;
1311e66f787SSean Bruno 	int ret = PQI_STATUS_SUCCESS;
1321e66f787SSean Bruno 	uint32_t tag = 0;
1331e66f787SSean Bruno 	struct dma_mem device_mem;
1341e66f787SSean Bruno 	sgt_t *sgd;
1351e66f787SSean Bruno 
1361e66f787SSean Bruno 	ib_queue_t *ib_q = &softs->op_raid_ib_q[PQI_DEFAULT_IB_QUEUE];
1371e66f787SSean Bruno 	ob_queue_t *ob_q = &softs->op_ob_q[PQI_DEFAULT_IB_QUEUE];
1381e66f787SSean Bruno 
1391e66f787SSean Bruno 	rcb_t *rcb = NULL;
1401e66f787SSean Bruno 
1411e66f787SSean Bruno 	DBG_FUNC("IN\n");
1421e66f787SSean Bruno 
1431e66f787SSean Bruno 	memset(&device_mem, 0, sizeof(struct dma_mem));
1441e66f787SSean Bruno 
1451e66f787SSean Bruno 	/* for TUR datasize: 0 buff: NULL */
1461e66f787SSean Bruno 	if (datasize) {
1471e66f787SSean Bruno 		device_mem.tag = "device_mem";
1481e66f787SSean Bruno 		device_mem.size = datasize;
1491e66f787SSean Bruno 		device_mem.align = PQISRC_DEFAULT_DMA_ALIGN;
1501e66f787SSean Bruno 
1511e66f787SSean Bruno 		ret = os_dma_mem_alloc(softs, &device_mem);
1521e66f787SSean Bruno 
1531e66f787SSean Bruno 		if (ret) {
1541e66f787SSean Bruno 			DBG_ERR("failed to allocate dma memory for device_mem return code %d\n", ret);
1551e66f787SSean Bruno 			return ret;
1561e66f787SSean Bruno 		}
1571e66f787SSean Bruno 
1581e66f787SSean Bruno 		sgd = (sgt_t *)&request->sg_descriptors[0];
1591e66f787SSean Bruno 
1601e66f787SSean Bruno 		sgd->addr = device_mem.dma_addr;
1611e66f787SSean Bruno 		sgd->len = datasize;
1621e66f787SSean Bruno 		sgd->flags = SG_FLAG_LAST;
1631e66f787SSean Bruno 
1641e66f787SSean Bruno 	}
1651e66f787SSean Bruno 
1661e66f787SSean Bruno 	/* Build raid path request */
1671e66f787SSean Bruno 	request->header.iu_type = PQI_IU_TYPE_RAID_PATH_IO_REQUEST;
1681e66f787SSean Bruno 
1691e66f787SSean Bruno 	request->header.iu_length = LE_16(offsetof(pqisrc_raid_req_t,
1701e66f787SSean Bruno 							sg_descriptors[1]) - PQI_REQUEST_HEADER_LENGTH);
1711e66f787SSean Bruno 	request->buffer_length = LE_32(datasize);
1721e66f787SSean Bruno 	memcpy(request->lun_number, scsi3addr, sizeof(request->lun_number));
1731e66f787SSean Bruno 	request->task_attribute = SOP_TASK_ATTRIBUTE_SIMPLE;
1741e66f787SSean Bruno 	request->additional_cdb_bytes_usage = PQI_ADDITIONAL_CDB_BYTES_0;
1751e66f787SSean Bruno 
1761e66f787SSean Bruno 	cdb = request->cdb;
1771e66f787SSean Bruno 
1781e66f787SSean Bruno 	switch (cmd) {
1791e66f787SSean Bruno 	case SA_INQUIRY:
1801e66f787SSean Bruno 		request->data_direction = SOP_DATA_DIR_TO_DEVICE;
1811e66f787SSean Bruno 		cdb[0] = SA_INQUIRY;
1821e66f787SSean Bruno 		if (vpd_page & VPD_PAGE) {
1831e66f787SSean Bruno 			cdb[1] = 0x1;
1841e66f787SSean Bruno 			cdb[2] = (uint8_t)vpd_page;
1851e66f787SSean Bruno 		}
1861e66f787SSean Bruno 		cdb[4] = (uint8_t)datasize;
1871e66f787SSean Bruno 		break;
1881e66f787SSean Bruno 	case SA_REPORT_LOG:
1891e66f787SSean Bruno 	case SA_REPORT_PHYS:
1901e66f787SSean Bruno 		request->data_direction = SOP_DATA_DIR_TO_DEVICE;
1911e66f787SSean Bruno 		cdb[0] = cmd;
1921e66f787SSean Bruno 		if (cmd == SA_REPORT_PHYS)
1931e66f787SSean Bruno 			cdb[1] = SA_REPORT_PHYS_EXTENDED;
1941e66f787SSean Bruno 		else
1951e66f787SSean Bruno 		cdb[1] = SA_REPORT_LOG_EXTENDED;
1961e66f787SSean Bruno 		cdb[8] = (uint8_t)((datasize) >> 8);
1971e66f787SSean Bruno 		cdb[9] = (uint8_t)datasize;
1981e66f787SSean Bruno 		break;
1991e66f787SSean Bruno 	case TEST_UNIT_READY:
2001e66f787SSean Bruno 		request->data_direction = SOP_DATA_DIR_NONE;
2011e66f787SSean Bruno 		break;
2021e66f787SSean Bruno 	case SA_GET_RAID_MAP:
2031e66f787SSean Bruno 		request->data_direction = SOP_DATA_DIR_TO_DEVICE;
2041e66f787SSean Bruno 		cdb[0] = SA_CISS_READ;
2051e66f787SSean Bruno 		cdb[1] = cmd;
2061e66f787SSean Bruno 		cdb[8] = (uint8_t)((datasize) >> 8);
2071e66f787SSean Bruno 		cdb[9] = (uint8_t)datasize;
2081e66f787SSean Bruno 		break;
2091e66f787SSean Bruno 	case SA_CACHE_FLUSH:
2101e66f787SSean Bruno 		request->data_direction = SOP_DATA_DIR_FROM_DEVICE;
211*b17f4335SSean Bruno 		memcpy(device_mem.virt_addr, buff, datasize);
2121e66f787SSean Bruno 		cdb[0] = BMIC_WRITE;
2131e66f787SSean Bruno 		cdb[6] = BMIC_CACHE_FLUSH;
2141e66f787SSean Bruno 		cdb[7] = (uint8_t)((datasize)  << 8);
2151e66f787SSean Bruno 		cdb[8] = (uint8_t)((datasize)  >> 8);
2161e66f787SSean Bruno 		break;
2171e66f787SSean Bruno 	case BMIC_IDENTIFY_CONTROLLER:
2181e66f787SSean Bruno 	case BMIC_IDENTIFY_PHYSICAL_DEVICE:
2191e66f787SSean Bruno 		request->data_direction = SOP_DATA_DIR_TO_DEVICE;
2201e66f787SSean Bruno 		cdb[0] = BMIC_READ;
2211e66f787SSean Bruno 		cdb[6] = cmd;
2221e66f787SSean Bruno 		cdb[7] = (uint8_t)((datasize)  << 8);
2231e66f787SSean Bruno 		cdb[8] = (uint8_t)((datasize)  >> 8);
2241e66f787SSean Bruno 		break;
2251e66f787SSean Bruno 	case BMIC_WRITE_HOST_WELLNESS:
2261e66f787SSean Bruno 		request->data_direction = SOP_DATA_DIR_FROM_DEVICE;
2271e66f787SSean Bruno 		memcpy(device_mem.virt_addr, buff, datasize);
2281e66f787SSean Bruno 		cdb[0] = BMIC_WRITE;
2291e66f787SSean Bruno 		cdb[6] = cmd;
2301e66f787SSean Bruno 		cdb[7] = (uint8_t)((datasize)  << 8);
2311e66f787SSean Bruno 		cdb[8] = (uint8_t)((datasize)  >> 8);
2321e66f787SSean Bruno 		break;
2331e66f787SSean Bruno 	case BMIC_SENSE_SUBSYSTEM_INFORMATION:
2341e66f787SSean Bruno 		request->data_direction = SOP_DATA_DIR_TO_DEVICE;
2351e66f787SSean Bruno 		cdb[0] = BMIC_READ;
2361e66f787SSean Bruno 		cdb[6] = cmd;
2371e66f787SSean Bruno 		cdb[7] = (uint8_t)((datasize)  << 8);
2381e66f787SSean Bruno 		cdb[8] = (uint8_t)((datasize)  >> 8);
2391e66f787SSean Bruno 		break;
2401e66f787SSean Bruno 	default:
2411e66f787SSean Bruno 		DBG_ERR("unknown command 0x%x", cmd);
2421e66f787SSean Bruno 		break;
2431e66f787SSean Bruno 	}
2441e66f787SSean Bruno 
2451e66f787SSean Bruno 	tag = pqisrc_get_tag(&softs->taglist);
2461e66f787SSean Bruno 	if (INVALID_ELEM == tag) {
2471e66f787SSean Bruno 		DBG_ERR("Tag not available\n");
2481e66f787SSean Bruno 		ret = PQI_STATUS_FAILURE;
2491e66f787SSean Bruno 		goto err_notag;
2501e66f787SSean Bruno 	}
2511e66f787SSean Bruno 
2521e66f787SSean Bruno 	((pqisrc_raid_req_t *)request)->request_id = tag;
2531e66f787SSean Bruno 	((pqisrc_raid_req_t *)request)->error_index = ((pqisrc_raid_req_t *)request)->request_id;
2541e66f787SSean Bruno 	((pqisrc_raid_req_t *)request)->response_queue_id = ob_q->q_id;
2551e66f787SSean Bruno 	rcb = &softs->rcb[tag];
2561e66f787SSean Bruno 	rcb->success_cmp_callback = pqisrc_process_internal_raid_response_success;
2571e66f787SSean Bruno 	rcb->error_cmp_callback = pqisrc_process_internal_raid_response_error;
2581e66f787SSean Bruno 
2591e66f787SSean Bruno 	rcb->req_pending = true;
2601e66f787SSean Bruno 	rcb->tag = tag;
2611e66f787SSean Bruno 	/* Submit Command */
2621e66f787SSean Bruno 	ret = pqisrc_submit_cmnd(softs, ib_q, request);
2631e66f787SSean Bruno 
2641e66f787SSean Bruno 	if (ret != PQI_STATUS_SUCCESS) {
2651e66f787SSean Bruno 		DBG_ERR("Unable to submit command\n");
2661e66f787SSean Bruno 		goto err_out;
2671e66f787SSean Bruno 	}
2681e66f787SSean Bruno 
2691e66f787SSean Bruno 	ret = pqisrc_wait_on_condition(softs, rcb);
2701e66f787SSean Bruno 	if (ret != PQI_STATUS_SUCCESS) {
2711e66f787SSean Bruno 		DBG_ERR("Internal RAID request timed out: cmd : 0x%c\n", cmd);
2721e66f787SSean Bruno 		goto err_out;
2731e66f787SSean Bruno 	}
2741e66f787SSean Bruno 
2751e66f787SSean Bruno 	if (datasize) {
2761e66f787SSean Bruno 		if (buff) {
2771e66f787SSean Bruno 			memcpy(buff, device_mem.virt_addr, datasize);
2781e66f787SSean Bruno 		}
2791e66f787SSean Bruno 		os_dma_mem_free(softs, &device_mem);
2801e66f787SSean Bruno 	}
2811e66f787SSean Bruno 
2821e66f787SSean Bruno 	ret = rcb->status;
2831e66f787SSean Bruno 	if (ret) {
2841e66f787SSean Bruno 		if(error_info) {
2851e66f787SSean Bruno 			memcpy(error_info,
2861e66f787SSean Bruno 			       rcb->error_info,
2871e66f787SSean Bruno 			       sizeof(*error_info));
2881e66f787SSean Bruno 
2891e66f787SSean Bruno 			if (error_info->data_out_result ==
2901e66f787SSean Bruno 			    PQI_RAID_DATA_IN_OUT_UNDERFLOW) {
2911e66f787SSean Bruno 				ret = PQI_STATUS_SUCCESS;
2921e66f787SSean Bruno 			}
2931e66f787SSean Bruno 			else{
294*b17f4335SSean Bruno 				DBG_DISC("Error!! Bus=%u Target=%u, Cmd=0x%x,"
2951e66f787SSean Bruno 					"Ret=%d\n", BMIC_GET_LEVEL_2_BUS(scsi3addr),
2961e66f787SSean Bruno 					BMIC_GET_LEVEL_TWO_TARGET(scsi3addr),
2971e66f787SSean Bruno 					cmd, ret);
2981e66f787SSean Bruno 				ret = PQI_STATUS_FAILURE;
2991e66f787SSean Bruno 			}
3001e66f787SSean Bruno 		}
3011e66f787SSean Bruno 	} else {
3021e66f787SSean Bruno 		if(error_info) {
3031e66f787SSean Bruno 			ret = PQI_STATUS_SUCCESS;
3041e66f787SSean Bruno 			memset(error_info, 0, sizeof(*error_info));
3051e66f787SSean Bruno 		}
3061e66f787SSean Bruno 	}
3071e66f787SSean Bruno 
3081e66f787SSean Bruno 	os_reset_rcb(rcb);
3091e66f787SSean Bruno 	pqisrc_put_tag(&softs->taglist, ((pqisrc_raid_req_t *)request)->request_id);
3101e66f787SSean Bruno 	DBG_FUNC("OUT\n");
3111e66f787SSean Bruno 	return ret;
3121e66f787SSean Bruno 
3131e66f787SSean Bruno err_out:
3141e66f787SSean Bruno 	DBG_ERR("Error!! Bus=%u Target=%u, Cmd=0x%x, Ret=%d\n",
3151e66f787SSean Bruno 		BMIC_GET_LEVEL_2_BUS(scsi3addr), BMIC_GET_LEVEL_TWO_TARGET(scsi3addr),
3161e66f787SSean Bruno 		cmd, ret);
3171e66f787SSean Bruno 	os_reset_rcb(rcb);
3181e66f787SSean Bruno 	pqisrc_put_tag(&softs->taglist, ((pqisrc_raid_req_t *)request)->request_id);
3191e66f787SSean Bruno err_notag:
3201e66f787SSean Bruno 	if (datasize)
3211e66f787SSean Bruno 		os_dma_mem_free(softs, &device_mem);
3221e66f787SSean Bruno 	DBG_FUNC("FAILED \n");
3231e66f787SSean Bruno 	return ret;
3241e66f787SSean Bruno }
3251e66f787SSean Bruno 
3261e66f787SSean Bruno /* common function used to send report physical and logical luns cmnds*/
3271e66f787SSean Bruno static int pqisrc_report_luns(pqisrc_softstate_t *softs, uint8_t cmd,
3281e66f787SSean Bruno 	void *buff, size_t buf_len)
3291e66f787SSean Bruno {
3301e66f787SSean Bruno 	int ret;
3311e66f787SSean Bruno 	pqisrc_raid_req_t request;
3321e66f787SSean Bruno 
3331e66f787SSean Bruno 	DBG_FUNC("IN\n");
3341e66f787SSean Bruno 
3351e66f787SSean Bruno 	memset(&request, 0, sizeof(request));
3361e66f787SSean Bruno 	ret =  pqisrc_build_send_raid_request(softs, &request, buff,
3371e66f787SSean Bruno 				buf_len, cmd, 0, (uint8_t *)RAID_CTLR_LUNID, NULL);
3381e66f787SSean Bruno 
3391e66f787SSean Bruno 	DBG_FUNC("OUT\n");
3401e66f787SSean Bruno 
3411e66f787SSean Bruno 	return ret;
3421e66f787SSean Bruno }
3431e66f787SSean Bruno 
3441e66f787SSean Bruno /* subroutine used to get physical and logical luns of the device */
3451e66f787SSean Bruno static int pqisrc_get_physical_logical_luns(pqisrc_softstate_t *softs, uint8_t cmd,
3461e66f787SSean Bruno 		reportlun_data_ext_t **buff, size_t *data_length)
3471e66f787SSean Bruno {
3481e66f787SSean Bruno 	int ret;
3491e66f787SSean Bruno 	size_t list_len;
3501e66f787SSean Bruno 	size_t data_len;
3511e66f787SSean Bruno 	size_t new_lun_list_length;
3521e66f787SSean Bruno 	reportlun_data_ext_t *lun_data;
3531e66f787SSean Bruno 	reportlun_header_t report_lun_header;
3541e66f787SSean Bruno 
3551e66f787SSean Bruno 	DBG_FUNC("IN\n");
3561e66f787SSean Bruno 
3571e66f787SSean Bruno 	ret = pqisrc_report_luns(softs, cmd, &report_lun_header,
3581e66f787SSean Bruno 		sizeof(report_lun_header));
3591e66f787SSean Bruno 
3601e66f787SSean Bruno 	if (ret) {
3611e66f787SSean Bruno 		DBG_ERR("failed return code: %d\n", ret);
3621e66f787SSean Bruno 		return ret;
3631e66f787SSean Bruno 	}
3641e66f787SSean Bruno 	list_len = BE_32(report_lun_header.list_length);
3651e66f787SSean Bruno 
3661e66f787SSean Bruno retry:
3671e66f787SSean Bruno 	data_len = sizeof(reportlun_header_t) + list_len;
3681e66f787SSean Bruno 	*data_length = data_len;
3691e66f787SSean Bruno 
3701e66f787SSean Bruno 	lun_data = os_mem_alloc(softs, data_len);
3711e66f787SSean Bruno 
3721e66f787SSean Bruno 	if (!lun_data) {
3731e66f787SSean Bruno 		DBG_ERR("failed to allocate memory for lun_data\n");
3741e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
3751e66f787SSean Bruno 	}
3761e66f787SSean Bruno 
3771e66f787SSean Bruno 	if (list_len == 0) {
378*b17f4335SSean Bruno 		DBG_DISC("list_len is 0\n");
3791e66f787SSean Bruno 		memcpy(lun_data, &report_lun_header, sizeof(report_lun_header));
3801e66f787SSean Bruno 		goto out;
3811e66f787SSean Bruno 	}
3821e66f787SSean Bruno 
3831e66f787SSean Bruno 	ret = pqisrc_report_luns(softs, cmd, lun_data, data_len);
3841e66f787SSean Bruno 
3851e66f787SSean Bruno 	if (ret) {
3861e66f787SSean Bruno 		DBG_ERR("error\n");
3871e66f787SSean Bruno 		goto error;
3881e66f787SSean Bruno 	}
3891e66f787SSean Bruno 
3901e66f787SSean Bruno 	new_lun_list_length = BE_32(lun_data->header.list_length);
3911e66f787SSean Bruno 
3921e66f787SSean Bruno 	if (new_lun_list_length > list_len) {
3931e66f787SSean Bruno 		list_len = new_lun_list_length;
3941e66f787SSean Bruno 		os_mem_free(softs, (void *)lun_data, data_len);
3951e66f787SSean Bruno 		goto retry;
3961e66f787SSean Bruno 	}
3971e66f787SSean Bruno 
3981e66f787SSean Bruno out:
3991e66f787SSean Bruno 	*buff = lun_data;
4001e66f787SSean Bruno 	DBG_FUNC("OUT\n");
4011e66f787SSean Bruno 	return 0;
4021e66f787SSean Bruno 
4031e66f787SSean Bruno error:
4041e66f787SSean Bruno 	os_mem_free(softs, (void *)lun_data, data_len);
4051e66f787SSean Bruno 	DBG_ERR("FAILED\n");
4061e66f787SSean Bruno 	return ret;
4071e66f787SSean Bruno }
4081e66f787SSean Bruno 
4091e66f787SSean Bruno /*
4101e66f787SSean Bruno  * Function used to get physical and logical device list
4111e66f787SSean Bruno  */
4121e66f787SSean Bruno static int pqisrc_get_phys_log_device_list(pqisrc_softstate_t *softs,
4131e66f787SSean Bruno 	reportlun_data_ext_t **physical_dev_list,
4141e66f787SSean Bruno 	reportlun_data_ext_t **logical_dev_list,
4151e66f787SSean Bruno 	size_t *phys_data_length,
4161e66f787SSean Bruno 	size_t *log_data_length)
4171e66f787SSean Bruno {
4181e66f787SSean Bruno 	int ret = PQI_STATUS_SUCCESS;
4191e66f787SSean Bruno 	size_t logical_list_length;
4201e66f787SSean Bruno 	size_t logdev_data_length;
4211e66f787SSean Bruno 	size_t data_length;
4221e66f787SSean Bruno 	reportlun_data_ext_t *local_logdev_list;
4231e66f787SSean Bruno 	reportlun_data_ext_t *logdev_data;
4241e66f787SSean Bruno 	reportlun_header_t report_lun_header;
4251e66f787SSean Bruno 
4261e66f787SSean Bruno 
4271e66f787SSean Bruno 	DBG_FUNC("IN\n");
4281e66f787SSean Bruno 
4291e66f787SSean Bruno 	ret = pqisrc_get_physical_logical_luns(softs, SA_REPORT_PHYS, physical_dev_list, phys_data_length);
4301e66f787SSean Bruno 	if (ret) {
4311e66f787SSean Bruno 		DBG_ERR("report physical LUNs failed");
4321e66f787SSean Bruno 		return ret;
4331e66f787SSean Bruno 	}
4341e66f787SSean Bruno 
4351e66f787SSean Bruno 	ret = pqisrc_get_physical_logical_luns(softs, SA_REPORT_LOG, logical_dev_list, log_data_length);
4361e66f787SSean Bruno 	if (ret) {
4371e66f787SSean Bruno 		DBG_ERR("report logical LUNs failed");
4381e66f787SSean Bruno 		return ret;
4391e66f787SSean Bruno 	}
4401e66f787SSean Bruno 
4411e66f787SSean Bruno 
4421e66f787SSean Bruno 	logdev_data = *logical_dev_list;
4431e66f787SSean Bruno 
4441e66f787SSean Bruno 	if (logdev_data) {
4451e66f787SSean Bruno 		logical_list_length =
4461e66f787SSean Bruno 			BE_32(logdev_data->header.list_length);
4471e66f787SSean Bruno 	} else {
4481e66f787SSean Bruno 		memset(&report_lun_header, 0, sizeof(report_lun_header));
4491e66f787SSean Bruno 		logdev_data =
4501e66f787SSean Bruno 			(reportlun_data_ext_t *)&report_lun_header;
4511e66f787SSean Bruno 		logical_list_length = 0;
4521e66f787SSean Bruno 	}
4531e66f787SSean Bruno 
4541e66f787SSean Bruno 	logdev_data_length = sizeof(reportlun_header_t) +
4551e66f787SSean Bruno 		logical_list_length;
4561e66f787SSean Bruno 
4571e66f787SSean Bruno 	/* Adding LOGICAL device entry for controller */
4581e66f787SSean Bruno 	local_logdev_list = os_mem_alloc(softs,
4591e66f787SSean Bruno 					    logdev_data_length + sizeof(reportlun_ext_entry_t));
4601e66f787SSean Bruno 	if (!local_logdev_list) {
4611e66f787SSean Bruno 		data_length = *log_data_length;
4621e66f787SSean Bruno 		os_mem_free(softs, (char *)*logical_dev_list, data_length);
4631e66f787SSean Bruno 		*logical_dev_list = NULL;
4641e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
4651e66f787SSean Bruno 	}
4661e66f787SSean Bruno 
4671e66f787SSean Bruno 	memcpy(local_logdev_list, logdev_data, logdev_data_length);
4681e66f787SSean Bruno 	memset((uint8_t *)local_logdev_list + logdev_data_length, 0,
4691e66f787SSean Bruno 		sizeof(reportlun_ext_entry_t));
4701e66f787SSean Bruno 	local_logdev_list->header.list_length = BE_32(logical_list_length +
4711e66f787SSean Bruno 							sizeof(reportlun_ext_entry_t));
4721e66f787SSean Bruno 	data_length = *log_data_length;
4731e66f787SSean Bruno 	os_mem_free(softs, (char *)*logical_dev_list, data_length);
4741e66f787SSean Bruno 	*log_data_length = logdev_data_length + sizeof(reportlun_ext_entry_t);
4751e66f787SSean Bruno 	*logical_dev_list = local_logdev_list;
4761e66f787SSean Bruno 
4771e66f787SSean Bruno 	DBG_FUNC("OUT\n");
4781e66f787SSean Bruno 
4791e66f787SSean Bruno 	return ret;
4801e66f787SSean Bruno }
4811e66f787SSean Bruno 
4821e66f787SSean Bruno /* Subroutine used to set Bus-Target-Lun for the requested device */
4831e66f787SSean Bruno static inline void pqisrc_set_btl(pqi_scsi_dev_t *device,
4841e66f787SSean Bruno 	int bus, int target, int lun)
4851e66f787SSean Bruno {
4861e66f787SSean Bruno 	DBG_FUNC("IN\n");
4871e66f787SSean Bruno 
4881e66f787SSean Bruno 	device->bus = bus;
4891e66f787SSean Bruno 	device->target = target;
4901e66f787SSean Bruno 	device->lun = lun;
4911e66f787SSean Bruno 
4921e66f787SSean Bruno 	DBG_FUNC("OUT\n");
4931e66f787SSean Bruno }
4941e66f787SSean Bruno 
4951e66f787SSean Bruno inline boolean_t pqisrc_is_external_raid_device(pqi_scsi_dev_t *device)
4961e66f787SSean Bruno {
4971e66f787SSean Bruno 	return device->is_external_raid_device;
4981e66f787SSean Bruno }
4991e66f787SSean Bruno 
5001e66f787SSean Bruno static inline boolean_t pqisrc_is_external_raid_addr(uint8_t *scsi3addr)
5011e66f787SSean Bruno {
5021e66f787SSean Bruno 	return scsi3addr[2] != 0;
5031e66f787SSean Bruno }
5041e66f787SSean Bruno 
5051e66f787SSean Bruno /* Function used to assign Bus-Target-Lun for the requested device */
5061e66f787SSean Bruno static void pqisrc_assign_btl(pqi_scsi_dev_t *device)
5071e66f787SSean Bruno {
5081e66f787SSean Bruno 	uint8_t *scsi3addr;
5091e66f787SSean Bruno 	uint32_t lunid;
5101e66f787SSean Bruno 	uint32_t bus;
5111e66f787SSean Bruno 	uint32_t target;
5121e66f787SSean Bruno 	uint32_t lun;
5131e66f787SSean Bruno 	DBG_FUNC("IN\n");
5141e66f787SSean Bruno 
5151e66f787SSean Bruno 	scsi3addr = device->scsi3addr;
5161e66f787SSean Bruno 	lunid = GET_LE32(scsi3addr);
5171e66f787SSean Bruno 
5181e66f787SSean Bruno 	if (pqisrc_is_hba_lunid(scsi3addr)) {
5191e66f787SSean Bruno 		/* The specified device is the controller. */
5201e66f787SSean Bruno 		pqisrc_set_btl(device, PQI_HBA_BUS, PQI_CTLR_INDEX, lunid & 0x3fff);
5211e66f787SSean Bruno 		device->target_lun_valid = true;
5221e66f787SSean Bruno 		return;
5231e66f787SSean Bruno 	}
5241e66f787SSean Bruno 
5251e66f787SSean Bruno 	if (pqisrc_is_logical_device(device)) {
5261e66f787SSean Bruno 		if (pqisrc_is_external_raid_device(device)) {
527*b17f4335SSean Bruno 			DBG_DISC("External Raid Device!!!");
5281e66f787SSean Bruno 			bus = PQI_EXTERNAL_RAID_VOLUME_BUS;
5291e66f787SSean Bruno 			target = (lunid >> 16) & 0x3fff;
5301e66f787SSean Bruno 			lun = lunid & 0xff;
5311e66f787SSean Bruno 		} else {
5321e66f787SSean Bruno 			bus = PQI_RAID_VOLUME_BUS;
5331e66f787SSean Bruno 			lun = 0;
5341e66f787SSean Bruno 			target = lunid & 0x3fff;
5351e66f787SSean Bruno 		}
5361e66f787SSean Bruno 		pqisrc_set_btl(device, bus, target, lun);
5371e66f787SSean Bruno 		device->target_lun_valid = true;
5381e66f787SSean Bruno 		return;
5391e66f787SSean Bruno 	}
5401e66f787SSean Bruno 
5411e66f787SSean Bruno 	DBG_FUNC("OUT\n");
5421e66f787SSean Bruno }
5431e66f787SSean Bruno 
5441e66f787SSean Bruno /* Build and send the internal INQUIRY command to particular device */
5451e66f787SSean Bruno static int pqisrc_send_scsi_inquiry(pqisrc_softstate_t *softs,
5461e66f787SSean Bruno 	uint8_t *scsi3addr, uint16_t vpd_page, uint8_t *buff, int buf_len)
5471e66f787SSean Bruno {
5481e66f787SSean Bruno 	int ret = PQI_STATUS_SUCCESS;
5491e66f787SSean Bruno 	pqisrc_raid_req_t request;
5501e66f787SSean Bruno 	raid_path_error_info_elem_t error_info;
5511e66f787SSean Bruno 
5521e66f787SSean Bruno 	DBG_FUNC("IN\n");
5531e66f787SSean Bruno 
5541e66f787SSean Bruno 	memset(&request, 0, sizeof(request));
5551e66f787SSean Bruno 	ret =  pqisrc_build_send_raid_request(softs, &request, buff, buf_len,
5561e66f787SSean Bruno 								SA_INQUIRY, vpd_page, scsi3addr, &error_info);
5571e66f787SSean Bruno 
5581e66f787SSean Bruno 	DBG_FUNC("OUT\n");
5591e66f787SSean Bruno 	return ret;
5601e66f787SSean Bruno }
5611e66f787SSean Bruno 
5621e66f787SSean Bruno /* Function used to parse the sense information from response */
5631e66f787SSean Bruno static void pqisrc_fetch_sense_info(const uint8_t *sense_data,
5641e66f787SSean Bruno 	unsigned sense_data_length, uint8_t *sense_key, uint8_t *asc, uint8_t *ascq)
5651e66f787SSean Bruno {
5661e66f787SSean Bruno 	struct sense_header_scsi header;
5671e66f787SSean Bruno 
5681e66f787SSean Bruno 	DBG_FUNC("IN\n");
5691e66f787SSean Bruno 
5701e66f787SSean Bruno 	*sense_key = 0;
5711e66f787SSean Bruno 	*ascq = 0;
5721e66f787SSean Bruno 	*asc = 0;
5731e66f787SSean Bruno 
5741e66f787SSean Bruno 	if (pqisrc_update_scsi_sense(sense_data, sense_data_length, &header)) {
5751e66f787SSean Bruno 		*sense_key = header.sense_key;
5761e66f787SSean Bruno 		*asc = header.asc;
5771e66f787SSean Bruno 		*ascq = header.ascq;
5781e66f787SSean Bruno 	}
5791e66f787SSean Bruno 
580*b17f4335SSean Bruno 	DBG_DISC("sense_key: %x asc: %x ascq: %x\n", *sense_key, *asc, *ascq);
5811e66f787SSean Bruno 
5821e66f787SSean Bruno 	DBG_FUNC("OUT\n");
5831e66f787SSean Bruno }
5841e66f787SSean Bruno 
5851e66f787SSean Bruno /* Function used to validate volume offline status */
5861e66f787SSean Bruno static uint8_t pqisrc_get_volume_offline_status(pqisrc_softstate_t *softs,
5871e66f787SSean Bruno 	uint8_t *scsi3addr)
5881e66f787SSean Bruno {
5891e66f787SSean Bruno 	int ret = PQI_STATUS_SUCCESS;
5901e66f787SSean Bruno 	uint8_t status = SA_LV_STATUS_VPD_UNSUPPORTED;
5911e66f787SSean Bruno 	uint8_t size;
5921e66f787SSean Bruno 	uint8_t *buff = NULL;
5931e66f787SSean Bruno 
5941e66f787SSean Bruno 	DBG_FUNC("IN\n");
5951e66f787SSean Bruno 
5961e66f787SSean Bruno 	buff = os_mem_alloc(softs, 64);
5971e66f787SSean Bruno 	if (!buff)
5981e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
5991e66f787SSean Bruno 
6001e66f787SSean Bruno 	/* Get the size of the VPD return buff. */
6011e66f787SSean Bruno 	ret = pqisrc_send_scsi_inquiry(softs, scsi3addr, VPD_PAGE | SA_VPD_LV_STATUS,
6021e66f787SSean Bruno 		buff, SCSI_VPD_HEADER_LENGTH);
6031e66f787SSean Bruno 
6041e66f787SSean Bruno 	if (ret)
6051e66f787SSean Bruno 		goto out;
6061e66f787SSean Bruno 
6071e66f787SSean Bruno 	size = buff[3];
6081e66f787SSean Bruno 
6091e66f787SSean Bruno 	/* Now get the whole VPD buff. */
6101e66f787SSean Bruno 	ret = pqisrc_send_scsi_inquiry(softs, scsi3addr, VPD_PAGE | SA_VPD_LV_STATUS,
6111e66f787SSean Bruno 		buff, size + SCSI_VPD_HEADER_LENGTH);
6121e66f787SSean Bruno 	if (ret)
6131e66f787SSean Bruno 		goto out;
6141e66f787SSean Bruno 
6151e66f787SSean Bruno 	status = buff[4];
6161e66f787SSean Bruno 
6171e66f787SSean Bruno out:
6181e66f787SSean Bruno 	os_mem_free(softs, (char *)buff, 64);
6191e66f787SSean Bruno 	DBG_FUNC("OUT\n");
6201e66f787SSean Bruno 
6211e66f787SSean Bruno 	return status;
6221e66f787SSean Bruno }
6231e66f787SSean Bruno 
6241e66f787SSean Bruno 
6251e66f787SSean Bruno /* Determine offline status of a volume.  Returns appropriate SA_LV_* status.*/
6261e66f787SSean Bruno static uint8_t pqisrc_get_dev_vol_status(pqisrc_softstate_t *softs,
6271e66f787SSean Bruno 	uint8_t *scsi3addr)
6281e66f787SSean Bruno {
6291e66f787SSean Bruno 	int ret = PQI_STATUS_SUCCESS;
6301e66f787SSean Bruno 	uint8_t *sense_data;
6311e66f787SSean Bruno 	unsigned sense_data_len;
6321e66f787SSean Bruno 	uint8_t sense_key;
6331e66f787SSean Bruno 	uint8_t asc;
6341e66f787SSean Bruno 	uint8_t ascq;
6351e66f787SSean Bruno 	uint8_t off_status;
6361e66f787SSean Bruno 	uint8_t scsi_status;
6371e66f787SSean Bruno 	pqisrc_raid_req_t request;
6381e66f787SSean Bruno 	raid_path_error_info_elem_t error_info;
6391e66f787SSean Bruno 
6401e66f787SSean Bruno 	DBG_FUNC("IN\n");
6411e66f787SSean Bruno 
6421e66f787SSean Bruno 	memset(&request, 0, sizeof(request));
6431e66f787SSean Bruno 	ret =  pqisrc_build_send_raid_request(softs, &request, NULL, 0,
6441e66f787SSean Bruno 				TEST_UNIT_READY, 0, scsi3addr, &error_info);
6451e66f787SSean Bruno 
6461e66f787SSean Bruno 	if (ret)
6471e66f787SSean Bruno 		goto error;
6481e66f787SSean Bruno 	sense_data = error_info.data;
6491e66f787SSean Bruno 	sense_data_len = LE_16(error_info.sense_data_len);
6501e66f787SSean Bruno 
6511e66f787SSean Bruno 	if (sense_data_len > sizeof(error_info.data))
6521e66f787SSean Bruno 		sense_data_len = sizeof(error_info.data);
6531e66f787SSean Bruno 
6541e66f787SSean Bruno 	pqisrc_fetch_sense_info(sense_data, sense_data_len, &sense_key, &asc,
6551e66f787SSean Bruno 		&ascq);
6561e66f787SSean Bruno 
6571e66f787SSean Bruno 	scsi_status = error_info.status;
6581e66f787SSean Bruno 
6591e66f787SSean Bruno 	/* scsi status: "CHECK CONDN" /  SK: "not ready" ? */
6601e66f787SSean Bruno 	if (scsi_status != 2 ||
6611e66f787SSean Bruno 	    sense_key != 2 ||
6621e66f787SSean Bruno 	    asc != ASC_LUN_NOT_READY) {
6631e66f787SSean Bruno 		return SA_LV_OK;
6641e66f787SSean Bruno 	}
6651e66f787SSean Bruno 
6661e66f787SSean Bruno 	/* Determine the reason for not ready state. */
6671e66f787SSean Bruno 	off_status = pqisrc_get_volume_offline_status(softs, scsi3addr);
6681e66f787SSean Bruno 
669*b17f4335SSean Bruno 	DBG_DISC("offline_status 0x%x\n", off_status);
6701e66f787SSean Bruno 
6711e66f787SSean Bruno 	/* Keep volume offline in certain cases. */
6721e66f787SSean Bruno 	switch (off_status) {
6731e66f787SSean Bruno 	case SA_LV_UNDERGOING_ERASE:
6741e66f787SSean Bruno 	case SA_LV_NOT_AVAILABLE:
6751e66f787SSean Bruno 	case SA_LV_UNDERGOING_RPI:
6761e66f787SSean Bruno 	case SA_LV_PENDING_RPI:
6771e66f787SSean Bruno 	case SA_LV_ENCRYPTED_NO_KEY:
6781e66f787SSean Bruno 	case SA_LV_PLAINTEXT_IN_ENCRYPT_ONLY_CONTROLLER:
6791e66f787SSean Bruno 	case SA_LV_UNDERGOING_ENCRYPTION:
6801e66f787SSean Bruno 	case SA_LV_UNDERGOING_ENCRYPTION_REKEYING:
6811e66f787SSean Bruno 	case SA_LV_ENCRYPTED_IN_NON_ENCRYPTED_CONTROLLER:
6821e66f787SSean Bruno 		return off_status;
6831e66f787SSean Bruno 	case SA_LV_STATUS_VPD_UNSUPPORTED:
6841e66f787SSean Bruno 		/*
6851e66f787SSean Bruno 		 * If the VPD status page isn't available,
6861e66f787SSean Bruno 		 * use ASC/ASCQ to determine state.
6871e66f787SSean Bruno 		 */
6881e66f787SSean Bruno 		if (ascq == ASCQ_LUN_NOT_READY_FORMAT_IN_PROGRESS ||
6891e66f787SSean Bruno 		    ascq == ASCQ_LUN_NOT_READY_INITIALIZING_CMD_REQ)
6901e66f787SSean Bruno 			return off_status;
6911e66f787SSean Bruno 		break;
6921e66f787SSean Bruno 	}
6931e66f787SSean Bruno 
6941e66f787SSean Bruno 	DBG_FUNC("OUT\n");
6951e66f787SSean Bruno 
6961e66f787SSean Bruno 	return SA_LV_OK;
6971e66f787SSean Bruno 
6981e66f787SSean Bruno error:
6991e66f787SSean Bruno 	return SA_LV_STATUS_VPD_UNSUPPORTED;
7001e66f787SSean Bruno }
7011e66f787SSean Bruno 
7021e66f787SSean Bruno /* Validate the RAID map parameters */
7031e66f787SSean Bruno static int pqisrc_raid_map_validation(pqisrc_softstate_t *softs,
7041e66f787SSean Bruno 	pqi_scsi_dev_t *device, pqisrc_raid_map_t *raid_map)
7051e66f787SSean Bruno {
7061e66f787SSean Bruno 	char *error_msg;
7071e66f787SSean Bruno 	uint32_t raidmap_size;
7081e66f787SSean Bruno 	uint32_t r5or6_blocks_per_row;
7091e66f787SSean Bruno 	unsigned phys_dev_num;
7101e66f787SSean Bruno 	unsigned num_raidmap_entries;
7111e66f787SSean Bruno 
7121e66f787SSean Bruno 	DBG_FUNC("IN\n");
7131e66f787SSean Bruno 
7141e66f787SSean Bruno 	raidmap_size = LE_32(raid_map->structure_size);
7151e66f787SSean Bruno 	if (raidmap_size < offsetof(pqisrc_raid_map_t, dev_data)) {
7161e66f787SSean Bruno 		error_msg = "RAID map too small\n";
7171e66f787SSean Bruno 		goto error;
7181e66f787SSean Bruno 	}
7191e66f787SSean Bruno 
7201e66f787SSean Bruno 	if (raidmap_size > sizeof(*raid_map)) {
7211e66f787SSean Bruno 		error_msg = "RAID map too large\n";
7221e66f787SSean Bruno 		goto error;
7231e66f787SSean Bruno 	}
7241e66f787SSean Bruno 
7251e66f787SSean Bruno 	phys_dev_num = LE_16(raid_map->layout_map_count) *
7261e66f787SSean Bruno 		(LE_16(raid_map->data_disks_per_row) +
7271e66f787SSean Bruno 		LE_16(raid_map->metadata_disks_per_row));
7281e66f787SSean Bruno 	num_raidmap_entries = phys_dev_num *
7291e66f787SSean Bruno 		LE_16(raid_map->row_cnt);
7301e66f787SSean Bruno 
7311e66f787SSean Bruno 	if (num_raidmap_entries > RAID_MAP_MAX_ENTRIES) {
7321e66f787SSean Bruno 		error_msg = "invalid number of map entries in RAID map\n";
7331e66f787SSean Bruno 		goto error;
7341e66f787SSean Bruno 	}
7351e66f787SSean Bruno 
7361e66f787SSean Bruno 	if (device->raid_level == SA_RAID_1) {
7371e66f787SSean Bruno 		if (LE_16(raid_map->layout_map_count) != 2) {
7381e66f787SSean Bruno 			error_msg = "invalid RAID-1 map\n";
7391e66f787SSean Bruno 			goto error;
7401e66f787SSean Bruno 		}
7411e66f787SSean Bruno 	} else if (device->raid_level == SA_RAID_ADM) {
7421e66f787SSean Bruno 		if (LE_16(raid_map->layout_map_count) != 3) {
7431e66f787SSean Bruno 			error_msg = "invalid RAID-1(ADM) map\n";
7441e66f787SSean Bruno 			goto error;
7451e66f787SSean Bruno 		}
7461e66f787SSean Bruno 	} else if ((device->raid_level == SA_RAID_5 ||
7471e66f787SSean Bruno 		device->raid_level == SA_RAID_6) &&
7481e66f787SSean Bruno 		LE_16(raid_map->layout_map_count) > 1) {
7491e66f787SSean Bruno 		/* RAID 50/60 */
7501e66f787SSean Bruno 		r5or6_blocks_per_row =
7511e66f787SSean Bruno 			LE_16(raid_map->strip_size) *
7521e66f787SSean Bruno 			LE_16(raid_map->data_disks_per_row);
7531e66f787SSean Bruno 		if (r5or6_blocks_per_row == 0) {
7541e66f787SSean Bruno 			error_msg = "invalid RAID-5 or RAID-6 map\n";
7551e66f787SSean Bruno 			goto error;
7561e66f787SSean Bruno 		}
7571e66f787SSean Bruno 	}
7581e66f787SSean Bruno 
7591e66f787SSean Bruno 	DBG_FUNC("OUT\n");
7601e66f787SSean Bruno 
7611e66f787SSean Bruno 	return 0;
7621e66f787SSean Bruno 
7631e66f787SSean Bruno error:
7641e66f787SSean Bruno 	DBG_ERR("%s\n", error_msg);
7651e66f787SSean Bruno 	return PQI_STATUS_FAILURE;
7661e66f787SSean Bruno }
7671e66f787SSean Bruno 
7681e66f787SSean Bruno /* Get device raidmap for the requested device */
7691e66f787SSean Bruno static int pqisrc_get_device_raidmap(pqisrc_softstate_t *softs,
7701e66f787SSean Bruno 	pqi_scsi_dev_t *device)
7711e66f787SSean Bruno {
7721e66f787SSean Bruno 	int ret = PQI_STATUS_SUCCESS;
7731e66f787SSean Bruno 	pqisrc_raid_req_t request;
7741e66f787SSean Bruno 	pqisrc_raid_map_t *raid_map;
7751e66f787SSean Bruno 
7761e66f787SSean Bruno 	DBG_FUNC("IN\n");
7771e66f787SSean Bruno 
7781e66f787SSean Bruno 	raid_map = os_mem_alloc(softs, sizeof(*raid_map));
7791e66f787SSean Bruno 	if (!raid_map)
7801e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
7811e66f787SSean Bruno 
7821e66f787SSean Bruno 	memset(&request, 0, sizeof(request));
7831e66f787SSean Bruno 	ret =  pqisrc_build_send_raid_request(softs, &request, raid_map, sizeof(*raid_map),
7841e66f787SSean Bruno 			 		SA_GET_RAID_MAP, 0, device->scsi3addr, NULL);
7851e66f787SSean Bruno 
7861e66f787SSean Bruno 	if (ret) {
7871e66f787SSean Bruno 		DBG_ERR("error in build send raid req ret=%d\n", ret);
7881e66f787SSean Bruno 		goto err_out;
7891e66f787SSean Bruno 	}
7901e66f787SSean Bruno 
7911e66f787SSean Bruno 	ret = pqisrc_raid_map_validation(softs, device, raid_map);
7921e66f787SSean Bruno 	if (ret) {
7931e66f787SSean Bruno 		DBG_ERR("error in raid map validation ret=%d\n", ret);
7941e66f787SSean Bruno 		goto err_out;
7951e66f787SSean Bruno 	}
7961e66f787SSean Bruno 
7971e66f787SSean Bruno 	device->raid_map = raid_map;
7981e66f787SSean Bruno 	DBG_FUNC("OUT\n");
7991e66f787SSean Bruno 	return 0;
8001e66f787SSean Bruno 
8011e66f787SSean Bruno err_out:
8021e66f787SSean Bruno 	os_mem_free(softs, (char*)raid_map, sizeof(*raid_map));
8031e66f787SSean Bruno 	DBG_FUNC("FAILED \n");
8041e66f787SSean Bruno 	return ret;
8051e66f787SSean Bruno }
8061e66f787SSean Bruno 
8071e66f787SSean Bruno /* Get device ioaccel_status to validate the type of device */
8081e66f787SSean Bruno static void pqisrc_get_dev_ioaccel_status(pqisrc_softstate_t *softs,
8091e66f787SSean Bruno 	pqi_scsi_dev_t *device)
8101e66f787SSean Bruno {
8111e66f787SSean Bruno 	int ret = PQI_STATUS_SUCCESS;
8121e66f787SSean Bruno 	uint8_t *buff;
8131e66f787SSean Bruno 	uint8_t ioaccel_status;
8141e66f787SSean Bruno 
8151e66f787SSean Bruno 	DBG_FUNC("IN\n");
8161e66f787SSean Bruno 
8171e66f787SSean Bruno 	buff = os_mem_alloc(softs, 64);
8181e66f787SSean Bruno 	if (!buff)
8191e66f787SSean Bruno 		return;
8201e66f787SSean Bruno 
8211e66f787SSean Bruno 	ret = pqisrc_send_scsi_inquiry(softs, device->scsi3addr,
8221e66f787SSean Bruno 					VPD_PAGE | SA_VPD_LV_IOACCEL_STATUS, buff, 64);
8231e66f787SSean Bruno 	if (ret) {
8241e66f787SSean Bruno 		DBG_ERR("error in send scsi inquiry ret=%d\n", ret);
8251e66f787SSean Bruno 		goto err_out;
8261e66f787SSean Bruno 	}
8271e66f787SSean Bruno 
8281e66f787SSean Bruno 	ioaccel_status = buff[IOACCEL_STATUS_BYTE];
8291e66f787SSean Bruno 	device->offload_config =
8301e66f787SSean Bruno 		!!(ioaccel_status & OFFLOAD_CONFIGURED_BIT);
8311e66f787SSean Bruno 
8321e66f787SSean Bruno 	if (device->offload_config) {
8331e66f787SSean Bruno 		device->offload_enabled_pending =
8341e66f787SSean Bruno 			!!(ioaccel_status & OFFLOAD_ENABLED_BIT);
8351e66f787SSean Bruno 		if (pqisrc_get_device_raidmap(softs, device))
8361e66f787SSean Bruno 			device->offload_enabled_pending = false;
8371e66f787SSean Bruno 	}
8381e66f787SSean Bruno 
839*b17f4335SSean Bruno 	DBG_DISC("offload_config: 0x%x offload_enabled_pending: 0x%x \n",
8401e66f787SSean Bruno 			device->offload_config, device->offload_enabled_pending);
8411e66f787SSean Bruno 
8421e66f787SSean Bruno err_out:
8431e66f787SSean Bruno 	os_mem_free(softs, (char*)buff, 64);
8441e66f787SSean Bruno 	DBG_FUNC("OUT\n");
8451e66f787SSean Bruno }
8461e66f787SSean Bruno 
8471e66f787SSean Bruno /* Get RAID level of requested device */
8481e66f787SSean Bruno static void pqisrc_get_dev_raid_level(pqisrc_softstate_t *softs,
8491e66f787SSean Bruno 	pqi_scsi_dev_t *device)
8501e66f787SSean Bruno {
8511e66f787SSean Bruno 	uint8_t raid_level;
8521e66f787SSean Bruno 	uint8_t *buff;
8531e66f787SSean Bruno 
8541e66f787SSean Bruno 	DBG_FUNC("IN\n");
8551e66f787SSean Bruno 
8561e66f787SSean Bruno 	raid_level = SA_RAID_UNKNOWN;
8571e66f787SSean Bruno 
8581e66f787SSean Bruno 	buff = os_mem_alloc(softs, 64);
8591e66f787SSean Bruno 	if (buff) {
8601e66f787SSean Bruno 		int ret;
8611e66f787SSean Bruno 		ret = pqisrc_send_scsi_inquiry(softs, device->scsi3addr,
8621e66f787SSean Bruno 			VPD_PAGE | SA_VPD_LV_DEVICE_GEOMETRY, buff, 64);
8631e66f787SSean Bruno 		if (ret == 0) {
8641e66f787SSean Bruno 			raid_level = buff[8];
8651e66f787SSean Bruno 			if (raid_level > SA_RAID_MAX)
8661e66f787SSean Bruno 				raid_level = SA_RAID_UNKNOWN;
8671e66f787SSean Bruno 		}
8681e66f787SSean Bruno 		os_mem_free(softs, (char*)buff, 64);
8691e66f787SSean Bruno 	}
8701e66f787SSean Bruno 
8711e66f787SSean Bruno 	device->raid_level = raid_level;
872*b17f4335SSean Bruno 	DBG_DISC("RAID LEVEL: %x \n",  raid_level);
8731e66f787SSean Bruno 	DBG_FUNC("OUT\n");
8741e66f787SSean Bruno }
8751e66f787SSean Bruno 
8761e66f787SSean Bruno /* Parse the inquiry response and determine the type of device */
8771e66f787SSean Bruno static int pqisrc_get_dev_data(pqisrc_softstate_t *softs,
8781e66f787SSean Bruno 	pqi_scsi_dev_t *device)
8791e66f787SSean Bruno {
8801e66f787SSean Bruno 	int ret = PQI_STATUS_SUCCESS;
8811e66f787SSean Bruno 	uint8_t *inq_buff;
8821e66f787SSean Bruno 
8831e66f787SSean Bruno 	DBG_FUNC("IN\n");
8841e66f787SSean Bruno 
8851e66f787SSean Bruno 	inq_buff = os_mem_alloc(softs, OBDR_TAPE_INQ_SIZE);
8861e66f787SSean Bruno 	if (!inq_buff)
8871e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
8881e66f787SSean Bruno 
8891e66f787SSean Bruno 	/* Send an inquiry to the device to see what it is. */
8901e66f787SSean Bruno 	ret = pqisrc_send_scsi_inquiry(softs, device->scsi3addr, 0, inq_buff,
8911e66f787SSean Bruno 		OBDR_TAPE_INQ_SIZE);
8921e66f787SSean Bruno 	if (ret)
8931e66f787SSean Bruno 		goto err_out;
8941e66f787SSean Bruno 	pqisrc_sanitize_inquiry_string(&inq_buff[8], 8);
8951e66f787SSean Bruno 	pqisrc_sanitize_inquiry_string(&inq_buff[16], 16);
8961e66f787SSean Bruno 
8971e66f787SSean Bruno 	device->devtype = inq_buff[0] & 0x1f;
8981e66f787SSean Bruno 	memcpy(device->vendor, &inq_buff[8],
8991e66f787SSean Bruno 		sizeof(device->vendor));
9001e66f787SSean Bruno 	memcpy(device->model, &inq_buff[16],
9011e66f787SSean Bruno 		sizeof(device->model));
902*b17f4335SSean Bruno 	DBG_DISC("DEV_TYPE: %x VENDOR: %s MODEL: %s\n",  device->devtype, device->vendor, device->model);
9031e66f787SSean Bruno 
9041e66f787SSean Bruno 	if (pqisrc_is_logical_device(device) && device->devtype == DISK_DEVICE) {
9051e66f787SSean Bruno 		if (pqisrc_is_external_raid_device(device)) {
9061e66f787SSean Bruno 			device->raid_level = SA_RAID_UNKNOWN;
9071e66f787SSean Bruno 			device->volume_status = SA_LV_OK;
9081e66f787SSean Bruno 			device->volume_offline = false;
9091e66f787SSean Bruno 		}
9101e66f787SSean Bruno 		else {
9111e66f787SSean Bruno 			pqisrc_get_dev_raid_level(softs, device);
9121e66f787SSean Bruno 			pqisrc_get_dev_ioaccel_status(softs, device);
9131e66f787SSean Bruno 			device->volume_status = pqisrc_get_dev_vol_status(softs,
9141e66f787SSean Bruno 						device->scsi3addr);
9151e66f787SSean Bruno 			device->volume_offline = device->volume_status != SA_LV_OK;
9161e66f787SSean Bruno 		}
9171e66f787SSean Bruno 	}
9181e66f787SSean Bruno 
9191e66f787SSean Bruno 	/*
9201e66f787SSean Bruno 	 * Check if this is a One-Button-Disaster-Recovery device
9211e66f787SSean Bruno 	 * by looking for "$DR-10" at offset 43 in the inquiry data.
9221e66f787SSean Bruno 	 */
9231e66f787SSean Bruno 	device->is_obdr_device = (device->devtype == ROM_DEVICE &&
9241e66f787SSean Bruno 		memcmp(&inq_buff[OBDR_SIG_OFFSET], OBDR_TAPE_SIG,
9251e66f787SSean Bruno 			OBDR_SIG_LEN) == 0);
9261e66f787SSean Bruno err_out:
9271e66f787SSean Bruno 	os_mem_free(softs, (char*)inq_buff, OBDR_TAPE_INQ_SIZE);
9281e66f787SSean Bruno 
9291e66f787SSean Bruno 	DBG_FUNC("OUT\n");
9301e66f787SSean Bruno 	return ret;
9311e66f787SSean Bruno }
9321e66f787SSean Bruno 
9331e66f787SSean Bruno /*
9341e66f787SSean Bruno  * BMIC (Basic Management And Interface Commands) command
9351e66f787SSean Bruno  * to get the controller identify params
9361e66f787SSean Bruno  */
9371e66f787SSean Bruno static int pqisrc_identify_ctrl(pqisrc_softstate_t *softs,
9381e66f787SSean Bruno 	bmic_ident_ctrl_t *buff)
9391e66f787SSean Bruno {
9401e66f787SSean Bruno 	int ret = PQI_STATUS_SUCCESS;
9411e66f787SSean Bruno 	pqisrc_raid_req_t request;
9421e66f787SSean Bruno 
9431e66f787SSean Bruno 	DBG_FUNC("IN\n");
9441e66f787SSean Bruno 
9451e66f787SSean Bruno 	memset(&request, 0, sizeof(request));
9461e66f787SSean Bruno 	ret =  pqisrc_build_send_raid_request(softs, &request, buff, sizeof(*buff),
9471e66f787SSean Bruno 				BMIC_IDENTIFY_CONTROLLER, 0, (uint8_t *)RAID_CTLR_LUNID, NULL);
9481e66f787SSean Bruno 	DBG_FUNC("OUT\n");
9491e66f787SSean Bruno 
9501e66f787SSean Bruno 	return ret;
9511e66f787SSean Bruno }
9521e66f787SSean Bruno 
9531e66f787SSean Bruno /* Get the adapter FW version using BMIC_IDENTIFY_CONTROLLER */
9541e66f787SSean Bruno int pqisrc_get_ctrl_fw_version(pqisrc_softstate_t *softs)
9551e66f787SSean Bruno {
9561e66f787SSean Bruno 	int ret = PQI_STATUS_SUCCESS;
9571e66f787SSean Bruno 	bmic_ident_ctrl_t *identify_ctrl;
9581e66f787SSean Bruno 
9591e66f787SSean Bruno 	DBG_FUNC("IN\n");
9601e66f787SSean Bruno 
9611e66f787SSean Bruno 	identify_ctrl = os_mem_alloc(softs, sizeof(*identify_ctrl));
9621e66f787SSean Bruno 	if (!identify_ctrl) {
9631e66f787SSean Bruno 		DBG_ERR("failed to allocate memory for identify_ctrl\n");
9641e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
9651e66f787SSean Bruno 	}
9661e66f787SSean Bruno 
9671e66f787SSean Bruno 	memset(identify_ctrl, 0, sizeof(*identify_ctrl));
9681e66f787SSean Bruno 
9691e66f787SSean Bruno 	ret = pqisrc_identify_ctrl(softs, identify_ctrl);
9701e66f787SSean Bruno 	if (ret)
9711e66f787SSean Bruno 		goto out;
9721e66f787SSean Bruno 
9731e66f787SSean Bruno 	softs->fw_build_number = identify_ctrl->fw_build_number;
9741e66f787SSean Bruno 	memcpy(softs->fw_version, identify_ctrl->fw_version,
9751e66f787SSean Bruno 		sizeof(identify_ctrl->fw_version));
9761e66f787SSean Bruno 	softs->fw_version[sizeof(identify_ctrl->fw_version)] = '\0';
9771e66f787SSean Bruno 	snprintf(softs->fw_version +
9781e66f787SSean Bruno 		strlen(softs->fw_version),
9791e66f787SSean Bruno 		sizeof(softs->fw_version),
9801e66f787SSean Bruno 		"-%u", identify_ctrl->fw_build_number);
9811e66f787SSean Bruno out:
9821e66f787SSean Bruno 	os_mem_free(softs, (char *)identify_ctrl, sizeof(*identify_ctrl));
983*b17f4335SSean Bruno 	DBG_INIT("Firmware version: %s Firmware build number: %d\n", softs->fw_version, softs->fw_build_number);
9841e66f787SSean Bruno 	DBG_FUNC("OUT\n");
9851e66f787SSean Bruno 	return ret;
9861e66f787SSean Bruno }
9871e66f787SSean Bruno 
9881e66f787SSean Bruno /* BMIC command to determine scsi device identify params */
9891e66f787SSean Bruno static int pqisrc_identify_physical_disk(pqisrc_softstate_t *softs,
9901e66f787SSean Bruno 	pqi_scsi_dev_t *device,
9911e66f787SSean Bruno 	bmic_ident_physdev_t *buff,
9921e66f787SSean Bruno 	int buf_len)
9931e66f787SSean Bruno {
9941e66f787SSean Bruno 	int ret = PQI_STATUS_SUCCESS;
9951e66f787SSean Bruno 	uint16_t bmic_device_index;
9961e66f787SSean Bruno 	pqisrc_raid_req_t request;
9971e66f787SSean Bruno 
9981e66f787SSean Bruno 
9991e66f787SSean Bruno 	DBG_FUNC("IN\n");
10001e66f787SSean Bruno 
10011e66f787SSean Bruno 	memset(&request, 0, sizeof(request));
10021e66f787SSean Bruno 	bmic_device_index = BMIC_GET_DRIVE_NUMBER(device->scsi3addr);
10031e66f787SSean Bruno 	request.cdb[2] = (uint8_t)bmic_device_index;
10041e66f787SSean Bruno 	request.cdb[9] = (uint8_t)(bmic_device_index >> 8);
10051e66f787SSean Bruno 
10061e66f787SSean Bruno 	ret =  pqisrc_build_send_raid_request(softs, &request, buff, buf_len,
10071e66f787SSean Bruno 				BMIC_IDENTIFY_PHYSICAL_DEVICE, 0, (uint8_t *)RAID_CTLR_LUNID, NULL);
10081e66f787SSean Bruno 	DBG_FUNC("OUT\n");
10091e66f787SSean Bruno 	return ret;
10101e66f787SSean Bruno }
10111e66f787SSean Bruno 
10121e66f787SSean Bruno /*
10131e66f787SSean Bruno  * Function used to get the scsi device information using one of BMIC
10141e66f787SSean Bruno  * BMIC_IDENTIFY_PHYSICAL_DEVICE
10151e66f787SSean Bruno  */
10161e66f787SSean Bruno static void pqisrc_get_physical_device_info(pqisrc_softstate_t *softs,
10171e66f787SSean Bruno 	pqi_scsi_dev_t *device,
10181e66f787SSean Bruno 	bmic_ident_physdev_t *id_phys)
10191e66f787SSean Bruno {
10201e66f787SSean Bruno 	int ret = PQI_STATUS_SUCCESS;
10211e66f787SSean Bruno 
10221e66f787SSean Bruno 	DBG_FUNC("IN\n");
10231e66f787SSean Bruno 	memset(id_phys, 0, sizeof(*id_phys));
10241e66f787SSean Bruno 
10251e66f787SSean Bruno 	ret= pqisrc_identify_physical_disk(softs, device,
10261e66f787SSean Bruno 		id_phys, sizeof(*id_phys));
10271e66f787SSean Bruno 	if (ret) {
10281e66f787SSean Bruno 		device->queue_depth = PQI_PHYSICAL_DISK_DEFAULT_MAX_QUEUE_DEPTH;
10291e66f787SSean Bruno 		return;
10301e66f787SSean Bruno 	}
10311e66f787SSean Bruno 
10321e66f787SSean Bruno 	device->queue_depth =
10331e66f787SSean Bruno 		LE_16(id_phys->current_queue_depth_limit);
10341e66f787SSean Bruno 	device->device_type = id_phys->device_type;
10351e66f787SSean Bruno 	device->active_path_index = id_phys->active_path_number;
10361e66f787SSean Bruno 	device->path_map = id_phys->redundant_path_present_map;
10371e66f787SSean Bruno 	memcpy(&device->box,
10381e66f787SSean Bruno 		&id_phys->alternate_paths_phys_box_on_port,
10391e66f787SSean Bruno 		sizeof(device->box));
10401e66f787SSean Bruno 	memcpy(&device->phys_connector,
10411e66f787SSean Bruno 		&id_phys->alternate_paths_phys_connector,
10421e66f787SSean Bruno 		sizeof(device->phys_connector));
10431e66f787SSean Bruno 	device->bay = id_phys->phys_bay_in_box;
10441e66f787SSean Bruno 
1045*b17f4335SSean Bruno 	DBG_DISC("BMIC DEV_TYPE: %x QUEUE DEPTH: 0x%x \n",  device->device_type, device->queue_depth);
10461e66f787SSean Bruno 	DBG_FUNC("OUT\n");
10471e66f787SSean Bruno }
10481e66f787SSean Bruno 
10491e66f787SSean Bruno 
10501e66f787SSean Bruno /* Function used to find the entry of the device in a list */
10511e66f787SSean Bruno static device_status_t pqisrc_scsi_find_entry(pqisrc_softstate_t *softs,
10521e66f787SSean Bruno 	pqi_scsi_dev_t *device_to_find,
10531e66f787SSean Bruno 	pqi_scsi_dev_t **same_device)
10541e66f787SSean Bruno {
10551e66f787SSean Bruno 	pqi_scsi_dev_t *device;
10561e66f787SSean Bruno 	int i,j;
10571e66f787SSean Bruno 	DBG_FUNC("IN\n");
10581e66f787SSean Bruno 	for(i = 0; i < PQI_MAX_DEVICES; i++) {
10591e66f787SSean Bruno 		for(j = 0; j < PQI_MAX_MULTILUN; j++) {
10601e66f787SSean Bruno 			if(softs->device_list[i][j] == NULL)
10611e66f787SSean Bruno 				continue;
10621e66f787SSean Bruno 			device = softs->device_list[i][j];
10631e66f787SSean Bruno 			if (pqisrc_scsi3addr_equal(device_to_find->scsi3addr,
10641e66f787SSean Bruno 				device->scsi3addr)) {
10651e66f787SSean Bruno 				*same_device = device;
10661e66f787SSean Bruno 				if (pqisrc_device_equal(device_to_find, device)) {
10671e66f787SSean Bruno 					if (device_to_find->volume_offline)
10681e66f787SSean Bruno 						return DEVICE_CHANGED;
10691e66f787SSean Bruno 					return DEVICE_UNCHANGED;
10701e66f787SSean Bruno 				}
10711e66f787SSean Bruno 				return DEVICE_CHANGED;
10721e66f787SSean Bruno 			}
10731e66f787SSean Bruno 		}
10741e66f787SSean Bruno 	}
10751e66f787SSean Bruno 	DBG_FUNC("OUT\n");
10761e66f787SSean Bruno 
10771e66f787SSean Bruno 	return DEVICE_NOT_FOUND;
10781e66f787SSean Bruno }
10791e66f787SSean Bruno 
10801e66f787SSean Bruno 
10811e66f787SSean Bruno /* Update the newly added devices as existed device */
10821e66f787SSean Bruno static void pqisrc_exist_device_update(pqisrc_softstate_t *softs,
10831e66f787SSean Bruno 	pqi_scsi_dev_t *device_exist,
10841e66f787SSean Bruno 	pqi_scsi_dev_t *new_device)
10851e66f787SSean Bruno {
10861e66f787SSean Bruno 	DBG_FUNC("IN\n");
10871e66f787SSean Bruno 	device_exist->expose_device = new_device->expose_device;
10881e66f787SSean Bruno 	memcpy(device_exist->vendor, new_device->vendor,
10891e66f787SSean Bruno 		sizeof(device_exist->vendor));
10901e66f787SSean Bruno 	memcpy(device_exist->model, new_device->model,
10911e66f787SSean Bruno 		sizeof(device_exist->model));
10921e66f787SSean Bruno 	device_exist->is_physical_device = new_device->is_physical_device;
10931e66f787SSean Bruno 	device_exist->is_external_raid_device =
10941e66f787SSean Bruno 		new_device->is_external_raid_device;
10951e66f787SSean Bruno 	device_exist->sas_address = new_device->sas_address;
10961e66f787SSean Bruno 	device_exist->raid_level = new_device->raid_level;
10971e66f787SSean Bruno 	device_exist->queue_depth = new_device->queue_depth;
10981e66f787SSean Bruno 	device_exist->ioaccel_handle = new_device->ioaccel_handle;
10991e66f787SSean Bruno 	device_exist->volume_status = new_device->volume_status;
11001e66f787SSean Bruno 	device_exist->active_path_index = new_device->active_path_index;
11011e66f787SSean Bruno 	device_exist->path_map = new_device->path_map;
11021e66f787SSean Bruno 	device_exist->bay = new_device->bay;
11031e66f787SSean Bruno 	memcpy(device_exist->box, new_device->box,
11041e66f787SSean Bruno 		sizeof(device_exist->box));
11051e66f787SSean Bruno 	memcpy(device_exist->phys_connector, new_device->phys_connector,
11061e66f787SSean Bruno 		sizeof(device_exist->phys_connector));
11071e66f787SSean Bruno 	device_exist->offload_config = new_device->offload_config;
11081e66f787SSean Bruno 	device_exist->offload_enabled = false;
11091e66f787SSean Bruno 	device_exist->offload_enabled_pending =
11101e66f787SSean Bruno 		new_device->offload_enabled_pending;
11111e66f787SSean Bruno 	device_exist->offload_to_mirror = 0;
11121e66f787SSean Bruno 	if (device_exist->raid_map)
11131e66f787SSean Bruno 		os_mem_free(softs,
11141e66f787SSean Bruno 			    (char *)device_exist->raid_map,
11151e66f787SSean Bruno 			    sizeof(*device_exist->raid_map));
11161e66f787SSean Bruno 	device_exist->raid_map = new_device->raid_map;
11171e66f787SSean Bruno 	/* To prevent this from being freed later. */
11181e66f787SSean Bruno 	new_device->raid_map = NULL;
11191e66f787SSean Bruno 	DBG_FUNC("OUT\n");
11201e66f787SSean Bruno }
11211e66f787SSean Bruno 
11221e66f787SSean Bruno /* Validate the ioaccel_handle for a newly added device */
11231e66f787SSean Bruno static pqi_scsi_dev_t *pqisrc_identify_device_via_ioaccel(
11241e66f787SSean Bruno 	pqisrc_softstate_t *softs, uint32_t ioaccel_handle)
11251e66f787SSean Bruno {
11261e66f787SSean Bruno 	pqi_scsi_dev_t *device;
11271e66f787SSean Bruno 	int i,j;
11281e66f787SSean Bruno 	DBG_FUNC("IN\n");
11291e66f787SSean Bruno 	for(i = 0; i < PQI_MAX_DEVICES; i++) {
11301e66f787SSean Bruno 		for(j = 0; j < PQI_MAX_MULTILUN; j++) {
11311e66f787SSean Bruno 			if(softs->device_list[i][j] == NULL)
11321e66f787SSean Bruno 				continue;
11331e66f787SSean Bruno 			device = softs->device_list[i][j];
11341e66f787SSean Bruno 			if (device->devtype != DISK_DEVICE)
11351e66f787SSean Bruno 				continue;
11361e66f787SSean Bruno 			if (pqisrc_is_logical_device(device))
11371e66f787SSean Bruno 				continue;
11381e66f787SSean Bruno 			if (device->ioaccel_handle == ioaccel_handle)
11391e66f787SSean Bruno 				return device;
11401e66f787SSean Bruno 		}
11411e66f787SSean Bruno 	}
11421e66f787SSean Bruno 	DBG_FUNC("OUT\n");
11431e66f787SSean Bruno 
11441e66f787SSean Bruno 	return NULL;
11451e66f787SSean Bruno }
11461e66f787SSean Bruno 
11471e66f787SSean Bruno /* Get the scsi device queue depth */
11481e66f787SSean Bruno static void pqisrc_update_log_dev_qdepth(pqisrc_softstate_t *softs)
11491e66f787SSean Bruno {
11501e66f787SSean Bruno 	unsigned i;
11511e66f787SSean Bruno 	unsigned phys_dev_num;
11521e66f787SSean Bruno 	unsigned num_raidmap_entries;
11531e66f787SSean Bruno 	unsigned queue_depth;
11541e66f787SSean Bruno 	pqisrc_raid_map_t *raid_map;
11551e66f787SSean Bruno 	pqi_scsi_dev_t *device;
11561e66f787SSean Bruno 	raidmap_data_t *dev_data;
11571e66f787SSean Bruno 	pqi_scsi_dev_t *phys_disk;
11581e66f787SSean Bruno 	unsigned j;
1159*b17f4335SSean Bruno 	unsigned k;
11601e66f787SSean Bruno 
11611e66f787SSean Bruno 	DBG_FUNC("IN\n");
11621e66f787SSean Bruno 
11631e66f787SSean Bruno 	for(i = 0; i < PQI_MAX_DEVICES; i++) {
11641e66f787SSean Bruno 		for(j = 0; j < PQI_MAX_MULTILUN; j++) {
11651e66f787SSean Bruno 			if(softs->device_list[i][j] == NULL)
11661e66f787SSean Bruno 				continue;
11671e66f787SSean Bruno 			device = softs->device_list[i][j];
11681e66f787SSean Bruno 			if (device->devtype != DISK_DEVICE)
11691e66f787SSean Bruno 				continue;
11701e66f787SSean Bruno 			if (!pqisrc_is_logical_device(device))
11711e66f787SSean Bruno 				continue;
11721e66f787SSean Bruno 			if (pqisrc_is_external_raid_device(device))
11731e66f787SSean Bruno 				continue;
11741e66f787SSean Bruno 			device->queue_depth = PQI_LOGICAL_DISK_DEFAULT_MAX_QUEUE_DEPTH;
11751e66f787SSean Bruno 			raid_map = device->raid_map;
11761e66f787SSean Bruno 			if (!raid_map)
11771e66f787SSean Bruno 				return;
11781e66f787SSean Bruno 			dev_data = raid_map->dev_data;
11791e66f787SSean Bruno 			phys_dev_num = LE_16(raid_map->layout_map_count) *
11801e66f787SSean Bruno 					(LE_16(raid_map->data_disks_per_row) +
11811e66f787SSean Bruno 					LE_16(raid_map->metadata_disks_per_row));
11821e66f787SSean Bruno 			num_raidmap_entries = phys_dev_num *
11831e66f787SSean Bruno 						LE_16(raid_map->row_cnt);
11841e66f787SSean Bruno 
11851e66f787SSean Bruno 			queue_depth = 0;
1186*b17f4335SSean Bruno 			for (k = 0; k < num_raidmap_entries; k++) {
11871e66f787SSean Bruno 				phys_disk = pqisrc_identify_device_via_ioaccel(softs,
1188*b17f4335SSean Bruno 						dev_data[k].ioaccel_handle);
11891e66f787SSean Bruno 
11901e66f787SSean Bruno 				if (!phys_disk) {
11911e66f787SSean Bruno 					DBG_WARN(
11921e66f787SSean Bruno 					"Failed to find physical disk handle for logical drive %016llx\n",
11931e66f787SSean Bruno 						(unsigned long long)BE_64(device->scsi3addr[0]));
11941e66f787SSean Bruno 					device->offload_enabled = false;
11951e66f787SSean Bruno 					device->offload_enabled_pending = false;
11961e66f787SSean Bruno 					if (raid_map)
11971e66f787SSean Bruno 						os_mem_free(softs, (char *)raid_map, sizeof(*raid_map));
11981e66f787SSean Bruno 					device->raid_map = NULL;
11991e66f787SSean Bruno 					return;
12001e66f787SSean Bruno 				}
12011e66f787SSean Bruno 
12021e66f787SSean Bruno 				queue_depth += phys_disk->queue_depth;
12031e66f787SSean Bruno 			}
12041e66f787SSean Bruno 
12051e66f787SSean Bruno 			device->queue_depth = queue_depth;
12061e66f787SSean Bruno 		} /* end inner loop */
12071e66f787SSean Bruno 	}/* end outer loop */
12081e66f787SSean Bruno 	DBG_FUNC("OUT\n");
12091e66f787SSean Bruno }
12101e66f787SSean Bruno 
12111e66f787SSean Bruno /* Function used to add a scsi device to OS scsi subsystem */
12121e66f787SSean Bruno static int pqisrc_add_device(pqisrc_softstate_t *softs,
12131e66f787SSean Bruno 	pqi_scsi_dev_t *device)
12141e66f787SSean Bruno {
12151e66f787SSean Bruno 	DBG_FUNC("IN\n");
1216*b17f4335SSean Bruno 	DBG_WARN("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",
12171e66f787SSean Bruno 		device->vendor, device->model, device->bus, device->target, device->lun, device->is_physical_device, device->expose_device, device->volume_offline, device->volume_status);
12181e66f787SSean Bruno 
12191e66f787SSean Bruno 	device->invalid = false;
12201e66f787SSean Bruno 
12211e66f787SSean Bruno 	if(device->expose_device) {
12221e66f787SSean Bruno 		/* TBD: Call OS upper layer function to add the device entry */
12231e66f787SSean Bruno 		os_add_device(softs,device);
12241e66f787SSean Bruno 	}
12251e66f787SSean Bruno 	DBG_FUNC("OUT\n");
12261e66f787SSean Bruno 	return PQI_STATUS_SUCCESS;
12271e66f787SSean Bruno 
12281e66f787SSean Bruno }
12291e66f787SSean Bruno 
12301e66f787SSean Bruno /* Function used to remove a scsi device from OS scsi subsystem */
12311e66f787SSean Bruno void pqisrc_remove_device(pqisrc_softstate_t *softs,
12321e66f787SSean Bruno 	pqi_scsi_dev_t *device)
12331e66f787SSean Bruno {
12341e66f787SSean Bruno 	DBG_FUNC("IN\n");
1235*b17f4335SSean Bruno 	DBG_DISC("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",
12361e66f787SSean Bruno 		device->vendor, device->model, device->bus, device->target, device->lun, device->is_physical_device, device->expose_device, device->volume_offline, device->volume_status);
12371e66f787SSean Bruno 
12381e66f787SSean Bruno 	/* TBD: Call OS upper layer function to remove the device entry */
12391e66f787SSean Bruno 	device->invalid = true;
12401e66f787SSean Bruno 	os_remove_device(softs,device);
12411e66f787SSean Bruno 	DBG_FUNC("OUT\n");
12421e66f787SSean Bruno }
12431e66f787SSean Bruno 
12441e66f787SSean Bruno 
12451e66f787SSean Bruno /*
12461e66f787SSean Bruno  * When exposing new device to OS fails then adjst list according to the
12471e66f787SSean Bruno  * mid scsi list
12481e66f787SSean Bruno  */
12491e66f787SSean Bruno static void pqisrc_adjust_list(pqisrc_softstate_t *softs,
12501e66f787SSean Bruno 	pqi_scsi_dev_t *device)
12511e66f787SSean Bruno {
12521e66f787SSean Bruno 	DBG_FUNC("IN\n");
12531e66f787SSean Bruno 
12541e66f787SSean Bruno 	if (!device) {
12551e66f787SSean Bruno 		DBG_ERR("softs = %p: device is NULL !!!\n", softs);
12561e66f787SSean Bruno 		return;
12571e66f787SSean Bruno 	}
12581e66f787SSean Bruno 
12591e66f787SSean Bruno 	OS_ACQUIRE_SPINLOCK(&softs->devlist_lock);
12601e66f787SSean Bruno 	softs->device_list[device->target][device->lun] = NULL;
12611e66f787SSean Bruno 	OS_RELEASE_SPINLOCK(&softs->devlist_lock);
12621e66f787SSean Bruno 	pqisrc_device_mem_free(softs, device);
12631e66f787SSean Bruno 
12641e66f787SSean Bruno 	DBG_FUNC("OUT\n");
12651e66f787SSean Bruno }
12661e66f787SSean Bruno 
12671e66f787SSean Bruno /* Debug routine used to display the RAID volume status of the device */
12681e66f787SSean Bruno static void pqisrc_display_volume_status(pqisrc_softstate_t *softs,
12691e66f787SSean Bruno 	pqi_scsi_dev_t *device)
12701e66f787SSean Bruno {
12711e66f787SSean Bruno 	char *status;
12721e66f787SSean Bruno 
12731e66f787SSean Bruno 	DBG_FUNC("IN\n");
12741e66f787SSean Bruno 	switch (device->volume_status) {
12751e66f787SSean Bruno 	case SA_LV_OK:
12761e66f787SSean Bruno 		status = "Volume is online.";
12771e66f787SSean Bruno 		break;
12781e66f787SSean Bruno 	case SA_LV_UNDERGOING_ERASE:
12791e66f787SSean Bruno 		status = "Volume is undergoing background erase process.";
12801e66f787SSean Bruno 		break;
12811e66f787SSean Bruno 	case SA_LV_NOT_AVAILABLE:
12821e66f787SSean Bruno 		status = "Volume is waiting for transforming volume.";
12831e66f787SSean Bruno 		break;
12841e66f787SSean Bruno 	case SA_LV_UNDERGOING_RPI:
12851e66f787SSean Bruno 		status = "Volume is undergoing rapid parity initialization process.";
12861e66f787SSean Bruno 		break;
12871e66f787SSean Bruno 	case SA_LV_PENDING_RPI:
12881e66f787SSean Bruno 		status = "Volume is queued for rapid parity initialization process.";
12891e66f787SSean Bruno 		break;
12901e66f787SSean Bruno 	case SA_LV_ENCRYPTED_NO_KEY:
12911e66f787SSean Bruno 		status = "Volume is encrypted and cannot be accessed because key is not present.";
12921e66f787SSean Bruno 		break;
12931e66f787SSean Bruno 	case SA_LV_PLAINTEXT_IN_ENCRYPT_ONLY_CONTROLLER:
12941e66f787SSean Bruno 		status = "Volume is not encrypted and cannot be accessed because controller is in encryption-only mode.";
12951e66f787SSean Bruno 		break;
12961e66f787SSean Bruno 	case SA_LV_UNDERGOING_ENCRYPTION:
12971e66f787SSean Bruno 		status = "Volume is undergoing encryption process.";
12981e66f787SSean Bruno 		break;
12991e66f787SSean Bruno 	case SA_LV_UNDERGOING_ENCRYPTION_REKEYING:
13001e66f787SSean Bruno 		status = "Volume is undergoing encryption re-keying process.";
13011e66f787SSean Bruno 		break;
13021e66f787SSean Bruno 	case SA_LV_ENCRYPTED_IN_NON_ENCRYPTED_CONTROLLER:
13031e66f787SSean Bruno 		status = "Volume is encrypted and cannot be accessed because controller does not have encryption enabled.";
13041e66f787SSean Bruno 		break;
13051e66f787SSean Bruno 	case SA_LV_PENDING_ENCRYPTION:
13061e66f787SSean Bruno 		status = "Volume is pending migration to encrypted state, but process has not started.";
13071e66f787SSean Bruno 		break;
13081e66f787SSean Bruno 	case SA_LV_PENDING_ENCRYPTION_REKEYING:
13091e66f787SSean Bruno 		status = "Volume is encrypted and is pending encryption rekeying.";
13101e66f787SSean Bruno 		break;
13111e66f787SSean Bruno 	case SA_LV_STATUS_VPD_UNSUPPORTED:
13121e66f787SSean Bruno 		status = "Volume status is not available through vital product data pages.";
13131e66f787SSean Bruno 		break;
13141e66f787SSean Bruno 	default:
13151e66f787SSean Bruno 		status = "Volume is in an unknown state.";
13161e66f787SSean Bruno 		break;
13171e66f787SSean Bruno 	}
13181e66f787SSean Bruno 
1319*b17f4335SSean Bruno 	DBG_DISC("scsi BTL %d:%d:%d %s\n",
13201e66f787SSean Bruno 		device->bus, device->target, device->lun, status);
13211e66f787SSean Bruno 	DBG_FUNC("OUT\n");
13221e66f787SSean Bruno }
13231e66f787SSean Bruno 
13241e66f787SSean Bruno void pqisrc_device_mem_free(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device)
13251e66f787SSean Bruno {
1326*b17f4335SSean Bruno 	DBG_FUNC("IN\n");
13271e66f787SSean Bruno 	if (!device)
13281e66f787SSean Bruno 		return;
13291e66f787SSean Bruno 	if (device->raid_map) {
13301e66f787SSean Bruno 			os_mem_free(softs, (char *)device->raid_map, sizeof(pqisrc_raid_map_t));
13311e66f787SSean Bruno 	}
13321e66f787SSean Bruno 	os_mem_free(softs, (char *)device,sizeof(*device));
1333*b17f4335SSean Bruno 	DBG_FUNC("OUT\n");
13341e66f787SSean Bruno 
13351e66f787SSean Bruno }
13361e66f787SSean Bruno 
13371e66f787SSean Bruno /* OS should call this function to free the scsi device */
13381e66f787SSean Bruno void pqisrc_free_device(pqisrc_softstate_t * softs,pqi_scsi_dev_t *device)
13391e66f787SSean Bruno {
13401e66f787SSean Bruno 
13411e66f787SSean Bruno 		OS_ACQUIRE_SPINLOCK(&softs->devlist_lock);
1342*b17f4335SSean Bruno 		if (!pqisrc_is_logical_device(device)) {
1343*b17f4335SSean Bruno 			pqisrc_free_tid(softs,device->target);
1344*b17f4335SSean Bruno 		}
13451e66f787SSean Bruno 		pqisrc_device_mem_free(softs, device);
13461e66f787SSean Bruno 		OS_RELEASE_SPINLOCK(&softs->devlist_lock);
13471e66f787SSean Bruno 
13481e66f787SSean Bruno }
13491e66f787SSean Bruno 
13501e66f787SSean Bruno 
13511e66f787SSean Bruno /* Update the newly added devices to the device list */
13521e66f787SSean Bruno static void pqisrc_update_device_list(pqisrc_softstate_t *softs,
13531e66f787SSean Bruno 	pqi_scsi_dev_t *new_device_list[], int num_new_devices)
13541e66f787SSean Bruno {
13551e66f787SSean Bruno 	int ret;
13561e66f787SSean Bruno 	int i;
13571e66f787SSean Bruno 	device_status_t dev_status;
13581e66f787SSean Bruno 	pqi_scsi_dev_t *device;
13591e66f787SSean Bruno 	pqi_scsi_dev_t *same_device;
13601e66f787SSean Bruno 	pqi_scsi_dev_t **added = NULL;
13611e66f787SSean Bruno 	pqi_scsi_dev_t **removed = NULL;
13621e66f787SSean Bruno 	int nadded = 0, nremoved = 0;
13631e66f787SSean Bruno 	int j;
1364*b17f4335SSean Bruno 	int tid = 0;
1365*b17f4335SSean Bruno 
1366*b17f4335SSean Bruno 	DBG_FUNC("IN\n");
13671e66f787SSean Bruno 
13681e66f787SSean Bruno 	added = os_mem_alloc(softs, sizeof(*added) * PQI_MAX_DEVICES);
13691e66f787SSean Bruno 	removed = os_mem_alloc(softs, sizeof(*removed) * PQI_MAX_DEVICES);
13701e66f787SSean Bruno 
13711e66f787SSean Bruno 	if (!added || !removed) {
13721e66f787SSean Bruno 		DBG_WARN("Out of memory \n");
13731e66f787SSean Bruno 		goto free_and_out;
13741e66f787SSean Bruno 	}
13751e66f787SSean Bruno 
13761e66f787SSean Bruno 	OS_ACQUIRE_SPINLOCK(&softs->devlist_lock);
13771e66f787SSean Bruno 
13781e66f787SSean Bruno 	for(i = 0; i < PQI_MAX_DEVICES; i++) {
13791e66f787SSean Bruno 		for(j = 0; j < PQI_MAX_MULTILUN; j++) {
13801e66f787SSean Bruno 			if(softs->device_list[i][j] == NULL)
13811e66f787SSean Bruno 				continue;
13821e66f787SSean Bruno 			device = softs->device_list[i][j];
13831e66f787SSean Bruno 			device->device_gone = true;
13841e66f787SSean Bruno 		}
13851e66f787SSean Bruno 	}
13861e66f787SSean Bruno 	DBG_IO("Device list used an array\n");
13871e66f787SSean Bruno 	for (i = 0; i < num_new_devices; i++) {
13881e66f787SSean Bruno 		device = new_device_list[i];
13891e66f787SSean Bruno 
13901e66f787SSean Bruno 		dev_status = pqisrc_scsi_find_entry(softs, device,
13911e66f787SSean Bruno 			&same_device);
13921e66f787SSean Bruno 
13931e66f787SSean Bruno 		switch (dev_status) {
13941e66f787SSean Bruno 		case DEVICE_UNCHANGED:
13951e66f787SSean Bruno 			/* New Device present in existing device list  */
13961e66f787SSean Bruno 			device->new_device = false;
13971e66f787SSean Bruno 			same_device->device_gone = false;
13981e66f787SSean Bruno 			pqisrc_exist_device_update(softs, same_device, device);
13991e66f787SSean Bruno 			break;
14001e66f787SSean Bruno 		case DEVICE_NOT_FOUND:
14011e66f787SSean Bruno 			/* Device not found in existing list */
14021e66f787SSean Bruno 			device->new_device = true;
14031e66f787SSean Bruno 			break;
14041e66f787SSean Bruno 		case DEVICE_CHANGED:
14051e66f787SSean Bruno 			/* Actual device gone need to add device to list*/
14061e66f787SSean Bruno 			device->new_device = true;
14071e66f787SSean Bruno 			break;
14081e66f787SSean Bruno 		default:
14091e66f787SSean Bruno 			break;
14101e66f787SSean Bruno 		}
14111e66f787SSean Bruno 	}
14121e66f787SSean Bruno 	/* Process all devices that have gone away. */
14131e66f787SSean Bruno 	for(i = 0, nremoved = 0; i < PQI_MAX_DEVICES; i++) {
14141e66f787SSean Bruno 		for(j = 0; j < PQI_MAX_MULTILUN; j++) {
14151e66f787SSean Bruno 			if(softs->device_list[i][j] == NULL)
14161e66f787SSean Bruno 				continue;
14171e66f787SSean Bruno 			device = softs->device_list[i][j];
14181e66f787SSean Bruno 			if (device->device_gone) {
14191e66f787SSean Bruno 				softs->device_list[device->target][device->lun] = NULL;
14201e66f787SSean Bruno 				removed[nremoved] = device;
14211e66f787SSean Bruno 				nremoved++;
14221e66f787SSean Bruno 			}
14231e66f787SSean Bruno 		}
14241e66f787SSean Bruno 	}
14251e66f787SSean Bruno 
14261e66f787SSean Bruno 	/* Process all new devices. */
14271e66f787SSean Bruno 	for (i = 0, nadded = 0; i < num_new_devices; i++) {
14281e66f787SSean Bruno 		device = new_device_list[i];
14291e66f787SSean Bruno 		if (!device->new_device)
14301e66f787SSean Bruno 			continue;
14311e66f787SSean Bruno 		if (device->volume_offline)
14321e66f787SSean Bruno 			continue;
14331e66f787SSean Bruno 
1434*b17f4335SSean Bruno 		/* physical device */
1435*b17f4335SSean Bruno 		if (!pqisrc_is_logical_device(device)) {
1436*b17f4335SSean Bruno 			tid = pqisrc_alloc_tid(softs);
1437*b17f4335SSean Bruno 			if(INVALID_ELEM != tid)
1438*b17f4335SSean Bruno 				pqisrc_set_btl(device, PQI_PHYSICAL_DEVICE_BUS, tid, 0);
1439*b17f4335SSean Bruno 		}
1440*b17f4335SSean Bruno 
14411e66f787SSean Bruno  		softs->device_list[device->target][device->lun] = device;
1442*b17f4335SSean Bruno 		DBG_DISC("Added device %p at B : %d T : %d L : %d\n",device,
14431e66f787SSean Bruno 			device->bus,device->target,device->lun);
14441e66f787SSean Bruno 		/* To prevent this entry from being freed later. */
14451e66f787SSean Bruno 		new_device_list[i] = NULL;
14461e66f787SSean Bruno 		added[nadded] = device;
14471e66f787SSean Bruno 		nadded++;
14481e66f787SSean Bruno 	}
14491e66f787SSean Bruno 
14501e66f787SSean Bruno 	pqisrc_update_log_dev_qdepth(softs);
14511e66f787SSean Bruno 
14521e66f787SSean Bruno 	for(i = 0; i < PQI_MAX_DEVICES; i++) {
14531e66f787SSean Bruno 		for(j = 0; j < PQI_MAX_MULTILUN; j++) {
14541e66f787SSean Bruno 			if(softs->device_list[i][j] == NULL)
14551e66f787SSean Bruno 				continue;
14561e66f787SSean Bruno 			device = softs->device_list[i][j];
14571e66f787SSean Bruno 			device->offload_enabled = device->offload_enabled_pending;
14581e66f787SSean Bruno 		}
14591e66f787SSean Bruno 	}
14601e66f787SSean Bruno 
14611e66f787SSean Bruno 	OS_RELEASE_SPINLOCK(&softs->devlist_lock);
14621e66f787SSean Bruno 
14631e66f787SSean Bruno 	for(i = 0; i < nremoved; i++) {
14641e66f787SSean Bruno 		device = removed[i];
14651e66f787SSean Bruno 		if (device == NULL)
14661e66f787SSean Bruno 			continue;
14671e66f787SSean Bruno 		pqisrc_remove_device(softs, device);
14681e66f787SSean Bruno 		pqisrc_display_device_info(softs, "removed", device);
14691e66f787SSean Bruno 
14701e66f787SSean Bruno 	}
14711e66f787SSean Bruno 
14721e66f787SSean Bruno 	for(i = 0; i < PQI_MAX_DEVICES; i++) {
14731e66f787SSean Bruno 		for(j = 0; j < PQI_MAX_MULTILUN; j++) {
14741e66f787SSean Bruno 			if(softs->device_list[i][j] == NULL)
14751e66f787SSean Bruno 				continue;
14761e66f787SSean Bruno 			device = softs->device_list[i][j];
14771e66f787SSean Bruno 			/*
14781e66f787SSean Bruno 			* Notify the OS upper layer if the queue depth of any existing device has
14791e66f787SSean Bruno 			* changed.
14801e66f787SSean Bruno 			*/
14811e66f787SSean Bruno 			if (device->queue_depth !=
14821e66f787SSean Bruno 				device->advertised_queue_depth) {
14831e66f787SSean Bruno 				device->advertised_queue_depth = device->queue_depth;
14841e66f787SSean Bruno 				/* TBD: Call OS upper layer function to change device Q depth */
14851e66f787SSean Bruno 			}
14861e66f787SSean Bruno 		}
14871e66f787SSean Bruno 	}
14881e66f787SSean Bruno 	for(i = 0; i < nadded; i++) {
14891e66f787SSean Bruno 		device = added[i];
14901e66f787SSean Bruno 		if (device->expose_device) {
14911e66f787SSean Bruno 			ret = pqisrc_add_device(softs, device);
14921e66f787SSean Bruno 			if (ret) {
14931e66f787SSean Bruno 				DBG_WARN("scsi %d:%d:%d addition failed, device not added\n",
14941e66f787SSean Bruno 					device->bus, device->target,
14951e66f787SSean Bruno 					device->lun);
14961e66f787SSean Bruno 				pqisrc_adjust_list(softs, device);
14971e66f787SSean Bruno 				continue;
14981e66f787SSean Bruno 			}
14991e66f787SSean Bruno 		}
15001e66f787SSean Bruno 
15011e66f787SSean Bruno 		pqisrc_display_device_info(softs, "added", device);
15021e66f787SSean Bruno 	}
15031e66f787SSean Bruno 
15041e66f787SSean Bruno 	/* Process all volumes that are offline. */
15051e66f787SSean Bruno 	for (i = 0; i < num_new_devices; i++) {
15061e66f787SSean Bruno 		device = new_device_list[i];
15071e66f787SSean Bruno 		if (!device)
15081e66f787SSean Bruno 			continue;
15091e66f787SSean Bruno 		if (!device->new_device)
15101e66f787SSean Bruno 			continue;
15111e66f787SSean Bruno 		if (device->volume_offline) {
15121e66f787SSean Bruno 			pqisrc_display_volume_status(softs, device);
15131e66f787SSean Bruno 			pqisrc_display_device_info(softs, "offline", device);
15141e66f787SSean Bruno 		}
15151e66f787SSean Bruno 	}
15161e66f787SSean Bruno 
15171e66f787SSean Bruno free_and_out:
15181e66f787SSean Bruno 	if (added)
15191e66f787SSean Bruno 		os_mem_free(softs, (char *)added,
15201e66f787SSean Bruno 			    sizeof(*added) * PQI_MAX_DEVICES);
15211e66f787SSean Bruno 	if (removed)
15221e66f787SSean Bruno 		os_mem_free(softs, (char *)removed,
15231e66f787SSean Bruno 			    sizeof(*removed) * PQI_MAX_DEVICES);
15241e66f787SSean Bruno 
1525*b17f4335SSean Bruno 	DBG_FUNC("OUT\n");
15261e66f787SSean Bruno }
15271e66f787SSean Bruno 
15281e66f787SSean Bruno /*
15291e66f787SSean Bruno  * Let the Adapter know about driver version using one of BMIC
15301e66f787SSean Bruno  * BMIC_WRITE_HOST_WELLNESS
15311e66f787SSean Bruno  */
15321e66f787SSean Bruno int pqisrc_write_driver_version_to_host_wellness(pqisrc_softstate_t *softs)
15331e66f787SSean Bruno {
15341e66f787SSean Bruno 	int rval = PQI_STATUS_SUCCESS;
15351e66f787SSean Bruno 	struct bmic_host_wellness_driver_version *host_wellness_driver_ver;
15361e66f787SSean Bruno 	size_t data_length;
15371e66f787SSean Bruno 	pqisrc_raid_req_t request;
15381e66f787SSean Bruno 
15391e66f787SSean Bruno 	DBG_FUNC("IN\n");
15401e66f787SSean Bruno 
15411e66f787SSean Bruno 	memset(&request, 0, sizeof(request));
15421e66f787SSean Bruno 	data_length = sizeof(*host_wellness_driver_ver);
15431e66f787SSean Bruno 
15441e66f787SSean Bruno 	host_wellness_driver_ver = os_mem_alloc(softs, data_length);
15451e66f787SSean Bruno 	if (!host_wellness_driver_ver) {
15461e66f787SSean Bruno 		DBG_ERR("failed to allocate memory for host wellness driver_version\n");
15471e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
15481e66f787SSean Bruno 	}
15491e66f787SSean Bruno 
15501e66f787SSean Bruno 	host_wellness_driver_ver->start_tag[0] = '<';
15511e66f787SSean Bruno 	host_wellness_driver_ver->start_tag[1] = 'H';
15521e66f787SSean Bruno 	host_wellness_driver_ver->start_tag[2] = 'W';
15531e66f787SSean Bruno 	host_wellness_driver_ver->start_tag[3] = '>';
15541e66f787SSean Bruno 	host_wellness_driver_ver->driver_version_tag[0] = 'D';
15551e66f787SSean Bruno 	host_wellness_driver_ver->driver_version_tag[1] = 'V';
15561e66f787SSean Bruno 	host_wellness_driver_ver->driver_version_length = LE_16(sizeof(host_wellness_driver_ver->driver_version));
15571e66f787SSean Bruno 	strncpy(host_wellness_driver_ver->driver_version, softs->os_name,
15581e66f787SSean Bruno         sizeof(host_wellness_driver_ver->driver_version));
15591e66f787SSean Bruno     if (strlen(softs->os_name) < sizeof(host_wellness_driver_ver->driver_version) ) {
15601e66f787SSean Bruno         strncpy(host_wellness_driver_ver->driver_version + strlen(softs->os_name), PQISRC_DRIVER_VERSION,
15611e66f787SSean Bruno 			sizeof(host_wellness_driver_ver->driver_version) -  strlen(softs->os_name));
15621e66f787SSean Bruno     } else {
1563*b17f4335SSean Bruno         DBG_DISC("OS name length(%lu) is longer than buffer of driver_version\n",
15641e66f787SSean Bruno             strlen(softs->os_name));
15651e66f787SSean Bruno     }
15661e66f787SSean Bruno 	host_wellness_driver_ver->driver_version[sizeof(host_wellness_driver_ver->driver_version) - 1] = '\0';
15671e66f787SSean Bruno 	host_wellness_driver_ver->end_tag[0] = 'Z';
15681e66f787SSean Bruno 	host_wellness_driver_ver->end_tag[1] = 'Z';
15691e66f787SSean Bruno 
15701e66f787SSean Bruno 	rval = pqisrc_build_send_raid_request(softs, &request, host_wellness_driver_ver,data_length,
15711e66f787SSean Bruno 					BMIC_WRITE_HOST_WELLNESS, 0, (uint8_t *)RAID_CTLR_LUNID, NULL);
15721e66f787SSean Bruno 
15731e66f787SSean Bruno 	os_mem_free(softs, (char *)host_wellness_driver_ver, data_length);
15741e66f787SSean Bruno 
15751e66f787SSean Bruno 	DBG_FUNC("OUT");
15761e66f787SSean Bruno 	return rval;
15771e66f787SSean Bruno }
15781e66f787SSean Bruno 
15791e66f787SSean Bruno /*
15801e66f787SSean Bruno  * Write current RTC time from host to the adapter using
15811e66f787SSean Bruno  * BMIC_WRITE_HOST_WELLNESS
15821e66f787SSean Bruno  */
15831e66f787SSean Bruno int pqisrc_write_current_time_to_host_wellness(pqisrc_softstate_t *softs)
15841e66f787SSean Bruno {
15851e66f787SSean Bruno 	int rval = PQI_STATUS_SUCCESS;
15861e66f787SSean Bruno 	struct bmic_host_wellness_time *host_wellness_time;
15871e66f787SSean Bruno 	size_t data_length;
15881e66f787SSean Bruno 	pqisrc_raid_req_t request;
15891e66f787SSean Bruno 
15901e66f787SSean Bruno 	DBG_FUNC("IN\n");
15911e66f787SSean Bruno 
15921e66f787SSean Bruno 	memset(&request, 0, sizeof(request));
15931e66f787SSean Bruno 	data_length = sizeof(*host_wellness_time);
15941e66f787SSean Bruno 
15951e66f787SSean Bruno 	host_wellness_time = os_mem_alloc(softs, data_length);
15961e66f787SSean Bruno 	if (!host_wellness_time) {
15971e66f787SSean Bruno 		DBG_ERR("failed to allocate memory for host wellness time structure\n");
15981e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
15991e66f787SSean Bruno 	}
16001e66f787SSean Bruno 
16011e66f787SSean Bruno 	host_wellness_time->start_tag[0] = '<';
16021e66f787SSean Bruno 	host_wellness_time->start_tag[1] = 'H';
16031e66f787SSean Bruno 	host_wellness_time->start_tag[2] = 'W';
16041e66f787SSean Bruno 	host_wellness_time->start_tag[3] = '>';
16051e66f787SSean Bruno 	host_wellness_time->time_tag[0] = 'T';
16061e66f787SSean Bruno 	host_wellness_time->time_tag[1] = 'D';
16071e66f787SSean Bruno 	host_wellness_time->time_length = LE_16(offsetof(struct bmic_host_wellness_time, time_length) -
16081e66f787SSean Bruno 											offsetof(struct bmic_host_wellness_time, century));
16091e66f787SSean Bruno 
16101e66f787SSean Bruno 	os_get_time(host_wellness_time);
16111e66f787SSean Bruno 
16121e66f787SSean Bruno 	host_wellness_time->dont_write_tag[0] = 'D';
16131e66f787SSean Bruno 	host_wellness_time->dont_write_tag[1] = 'W';
16141e66f787SSean Bruno 	host_wellness_time->end_tag[0] = 'Z';
16151e66f787SSean Bruno 	host_wellness_time->end_tag[1] = 'Z';
16161e66f787SSean Bruno 
16171e66f787SSean Bruno 	rval = pqisrc_build_send_raid_request(softs, &request, host_wellness_time,data_length,
16181e66f787SSean Bruno 					BMIC_WRITE_HOST_WELLNESS, 0, (uint8_t *)RAID_CTLR_LUNID, NULL);
16191e66f787SSean Bruno 
16201e66f787SSean Bruno 	os_mem_free(softs, (char *)host_wellness_time, data_length);
16211e66f787SSean Bruno 
16221e66f787SSean Bruno 	DBG_FUNC("OUT");
16231e66f787SSean Bruno 	return rval;
16241e66f787SSean Bruno }
16251e66f787SSean Bruno 
16261e66f787SSean Bruno /*
16271e66f787SSean Bruno  * Function used to perform a rescan of scsi devices
16281e66f787SSean Bruno  * for any config change events
16291e66f787SSean Bruno  */
16301e66f787SSean Bruno int pqisrc_scan_devices(pqisrc_softstate_t *softs)
16311e66f787SSean Bruno {
16321e66f787SSean Bruno 	boolean_t is_physical_device;
16331e66f787SSean Bruno 	int ret = PQI_STATUS_FAILURE;
16341e66f787SSean Bruno 	int i;
16351e66f787SSean Bruno 	int new_dev_cnt;
16361e66f787SSean Bruno 	int phy_log_dev_cnt;
16371e66f787SSean Bruno 	uint8_t *scsi3addr;
16381e66f787SSean Bruno 	uint32_t physical_cnt;
16391e66f787SSean Bruno 	uint32_t logical_cnt;
16401e66f787SSean Bruno 	uint32_t ndev_allocated = 0;
16411e66f787SSean Bruno 	size_t phys_data_length, log_data_length;
16421e66f787SSean Bruno 	reportlun_data_ext_t *physical_dev_list = NULL;
16431e66f787SSean Bruno 	reportlun_data_ext_t *logical_dev_list = NULL;
16441e66f787SSean Bruno 	reportlun_ext_entry_t *lun_ext_entry = NULL;
16451e66f787SSean Bruno 	bmic_ident_physdev_t *bmic_phy_info = NULL;
16461e66f787SSean Bruno 	pqi_scsi_dev_t **new_device_list = NULL;
16471e66f787SSean Bruno 	pqi_scsi_dev_t *device = NULL;
16481e66f787SSean Bruno 
16491e66f787SSean Bruno 
16501e66f787SSean Bruno 	DBG_FUNC("IN\n");
16511e66f787SSean Bruno 
16521e66f787SSean Bruno 	ret = pqisrc_get_phys_log_device_list(softs, &physical_dev_list, &logical_dev_list,
16531e66f787SSean Bruno 				      &phys_data_length, &log_data_length);
16541e66f787SSean Bruno 
16551e66f787SSean Bruno 	if (ret)
16561e66f787SSean Bruno 		goto err_out;
16571e66f787SSean Bruno 
16581e66f787SSean Bruno 	physical_cnt = BE_32(physical_dev_list->header.list_length)
16591e66f787SSean Bruno 		/ sizeof(physical_dev_list->lun_entries[0]);
16601e66f787SSean Bruno 
16611e66f787SSean Bruno 	logical_cnt = BE_32(logical_dev_list->header.list_length)
16621e66f787SSean Bruno 		/ sizeof(logical_dev_list->lun_entries[0]);
16631e66f787SSean Bruno 
1664*b17f4335SSean Bruno 	DBG_DISC("physical_cnt %d logical_cnt %d\n", physical_cnt, logical_cnt);
16651e66f787SSean Bruno 
16661e66f787SSean Bruno 	if (physical_cnt) {
16671e66f787SSean Bruno 		bmic_phy_info = os_mem_alloc(softs, sizeof(*bmic_phy_info));
16681e66f787SSean Bruno 		if (bmic_phy_info == NULL) {
16691e66f787SSean Bruno 			ret = PQI_STATUS_FAILURE;
16701e66f787SSean Bruno 			DBG_ERR("failed to allocate memory for BMIC ID PHYS Device : %d\n", ret);
16711e66f787SSean Bruno 			goto err_out;
16721e66f787SSean Bruno 		}
16731e66f787SSean Bruno 	}
16741e66f787SSean Bruno 	phy_log_dev_cnt = physical_cnt + logical_cnt;
16751e66f787SSean Bruno 	new_device_list = os_mem_alloc(softs,
16761e66f787SSean Bruno 				sizeof(*new_device_list) * phy_log_dev_cnt);
16771e66f787SSean Bruno 
16781e66f787SSean Bruno 	if (new_device_list == NULL) {
16791e66f787SSean Bruno 		ret = PQI_STATUS_FAILURE;
16801e66f787SSean Bruno 		DBG_ERR("failed to allocate memory for device list : %d\n", ret);
16811e66f787SSean Bruno 		goto err_out;
16821e66f787SSean Bruno 	}
16831e66f787SSean Bruno 
16841e66f787SSean Bruno 	for (i = 0; i < phy_log_dev_cnt; i++) {
16851e66f787SSean Bruno 		new_device_list[i] = os_mem_alloc(softs,
16861e66f787SSean Bruno 						sizeof(*new_device_list[i]));
16871e66f787SSean Bruno 		if (new_device_list[i] == NULL) {
16881e66f787SSean Bruno 			ret = PQI_STATUS_FAILURE;
16891e66f787SSean Bruno 			DBG_ERR("failed to allocate memory for device list : %d\n", ret);
16901e66f787SSean Bruno 			ndev_allocated = i;
16911e66f787SSean Bruno 			goto err_out;
16921e66f787SSean Bruno 		}
16931e66f787SSean Bruno 	}
16941e66f787SSean Bruno 
16951e66f787SSean Bruno 	ndev_allocated = phy_log_dev_cnt;
16961e66f787SSean Bruno 	new_dev_cnt = 0;
16971e66f787SSean Bruno 	for (i = 0; i < phy_log_dev_cnt; i++) {
16981e66f787SSean Bruno 
16991e66f787SSean Bruno 		if (i < physical_cnt) {
17001e66f787SSean Bruno 			is_physical_device = true;
17011e66f787SSean Bruno 			lun_ext_entry = &physical_dev_list->lun_entries[i];
17021e66f787SSean Bruno 		} else {
17031e66f787SSean Bruno 			is_physical_device = false;
17041e66f787SSean Bruno 			lun_ext_entry =
17051e66f787SSean Bruno 				&logical_dev_list->lun_entries[i - physical_cnt];
17061e66f787SSean Bruno 		}
17071e66f787SSean Bruno 
17081e66f787SSean Bruno 		scsi3addr = lun_ext_entry->lunid;
1709*b17f4335SSean Bruno 		/* Save the target sas adderess for external raid device */
1710*b17f4335SSean Bruno 		if(lun_ext_entry->device_type == CONTROLLER_DEVICE) {
1711*b17f4335SSean Bruno 			int target = lun_ext_entry->lunid[3] & 0x3f;
1712*b17f4335SSean Bruno 			softs->target_sas_addr[target] = BE_64(lun_ext_entry->wwid);
1713*b17f4335SSean Bruno 		}
17141e66f787SSean Bruno 
17151e66f787SSean Bruno 		/* Skip masked physical non-disk devices. */
1716*b17f4335SSean Bruno 		if (MASKED_DEVICE(scsi3addr) && is_physical_device
1717*b17f4335SSean Bruno 				&& (lun_ext_entry->ioaccel_handle == 0))
17181e66f787SSean Bruno 			continue;
17191e66f787SSean Bruno 
17201e66f787SSean Bruno 		device = new_device_list[new_dev_cnt];
17211e66f787SSean Bruno 		memset(device, 0, sizeof(*device));
17221e66f787SSean Bruno 		memcpy(device->scsi3addr, scsi3addr, sizeof(device->scsi3addr));
17231e66f787SSean Bruno 		device->wwid = lun_ext_entry->wwid;
17241e66f787SSean Bruno 		device->is_physical_device = is_physical_device;
17251e66f787SSean Bruno 		if (!is_physical_device)
17261e66f787SSean Bruno 			device->is_external_raid_device =
17271e66f787SSean Bruno 				pqisrc_is_external_raid_addr(scsi3addr);
17281e66f787SSean Bruno 
17291e66f787SSean Bruno 
17301e66f787SSean Bruno 		/* Get device type, vendor, model, device ID. */
17311e66f787SSean Bruno 		ret = pqisrc_get_dev_data(softs, device);
17321e66f787SSean Bruno 		if (ret) {
17331e66f787SSean Bruno 			DBG_WARN("Inquiry failed, skipping device %016llx\n",
17341e66f787SSean Bruno 				 (unsigned long long)BE_64(device->scsi3addr[0]));
1735*b17f4335SSean Bruno 			DBG_DISC("INQUIRY FAILED \n");
17361e66f787SSean Bruno 			continue;
17371e66f787SSean Bruno 		}
17381e66f787SSean Bruno 		pqisrc_assign_btl(device);
17391e66f787SSean Bruno 
17401e66f787SSean Bruno 		/*
17411e66f787SSean Bruno 		 * Expose all devices except for physical devices that
17421e66f787SSean Bruno 		 * are masked.
17431e66f787SSean Bruno 		 */
17441e66f787SSean Bruno 		if (device->is_physical_device &&
17451e66f787SSean Bruno 			MASKED_DEVICE(scsi3addr))
17461e66f787SSean Bruno 			device->expose_device = false;
17471e66f787SSean Bruno 		else
17481e66f787SSean Bruno 			device->expose_device = true;
17491e66f787SSean Bruno 
17501e66f787SSean Bruno 		if (device->is_physical_device &&
17511e66f787SSean Bruno 		    (lun_ext_entry->device_flags &
17521e66f787SSean Bruno 		     REPORT_LUN_DEV_FLAG_AIO_ENABLED) &&
17531e66f787SSean Bruno 		     lun_ext_entry->ioaccel_handle) {
17541e66f787SSean Bruno 			device->aio_enabled = true;
17551e66f787SSean Bruno 		}
17561e66f787SSean Bruno 		switch (device->devtype) {
17571e66f787SSean Bruno 		case ROM_DEVICE:
17581e66f787SSean Bruno 			/*
17591e66f787SSean Bruno 			 * We don't *really* support actual CD-ROM devices,
17601e66f787SSean Bruno 			 * but we do support the HP "One Button Disaster
17611e66f787SSean Bruno 			 * Recovery" tape drive which temporarily pretends to
17621e66f787SSean Bruno 			 * be a CD-ROM drive.
17631e66f787SSean Bruno 			 */
17641e66f787SSean Bruno 			if (device->is_obdr_device)
17651e66f787SSean Bruno 				new_dev_cnt++;
17661e66f787SSean Bruno 			break;
17671e66f787SSean Bruno 		case DISK_DEVICE:
17681e66f787SSean Bruno 		case ZBC_DEVICE:
17691e66f787SSean Bruno 			if (device->is_physical_device) {
17701e66f787SSean Bruno 				device->ioaccel_handle =
17711e66f787SSean Bruno 					lun_ext_entry->ioaccel_handle;
17721e66f787SSean Bruno 				device->sas_address = BE_64(lun_ext_entry->wwid);
17731e66f787SSean Bruno 				pqisrc_get_physical_device_info(softs, device,
17741e66f787SSean Bruno 					bmic_phy_info);
17751e66f787SSean Bruno 			}
17761e66f787SSean Bruno 			new_dev_cnt++;
17771e66f787SSean Bruno 			break;
17781e66f787SSean Bruno 		case ENCLOSURE_DEVICE:
17791e66f787SSean Bruno 			if (device->is_physical_device) {
17801e66f787SSean Bruno 				device->sas_address = BE_64(lun_ext_entry->wwid);
17811e66f787SSean Bruno 			}
17821e66f787SSean Bruno 			new_dev_cnt++;
17831e66f787SSean Bruno 			break;
17841e66f787SSean Bruno 		case TAPE_DEVICE:
17851e66f787SSean Bruno 		case MEDIUM_CHANGER_DEVICE:
17861e66f787SSean Bruno 			new_dev_cnt++;
17871e66f787SSean Bruno 			break;
17881e66f787SSean Bruno 		case RAID_DEVICE:
17891e66f787SSean Bruno 			/*
17901e66f787SSean Bruno 			 * Only present the HBA controller itself as a RAID
17911e66f787SSean Bruno 			 * controller.  If it's a RAID controller other than
17921e66f787SSean Bruno 			 * the HBA itself (an external RAID controller, MSA500
17931e66f787SSean Bruno 			 * or similar), don't present it.
17941e66f787SSean Bruno 			 */
17951e66f787SSean Bruno 			if (pqisrc_is_hba_lunid(scsi3addr))
17961e66f787SSean Bruno 				new_dev_cnt++;
17971e66f787SSean Bruno 			break;
1798*b17f4335SSean Bruno 		case SES_DEVICE:
1799*b17f4335SSean Bruno 		case CONTROLLER_DEVICE:
1800*b17f4335SSean Bruno 			break;
18011e66f787SSean Bruno 		}
18021e66f787SSean Bruno 	}
1803*b17f4335SSean Bruno 	DBG_DISC("new_dev_cnt %d\n", new_dev_cnt);
18041e66f787SSean Bruno 
18051e66f787SSean Bruno 	pqisrc_update_device_list(softs, new_device_list, new_dev_cnt);
18061e66f787SSean Bruno 
18071e66f787SSean Bruno err_out:
18081e66f787SSean Bruno 	if (new_device_list) {
18091e66f787SSean Bruno 		for (i = 0; i < ndev_allocated; i++) {
18101e66f787SSean Bruno 			if (new_device_list[i]) {
18111e66f787SSean Bruno 				if(new_device_list[i]->raid_map)
18121e66f787SSean Bruno 					os_mem_free(softs, (char *)new_device_list[i]->raid_map,
18131e66f787SSean Bruno 					    					sizeof(pqisrc_raid_map_t));
18141e66f787SSean Bruno 				os_mem_free(softs, (char*)new_device_list[i],
18151e66f787SSean Bruno 					    			sizeof(*new_device_list[i]));
18161e66f787SSean Bruno 			}
18171e66f787SSean Bruno 		}
18181e66f787SSean Bruno 		os_mem_free(softs, (char *)new_device_list,
18191e66f787SSean Bruno 			    		sizeof(*new_device_list) * ndev_allocated);
18201e66f787SSean Bruno 	}
18211e66f787SSean Bruno 	if(physical_dev_list)
18221e66f787SSean Bruno 		os_mem_free(softs, (char *)physical_dev_list, phys_data_length);
18231e66f787SSean Bruno     	if(logical_dev_list)
18241e66f787SSean Bruno 		os_mem_free(softs, (char *)logical_dev_list, log_data_length);
18251e66f787SSean Bruno 	if (bmic_phy_info)
18261e66f787SSean Bruno 		os_mem_free(softs, (char *)bmic_phy_info, sizeof(*bmic_phy_info));
18271e66f787SSean Bruno 
18281e66f787SSean Bruno 	DBG_FUNC("OUT \n");
18291e66f787SSean Bruno 
18301e66f787SSean Bruno 	return ret;
18311e66f787SSean Bruno }
18321e66f787SSean Bruno 
18331e66f787SSean Bruno /*
18341e66f787SSean Bruno  * Clean up memory allocated for devices.
18351e66f787SSean Bruno  */
18361e66f787SSean Bruno void pqisrc_cleanup_devices(pqisrc_softstate_t *softs)
18371e66f787SSean Bruno {
18381e66f787SSean Bruno 
18391e66f787SSean Bruno 	int i = 0,j = 0;
18401e66f787SSean Bruno 	pqi_scsi_dev_t *dvp = NULL;
18411e66f787SSean Bruno 	DBG_FUNC("IN\n");
18421e66f787SSean Bruno 
18431e66f787SSean Bruno  	for(i = 0; i < PQI_MAX_DEVICES; i++) {
18441e66f787SSean Bruno 		for(j = 0; j < PQI_MAX_MULTILUN; j++) {
18451e66f787SSean Bruno 			if (softs->device_list[i][j] == NULL)
18461e66f787SSean Bruno 				continue;
18471e66f787SSean Bruno 			dvp = softs->device_list[i][j];
18481e66f787SSean Bruno 			pqisrc_device_mem_free(softs, dvp);
18491e66f787SSean Bruno 		}
18501e66f787SSean Bruno 	}
18511e66f787SSean Bruno 	DBG_FUNC("OUT\n");
18521e66f787SSean Bruno }
18531e66f787SSean Bruno 
1854