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