xref: /freebsd/sys/dev/smartpqi/smartpqi_request.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 #define SG_FLAG_LAST	0x40000000
32*1e66f787SSean Bruno #define SG_FLAG_CHAIN	0x80000000
33*1e66f787SSean Bruno 
34*1e66f787SSean Bruno /* Subroutine to find out embedded sgl count in IU */
35*1e66f787SSean Bruno static inline
36*1e66f787SSean Bruno uint32_t pqisrc_embedded_sgl_count(uint32_t elem_alloted)
37*1e66f787SSean Bruno {
38*1e66f787SSean Bruno 	uint32_t embedded_sgl_count = MAX_EMBEDDED_SG_IN_FIRST_IU;
39*1e66f787SSean Bruno 	DBG_FUNC(" IN ");
40*1e66f787SSean Bruno 	/**
41*1e66f787SSean Bruno 	calculate embedded sgl count using num_elem_alloted for IO
42*1e66f787SSean Bruno 	**/
43*1e66f787SSean Bruno 	if(elem_alloted - 1)
44*1e66f787SSean Bruno 		embedded_sgl_count += ((elem_alloted - 1) * MAX_EMBEDDED_SG_IN_IU);
45*1e66f787SSean Bruno 	DBG_IO("embedded_sgl_count :%d\n",embedded_sgl_count);
46*1e66f787SSean Bruno 
47*1e66f787SSean Bruno 	DBG_FUNC(" OUT ");
48*1e66f787SSean Bruno 
49*1e66f787SSean Bruno 	return embedded_sgl_count;
50*1e66f787SSean Bruno 
51*1e66f787SSean Bruno }
52*1e66f787SSean Bruno 
53*1e66f787SSean Bruno /* Subroutine to find out contiguous free elem in IU */
54*1e66f787SSean Bruno static inline
55*1e66f787SSean Bruno uint32_t pqisrc_contiguous_free_elem(uint32_t pi, uint32_t ci, uint32_t elem_in_q)
56*1e66f787SSean Bruno {
57*1e66f787SSean Bruno 	uint32_t contiguous_free_elem = 0;
58*1e66f787SSean Bruno 
59*1e66f787SSean Bruno 	DBG_FUNC(" IN ");
60*1e66f787SSean Bruno 
61*1e66f787SSean Bruno 	if(pi >= ci) {
62*1e66f787SSean Bruno 		contiguous_free_elem = (elem_in_q - pi);
63*1e66f787SSean Bruno 		if(ci == 0)
64*1e66f787SSean Bruno 			contiguous_free_elem -= 1;
65*1e66f787SSean Bruno 	} else {
66*1e66f787SSean Bruno 		contiguous_free_elem = (ci - pi - 1);
67*1e66f787SSean Bruno 	}
68*1e66f787SSean Bruno 
69*1e66f787SSean Bruno 	DBG_FUNC(" OUT ");
70*1e66f787SSean Bruno 
71*1e66f787SSean Bruno 	return contiguous_free_elem;
72*1e66f787SSean Bruno }
73*1e66f787SSean Bruno 
74*1e66f787SSean Bruno /* Subroutine to find out num of elements need for the request */
75*1e66f787SSean Bruno static uint32_t
76*1e66f787SSean Bruno pqisrc_num_elem_needed(pqisrc_softstate_t *softs, uint32_t SG_Count)
77*1e66f787SSean Bruno {
78*1e66f787SSean Bruno 	uint32_t num_sg;
79*1e66f787SSean Bruno 	uint32_t num_elem_required = 1;
80*1e66f787SSean Bruno 	DBG_FUNC(" IN ");
81*1e66f787SSean Bruno 	DBG_IO("SGL_Count :%d",SG_Count);
82*1e66f787SSean Bruno 	/********
83*1e66f787SSean Bruno 	If SG_Count greater than max sg per IU i.e 4 or 68
84*1e66f787SSean Bruno 	(4 is with out spanning or 68 is with spanning) chaining is required.
85*1e66f787SSean Bruno 	OR, If SG_Count <= MAX_EMBEDDED_SG_IN_FIRST_IU then,
86*1e66f787SSean Bruno 	on these two cases one element is enough.
87*1e66f787SSean Bruno 	********/
88*1e66f787SSean Bruno 	if(SG_Count > softs->max_sg_per_iu || SG_Count <= MAX_EMBEDDED_SG_IN_FIRST_IU)
89*1e66f787SSean Bruno 		return num_elem_required;
90*1e66f787SSean Bruno 	/*
91*1e66f787SSean Bruno 	SGL Count Other Than First IU
92*1e66f787SSean Bruno 	 */
93*1e66f787SSean Bruno 	num_sg = SG_Count - MAX_EMBEDDED_SG_IN_FIRST_IU;
94*1e66f787SSean Bruno 	num_elem_required += PQISRC_DIV_ROUND_UP(num_sg, MAX_EMBEDDED_SG_IN_IU);
95*1e66f787SSean Bruno 	DBG_FUNC(" OUT ");
96*1e66f787SSean Bruno 	return num_elem_required;
97*1e66f787SSean Bruno }
98*1e66f787SSean Bruno 
99*1e66f787SSean Bruno /* Subroutine to build SG list for the IU submission*/
100*1e66f787SSean Bruno static
101*1e66f787SSean Bruno boolean_t pqisrc_build_sgl(sgt_t *sg_array, rcb_t *rcb, iu_header_t *iu_hdr,
102*1e66f787SSean Bruno 			uint32_t num_elem_alloted)
103*1e66f787SSean Bruno {
104*1e66f787SSean Bruno 	uint32_t i;
105*1e66f787SSean Bruno 	uint32_t num_sg = OS_GET_IO_SG_COUNT(rcb);
106*1e66f787SSean Bruno 	sgt_t *sgt = sg_array;
107*1e66f787SSean Bruno 	sgt_t *sg_chain = NULL;
108*1e66f787SSean Bruno 	boolean_t partial = false;
109*1e66f787SSean Bruno 
110*1e66f787SSean Bruno 	DBG_FUNC(" IN ");
111*1e66f787SSean Bruno 
112*1e66f787SSean Bruno 	DBG_IO("SGL_Count :%d",num_sg);
113*1e66f787SSean Bruno 	if (0 == num_sg) {
114*1e66f787SSean Bruno 		goto out;
115*1e66f787SSean Bruno 	}
116*1e66f787SSean Bruno 
117*1e66f787SSean Bruno 	if (num_sg <= pqisrc_embedded_sgl_count(num_elem_alloted)) {
118*1e66f787SSean Bruno 		for (i = 0; i < num_sg; i++, sgt++) {
119*1e66f787SSean Bruno                         sgt->addr= OS_GET_IO_SG_ADDR(rcb,i);
120*1e66f787SSean Bruno                         sgt->len= OS_GET_IO_SG_LEN(rcb,i);
121*1e66f787SSean Bruno                         sgt->flags= 0;
122*1e66f787SSean Bruno                 }
123*1e66f787SSean Bruno 
124*1e66f787SSean Bruno 		sg_array[num_sg - 1].flags = SG_FLAG_LAST;
125*1e66f787SSean Bruno 	} else {
126*1e66f787SSean Bruno 	/**
127*1e66f787SSean Bruno 	SGL Chaining
128*1e66f787SSean Bruno 	**/
129*1e66f787SSean Bruno 		sg_chain = rcb->sg_chain_virt;
130*1e66f787SSean Bruno 		sgt->addr = rcb->sg_chain_dma;
131*1e66f787SSean Bruno 		sgt->len = num_sg * sizeof(sgt_t);
132*1e66f787SSean Bruno 		sgt->flags = SG_FLAG_CHAIN;
133*1e66f787SSean Bruno 
134*1e66f787SSean Bruno 		sgt = sg_chain;
135*1e66f787SSean Bruno 		for (i = 0; i < num_sg; i++, sgt++) {
136*1e66f787SSean Bruno 			sgt->addr = OS_GET_IO_SG_ADDR(rcb,i);
137*1e66f787SSean Bruno 			sgt->len = OS_GET_IO_SG_LEN(rcb,i);
138*1e66f787SSean Bruno 			sgt->flags = 0;
139*1e66f787SSean Bruno 		}
140*1e66f787SSean Bruno 
141*1e66f787SSean Bruno 		sg_chain[num_sg - 1].flags = SG_FLAG_LAST;
142*1e66f787SSean Bruno 		num_sg = 1;
143*1e66f787SSean Bruno 		partial = true;
144*1e66f787SSean Bruno 
145*1e66f787SSean Bruno 	}
146*1e66f787SSean Bruno out:
147*1e66f787SSean Bruno 	iu_hdr->iu_length = num_sg * sizeof(sgt_t);
148*1e66f787SSean Bruno 	DBG_FUNC(" OUT ");
149*1e66f787SSean Bruno 	return partial;
150*1e66f787SSean Bruno 
151*1e66f787SSean Bruno }
152*1e66f787SSean Bruno 
153*1e66f787SSean Bruno /*Subroutine used to Build the RAID request */
154*1e66f787SSean Bruno static void
155*1e66f787SSean Bruno pqisrc_build_raid_io(pqisrc_softstate_t *softs, rcb_t *rcb,
156*1e66f787SSean Bruno  	pqisrc_raid_req_t *raid_req, uint32_t num_elem_alloted)
157*1e66f787SSean Bruno {
158*1e66f787SSean Bruno 	DBG_FUNC(" IN ");
159*1e66f787SSean Bruno 
160*1e66f787SSean Bruno 	raid_req->header.iu_type = PQI_IU_TYPE_RAID_PATH_IO_REQUEST;
161*1e66f787SSean Bruno 	raid_req->header.comp_feature = 0;
162*1e66f787SSean Bruno 	raid_req->response_queue_id = OS_GET_IO_RESP_QID(softs, rcb);
163*1e66f787SSean Bruno 	raid_req->work_area[0] = 0;
164*1e66f787SSean Bruno 	raid_req->work_area[1] = 0;
165*1e66f787SSean Bruno 	raid_req->request_id = rcb->tag;
166*1e66f787SSean Bruno 	raid_req->nexus_id = 0;
167*1e66f787SSean Bruno 	raid_req->buffer_length = GET_SCSI_BUFFLEN(rcb);
168*1e66f787SSean Bruno 	memcpy(raid_req->lun_number, rcb->dvp->scsi3addr,
169*1e66f787SSean Bruno  		sizeof(raid_req->lun_number));
170*1e66f787SSean Bruno 	raid_req->protocol_spec = 0;
171*1e66f787SSean Bruno 	raid_req->data_direction = rcb->data_dir;
172*1e66f787SSean Bruno 	raid_req->reserved1 = 0;
173*1e66f787SSean Bruno 	raid_req->fence = 0;
174*1e66f787SSean Bruno 	raid_req->error_index = raid_req->request_id;
175*1e66f787SSean Bruno 	raid_req->reserved2 = 0;
176*1e66f787SSean Bruno   	raid_req->task_attribute = OS_GET_TASK_ATTR(rcb);
177*1e66f787SSean Bruno   	raid_req->command_priority = 0;
178*1e66f787SSean Bruno 	raid_req->reserved3 = 0;
179*1e66f787SSean Bruno 	raid_req->reserved4 = 0;
180*1e66f787SSean Bruno 	raid_req->reserved5 = 0;
181*1e66f787SSean Bruno 
182*1e66f787SSean Bruno 	/* As cdb and additional_cdb_bytes are contiguous,
183*1e66f787SSean Bruno 	   update them in a single statement */
184*1e66f787SSean Bruno 	memcpy(raid_req->cdb, rcb->cdbp, rcb->cmdlen);
185*1e66f787SSean Bruno #if 0
186*1e66f787SSean Bruno 	DBG_IO("CDB :");
187*1e66f787SSean Bruno 	for(i = 0; i < rcb->cmdlen ; i++)
188*1e66f787SSean Bruno 		DBG_IO(" 0x%x \n ",raid_req->cdb[i]);
189*1e66f787SSean Bruno #endif
190*1e66f787SSean Bruno 
191*1e66f787SSean Bruno 	switch (rcb->cmdlen) {
192*1e66f787SSean Bruno 		case 6:
193*1e66f787SSean Bruno 		case 10:
194*1e66f787SSean Bruno 		case 12:
195*1e66f787SSean Bruno 		case 16:
196*1e66f787SSean Bruno 			raid_req->additional_cdb_bytes_usage =
197*1e66f787SSean Bruno 				PQI_ADDITIONAL_CDB_BYTES_0;
198*1e66f787SSean Bruno 			break;
199*1e66f787SSean Bruno 		case 20:
200*1e66f787SSean Bruno 			raid_req->additional_cdb_bytes_usage =
201*1e66f787SSean Bruno 				PQI_ADDITIONAL_CDB_BYTES_4;
202*1e66f787SSean Bruno 			break;
203*1e66f787SSean Bruno 		case 24:
204*1e66f787SSean Bruno 			raid_req->additional_cdb_bytes_usage =
205*1e66f787SSean Bruno 				PQI_ADDITIONAL_CDB_BYTES_8;
206*1e66f787SSean Bruno 			break;
207*1e66f787SSean Bruno 		case 28:
208*1e66f787SSean Bruno 			raid_req->additional_cdb_bytes_usage =
209*1e66f787SSean Bruno 				PQI_ADDITIONAL_CDB_BYTES_12;
210*1e66f787SSean Bruno 			break;
211*1e66f787SSean Bruno 		case 32:
212*1e66f787SSean Bruno 		default: /* todo:review again */
213*1e66f787SSean Bruno 			raid_req->additional_cdb_bytes_usage =
214*1e66f787SSean Bruno 				PQI_ADDITIONAL_CDB_BYTES_16;
215*1e66f787SSean Bruno 			break;
216*1e66f787SSean Bruno 	}
217*1e66f787SSean Bruno 
218*1e66f787SSean Bruno 	/* Frame SGL Descriptor */
219*1e66f787SSean Bruno 	raid_req->partial = pqisrc_build_sgl(&raid_req->sg_descriptors[0], rcb,
220*1e66f787SSean Bruno 		&raid_req->header, num_elem_alloted);
221*1e66f787SSean Bruno 
222*1e66f787SSean Bruno 	raid_req->header.iu_length +=
223*1e66f787SSean Bruno 			offsetof(pqisrc_raid_req_t, sg_descriptors) - sizeof(iu_header_t);
224*1e66f787SSean Bruno 
225*1e66f787SSean Bruno #if 0
226*1e66f787SSean Bruno 	DBG_IO("raid_req->header.iu_type : 0x%x", raid_req->header.iu_type);
227*1e66f787SSean Bruno 	DBG_IO("raid_req->response_queue_id :%d\n"raid_req->response_queue_id);
228*1e66f787SSean Bruno 	DBG_IO("raid_req->request_id : 0x%x", raid_req->request_id);
229*1e66f787SSean Bruno 	DBG_IO("raid_req->buffer_length : 0x%x", raid_req->buffer_length);
230*1e66f787SSean Bruno 	DBG_IO("raid_req->task_attribute : 0x%x", raid_req->task_attribute);
231*1e66f787SSean Bruno 	DBG_IO("raid_req->lun_number  : 0x%x", raid_req->lun_number);
232*1e66f787SSean Bruno 	DBG_IO("raid_req->error_index : 0x%x", raid_req->error_index);
233*1e66f787SSean Bruno 	DBG_IO("raid_req->sg_descriptors[0].addr : %p", (void*)raid_req->sg_descriptors[0].addr);
234*1e66f787SSean Bruno 	DBG_IO("raid_req->sg_descriptors[0].len : 0x%x", raid_req->sg_descriptors[0].len);
235*1e66f787SSean Bruno 	DBG_IO("raid_req->sg_descriptors[0].flags : 0%x", raid_req->sg_descriptors[0].flags);
236*1e66f787SSean Bruno #endif
237*1e66f787SSean Bruno 	rcb->success_cmp_callback = pqisrc_process_io_response_success;
238*1e66f787SSean Bruno 	rcb->error_cmp_callback = pqisrc_process_raid_response_error;
239*1e66f787SSean Bruno 	rcb->resp_qid = raid_req->response_queue_id;
240*1e66f787SSean Bruno 
241*1e66f787SSean Bruno  	DBG_FUNC(" OUT ");
242*1e66f787SSean Bruno 
243*1e66f787SSean Bruno }
244*1e66f787SSean Bruno 
245*1e66f787SSean Bruno /*Subroutine used to Build the AIO request */
246*1e66f787SSean Bruno static void
247*1e66f787SSean Bruno pqisrc_build_aio_io(pqisrc_softstate_t *softs, rcb_t *rcb,
248*1e66f787SSean Bruno  				pqi_aio_req_t *aio_req, uint32_t num_elem_alloted)
249*1e66f787SSean Bruno {
250*1e66f787SSean Bruno 	DBG_FUNC(" IN ");
251*1e66f787SSean Bruno 
252*1e66f787SSean Bruno 	aio_req->header.iu_type = PQI_IU_TYPE_AIO_PATH_IO_REQUEST;
253*1e66f787SSean Bruno 	aio_req->header.comp_feature = 0;
254*1e66f787SSean Bruno 	aio_req->response_queue_id = OS_GET_IO_RESP_QID(softs, rcb);
255*1e66f787SSean Bruno 	aio_req->work_area[0] = 0;
256*1e66f787SSean Bruno 	aio_req->work_area[1] = 0;
257*1e66f787SSean Bruno 	aio_req->req_id = rcb->tag;
258*1e66f787SSean Bruno 	aio_req->res1[0] = 0;
259*1e66f787SSean Bruno 	aio_req->res1[1] = 0;
260*1e66f787SSean Bruno 	aio_req->nexus = rcb->ioaccel_handle;
261*1e66f787SSean Bruno 	aio_req->buf_len = GET_SCSI_BUFFLEN(rcb);
262*1e66f787SSean Bruno 	aio_req->data_dir = rcb->data_dir;
263*1e66f787SSean Bruno 	aio_req->mem_type = 0;
264*1e66f787SSean Bruno 	aio_req->fence = 0;
265*1e66f787SSean Bruno 	aio_req->res2 = 0;
266*1e66f787SSean Bruno 	aio_req->task_attr = OS_GET_TASK_ATTR(rcb);
267*1e66f787SSean Bruno 	aio_req->cmd_prio = 0;
268*1e66f787SSean Bruno 	aio_req->res3 = 0;
269*1e66f787SSean Bruno 	aio_req->err_idx = aio_req->req_id;
270*1e66f787SSean Bruno 	aio_req->cdb_len = rcb->cmdlen;
271*1e66f787SSean Bruno 	memcpy(aio_req->cdb, rcb->cdbp, rcb->cmdlen);
272*1e66f787SSean Bruno #if 0
273*1e66f787SSean Bruno 	DBG_IO("CDB : \n");
274*1e66f787SSean Bruno 	for(int i = 0; i < rcb->cmdlen ; i++)
275*1e66f787SSean Bruno 		 DBG_IO(" 0x%x \n",aio_req->cdb[i]);
276*1e66f787SSean Bruno #endif
277*1e66f787SSean Bruno 	memset(aio_req->lun,0,sizeof(aio_req->lun));
278*1e66f787SSean Bruno 	memset(aio_req->res4,0,sizeof(aio_req->res4));
279*1e66f787SSean Bruno 
280*1e66f787SSean Bruno 	if(rcb->encrypt_enable == true) {
281*1e66f787SSean Bruno 		aio_req->encrypt_enable = true;
282*1e66f787SSean Bruno 		aio_req->encrypt_key_index = LE_16(rcb->enc_info.data_enc_key_index);
283*1e66f787SSean Bruno 		aio_req->encrypt_twk_low = LE_32(rcb->enc_info.encrypt_tweak_lower);
284*1e66f787SSean Bruno 		aio_req->encrypt_twk_high = LE_32(rcb->enc_info.encrypt_tweak_upper);
285*1e66f787SSean Bruno 	} else {
286*1e66f787SSean Bruno 		aio_req->encrypt_enable = 0;
287*1e66f787SSean Bruno 		aio_req->encrypt_key_index = 0;
288*1e66f787SSean Bruno 		aio_req->encrypt_twk_high = 0;
289*1e66f787SSean Bruno 		aio_req->encrypt_twk_low = 0;
290*1e66f787SSean Bruno 	}
291*1e66f787SSean Bruno 
292*1e66f787SSean Bruno 	/* Frame SGL Descriptor */
293*1e66f787SSean Bruno 	aio_req->partial = pqisrc_build_sgl(&aio_req->sg_desc[0], rcb,
294*1e66f787SSean Bruno  		&aio_req->header, num_elem_alloted);
295*1e66f787SSean Bruno 
296*1e66f787SSean Bruno 	aio_req->num_sg = aio_req->header.iu_length / sizeof(sgt_t);
297*1e66f787SSean Bruno 
298*1e66f787SSean Bruno 	DBG_INFO("aio_req->num_sg :%d",aio_req->num_sg);
299*1e66f787SSean Bruno 
300*1e66f787SSean Bruno 	aio_req->header.iu_length += offsetof(pqi_aio_req_t, sg_desc) -
301*1e66f787SSean Bruno 		sizeof(iu_header_t);
302*1e66f787SSean Bruno #if 0
303*1e66f787SSean Bruno 	DBG_IO("aio_req->header.iu_type : 0x%x \n",aio_req->header.iu_type);
304*1e66f787SSean Bruno 	DBG_IO("aio_req->resp_qid :0x%x",aio_req->resp_qid);
305*1e66f787SSean Bruno 	DBG_IO("aio_req->req_id : 0x%x \n",aio_req->req_id);
306*1e66f787SSean Bruno 	DBG_IO("aio_req->nexus : 0x%x  \n",aio_req->nexus);
307*1e66f787SSean Bruno 	DBG_IO("aio_req->buf_len : 0x%x \n",aio_req->buf_len);
308*1e66f787SSean Bruno 	DBG_IO("aio_req->data_dir : 0x%x \n",aio_req->data_dir);
309*1e66f787SSean Bruno 	DBG_IO("aio_req->task_attr : 0x%x \n",aio_req->task_attr);
310*1e66f787SSean Bruno 	DBG_IO("aio_req->err_idx : 0x%x \n",aio_req->err_idx);
311*1e66f787SSean Bruno 	DBG_IO("aio_req->num_sg :%d",aio_req->num_sg);
312*1e66f787SSean Bruno 	DBG_IO("aio_req->sg_desc[0].addr : %p \n", (void*)aio_req->sg_desc[0].addr);
313*1e66f787SSean Bruno 	DBG_IO("aio_req->sg_desc[0].len : 0%x \n", aio_req->sg_desc[0].len);
314*1e66f787SSean Bruno 	DBG_IO("aio_req->sg_desc[0].flags : 0%x \n", aio_req->sg_desc[0].flags);
315*1e66f787SSean Bruno #endif
316*1e66f787SSean Bruno 
317*1e66f787SSean Bruno 	rcb->success_cmp_callback = pqisrc_process_io_response_success;
318*1e66f787SSean Bruno 	rcb->error_cmp_callback = pqisrc_process_aio_response_error;
319*1e66f787SSean Bruno 	rcb->resp_qid = aio_req->response_queue_id;
320*1e66f787SSean Bruno 
321*1e66f787SSean Bruno 	DBG_FUNC(" OUT ");
322*1e66f787SSean Bruno 
323*1e66f787SSean Bruno }
324*1e66f787SSean Bruno 
325*1e66f787SSean Bruno /*Function used to build and send RAID/AIO */
326*1e66f787SSean Bruno int pqisrc_build_send_io(pqisrc_softstate_t *softs,rcb_t *rcb)
327*1e66f787SSean Bruno {
328*1e66f787SSean Bruno 	ib_queue_t *ib_q_array = softs->op_aio_ib_q;
329*1e66f787SSean Bruno 	ib_queue_t *ib_q = NULL;
330*1e66f787SSean Bruno 	char *ib_iu = NULL;
331*1e66f787SSean Bruno 	IO_PATH_T io_path = AIO_PATH;
332*1e66f787SSean Bruno 	uint32_t TraverseCount = 0;
333*1e66f787SSean Bruno 	int first_qindex = OS_GET_IO_REQ_QINDEX(softs, rcb);
334*1e66f787SSean Bruno 	int qindex = first_qindex;
335*1e66f787SSean Bruno 	uint32_t num_op_ib_q = softs->num_op_aio_ibq;
336*1e66f787SSean Bruno 	uint32_t num_elem_needed;
337*1e66f787SSean Bruno 	uint32_t num_elem_alloted = 0;
338*1e66f787SSean Bruno 	pqi_scsi_dev_t *devp = rcb->dvp;
339*1e66f787SSean Bruno 	uint8_t raidbypass_cdb[16];
340*1e66f787SSean Bruno 
341*1e66f787SSean Bruno 	DBG_FUNC(" IN ");
342*1e66f787SSean Bruno 
343*1e66f787SSean Bruno 
344*1e66f787SSean Bruno 	rcb->cdbp = OS_GET_CDBP(rcb);
345*1e66f787SSean Bruno 
346*1e66f787SSean Bruno 	if(IS_AIO_PATH(devp)) {
347*1e66f787SSean Bruno 		/**  IO for Physical Drive  **/
348*1e66f787SSean Bruno 		/** Send in AIO PATH**/
349*1e66f787SSean Bruno 		rcb->ioaccel_handle = devp->ioaccel_handle;
350*1e66f787SSean Bruno 	} else {
351*1e66f787SSean Bruno 		int ret = PQI_STATUS_FAILURE;
352*1e66f787SSean Bruno 		/** IO for RAID Volume **/
353*1e66f787SSean Bruno 		if (devp->offload_enabled) {
354*1e66f787SSean Bruno 			/** ByPass IO ,Send in AIO PATH **/
355*1e66f787SSean Bruno 			ret = pqisrc_send_scsi_cmd_raidbypass(softs,
356*1e66f787SSean Bruno 				devp, rcb, raidbypass_cdb);
357*1e66f787SSean Bruno 		}
358*1e66f787SSean Bruno 
359*1e66f787SSean Bruno 		if (PQI_STATUS_FAILURE == ret) {
360*1e66f787SSean Bruno 			/** Send in RAID PATH **/
361*1e66f787SSean Bruno 			io_path = RAID_PATH;
362*1e66f787SSean Bruno 			num_op_ib_q = softs->num_op_raid_ibq;
363*1e66f787SSean Bruno 			ib_q_array = softs->op_raid_ib_q;
364*1e66f787SSean Bruno 		} else {
365*1e66f787SSean Bruno 			rcb->cdbp = raidbypass_cdb;
366*1e66f787SSean Bruno 		}
367*1e66f787SSean Bruno 	}
368*1e66f787SSean Bruno 
369*1e66f787SSean Bruno 	num_elem_needed = pqisrc_num_elem_needed(softs, OS_GET_IO_SG_COUNT(rcb));
370*1e66f787SSean Bruno 	DBG_IO("num_elem_needed :%d",num_elem_needed);
371*1e66f787SSean Bruno 
372*1e66f787SSean Bruno 	do {
373*1e66f787SSean Bruno 		uint32_t num_elem_available;
374*1e66f787SSean Bruno 		ib_q = (ib_q_array + qindex);
375*1e66f787SSean Bruno 		PQI_LOCK(&ib_q->lock);
376*1e66f787SSean Bruno 		num_elem_available = pqisrc_contiguous_free_elem(ib_q->pi_local,
377*1e66f787SSean Bruno 					*(ib_q->ci_virt_addr), ib_q->num_elem);
378*1e66f787SSean Bruno 
379*1e66f787SSean Bruno 		DBG_IO("num_elem_avialable :%d\n",num_elem_available);
380*1e66f787SSean Bruno 		if(num_elem_available >= num_elem_needed) {
381*1e66f787SSean Bruno 			num_elem_alloted = num_elem_needed;
382*1e66f787SSean Bruno 			break;
383*1e66f787SSean Bruno 		}
384*1e66f787SSean Bruno 		DBG_IO("Current queue is busy! Hop to next queue\n");
385*1e66f787SSean Bruno 
386*1e66f787SSean Bruno 		PQI_UNLOCK(&ib_q->lock);
387*1e66f787SSean Bruno 		qindex = (qindex + 1) % num_op_ib_q;
388*1e66f787SSean Bruno 		if(qindex == first_qindex) {
389*1e66f787SSean Bruno 			if (num_elem_needed == 1)
390*1e66f787SSean Bruno 				break;
391*1e66f787SSean Bruno 			TraverseCount += 1;
392*1e66f787SSean Bruno 			num_elem_needed = 1;
393*1e66f787SSean Bruno 		}
394*1e66f787SSean Bruno 	}while(TraverseCount < 2);
395*1e66f787SSean Bruno 
396*1e66f787SSean Bruno 	DBG_IO("num_elem_alloted :%d",num_elem_alloted);
397*1e66f787SSean Bruno 	if (num_elem_alloted == 0) {
398*1e66f787SSean Bruno 		DBG_WARN("OUT: IB Queues were full\n");
399*1e66f787SSean Bruno 		return PQI_STATUS_QFULL;
400*1e66f787SSean Bruno 	}
401*1e66f787SSean Bruno 
402*1e66f787SSean Bruno 	/* Get IB Queue Slot address to build IU */
403*1e66f787SSean Bruno 	ib_iu = ib_q->array_virt_addr + (ib_q->pi_local * ib_q->elem_size);
404*1e66f787SSean Bruno 
405*1e66f787SSean Bruno 	if(io_path == AIO_PATH) {
406*1e66f787SSean Bruno 		/** Build AIO structure **/
407*1e66f787SSean Bruno  		pqisrc_build_aio_io(softs, rcb, (pqi_aio_req_t*)ib_iu,
408*1e66f787SSean Bruno  			num_elem_alloted);
409*1e66f787SSean Bruno 	} else {
410*1e66f787SSean Bruno 		/** Build RAID structure **/
411*1e66f787SSean Bruno 		pqisrc_build_raid_io(softs, rcb, (pqisrc_raid_req_t*)ib_iu,
412*1e66f787SSean Bruno 			num_elem_alloted);
413*1e66f787SSean Bruno 	}
414*1e66f787SSean Bruno 
415*1e66f787SSean Bruno 	rcb->req_pending = true;
416*1e66f787SSean Bruno 
417*1e66f787SSean Bruno 	/* Update the local PI */
418*1e66f787SSean Bruno 	ib_q->pi_local = (ib_q->pi_local + num_elem_alloted) % ib_q->num_elem;
419*1e66f787SSean Bruno 
420*1e66f787SSean Bruno 	DBG_INFO("ib_q->pi_local : %x\n", ib_q->pi_local);
421*1e66f787SSean Bruno 	DBG_INFO("*ib_q->ci_virt_addr: %x\n",*(ib_q->ci_virt_addr));
422*1e66f787SSean Bruno 
423*1e66f787SSean Bruno 	/* Inform the fw about the new IU */
424*1e66f787SSean Bruno 	PCI_MEM_PUT32(softs, ib_q->pi_register_abs, ib_q->pi_register_offset, ib_q->pi_local);
425*1e66f787SSean Bruno 
426*1e66f787SSean Bruno 	PQI_UNLOCK(&ib_q->lock);
427*1e66f787SSean Bruno 	DBG_FUNC(" OUT ");
428*1e66f787SSean Bruno 	return PQI_STATUS_SUCCESS;
429*1e66f787SSean Bruno }
430*1e66f787SSean Bruno 
431*1e66f787SSean Bruno /* Subroutine used to set encryption info as part of RAID bypass IO*/
432*1e66f787SSean Bruno static inline void pqisrc_set_enc_info(
433*1e66f787SSean Bruno 	struct pqi_enc_info *enc_info, struct raid_map *raid_map,
434*1e66f787SSean Bruno 	uint64_t first_block)
435*1e66f787SSean Bruno {
436*1e66f787SSean Bruno 	uint32_t volume_blk_size;
437*1e66f787SSean Bruno 
438*1e66f787SSean Bruno 	/*
439*1e66f787SSean Bruno 	 * Set the encryption tweak values based on logical block address.
440*1e66f787SSean Bruno 	 * If the block size is 512, the tweak value is equal to the LBA.
441*1e66f787SSean Bruno 	 * For other block sizes, tweak value is (LBA * block size) / 512.
442*1e66f787SSean Bruno 	 */
443*1e66f787SSean Bruno 	volume_blk_size = GET_LE32((uint8_t *)&raid_map->volume_blk_size);
444*1e66f787SSean Bruno 	if (volume_blk_size != 512)
445*1e66f787SSean Bruno 		first_block = (first_block * volume_blk_size) / 512;
446*1e66f787SSean Bruno 
447*1e66f787SSean Bruno 	enc_info->data_enc_key_index =
448*1e66f787SSean Bruno 		GET_LE16((uint8_t *)&raid_map->data_encryption_key_index);
449*1e66f787SSean Bruno 	enc_info->encrypt_tweak_upper = ((uint32_t)(((first_block) >> 16) >> 16));
450*1e66f787SSean Bruno 	enc_info->encrypt_tweak_lower = ((uint32_t)(first_block));
451*1e66f787SSean Bruno }
452*1e66f787SSean Bruno 
453*1e66f787SSean Bruno 
454*1e66f787SSean Bruno /*
455*1e66f787SSean Bruno  * Attempt to perform offload RAID mapping for a logical volume I/O.
456*1e66f787SSean Bruno  */
457*1e66f787SSean Bruno 
458*1e66f787SSean Bruno #define HPSA_RAID_0		0
459*1e66f787SSean Bruno #define HPSA_RAID_4		1
460*1e66f787SSean Bruno #define HPSA_RAID_1		2	/* also used for RAID 10 */
461*1e66f787SSean Bruno #define HPSA_RAID_5		3	/* also used for RAID 50 */
462*1e66f787SSean Bruno #define HPSA_RAID_51		4
463*1e66f787SSean Bruno #define HPSA_RAID_6		5	/* also used for RAID 60 */
464*1e66f787SSean Bruno #define HPSA_RAID_ADM		6	/* also used for RAID 1+0 ADM */
465*1e66f787SSean Bruno #define HPSA_RAID_MAX		HPSA_RAID_ADM
466*1e66f787SSean Bruno #define HPSA_RAID_UNKNOWN	0xff
467*1e66f787SSean Bruno 
468*1e66f787SSean Bruno /* Subroutine used to parse the scsi opcode and build the CDB for RAID bypass*/
469*1e66f787SSean Bruno int check_for_scsi_opcode(uint8_t *cdb, boolean_t *is_write, uint64_t *fst_blk,
470*1e66f787SSean Bruno 				uint32_t *blk_cnt) {
471*1e66f787SSean Bruno 
472*1e66f787SSean Bruno 	switch (cdb[0]) {
473*1e66f787SSean Bruno 	case SCMD_WRITE_6:
474*1e66f787SSean Bruno 		*is_write = true;
475*1e66f787SSean Bruno 	case SCMD_READ_6:
476*1e66f787SSean Bruno 		*fst_blk = (uint64_t)(((cdb[1] & 0x1F) << 16) |
477*1e66f787SSean Bruno 				(cdb[2] << 8) | cdb[3]);
478*1e66f787SSean Bruno 		*blk_cnt = (uint32_t)cdb[4];
479*1e66f787SSean Bruno 		if (*blk_cnt == 0)
480*1e66f787SSean Bruno 			*blk_cnt = 256;
481*1e66f787SSean Bruno 		break;
482*1e66f787SSean Bruno 	case SCMD_WRITE_10:
483*1e66f787SSean Bruno 		*is_write = true;
484*1e66f787SSean Bruno 	case SCMD_READ_10:
485*1e66f787SSean Bruno 		*fst_blk = (uint64_t)GET_BE32(&cdb[2]);
486*1e66f787SSean Bruno 		*blk_cnt = (uint32_t)GET_BE16(&cdb[7]);
487*1e66f787SSean Bruno 		break;
488*1e66f787SSean Bruno 	case SCMD_WRITE_12:
489*1e66f787SSean Bruno 		*is_write = true;
490*1e66f787SSean Bruno 	case SCMD_READ_12:
491*1e66f787SSean Bruno 		*fst_blk = (uint64_t)GET_BE32(&cdb[2]);
492*1e66f787SSean Bruno 		*blk_cnt = GET_BE32(&cdb[6]);
493*1e66f787SSean Bruno 		break;
494*1e66f787SSean Bruno 	case SCMD_WRITE_16:
495*1e66f787SSean Bruno 		*is_write = true;
496*1e66f787SSean Bruno 	case SCMD_READ_16:
497*1e66f787SSean Bruno 		*fst_blk = GET_BE64(&cdb[2]);
498*1e66f787SSean Bruno 		*blk_cnt = GET_BE32(&cdb[10]);
499*1e66f787SSean Bruno 		break;
500*1e66f787SSean Bruno 	default:
501*1e66f787SSean Bruno 		/* Process via normal I/O path. */
502*1e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
503*1e66f787SSean Bruno 	}
504*1e66f787SSean Bruno 	return PQI_STATUS_SUCCESS;
505*1e66f787SSean Bruno }
506*1e66f787SSean Bruno 
507*1e66f787SSean Bruno /*
508*1e66f787SSean Bruno  * Function used to build and send RAID bypass request to the adapter
509*1e66f787SSean Bruno  */
510*1e66f787SSean Bruno int pqisrc_send_scsi_cmd_raidbypass(pqisrc_softstate_t *softs,
511*1e66f787SSean Bruno 				pqi_scsi_dev_t *device, rcb_t *rcb, uint8_t *cdb)
512*1e66f787SSean Bruno {
513*1e66f787SSean Bruno 	struct raid_map *raid_map;
514*1e66f787SSean Bruno 	boolean_t is_write = false;
515*1e66f787SSean Bruno 	uint32_t map_idx;
516*1e66f787SSean Bruno 	uint64_t fst_blk, lst_blk;
517*1e66f787SSean Bruno 	uint32_t blk_cnt, blks_per_row;
518*1e66f787SSean Bruno 	uint64_t fst_row, lst_row;
519*1e66f787SSean Bruno 	uint32_t fst_row_offset, lst_row_offset;
520*1e66f787SSean Bruno 	uint32_t fst_col, lst_col;
521*1e66f787SSean Bruno 	uint32_t r5or6_blks_per_row;
522*1e66f787SSean Bruno 	uint64_t r5or6_fst_row, r5or6_lst_row;
523*1e66f787SSean Bruno 	uint32_t r5or6_fst_row_offset, r5or6_lst_row_offset;
524*1e66f787SSean Bruno 	uint32_t r5or6_fst_col, r5or6_lst_col;
525*1e66f787SSean Bruno 	uint16_t data_disks_per_row, total_disks_per_row;
526*1e66f787SSean Bruno 	uint16_t layout_map_count;
527*1e66f787SSean Bruno 	uint32_t stripesz;
528*1e66f787SSean Bruno 	uint16_t strip_sz;
529*1e66f787SSean Bruno 	uint32_t fst_grp, lst_grp, cur_grp;
530*1e66f787SSean Bruno 	uint32_t map_row;
531*1e66f787SSean Bruno 	uint64_t disk_block;
532*1e66f787SSean Bruno 	uint32_t disk_blk_cnt;
533*1e66f787SSean Bruno 	uint8_t cdb_length;
534*1e66f787SSean Bruno 	int offload_to_mirror;
535*1e66f787SSean Bruno 	int i;
536*1e66f787SSean Bruno 	DBG_FUNC(" IN \n");
537*1e66f787SSean Bruno 	DBG_IO("!!!!!\n");
538*1e66f787SSean Bruno 
539*1e66f787SSean Bruno 	/* Check for eligible opcode, get LBA and block count. */
540*1e66f787SSean Bruno 	memcpy(cdb, OS_GET_CDBP(rcb), rcb->cmdlen);
541*1e66f787SSean Bruno 
542*1e66f787SSean Bruno 	for(i = 0; i < rcb->cmdlen ; i++)
543*1e66f787SSean Bruno 		DBG_IO(" CDB [ %d ] : %x\n",i,cdb[i]);
544*1e66f787SSean Bruno 	if(check_for_scsi_opcode(cdb, &is_write,
545*1e66f787SSean Bruno 		&fst_blk, &blk_cnt) == PQI_STATUS_FAILURE)
546*1e66f787SSean Bruno 			return PQI_STATUS_FAILURE;
547*1e66f787SSean Bruno 	/* Check for write to non-RAID-0. */
548*1e66f787SSean Bruno 	if (is_write && device->raid_level != SA_RAID_0)
549*1e66f787SSean Bruno 		return PQI_STATUS_FAILURE;;
550*1e66f787SSean Bruno 
551*1e66f787SSean Bruno 	if(blk_cnt == 0)
552*1e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
553*1e66f787SSean Bruno 
554*1e66f787SSean Bruno 	lst_blk = fst_blk + blk_cnt - 1;
555*1e66f787SSean Bruno 	raid_map = device->raid_map;
556*1e66f787SSean Bruno 
557*1e66f787SSean Bruno 	/* Check for invalid block or wraparound. */
558*1e66f787SSean Bruno 	if (lst_blk >= GET_LE64((uint8_t *)&raid_map->volume_blk_cnt) ||
559*1e66f787SSean Bruno 		lst_blk < fst_blk)
560*1e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
561*1e66f787SSean Bruno 
562*1e66f787SSean Bruno 	data_disks_per_row = GET_LE16((uint8_t *)&raid_map->data_disks_per_row);
563*1e66f787SSean Bruno 	strip_sz = GET_LE16((uint8_t *)(&raid_map->strip_size));
564*1e66f787SSean Bruno 	layout_map_count = GET_LE16((uint8_t *)(&raid_map->layout_map_count));
565*1e66f787SSean Bruno 
566*1e66f787SSean Bruno 	/* Calculate stripe information for the request. */
567*1e66f787SSean Bruno 	blks_per_row = data_disks_per_row * strip_sz;
568*1e66f787SSean Bruno 
569*1e66f787SSean Bruno 	/* use __udivdi3 ? */
570*1e66f787SSean Bruno 	fst_row = fst_blk / blks_per_row;
571*1e66f787SSean Bruno 	lst_row = lst_blk / blks_per_row;
572*1e66f787SSean Bruno 	fst_row_offset = (uint32_t)(fst_blk - (fst_row * blks_per_row));
573*1e66f787SSean Bruno 	lst_row_offset = (uint32_t)(lst_blk - (lst_row * blks_per_row));
574*1e66f787SSean Bruno 	fst_col = fst_row_offset / strip_sz;
575*1e66f787SSean Bruno 	lst_col = lst_row_offset / strip_sz;
576*1e66f787SSean Bruno 
577*1e66f787SSean Bruno 	/* If this isn't a single row/column then give to the controller. */
578*1e66f787SSean Bruno 	if (fst_row != lst_row || fst_col != lst_col)
579*1e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
580*1e66f787SSean Bruno 
581*1e66f787SSean Bruno 	/* Proceeding with driver mapping. */
582*1e66f787SSean Bruno 	total_disks_per_row = data_disks_per_row +
583*1e66f787SSean Bruno 		GET_LE16((uint8_t *)(&raid_map->metadata_disks_per_row));
584*1e66f787SSean Bruno 	map_row = ((uint32_t)(fst_row >> raid_map->parity_rotation_shift)) %
585*1e66f787SSean Bruno 		GET_LE16((uint8_t *)(&raid_map->row_cnt));
586*1e66f787SSean Bruno 	map_idx = (map_row * total_disks_per_row) + fst_col;
587*1e66f787SSean Bruno 
588*1e66f787SSean Bruno 	/* RAID 1 */
589*1e66f787SSean Bruno 	if (device->raid_level == SA_RAID_1) {
590*1e66f787SSean Bruno 		if (device->offload_to_mirror)
591*1e66f787SSean Bruno 			map_idx += data_disks_per_row;
592*1e66f787SSean Bruno 		device->offload_to_mirror = !device->offload_to_mirror;
593*1e66f787SSean Bruno 	} else if (device->raid_level == SA_RAID_ADM) {
594*1e66f787SSean Bruno 		/* RAID ADM */
595*1e66f787SSean Bruno 		/*
596*1e66f787SSean Bruno 		 * Handles N-way mirrors  (R1-ADM) and R10 with # of drives
597*1e66f787SSean Bruno 		 * divisible by 3.
598*1e66f787SSean Bruno 		 */
599*1e66f787SSean Bruno 		offload_to_mirror = device->offload_to_mirror;
600*1e66f787SSean Bruno 		if (offload_to_mirror == 0)  {
601*1e66f787SSean Bruno 			/* use physical disk in the first mirrored group. */
602*1e66f787SSean Bruno 			map_idx %= data_disks_per_row;
603*1e66f787SSean Bruno 		} else {
604*1e66f787SSean Bruno 			do {
605*1e66f787SSean Bruno 				/*
606*1e66f787SSean Bruno 				 * Determine mirror group that map_idx
607*1e66f787SSean Bruno 				 * indicates.
608*1e66f787SSean Bruno 				 */
609*1e66f787SSean Bruno 				cur_grp = map_idx / data_disks_per_row;
610*1e66f787SSean Bruno 
611*1e66f787SSean Bruno 				if (offload_to_mirror != cur_grp) {
612*1e66f787SSean Bruno 					if (cur_grp <
613*1e66f787SSean Bruno 						layout_map_count - 1) {
614*1e66f787SSean Bruno 						/*
615*1e66f787SSean Bruno 						 * Select raid index from
616*1e66f787SSean Bruno 						 * next group.
617*1e66f787SSean Bruno 						 */
618*1e66f787SSean Bruno 						map_idx += data_disks_per_row;
619*1e66f787SSean Bruno 						cur_grp++;
620*1e66f787SSean Bruno 					} else {
621*1e66f787SSean Bruno 						/*
622*1e66f787SSean Bruno 						 * Select raid index from first
623*1e66f787SSean Bruno 						 * group.
624*1e66f787SSean Bruno 						 */
625*1e66f787SSean Bruno 						map_idx %= data_disks_per_row;
626*1e66f787SSean Bruno 						cur_grp = 0;
627*1e66f787SSean Bruno 					}
628*1e66f787SSean Bruno 				}
629*1e66f787SSean Bruno 			} while (offload_to_mirror != cur_grp);
630*1e66f787SSean Bruno 		}
631*1e66f787SSean Bruno 
632*1e66f787SSean Bruno 		/* Set mirror group to use next time. */
633*1e66f787SSean Bruno 		offload_to_mirror =
634*1e66f787SSean Bruno 			(offload_to_mirror >= layout_map_count - 1) ?
635*1e66f787SSean Bruno 				0 : offload_to_mirror + 1;
636*1e66f787SSean Bruno 		if(offload_to_mirror >= layout_map_count)
637*1e66f787SSean Bruno 			return PQI_STATUS_FAILURE;
638*1e66f787SSean Bruno 
639*1e66f787SSean Bruno 		device->offload_to_mirror = offload_to_mirror;
640*1e66f787SSean Bruno 		/*
641*1e66f787SSean Bruno 		 * Avoid direct use of device->offload_to_mirror within this
642*1e66f787SSean Bruno 		 * function since multiple threads might simultaneously
643*1e66f787SSean Bruno 		 * increment it beyond the range of device->layout_map_count -1.
644*1e66f787SSean Bruno 		 */
645*1e66f787SSean Bruno 	} else if ((device->raid_level == SA_RAID_5 ||
646*1e66f787SSean Bruno 		device->raid_level == SA_RAID_6) && layout_map_count > 1) {
647*1e66f787SSean Bruno 		/* RAID 50/60 */
648*1e66f787SSean Bruno 		/* Verify first and last block are in same RAID group */
649*1e66f787SSean Bruno 		r5or6_blks_per_row = strip_sz * data_disks_per_row;
650*1e66f787SSean Bruno 		stripesz = r5or6_blks_per_row * layout_map_count;
651*1e66f787SSean Bruno 
652*1e66f787SSean Bruno 		fst_grp = (fst_blk % stripesz) / r5or6_blks_per_row;
653*1e66f787SSean Bruno 		lst_grp = (lst_blk % stripesz) / r5or6_blks_per_row;
654*1e66f787SSean Bruno 
655*1e66f787SSean Bruno 		if (fst_grp != lst_grp)
656*1e66f787SSean Bruno 			return PQI_STATUS_FAILURE;
657*1e66f787SSean Bruno 
658*1e66f787SSean Bruno 		/* Verify request is in a single row of RAID 5/6 */
659*1e66f787SSean Bruno 		fst_row = r5or6_fst_row =
660*1e66f787SSean Bruno 			fst_blk / stripesz;
661*1e66f787SSean Bruno 		r5or6_lst_row = lst_blk / stripesz;
662*1e66f787SSean Bruno 
663*1e66f787SSean Bruno 		if (r5or6_fst_row != r5or6_lst_row)
664*1e66f787SSean Bruno 			return PQI_STATUS_FAILURE;
665*1e66f787SSean Bruno 
666*1e66f787SSean Bruno 		/* Verify request is in a single column */
667*1e66f787SSean Bruno 		fst_row_offset = r5or6_fst_row_offset =
668*1e66f787SSean Bruno 			(uint32_t)((fst_blk % stripesz) %
669*1e66f787SSean Bruno 			r5or6_blks_per_row);
670*1e66f787SSean Bruno 
671*1e66f787SSean Bruno 		r5or6_lst_row_offset =
672*1e66f787SSean Bruno 			(uint32_t)((lst_blk % stripesz) %
673*1e66f787SSean Bruno 			r5or6_blks_per_row);
674*1e66f787SSean Bruno 
675*1e66f787SSean Bruno 		fst_col = r5or6_fst_row_offset / strip_sz;
676*1e66f787SSean Bruno 		r5or6_fst_col = fst_col;
677*1e66f787SSean Bruno 		r5or6_lst_col = r5or6_lst_row_offset / strip_sz;
678*1e66f787SSean Bruno 
679*1e66f787SSean Bruno 		if (r5or6_fst_col != r5or6_lst_col)
680*1e66f787SSean Bruno 			return PQI_STATUS_FAILURE;
681*1e66f787SSean Bruno 
682*1e66f787SSean Bruno 		/* Request is eligible */
683*1e66f787SSean Bruno 		map_row =
684*1e66f787SSean Bruno 			((uint32_t)(fst_row >> raid_map->parity_rotation_shift)) %
685*1e66f787SSean Bruno 			GET_LE16((uint8_t *)(&raid_map->row_cnt));
686*1e66f787SSean Bruno 
687*1e66f787SSean Bruno 		map_idx = (fst_grp *
688*1e66f787SSean Bruno 			(GET_LE16((uint8_t *)(&raid_map->row_cnt)) *
689*1e66f787SSean Bruno 			total_disks_per_row)) +
690*1e66f787SSean Bruno 			(map_row * total_disks_per_row) + fst_col;
691*1e66f787SSean Bruno 	}
692*1e66f787SSean Bruno 
693*1e66f787SSean Bruno 	if (map_idx >= RAID_MAP_MAX_ENTRIES)
694*1e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
695*1e66f787SSean Bruno 
696*1e66f787SSean Bruno 	rcb->ioaccel_handle = raid_map->dev_data[map_idx].ioaccel_handle;
697*1e66f787SSean Bruno 	disk_block = GET_LE64((uint8_t *)(&raid_map->disk_starting_blk)) +
698*1e66f787SSean Bruno 		fst_row * strip_sz +
699*1e66f787SSean Bruno 		(fst_row_offset - fst_col * strip_sz);
700*1e66f787SSean Bruno 	disk_blk_cnt = blk_cnt;
701*1e66f787SSean Bruno 
702*1e66f787SSean Bruno 	/* Handle differing logical/physical block sizes. */
703*1e66f787SSean Bruno 	if (raid_map->phys_blk_shift) {
704*1e66f787SSean Bruno 		disk_block <<= raid_map->phys_blk_shift;
705*1e66f787SSean Bruno 		disk_blk_cnt <<= raid_map->phys_blk_shift;
706*1e66f787SSean Bruno 	}
707*1e66f787SSean Bruno 
708*1e66f787SSean Bruno 	if (disk_blk_cnt > 0xffff)
709*1e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
710*1e66f787SSean Bruno 
711*1e66f787SSean Bruno 	/* Build the new CDB for the physical disk I/O. */
712*1e66f787SSean Bruno 	if (disk_block > 0xffffffff) {
713*1e66f787SSean Bruno 		cdb[0] = is_write ? SCMD_WRITE_16 : SCMD_READ_16;
714*1e66f787SSean Bruno 		cdb[1] = 0;
715*1e66f787SSean Bruno 		PUT_BE64(disk_block, &cdb[2]);
716*1e66f787SSean Bruno 		PUT_BE32(disk_blk_cnt, &cdb[10]);
717*1e66f787SSean Bruno 		cdb[14] = 0;
718*1e66f787SSean Bruno 		cdb[15] = 0;
719*1e66f787SSean Bruno 		cdb_length = 16;
720*1e66f787SSean Bruno 	} else {
721*1e66f787SSean Bruno 		cdb[0] = is_write ? SCMD_WRITE_10 : SCMD_READ_10;
722*1e66f787SSean Bruno 		cdb[1] = 0;
723*1e66f787SSean Bruno 		PUT_BE32(disk_block, &cdb[2]);
724*1e66f787SSean Bruno 		cdb[6] = 0;
725*1e66f787SSean Bruno 		PUT_BE16(disk_blk_cnt, &cdb[7]);
726*1e66f787SSean Bruno 		cdb[9] = 0;
727*1e66f787SSean Bruno 		cdb_length = 10;
728*1e66f787SSean Bruno 	}
729*1e66f787SSean Bruno 
730*1e66f787SSean Bruno 	if (GET_LE16((uint8_t *)(&raid_map->flags)) &
731*1e66f787SSean Bruno 		RAID_MAP_ENCRYPTION_ENABLED) {
732*1e66f787SSean Bruno 		pqisrc_set_enc_info(&rcb->enc_info, raid_map,
733*1e66f787SSean Bruno 			fst_blk);
734*1e66f787SSean Bruno 		rcb->encrypt_enable = true;
735*1e66f787SSean Bruno 	} else {
736*1e66f787SSean Bruno 		rcb->encrypt_enable = false;
737*1e66f787SSean Bruno 	}
738*1e66f787SSean Bruno 
739*1e66f787SSean Bruno 	rcb->cmdlen = cdb_length;
740*1e66f787SSean Bruno 
741*1e66f787SSean Bruno 
742*1e66f787SSean Bruno 	DBG_FUNC("OUT");
743*1e66f787SSean Bruno 
744*1e66f787SSean Bruno 	return PQI_STATUS_SUCCESS;
745*1e66f787SSean Bruno }
746*1e66f787SSean Bruno 
747*1e66f787SSean Bruno /* Function used to submit a TMF to the adater */
748*1e66f787SSean Bruno int pqisrc_send_tmf(pqisrc_softstate_t *softs, pqi_scsi_dev_t *devp,
749*1e66f787SSean Bruno                     rcb_t *rcb, int req_id, int tmf_type)
750*1e66f787SSean Bruno {
751*1e66f787SSean Bruno 	int rval = PQI_STATUS_SUCCESS;
752*1e66f787SSean Bruno 	pqi_tmf_req_t tmf_req;
753*1e66f787SSean Bruno 
754*1e66f787SSean Bruno 	memset(&tmf_req, 0, sizeof(pqi_tmf_req_t));
755*1e66f787SSean Bruno 
756*1e66f787SSean Bruno 	DBG_FUNC("IN");
757*1e66f787SSean Bruno 
758*1e66f787SSean Bruno 	tmf_req.header.iu_type = PQI_REQUEST_IU_TASK_MANAGEMENT;
759*1e66f787SSean Bruno 	tmf_req.header.iu_length = sizeof(tmf_req) - sizeof(iu_header_t);
760*1e66f787SSean Bruno 	tmf_req.req_id = rcb->tag;
761*1e66f787SSean Bruno 
762*1e66f787SSean Bruno 	memcpy(tmf_req.lun, devp->scsi3addr, sizeof(tmf_req.lun));
763*1e66f787SSean Bruno 	tmf_req.tmf = tmf_type;
764*1e66f787SSean Bruno 	tmf_req.req_id_to_manage = req_id;
765*1e66f787SSean Bruno 	tmf_req.resp_qid = OS_GET_TMF_RESP_QID(softs, rcb);
766*1e66f787SSean Bruno 	tmf_req.obq_id_to_manage = rcb->resp_qid;
767*1e66f787SSean Bruno 
768*1e66f787SSean Bruno 	rcb->req_pending = true;
769*1e66f787SSean Bruno 
770*1e66f787SSean Bruno 	rval = pqisrc_submit_cmnd(softs,
771*1e66f787SSean Bruno 	&softs->op_raid_ib_q[OS_GET_TMF_REQ_QINDEX(softs, rcb)], &tmf_req);
772*1e66f787SSean Bruno 	if (rval != PQI_STATUS_SUCCESS) {
773*1e66f787SSean Bruno 		DBG_ERR("Unable to submit command rval=%d\n", rval);
774*1e66f787SSean Bruno 		return rval;
775*1e66f787SSean Bruno 	}
776*1e66f787SSean Bruno 
777*1e66f787SSean Bruno 	rval = pqisrc_wait_on_condition(softs, rcb);
778*1e66f787SSean Bruno 	if (rval != PQI_STATUS_SUCCESS){
779*1e66f787SSean Bruno 		DBG_ERR("Task Management tmf_type : %d timeout\n", tmf_type);
780*1e66f787SSean Bruno 		rcb->status = REQUEST_FAILED;
781*1e66f787SSean Bruno 	}
782*1e66f787SSean Bruno 
783*1e66f787SSean Bruno 	if (rcb->status  != REQUEST_SUCCESS) {
784*1e66f787SSean Bruno 		DBG_ERR_BTL(devp, "Task Management failed tmf_type:%d "
785*1e66f787SSean Bruno 				"stat:0x%x\n", tmf_type, rcb->status);
786*1e66f787SSean Bruno 		rval = PQI_STATUS_FAILURE;
787*1e66f787SSean Bruno 	}
788*1e66f787SSean Bruno 
789*1e66f787SSean Bruno 	DBG_FUNC("OUT");
790*1e66f787SSean Bruno 	return rval;
791*1e66f787SSean Bruno }
792