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