xref: /freebsd/sys/dev/smartpqi/smartpqi_request.c (revision b17f4335d2becd4ad1a74636675e4a3d273807a2)
11e66f787SSean Bruno /*-
21e66f787SSean Bruno  * Copyright (c) 2018 Microsemi Corporation.
31e66f787SSean Bruno  * All rights reserved.
41e66f787SSean Bruno  *
51e66f787SSean Bruno  * Redistribution and use in source and binary forms, with or without
61e66f787SSean Bruno  * modification, are permitted provided that the following conditions
71e66f787SSean Bruno  * are met:
81e66f787SSean Bruno  * 1. Redistributions of source code must retain the above copyright
91e66f787SSean Bruno  *    notice, this list of conditions and the following disclaimer.
101e66f787SSean Bruno  * 2. Redistributions in binary form must reproduce the above copyright
111e66f787SSean Bruno  *    notice, this list of conditions and the following disclaimer in the
121e66f787SSean Bruno  *    documentation and/or other materials provided with the distribution.
131e66f787SSean Bruno  *
141e66f787SSean Bruno  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151e66f787SSean Bruno  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161e66f787SSean Bruno  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171e66f787SSean Bruno  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181e66f787SSean Bruno  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191e66f787SSean Bruno  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201e66f787SSean Bruno  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211e66f787SSean Bruno  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221e66f787SSean Bruno  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231e66f787SSean Bruno  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241e66f787SSean Bruno  * SUCH DAMAGE.
251e66f787SSean Bruno  */
261e66f787SSean Bruno 
271e66f787SSean Bruno /* $FreeBSD$ */
281e66f787SSean Bruno 
291e66f787SSean Bruno #include "smartpqi_includes.h"
301e66f787SSean Bruno 
311e66f787SSean Bruno #define SG_FLAG_LAST	0x40000000
321e66f787SSean Bruno #define SG_FLAG_CHAIN	0x80000000
331e66f787SSean Bruno 
341e66f787SSean Bruno /* Subroutine to find out embedded sgl count in IU */
351e66f787SSean Bruno static inline
361e66f787SSean Bruno uint32_t pqisrc_embedded_sgl_count(uint32_t elem_alloted)
371e66f787SSean Bruno {
381e66f787SSean Bruno 	uint32_t embedded_sgl_count = MAX_EMBEDDED_SG_IN_FIRST_IU;
391e66f787SSean Bruno 	DBG_FUNC(" IN ");
401e66f787SSean Bruno 	/**
411e66f787SSean Bruno 	calculate embedded sgl count using num_elem_alloted for IO
421e66f787SSean Bruno 	**/
431e66f787SSean Bruno 	if(elem_alloted - 1)
441e66f787SSean Bruno 		embedded_sgl_count += ((elem_alloted - 1) * MAX_EMBEDDED_SG_IN_IU);
451e66f787SSean Bruno 	DBG_IO("embedded_sgl_count :%d\n",embedded_sgl_count);
461e66f787SSean Bruno 
471e66f787SSean Bruno 	DBG_FUNC(" OUT ");
481e66f787SSean Bruno 
491e66f787SSean Bruno 	return embedded_sgl_count;
501e66f787SSean Bruno 
511e66f787SSean Bruno }
521e66f787SSean Bruno 
531e66f787SSean Bruno /* Subroutine to find out contiguous free elem in IU */
541e66f787SSean Bruno static inline
551e66f787SSean Bruno uint32_t pqisrc_contiguous_free_elem(uint32_t pi, uint32_t ci, uint32_t elem_in_q)
561e66f787SSean Bruno {
571e66f787SSean Bruno 	uint32_t contiguous_free_elem = 0;
581e66f787SSean Bruno 
591e66f787SSean Bruno 	DBG_FUNC(" IN ");
601e66f787SSean Bruno 
611e66f787SSean Bruno 	if(pi >= ci) {
621e66f787SSean Bruno 		contiguous_free_elem = (elem_in_q - pi);
631e66f787SSean Bruno 		if(ci == 0)
641e66f787SSean Bruno 			contiguous_free_elem -= 1;
651e66f787SSean Bruno 	} else {
661e66f787SSean Bruno 		contiguous_free_elem = (ci - pi - 1);
671e66f787SSean Bruno 	}
681e66f787SSean Bruno 
691e66f787SSean Bruno 	DBG_FUNC(" OUT ");
701e66f787SSean Bruno 
711e66f787SSean Bruno 	return contiguous_free_elem;
721e66f787SSean Bruno }
731e66f787SSean Bruno 
741e66f787SSean Bruno /* Subroutine to find out num of elements need for the request */
751e66f787SSean Bruno static uint32_t
761e66f787SSean Bruno pqisrc_num_elem_needed(pqisrc_softstate_t *softs, uint32_t SG_Count)
771e66f787SSean Bruno {
781e66f787SSean Bruno 	uint32_t num_sg;
791e66f787SSean Bruno 	uint32_t num_elem_required = 1;
801e66f787SSean Bruno 	DBG_FUNC(" IN ");
811e66f787SSean Bruno 	DBG_IO("SGL_Count :%d",SG_Count);
821e66f787SSean Bruno 	/********
831e66f787SSean Bruno 	If SG_Count greater than max sg per IU i.e 4 or 68
841e66f787SSean Bruno 	(4 is with out spanning or 68 is with spanning) chaining is required.
851e66f787SSean Bruno 	OR, If SG_Count <= MAX_EMBEDDED_SG_IN_FIRST_IU then,
861e66f787SSean Bruno 	on these two cases one element is enough.
871e66f787SSean Bruno 	********/
881e66f787SSean Bruno 	if(SG_Count > softs->max_sg_per_iu || SG_Count <= MAX_EMBEDDED_SG_IN_FIRST_IU)
891e66f787SSean Bruno 		return num_elem_required;
901e66f787SSean Bruno 	/*
911e66f787SSean Bruno 	SGL Count Other Than First IU
921e66f787SSean Bruno 	 */
931e66f787SSean Bruno 	num_sg = SG_Count - MAX_EMBEDDED_SG_IN_FIRST_IU;
941e66f787SSean Bruno 	num_elem_required += PQISRC_DIV_ROUND_UP(num_sg, MAX_EMBEDDED_SG_IN_IU);
951e66f787SSean Bruno 	DBG_FUNC(" OUT ");
961e66f787SSean Bruno 	return num_elem_required;
971e66f787SSean Bruno }
981e66f787SSean Bruno 
991e66f787SSean Bruno /* Subroutine to build SG list for the IU submission*/
1001e66f787SSean Bruno static
1011e66f787SSean Bruno boolean_t pqisrc_build_sgl(sgt_t *sg_array, rcb_t *rcb, iu_header_t *iu_hdr,
1021e66f787SSean Bruno 			uint32_t num_elem_alloted)
1031e66f787SSean Bruno {
1041e66f787SSean Bruno 	uint32_t i;
1051e66f787SSean Bruno 	uint32_t num_sg = OS_GET_IO_SG_COUNT(rcb);
1061e66f787SSean Bruno 	sgt_t *sgt = sg_array;
1071e66f787SSean Bruno 	sgt_t *sg_chain = NULL;
1081e66f787SSean Bruno 	boolean_t partial = false;
1091e66f787SSean Bruno 
1101e66f787SSean Bruno 	DBG_FUNC(" IN ");
1111e66f787SSean Bruno 
1121e66f787SSean Bruno 	DBG_IO("SGL_Count :%d",num_sg);
1131e66f787SSean Bruno 	if (0 == num_sg) {
1141e66f787SSean Bruno 		goto out;
1151e66f787SSean Bruno 	}
1161e66f787SSean Bruno 
1171e66f787SSean Bruno 	if (num_sg <= pqisrc_embedded_sgl_count(num_elem_alloted)) {
1181e66f787SSean Bruno 		for (i = 0; i < num_sg; i++, sgt++) {
1191e66f787SSean Bruno                         sgt->addr= OS_GET_IO_SG_ADDR(rcb,i);
1201e66f787SSean Bruno                         sgt->len= OS_GET_IO_SG_LEN(rcb,i);
1211e66f787SSean Bruno                         sgt->flags= 0;
1221e66f787SSean Bruno                 }
1231e66f787SSean Bruno 
1241e66f787SSean Bruno 		sg_array[num_sg - 1].flags = SG_FLAG_LAST;
1251e66f787SSean Bruno 	} else {
1261e66f787SSean Bruno 	/**
1271e66f787SSean Bruno 	SGL Chaining
1281e66f787SSean Bruno 	**/
1291e66f787SSean Bruno 		sg_chain = rcb->sg_chain_virt;
1301e66f787SSean Bruno 		sgt->addr = rcb->sg_chain_dma;
1311e66f787SSean Bruno 		sgt->len = num_sg * sizeof(sgt_t);
1321e66f787SSean Bruno 		sgt->flags = SG_FLAG_CHAIN;
1331e66f787SSean Bruno 
1341e66f787SSean Bruno 		sgt = sg_chain;
1351e66f787SSean Bruno 		for (i = 0; i < num_sg; i++, sgt++) {
1361e66f787SSean Bruno 			sgt->addr = OS_GET_IO_SG_ADDR(rcb,i);
1371e66f787SSean Bruno 			sgt->len = OS_GET_IO_SG_LEN(rcb,i);
1381e66f787SSean Bruno 			sgt->flags = 0;
1391e66f787SSean Bruno 		}
1401e66f787SSean Bruno 
1411e66f787SSean Bruno 		sg_chain[num_sg - 1].flags = SG_FLAG_LAST;
1421e66f787SSean Bruno 		num_sg = 1;
1431e66f787SSean Bruno 		partial = true;
1441e66f787SSean Bruno 
1451e66f787SSean Bruno 	}
1461e66f787SSean Bruno out:
1471e66f787SSean Bruno 	iu_hdr->iu_length = num_sg * sizeof(sgt_t);
1481e66f787SSean Bruno 	DBG_FUNC(" OUT ");
1491e66f787SSean Bruno 	return partial;
1501e66f787SSean Bruno 
1511e66f787SSean Bruno }
1521e66f787SSean Bruno 
1531e66f787SSean Bruno /*Subroutine used to Build the RAID request */
1541e66f787SSean Bruno static void
1551e66f787SSean Bruno pqisrc_build_raid_io(pqisrc_softstate_t *softs, rcb_t *rcb,
1561e66f787SSean Bruno  	pqisrc_raid_req_t *raid_req, uint32_t num_elem_alloted)
1571e66f787SSean Bruno {
1581e66f787SSean Bruno 	DBG_FUNC(" IN ");
1591e66f787SSean Bruno 
1601e66f787SSean Bruno 	raid_req->header.iu_type = PQI_IU_TYPE_RAID_PATH_IO_REQUEST;
1611e66f787SSean Bruno 	raid_req->header.comp_feature = 0;
1621e66f787SSean Bruno 	raid_req->response_queue_id = OS_GET_IO_RESP_QID(softs, rcb);
1631e66f787SSean Bruno 	raid_req->work_area[0] = 0;
1641e66f787SSean Bruno 	raid_req->work_area[1] = 0;
1651e66f787SSean Bruno 	raid_req->request_id = rcb->tag;
1661e66f787SSean Bruno 	raid_req->nexus_id = 0;
1671e66f787SSean Bruno 	raid_req->buffer_length = GET_SCSI_BUFFLEN(rcb);
1681e66f787SSean Bruno 	memcpy(raid_req->lun_number, rcb->dvp->scsi3addr,
1691e66f787SSean Bruno  		sizeof(raid_req->lun_number));
1701e66f787SSean Bruno 	raid_req->protocol_spec = 0;
1711e66f787SSean Bruno 	raid_req->data_direction = rcb->data_dir;
1721e66f787SSean Bruno 	raid_req->reserved1 = 0;
1731e66f787SSean Bruno 	raid_req->fence = 0;
1741e66f787SSean Bruno 	raid_req->error_index = raid_req->request_id;
1751e66f787SSean Bruno 	raid_req->reserved2 = 0;
1761e66f787SSean Bruno   	raid_req->task_attribute = OS_GET_TASK_ATTR(rcb);
1771e66f787SSean Bruno   	raid_req->command_priority = 0;
1781e66f787SSean Bruno 	raid_req->reserved3 = 0;
1791e66f787SSean Bruno 	raid_req->reserved4 = 0;
1801e66f787SSean Bruno 	raid_req->reserved5 = 0;
1811e66f787SSean Bruno 
1821e66f787SSean Bruno 	/* As cdb and additional_cdb_bytes are contiguous,
1831e66f787SSean Bruno 	   update them in a single statement */
1841e66f787SSean Bruno 	memcpy(raid_req->cdb, rcb->cdbp, rcb->cmdlen);
1851e66f787SSean Bruno #if 0
1861e66f787SSean Bruno 	DBG_IO("CDB :");
1871e66f787SSean Bruno 	for(i = 0; i < rcb->cmdlen ; i++)
1881e66f787SSean Bruno 		DBG_IO(" 0x%x \n ",raid_req->cdb[i]);
1891e66f787SSean Bruno #endif
1901e66f787SSean Bruno 
1911e66f787SSean Bruno 	switch (rcb->cmdlen) {
1921e66f787SSean Bruno 		case 6:
1931e66f787SSean Bruno 		case 10:
1941e66f787SSean Bruno 		case 12:
1951e66f787SSean Bruno 		case 16:
1961e66f787SSean Bruno 			raid_req->additional_cdb_bytes_usage =
1971e66f787SSean Bruno 				PQI_ADDITIONAL_CDB_BYTES_0;
1981e66f787SSean Bruno 			break;
1991e66f787SSean Bruno 		case 20:
2001e66f787SSean Bruno 			raid_req->additional_cdb_bytes_usage =
2011e66f787SSean Bruno 				PQI_ADDITIONAL_CDB_BYTES_4;
2021e66f787SSean Bruno 			break;
2031e66f787SSean Bruno 		case 24:
2041e66f787SSean Bruno 			raid_req->additional_cdb_bytes_usage =
2051e66f787SSean Bruno 				PQI_ADDITIONAL_CDB_BYTES_8;
2061e66f787SSean Bruno 			break;
2071e66f787SSean Bruno 		case 28:
2081e66f787SSean Bruno 			raid_req->additional_cdb_bytes_usage =
2091e66f787SSean Bruno 				PQI_ADDITIONAL_CDB_BYTES_12;
2101e66f787SSean Bruno 			break;
2111e66f787SSean Bruno 		case 32:
2121e66f787SSean Bruno 		default: /* todo:review again */
2131e66f787SSean Bruno 			raid_req->additional_cdb_bytes_usage =
2141e66f787SSean Bruno 				PQI_ADDITIONAL_CDB_BYTES_16;
2151e66f787SSean Bruno 			break;
2161e66f787SSean Bruno 	}
2171e66f787SSean Bruno 
2181e66f787SSean Bruno 	/* Frame SGL Descriptor */
2191e66f787SSean Bruno 	raid_req->partial = pqisrc_build_sgl(&raid_req->sg_descriptors[0], rcb,
2201e66f787SSean Bruno 		&raid_req->header, num_elem_alloted);
2211e66f787SSean Bruno 
2221e66f787SSean Bruno 	raid_req->header.iu_length +=
2231e66f787SSean Bruno 			offsetof(pqisrc_raid_req_t, sg_descriptors) - sizeof(iu_header_t);
2241e66f787SSean Bruno 
2251e66f787SSean Bruno #if 0
2261e66f787SSean Bruno 	DBG_IO("raid_req->header.iu_type : 0x%x", raid_req->header.iu_type);
2271e66f787SSean Bruno 	DBG_IO("raid_req->response_queue_id :%d\n"raid_req->response_queue_id);
2281e66f787SSean Bruno 	DBG_IO("raid_req->request_id : 0x%x", raid_req->request_id);
2291e66f787SSean Bruno 	DBG_IO("raid_req->buffer_length : 0x%x", raid_req->buffer_length);
2301e66f787SSean Bruno 	DBG_IO("raid_req->task_attribute : 0x%x", raid_req->task_attribute);
2311e66f787SSean Bruno 	DBG_IO("raid_req->lun_number  : 0x%x", raid_req->lun_number);
2321e66f787SSean Bruno 	DBG_IO("raid_req->error_index : 0x%x", raid_req->error_index);
2331e66f787SSean Bruno 	DBG_IO("raid_req->sg_descriptors[0].addr : %p", (void*)raid_req->sg_descriptors[0].addr);
2341e66f787SSean Bruno 	DBG_IO("raid_req->sg_descriptors[0].len : 0x%x", raid_req->sg_descriptors[0].len);
2351e66f787SSean Bruno 	DBG_IO("raid_req->sg_descriptors[0].flags : 0%x", raid_req->sg_descriptors[0].flags);
2361e66f787SSean Bruno #endif
2371e66f787SSean Bruno 	rcb->success_cmp_callback = pqisrc_process_io_response_success;
2381e66f787SSean Bruno 	rcb->error_cmp_callback = pqisrc_process_raid_response_error;
2391e66f787SSean Bruno 	rcb->resp_qid = raid_req->response_queue_id;
2401e66f787SSean Bruno 
2411e66f787SSean Bruno  	DBG_FUNC(" OUT ");
2421e66f787SSean Bruno 
2431e66f787SSean Bruno }
2441e66f787SSean Bruno 
2451e66f787SSean Bruno /*Subroutine used to Build the AIO request */
2461e66f787SSean Bruno static void
2471e66f787SSean Bruno pqisrc_build_aio_io(pqisrc_softstate_t *softs, rcb_t *rcb,
2481e66f787SSean Bruno  				pqi_aio_req_t *aio_req, uint32_t num_elem_alloted)
2491e66f787SSean Bruno {
2501e66f787SSean Bruno 	DBG_FUNC(" IN ");
2511e66f787SSean Bruno 
2521e66f787SSean Bruno 	aio_req->header.iu_type = PQI_IU_TYPE_AIO_PATH_IO_REQUEST;
2531e66f787SSean Bruno 	aio_req->header.comp_feature = 0;
2541e66f787SSean Bruno 	aio_req->response_queue_id = OS_GET_IO_RESP_QID(softs, rcb);
2551e66f787SSean Bruno 	aio_req->work_area[0] = 0;
2561e66f787SSean Bruno 	aio_req->work_area[1] = 0;
2571e66f787SSean Bruno 	aio_req->req_id = rcb->tag;
2581e66f787SSean Bruno 	aio_req->res1[0] = 0;
2591e66f787SSean Bruno 	aio_req->res1[1] = 0;
2601e66f787SSean Bruno 	aio_req->nexus = rcb->ioaccel_handle;
2611e66f787SSean Bruno 	aio_req->buf_len = GET_SCSI_BUFFLEN(rcb);
2621e66f787SSean Bruno 	aio_req->data_dir = rcb->data_dir;
2631e66f787SSean Bruno 	aio_req->mem_type = 0;
2641e66f787SSean Bruno 	aio_req->fence = 0;
2651e66f787SSean Bruno 	aio_req->res2 = 0;
2661e66f787SSean Bruno 	aio_req->task_attr = OS_GET_TASK_ATTR(rcb);
2671e66f787SSean Bruno 	aio_req->cmd_prio = 0;
2681e66f787SSean Bruno 	aio_req->res3 = 0;
2691e66f787SSean Bruno 	aio_req->err_idx = aio_req->req_id;
2701e66f787SSean Bruno 	aio_req->cdb_len = rcb->cmdlen;
271*b17f4335SSean Bruno 	if(rcb->cmdlen > sizeof(aio_req->cdb))
272*b17f4335SSean Bruno 		rcb->cmdlen = sizeof(aio_req->cdb);
2731e66f787SSean Bruno 	memcpy(aio_req->cdb, rcb->cdbp, rcb->cmdlen);
2741e66f787SSean Bruno #if 0
2751e66f787SSean Bruno 	DBG_IO("CDB : \n");
2761e66f787SSean Bruno 	for(int i = 0; i < rcb->cmdlen ; i++)
2771e66f787SSean Bruno 		 DBG_IO(" 0x%x \n",aio_req->cdb[i]);
2781e66f787SSean Bruno #endif
2791e66f787SSean Bruno 	memset(aio_req->lun,0,sizeof(aio_req->lun));
2801e66f787SSean Bruno 	memset(aio_req->res4,0,sizeof(aio_req->res4));
2811e66f787SSean Bruno 
2821e66f787SSean Bruno 	if(rcb->encrypt_enable == true) {
2831e66f787SSean Bruno 		aio_req->encrypt_enable = true;
2841e66f787SSean Bruno 		aio_req->encrypt_key_index = LE_16(rcb->enc_info.data_enc_key_index);
2851e66f787SSean Bruno 		aio_req->encrypt_twk_low = LE_32(rcb->enc_info.encrypt_tweak_lower);
2861e66f787SSean Bruno 		aio_req->encrypt_twk_high = LE_32(rcb->enc_info.encrypt_tweak_upper);
2871e66f787SSean Bruno 	} else {
2881e66f787SSean Bruno 		aio_req->encrypt_enable = 0;
2891e66f787SSean Bruno 		aio_req->encrypt_key_index = 0;
2901e66f787SSean Bruno 		aio_req->encrypt_twk_high = 0;
2911e66f787SSean Bruno 		aio_req->encrypt_twk_low = 0;
2921e66f787SSean Bruno 	}
2931e66f787SSean Bruno 
2941e66f787SSean Bruno 	/* Frame SGL Descriptor */
2951e66f787SSean Bruno 	aio_req->partial = pqisrc_build_sgl(&aio_req->sg_desc[0], rcb,
2961e66f787SSean Bruno  		&aio_req->header, num_elem_alloted);
2971e66f787SSean Bruno 
2981e66f787SSean Bruno 	aio_req->num_sg = aio_req->header.iu_length / sizeof(sgt_t);
2991e66f787SSean Bruno 
3001e66f787SSean Bruno 	DBG_INFO("aio_req->num_sg :%d",aio_req->num_sg);
3011e66f787SSean Bruno 
3021e66f787SSean Bruno 	aio_req->header.iu_length += offsetof(pqi_aio_req_t, sg_desc) -
3031e66f787SSean Bruno 		sizeof(iu_header_t);
3041e66f787SSean Bruno #if 0
3051e66f787SSean Bruno 	DBG_IO("aio_req->header.iu_type : 0x%x \n",aio_req->header.iu_type);
3061e66f787SSean Bruno 	DBG_IO("aio_req->resp_qid :0x%x",aio_req->resp_qid);
3071e66f787SSean Bruno 	DBG_IO("aio_req->req_id : 0x%x \n",aio_req->req_id);
3081e66f787SSean Bruno 	DBG_IO("aio_req->nexus : 0x%x  \n",aio_req->nexus);
3091e66f787SSean Bruno 	DBG_IO("aio_req->buf_len : 0x%x \n",aio_req->buf_len);
3101e66f787SSean Bruno 	DBG_IO("aio_req->data_dir : 0x%x \n",aio_req->data_dir);
3111e66f787SSean Bruno 	DBG_IO("aio_req->task_attr : 0x%x \n",aio_req->task_attr);
3121e66f787SSean Bruno 	DBG_IO("aio_req->err_idx : 0x%x \n",aio_req->err_idx);
3131e66f787SSean Bruno 	DBG_IO("aio_req->num_sg :%d",aio_req->num_sg);
3141e66f787SSean Bruno 	DBG_IO("aio_req->sg_desc[0].addr : %p \n", (void*)aio_req->sg_desc[0].addr);
3151e66f787SSean Bruno 	DBG_IO("aio_req->sg_desc[0].len : 0%x \n", aio_req->sg_desc[0].len);
3161e66f787SSean Bruno 	DBG_IO("aio_req->sg_desc[0].flags : 0%x \n", aio_req->sg_desc[0].flags);
3171e66f787SSean Bruno #endif
3181e66f787SSean Bruno 
3191e66f787SSean Bruno 	rcb->success_cmp_callback = pqisrc_process_io_response_success;
3201e66f787SSean Bruno 	rcb->error_cmp_callback = pqisrc_process_aio_response_error;
3211e66f787SSean Bruno 	rcb->resp_qid = aio_req->response_queue_id;
3221e66f787SSean Bruno 
3231e66f787SSean Bruno 	DBG_FUNC(" OUT ");
3241e66f787SSean Bruno 
3251e66f787SSean Bruno }
3261e66f787SSean Bruno 
3271e66f787SSean Bruno /*Function used to build and send RAID/AIO */
3281e66f787SSean Bruno int pqisrc_build_send_io(pqisrc_softstate_t *softs,rcb_t *rcb)
3291e66f787SSean Bruno {
3301e66f787SSean Bruno 	ib_queue_t *ib_q_array = softs->op_aio_ib_q;
3311e66f787SSean Bruno 	ib_queue_t *ib_q = NULL;
3321e66f787SSean Bruno 	char *ib_iu = NULL;
3331e66f787SSean Bruno 	IO_PATH_T io_path = AIO_PATH;
3341e66f787SSean Bruno 	uint32_t TraverseCount = 0;
3351e66f787SSean Bruno 	int first_qindex = OS_GET_IO_REQ_QINDEX(softs, rcb);
3361e66f787SSean Bruno 	int qindex = first_qindex;
3371e66f787SSean Bruno 	uint32_t num_op_ib_q = softs->num_op_aio_ibq;
3381e66f787SSean Bruno 	uint32_t num_elem_needed;
3391e66f787SSean Bruno 	uint32_t num_elem_alloted = 0;
3401e66f787SSean Bruno 	pqi_scsi_dev_t *devp = rcb->dvp;
3411e66f787SSean Bruno 	uint8_t raidbypass_cdb[16];
3421e66f787SSean Bruno 
3431e66f787SSean Bruno 	DBG_FUNC(" IN ");
3441e66f787SSean Bruno 
3451e66f787SSean Bruno 
3461e66f787SSean Bruno 	rcb->cdbp = OS_GET_CDBP(rcb);
3471e66f787SSean Bruno 
3481e66f787SSean Bruno 	if(IS_AIO_PATH(devp)) {
3491e66f787SSean Bruno 		/**  IO for Physical Drive  **/
3501e66f787SSean Bruno 		/** Send in AIO PATH**/
3511e66f787SSean Bruno 		rcb->ioaccel_handle = devp->ioaccel_handle;
3521e66f787SSean Bruno 	} else {
3531e66f787SSean Bruno 		int ret = PQI_STATUS_FAILURE;
3541e66f787SSean Bruno 		/** IO for RAID Volume **/
3551e66f787SSean Bruno 		if (devp->offload_enabled) {
3561e66f787SSean Bruno 			/** ByPass IO ,Send in AIO PATH **/
3571e66f787SSean Bruno 			ret = pqisrc_send_scsi_cmd_raidbypass(softs,
3581e66f787SSean Bruno 				devp, rcb, raidbypass_cdb);
3591e66f787SSean Bruno 		}
3601e66f787SSean Bruno 
3611e66f787SSean Bruno 		if (PQI_STATUS_FAILURE == ret) {
3621e66f787SSean Bruno 			/** Send in RAID PATH **/
3631e66f787SSean Bruno 			io_path = RAID_PATH;
3641e66f787SSean Bruno 			num_op_ib_q = softs->num_op_raid_ibq;
3651e66f787SSean Bruno 			ib_q_array = softs->op_raid_ib_q;
3661e66f787SSean Bruno 		} else {
3671e66f787SSean Bruno 			rcb->cdbp = raidbypass_cdb;
3681e66f787SSean Bruno 		}
3691e66f787SSean Bruno 	}
3701e66f787SSean Bruno 
3711e66f787SSean Bruno 	num_elem_needed = pqisrc_num_elem_needed(softs, OS_GET_IO_SG_COUNT(rcb));
3721e66f787SSean Bruno 	DBG_IO("num_elem_needed :%d",num_elem_needed);
3731e66f787SSean Bruno 
3741e66f787SSean Bruno 	do {
3751e66f787SSean Bruno 		uint32_t num_elem_available;
3761e66f787SSean Bruno 		ib_q = (ib_q_array + qindex);
3771e66f787SSean Bruno 		PQI_LOCK(&ib_q->lock);
3781e66f787SSean Bruno 		num_elem_available = pqisrc_contiguous_free_elem(ib_q->pi_local,
3791e66f787SSean Bruno 					*(ib_q->ci_virt_addr), ib_q->num_elem);
3801e66f787SSean Bruno 
3811e66f787SSean Bruno 		DBG_IO("num_elem_avialable :%d\n",num_elem_available);
3821e66f787SSean Bruno 		if(num_elem_available >= num_elem_needed) {
3831e66f787SSean Bruno 			num_elem_alloted = num_elem_needed;
3841e66f787SSean Bruno 			break;
3851e66f787SSean Bruno 		}
3861e66f787SSean Bruno 		DBG_IO("Current queue is busy! Hop to next queue\n");
3871e66f787SSean Bruno 
3881e66f787SSean Bruno 		PQI_UNLOCK(&ib_q->lock);
3891e66f787SSean Bruno 		qindex = (qindex + 1) % num_op_ib_q;
3901e66f787SSean Bruno 		if(qindex == first_qindex) {
3911e66f787SSean Bruno 			if (num_elem_needed == 1)
3921e66f787SSean Bruno 				break;
3931e66f787SSean Bruno 			TraverseCount += 1;
3941e66f787SSean Bruno 			num_elem_needed = 1;
3951e66f787SSean Bruno 		}
3961e66f787SSean Bruno 	}while(TraverseCount < 2);
3971e66f787SSean Bruno 
3981e66f787SSean Bruno 	DBG_IO("num_elem_alloted :%d",num_elem_alloted);
3991e66f787SSean Bruno 	if (num_elem_alloted == 0) {
4001e66f787SSean Bruno 		DBG_WARN("OUT: IB Queues were full\n");
4011e66f787SSean Bruno 		return PQI_STATUS_QFULL;
4021e66f787SSean Bruno 	}
4031e66f787SSean Bruno 
4041e66f787SSean Bruno 	/* Get IB Queue Slot address to build IU */
4051e66f787SSean Bruno 	ib_iu = ib_q->array_virt_addr + (ib_q->pi_local * ib_q->elem_size);
4061e66f787SSean Bruno 
4071e66f787SSean Bruno 	if(io_path == AIO_PATH) {
4081e66f787SSean Bruno 		/** Build AIO structure **/
4091e66f787SSean Bruno  		pqisrc_build_aio_io(softs, rcb, (pqi_aio_req_t*)ib_iu,
4101e66f787SSean Bruno  			num_elem_alloted);
4111e66f787SSean Bruno 	} else {
4121e66f787SSean Bruno 		/** Build RAID structure **/
4131e66f787SSean Bruno 		pqisrc_build_raid_io(softs, rcb, (pqisrc_raid_req_t*)ib_iu,
4141e66f787SSean Bruno 			num_elem_alloted);
4151e66f787SSean Bruno 	}
4161e66f787SSean Bruno 
4171e66f787SSean Bruno 	rcb->req_pending = true;
4181e66f787SSean Bruno 
4191e66f787SSean Bruno 	/* Update the local PI */
4201e66f787SSean Bruno 	ib_q->pi_local = (ib_q->pi_local + num_elem_alloted) % ib_q->num_elem;
4211e66f787SSean Bruno 
4221e66f787SSean Bruno 	DBG_INFO("ib_q->pi_local : %x\n", ib_q->pi_local);
4231e66f787SSean Bruno 	DBG_INFO("*ib_q->ci_virt_addr: %x\n",*(ib_q->ci_virt_addr));
4241e66f787SSean Bruno 
4251e66f787SSean Bruno 	/* Inform the fw about the new IU */
4261e66f787SSean Bruno 	PCI_MEM_PUT32(softs, ib_q->pi_register_abs, ib_q->pi_register_offset, ib_q->pi_local);
4271e66f787SSean Bruno 
4281e66f787SSean Bruno 	PQI_UNLOCK(&ib_q->lock);
4291e66f787SSean Bruno 	DBG_FUNC(" OUT ");
4301e66f787SSean Bruno 	return PQI_STATUS_SUCCESS;
4311e66f787SSean Bruno }
4321e66f787SSean Bruno 
4331e66f787SSean Bruno /* Subroutine used to set encryption info as part of RAID bypass IO*/
4341e66f787SSean Bruno static inline void pqisrc_set_enc_info(
4351e66f787SSean Bruno 	struct pqi_enc_info *enc_info, struct raid_map *raid_map,
4361e66f787SSean Bruno 	uint64_t first_block)
4371e66f787SSean Bruno {
4381e66f787SSean Bruno 	uint32_t volume_blk_size;
4391e66f787SSean Bruno 
4401e66f787SSean Bruno 	/*
4411e66f787SSean Bruno 	 * Set the encryption tweak values based on logical block address.
4421e66f787SSean Bruno 	 * If the block size is 512, the tweak value is equal to the LBA.
4431e66f787SSean Bruno 	 * For other block sizes, tweak value is (LBA * block size) / 512.
4441e66f787SSean Bruno 	 */
4451e66f787SSean Bruno 	volume_blk_size = GET_LE32((uint8_t *)&raid_map->volume_blk_size);
4461e66f787SSean Bruno 	if (volume_blk_size != 512)
4471e66f787SSean Bruno 		first_block = (first_block * volume_blk_size) / 512;
4481e66f787SSean Bruno 
4491e66f787SSean Bruno 	enc_info->data_enc_key_index =
4501e66f787SSean Bruno 		GET_LE16((uint8_t *)&raid_map->data_encryption_key_index);
4511e66f787SSean Bruno 	enc_info->encrypt_tweak_upper = ((uint32_t)(((first_block) >> 16) >> 16));
4521e66f787SSean Bruno 	enc_info->encrypt_tweak_lower = ((uint32_t)(first_block));
4531e66f787SSean Bruno }
4541e66f787SSean Bruno 
4551e66f787SSean Bruno 
4561e66f787SSean Bruno /*
4571e66f787SSean Bruno  * Attempt to perform offload RAID mapping for a logical volume I/O.
4581e66f787SSean Bruno  */
4591e66f787SSean Bruno 
4601e66f787SSean Bruno #define HPSA_RAID_0		0
4611e66f787SSean Bruno #define HPSA_RAID_4		1
4621e66f787SSean Bruno #define HPSA_RAID_1		2	/* also used for RAID 10 */
4631e66f787SSean Bruno #define HPSA_RAID_5		3	/* also used for RAID 50 */
4641e66f787SSean Bruno #define HPSA_RAID_51		4
4651e66f787SSean Bruno #define HPSA_RAID_6		5	/* also used for RAID 60 */
4661e66f787SSean Bruno #define HPSA_RAID_ADM		6	/* also used for RAID 1+0 ADM */
4671e66f787SSean Bruno #define HPSA_RAID_MAX		HPSA_RAID_ADM
4681e66f787SSean Bruno #define HPSA_RAID_UNKNOWN	0xff
4691e66f787SSean Bruno 
4701e66f787SSean Bruno /* Subroutine used to parse the scsi opcode and build the CDB for RAID bypass*/
4711e66f787SSean Bruno int check_for_scsi_opcode(uint8_t *cdb, boolean_t *is_write, uint64_t *fst_blk,
4721e66f787SSean Bruno 				uint32_t *blk_cnt) {
4731e66f787SSean Bruno 
4741e66f787SSean Bruno 	switch (cdb[0]) {
4751e66f787SSean Bruno 	case SCMD_WRITE_6:
4761e66f787SSean Bruno 		*is_write = true;
4771e66f787SSean Bruno 	case SCMD_READ_6:
4781e66f787SSean Bruno 		*fst_blk = (uint64_t)(((cdb[1] & 0x1F) << 16) |
4791e66f787SSean Bruno 				(cdb[2] << 8) | cdb[3]);
4801e66f787SSean Bruno 		*blk_cnt = (uint32_t)cdb[4];
4811e66f787SSean Bruno 		if (*blk_cnt == 0)
4821e66f787SSean Bruno 			*blk_cnt = 256;
4831e66f787SSean Bruno 		break;
4841e66f787SSean Bruno 	case SCMD_WRITE_10:
4851e66f787SSean Bruno 		*is_write = true;
4861e66f787SSean Bruno 	case SCMD_READ_10:
4871e66f787SSean Bruno 		*fst_blk = (uint64_t)GET_BE32(&cdb[2]);
4881e66f787SSean Bruno 		*blk_cnt = (uint32_t)GET_BE16(&cdb[7]);
4891e66f787SSean Bruno 		break;
4901e66f787SSean Bruno 	case SCMD_WRITE_12:
4911e66f787SSean Bruno 		*is_write = true;
4921e66f787SSean Bruno 	case SCMD_READ_12:
4931e66f787SSean Bruno 		*fst_blk = (uint64_t)GET_BE32(&cdb[2]);
4941e66f787SSean Bruno 		*blk_cnt = GET_BE32(&cdb[6]);
4951e66f787SSean Bruno 		break;
4961e66f787SSean Bruno 	case SCMD_WRITE_16:
4971e66f787SSean Bruno 		*is_write = true;
4981e66f787SSean Bruno 	case SCMD_READ_16:
4991e66f787SSean Bruno 		*fst_blk = GET_BE64(&cdb[2]);
5001e66f787SSean Bruno 		*blk_cnt = GET_BE32(&cdb[10]);
5011e66f787SSean Bruno 		break;
5021e66f787SSean Bruno 	default:
5031e66f787SSean Bruno 		/* Process via normal I/O path. */
5041e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
5051e66f787SSean Bruno 	}
5061e66f787SSean Bruno 	return PQI_STATUS_SUCCESS;
5071e66f787SSean Bruno }
5081e66f787SSean Bruno 
5091e66f787SSean Bruno /*
5101e66f787SSean Bruno  * Function used to build and send RAID bypass request to the adapter
5111e66f787SSean Bruno  */
5121e66f787SSean Bruno int pqisrc_send_scsi_cmd_raidbypass(pqisrc_softstate_t *softs,
5131e66f787SSean Bruno 				pqi_scsi_dev_t *device, rcb_t *rcb, uint8_t *cdb)
5141e66f787SSean Bruno {
5151e66f787SSean Bruno 	struct raid_map *raid_map;
5161e66f787SSean Bruno 	boolean_t is_write = false;
5171e66f787SSean Bruno 	uint32_t map_idx;
5181e66f787SSean Bruno 	uint64_t fst_blk, lst_blk;
5191e66f787SSean Bruno 	uint32_t blk_cnt, blks_per_row;
5201e66f787SSean Bruno 	uint64_t fst_row, lst_row;
5211e66f787SSean Bruno 	uint32_t fst_row_offset, lst_row_offset;
5221e66f787SSean Bruno 	uint32_t fst_col, lst_col;
5231e66f787SSean Bruno 	uint32_t r5or6_blks_per_row;
5241e66f787SSean Bruno 	uint64_t r5or6_fst_row, r5or6_lst_row;
5251e66f787SSean Bruno 	uint32_t r5or6_fst_row_offset, r5or6_lst_row_offset;
5261e66f787SSean Bruno 	uint32_t r5or6_fst_col, r5or6_lst_col;
5271e66f787SSean Bruno 	uint16_t data_disks_per_row, total_disks_per_row;
5281e66f787SSean Bruno 	uint16_t layout_map_count;
5291e66f787SSean Bruno 	uint32_t stripesz;
5301e66f787SSean Bruno 	uint16_t strip_sz;
5311e66f787SSean Bruno 	uint32_t fst_grp, lst_grp, cur_grp;
5321e66f787SSean Bruno 	uint32_t map_row;
5331e66f787SSean Bruno 	uint64_t disk_block;
5341e66f787SSean Bruno 	uint32_t disk_blk_cnt;
5351e66f787SSean Bruno 	uint8_t cdb_length;
5361e66f787SSean Bruno 	int offload_to_mirror;
5371e66f787SSean Bruno 	int i;
5381e66f787SSean Bruno 	DBG_FUNC(" IN \n");
5391e66f787SSean Bruno 	DBG_IO("!!!!!\n");
5401e66f787SSean Bruno 
5411e66f787SSean Bruno 	/* Check for eligible opcode, get LBA and block count. */
5421e66f787SSean Bruno 	memcpy(cdb, OS_GET_CDBP(rcb), rcb->cmdlen);
5431e66f787SSean Bruno 
5441e66f787SSean Bruno 	for(i = 0; i < rcb->cmdlen ; i++)
5451e66f787SSean Bruno 		DBG_IO(" CDB [ %d ] : %x\n",i,cdb[i]);
5461e66f787SSean Bruno 	if(check_for_scsi_opcode(cdb, &is_write,
5471e66f787SSean Bruno 		&fst_blk, &blk_cnt) == PQI_STATUS_FAILURE)
5481e66f787SSean Bruno 			return PQI_STATUS_FAILURE;
5491e66f787SSean Bruno 	/* Check for write to non-RAID-0. */
5501e66f787SSean Bruno 	if (is_write && device->raid_level != SA_RAID_0)
5511e66f787SSean Bruno 		return PQI_STATUS_FAILURE;;
5521e66f787SSean Bruno 
5531e66f787SSean Bruno 	if(blk_cnt == 0)
5541e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
5551e66f787SSean Bruno 
5561e66f787SSean Bruno 	lst_blk = fst_blk + blk_cnt - 1;
5571e66f787SSean Bruno 	raid_map = device->raid_map;
5581e66f787SSean Bruno 
5591e66f787SSean Bruno 	/* Check for invalid block or wraparound. */
5601e66f787SSean Bruno 	if (lst_blk >= GET_LE64((uint8_t *)&raid_map->volume_blk_cnt) ||
5611e66f787SSean Bruno 		lst_blk < fst_blk)
5621e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
5631e66f787SSean Bruno 
5641e66f787SSean Bruno 	data_disks_per_row = GET_LE16((uint8_t *)&raid_map->data_disks_per_row);
5651e66f787SSean Bruno 	strip_sz = GET_LE16((uint8_t *)(&raid_map->strip_size));
5661e66f787SSean Bruno 	layout_map_count = GET_LE16((uint8_t *)(&raid_map->layout_map_count));
5671e66f787SSean Bruno 
5681e66f787SSean Bruno 	/* Calculate stripe information for the request. */
5691e66f787SSean Bruno 	blks_per_row = data_disks_per_row * strip_sz;
570*b17f4335SSean Bruno 	if (!blks_per_row)
571*b17f4335SSean Bruno 		return PQI_STATUS_FAILURE;
5721e66f787SSean Bruno 	/* use __udivdi3 ? */
5731e66f787SSean Bruno 	fst_row = fst_blk / blks_per_row;
5741e66f787SSean Bruno 	lst_row = lst_blk / blks_per_row;
5751e66f787SSean Bruno 	fst_row_offset = (uint32_t)(fst_blk - (fst_row * blks_per_row));
5761e66f787SSean Bruno 	lst_row_offset = (uint32_t)(lst_blk - (lst_row * blks_per_row));
5771e66f787SSean Bruno 	fst_col = fst_row_offset / strip_sz;
5781e66f787SSean Bruno 	lst_col = lst_row_offset / strip_sz;
5791e66f787SSean Bruno 
5801e66f787SSean Bruno 	/* If this isn't a single row/column then give to the controller. */
5811e66f787SSean Bruno 	if (fst_row != lst_row || fst_col != lst_col)
5821e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
5831e66f787SSean Bruno 
5841e66f787SSean Bruno 	/* Proceeding with driver mapping. */
5851e66f787SSean Bruno 	total_disks_per_row = data_disks_per_row +
5861e66f787SSean Bruno 		GET_LE16((uint8_t *)(&raid_map->metadata_disks_per_row));
5871e66f787SSean Bruno 	map_row = ((uint32_t)(fst_row >> raid_map->parity_rotation_shift)) %
5881e66f787SSean Bruno 		GET_LE16((uint8_t *)(&raid_map->row_cnt));
5891e66f787SSean Bruno 	map_idx = (map_row * total_disks_per_row) + fst_col;
5901e66f787SSean Bruno 
5911e66f787SSean Bruno 	/* RAID 1 */
5921e66f787SSean Bruno 	if (device->raid_level == SA_RAID_1) {
5931e66f787SSean Bruno 		if (device->offload_to_mirror)
5941e66f787SSean Bruno 			map_idx += data_disks_per_row;
5951e66f787SSean Bruno 		device->offload_to_mirror = !device->offload_to_mirror;
5961e66f787SSean Bruno 	} else if (device->raid_level == SA_RAID_ADM) {
5971e66f787SSean Bruno 		/* RAID ADM */
5981e66f787SSean Bruno 		/*
5991e66f787SSean Bruno 		 * Handles N-way mirrors  (R1-ADM) and R10 with # of drives
6001e66f787SSean Bruno 		 * divisible by 3.
6011e66f787SSean Bruno 		 */
6021e66f787SSean Bruno 		offload_to_mirror = device->offload_to_mirror;
6031e66f787SSean Bruno 		if (offload_to_mirror == 0)  {
6041e66f787SSean Bruno 			/* use physical disk in the first mirrored group. */
6051e66f787SSean Bruno 			map_idx %= data_disks_per_row;
6061e66f787SSean Bruno 		} else {
6071e66f787SSean Bruno 			do {
6081e66f787SSean Bruno 				/*
6091e66f787SSean Bruno 				 * Determine mirror group that map_idx
6101e66f787SSean Bruno 				 * indicates.
6111e66f787SSean Bruno 				 */
6121e66f787SSean Bruno 				cur_grp = map_idx / data_disks_per_row;
6131e66f787SSean Bruno 
6141e66f787SSean Bruno 				if (offload_to_mirror != cur_grp) {
6151e66f787SSean Bruno 					if (cur_grp <
6161e66f787SSean Bruno 						layout_map_count - 1) {
6171e66f787SSean Bruno 						/*
6181e66f787SSean Bruno 						 * Select raid index from
6191e66f787SSean Bruno 						 * next group.
6201e66f787SSean Bruno 						 */
6211e66f787SSean Bruno 						map_idx += data_disks_per_row;
6221e66f787SSean Bruno 						cur_grp++;
6231e66f787SSean Bruno 					} else {
6241e66f787SSean Bruno 						/*
6251e66f787SSean Bruno 						 * Select raid index from first
6261e66f787SSean Bruno 						 * group.
6271e66f787SSean Bruno 						 */
6281e66f787SSean Bruno 						map_idx %= data_disks_per_row;
6291e66f787SSean Bruno 						cur_grp = 0;
6301e66f787SSean Bruno 					}
6311e66f787SSean Bruno 				}
6321e66f787SSean Bruno 			} while (offload_to_mirror != cur_grp);
6331e66f787SSean Bruno 		}
6341e66f787SSean Bruno 
6351e66f787SSean Bruno 		/* Set mirror group to use next time. */
6361e66f787SSean Bruno 		offload_to_mirror =
6371e66f787SSean Bruno 			(offload_to_mirror >= layout_map_count - 1) ?
6381e66f787SSean Bruno 				0 : offload_to_mirror + 1;
6391e66f787SSean Bruno 		if(offload_to_mirror >= layout_map_count)
6401e66f787SSean Bruno 			return PQI_STATUS_FAILURE;
6411e66f787SSean Bruno 
6421e66f787SSean Bruno 		device->offload_to_mirror = offload_to_mirror;
6431e66f787SSean Bruno 		/*
6441e66f787SSean Bruno 		 * Avoid direct use of device->offload_to_mirror within this
6451e66f787SSean Bruno 		 * function since multiple threads might simultaneously
6461e66f787SSean Bruno 		 * increment it beyond the range of device->layout_map_count -1.
6471e66f787SSean Bruno 		 */
6481e66f787SSean Bruno 	} else if ((device->raid_level == SA_RAID_5 ||
6491e66f787SSean Bruno 		device->raid_level == SA_RAID_6) && layout_map_count > 1) {
6501e66f787SSean Bruno 		/* RAID 50/60 */
6511e66f787SSean Bruno 		/* Verify first and last block are in same RAID group */
6521e66f787SSean Bruno 		r5or6_blks_per_row = strip_sz * data_disks_per_row;
6531e66f787SSean Bruno 		stripesz = r5or6_blks_per_row * layout_map_count;
6541e66f787SSean Bruno 
6551e66f787SSean Bruno 		fst_grp = (fst_blk % stripesz) / r5or6_blks_per_row;
6561e66f787SSean Bruno 		lst_grp = (lst_blk % stripesz) / r5or6_blks_per_row;
6571e66f787SSean Bruno 
6581e66f787SSean Bruno 		if (fst_grp != lst_grp)
6591e66f787SSean Bruno 			return PQI_STATUS_FAILURE;
6601e66f787SSean Bruno 
6611e66f787SSean Bruno 		/* Verify request is in a single row of RAID 5/6 */
6621e66f787SSean Bruno 		fst_row = r5or6_fst_row =
6631e66f787SSean Bruno 			fst_blk / stripesz;
6641e66f787SSean Bruno 		r5or6_lst_row = lst_blk / stripesz;
6651e66f787SSean Bruno 
6661e66f787SSean Bruno 		if (r5or6_fst_row != r5or6_lst_row)
6671e66f787SSean Bruno 			return PQI_STATUS_FAILURE;
6681e66f787SSean Bruno 
6691e66f787SSean Bruno 		/* Verify request is in a single column */
6701e66f787SSean Bruno 		fst_row_offset = r5or6_fst_row_offset =
6711e66f787SSean Bruno 			(uint32_t)((fst_blk % stripesz) %
6721e66f787SSean Bruno 			r5or6_blks_per_row);
6731e66f787SSean Bruno 
6741e66f787SSean Bruno 		r5or6_lst_row_offset =
6751e66f787SSean Bruno 			(uint32_t)((lst_blk % stripesz) %
6761e66f787SSean Bruno 			r5or6_blks_per_row);
6771e66f787SSean Bruno 
6781e66f787SSean Bruno 		fst_col = r5or6_fst_row_offset / strip_sz;
6791e66f787SSean Bruno 		r5or6_fst_col = fst_col;
6801e66f787SSean Bruno 		r5or6_lst_col = r5or6_lst_row_offset / strip_sz;
6811e66f787SSean Bruno 
6821e66f787SSean Bruno 		if (r5or6_fst_col != r5or6_lst_col)
6831e66f787SSean Bruno 			return PQI_STATUS_FAILURE;
6841e66f787SSean Bruno 
6851e66f787SSean Bruno 		/* Request is eligible */
6861e66f787SSean Bruno 		map_row =
6871e66f787SSean Bruno 			((uint32_t)(fst_row >> raid_map->parity_rotation_shift)) %
6881e66f787SSean Bruno 			GET_LE16((uint8_t *)(&raid_map->row_cnt));
6891e66f787SSean Bruno 
6901e66f787SSean Bruno 		map_idx = (fst_grp *
6911e66f787SSean Bruno 			(GET_LE16((uint8_t *)(&raid_map->row_cnt)) *
6921e66f787SSean Bruno 			total_disks_per_row)) +
6931e66f787SSean Bruno 			(map_row * total_disks_per_row) + fst_col;
6941e66f787SSean Bruno 	}
6951e66f787SSean Bruno 
6961e66f787SSean Bruno 	if (map_idx >= RAID_MAP_MAX_ENTRIES)
6971e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
6981e66f787SSean Bruno 
6991e66f787SSean Bruno 	rcb->ioaccel_handle = raid_map->dev_data[map_idx].ioaccel_handle;
7001e66f787SSean Bruno 	disk_block = GET_LE64((uint8_t *)(&raid_map->disk_starting_blk)) +
7011e66f787SSean Bruno 		fst_row * strip_sz +
7021e66f787SSean Bruno 		(fst_row_offset - fst_col * strip_sz);
7031e66f787SSean Bruno 	disk_blk_cnt = blk_cnt;
7041e66f787SSean Bruno 
7051e66f787SSean Bruno 	/* Handle differing logical/physical block sizes. */
7061e66f787SSean Bruno 	if (raid_map->phys_blk_shift) {
7071e66f787SSean Bruno 		disk_block <<= raid_map->phys_blk_shift;
7081e66f787SSean Bruno 		disk_blk_cnt <<= raid_map->phys_blk_shift;
7091e66f787SSean Bruno 	}
7101e66f787SSean Bruno 
7111e66f787SSean Bruno 	if (disk_blk_cnt > 0xffff)
7121e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
7131e66f787SSean Bruno 
7141e66f787SSean Bruno 	/* Build the new CDB for the physical disk I/O. */
7151e66f787SSean Bruno 	if (disk_block > 0xffffffff) {
7161e66f787SSean Bruno 		cdb[0] = is_write ? SCMD_WRITE_16 : SCMD_READ_16;
7171e66f787SSean Bruno 		cdb[1] = 0;
7181e66f787SSean Bruno 		PUT_BE64(disk_block, &cdb[2]);
7191e66f787SSean Bruno 		PUT_BE32(disk_blk_cnt, &cdb[10]);
7201e66f787SSean Bruno 		cdb[14] = 0;
7211e66f787SSean Bruno 		cdb[15] = 0;
7221e66f787SSean Bruno 		cdb_length = 16;
7231e66f787SSean Bruno 	} else {
7241e66f787SSean Bruno 		cdb[0] = is_write ? SCMD_WRITE_10 : SCMD_READ_10;
7251e66f787SSean Bruno 		cdb[1] = 0;
7261e66f787SSean Bruno 		PUT_BE32(disk_block, &cdb[2]);
7271e66f787SSean Bruno 		cdb[6] = 0;
7281e66f787SSean Bruno 		PUT_BE16(disk_blk_cnt, &cdb[7]);
7291e66f787SSean Bruno 		cdb[9] = 0;
7301e66f787SSean Bruno 		cdb_length = 10;
7311e66f787SSean Bruno 	}
7321e66f787SSean Bruno 
7331e66f787SSean Bruno 	if (GET_LE16((uint8_t *)(&raid_map->flags)) &
7341e66f787SSean Bruno 		RAID_MAP_ENCRYPTION_ENABLED) {
7351e66f787SSean Bruno 		pqisrc_set_enc_info(&rcb->enc_info, raid_map,
7361e66f787SSean Bruno 			fst_blk);
7371e66f787SSean Bruno 		rcb->encrypt_enable = true;
7381e66f787SSean Bruno 	} else {
7391e66f787SSean Bruno 		rcb->encrypt_enable = false;
7401e66f787SSean Bruno 	}
7411e66f787SSean Bruno 
7421e66f787SSean Bruno 	rcb->cmdlen = cdb_length;
7431e66f787SSean Bruno 
7441e66f787SSean Bruno 
7451e66f787SSean Bruno 	DBG_FUNC("OUT");
7461e66f787SSean Bruno 
7471e66f787SSean Bruno 	return PQI_STATUS_SUCCESS;
7481e66f787SSean Bruno }
7491e66f787SSean Bruno 
7501e66f787SSean Bruno /* Function used to submit a TMF to the adater */
7511e66f787SSean Bruno int pqisrc_send_tmf(pqisrc_softstate_t *softs, pqi_scsi_dev_t *devp,
7521e66f787SSean Bruno                     rcb_t *rcb, int req_id, int tmf_type)
7531e66f787SSean Bruno {
7541e66f787SSean Bruno 	int rval = PQI_STATUS_SUCCESS;
7551e66f787SSean Bruno 	pqi_tmf_req_t tmf_req;
7561e66f787SSean Bruno 
7571e66f787SSean Bruno 	memset(&tmf_req, 0, sizeof(pqi_tmf_req_t));
7581e66f787SSean Bruno 
7591e66f787SSean Bruno 	DBG_FUNC("IN");
7601e66f787SSean Bruno 
7611e66f787SSean Bruno 	tmf_req.header.iu_type = PQI_REQUEST_IU_TASK_MANAGEMENT;
7621e66f787SSean Bruno 	tmf_req.header.iu_length = sizeof(tmf_req) - sizeof(iu_header_t);
7631e66f787SSean Bruno 	tmf_req.req_id = rcb->tag;
7641e66f787SSean Bruno 
7651e66f787SSean Bruno 	memcpy(tmf_req.lun, devp->scsi3addr, sizeof(tmf_req.lun));
7661e66f787SSean Bruno 	tmf_req.tmf = tmf_type;
7671e66f787SSean Bruno 	tmf_req.req_id_to_manage = req_id;
7681e66f787SSean Bruno 	tmf_req.resp_qid = OS_GET_TMF_RESP_QID(softs, rcb);
7691e66f787SSean Bruno 	tmf_req.obq_id_to_manage = rcb->resp_qid;
7701e66f787SSean Bruno 
7711e66f787SSean Bruno 	rcb->req_pending = true;
7721e66f787SSean Bruno 
7731e66f787SSean Bruno 	rval = pqisrc_submit_cmnd(softs,
7741e66f787SSean Bruno 	&softs->op_raid_ib_q[OS_GET_TMF_REQ_QINDEX(softs, rcb)], &tmf_req);
7751e66f787SSean Bruno 	if (rval != PQI_STATUS_SUCCESS) {
7761e66f787SSean Bruno 		DBG_ERR("Unable to submit command rval=%d\n", rval);
7771e66f787SSean Bruno 		return rval;
7781e66f787SSean Bruno 	}
7791e66f787SSean Bruno 
7801e66f787SSean Bruno 	rval = pqisrc_wait_on_condition(softs, rcb);
7811e66f787SSean Bruno 	if (rval != PQI_STATUS_SUCCESS){
7821e66f787SSean Bruno 		DBG_ERR("Task Management tmf_type : %d timeout\n", tmf_type);
7831e66f787SSean Bruno 		rcb->status = REQUEST_FAILED;
7841e66f787SSean Bruno 	}
7851e66f787SSean Bruno 
7861e66f787SSean Bruno 	if (rcb->status  != REQUEST_SUCCESS) {
7871e66f787SSean Bruno 		DBG_ERR_BTL(devp, "Task Management failed tmf_type:%d "
7881e66f787SSean Bruno 				"stat:0x%x\n", tmf_type, rcb->status);
7891e66f787SSean Bruno 		rval = PQI_STATUS_FAILURE;
7901e66f787SSean Bruno 	}
7911e66f787SSean Bruno 
7921e66f787SSean Bruno 	DBG_FUNC("OUT");
7931e66f787SSean Bruno 	return rval;
7941e66f787SSean Bruno }
795