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