18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * QLogic Fibre Channel HBA Driver 48c2ecf20Sopenharmony_ci * Copyright (c) 2003-2014 QLogic Corporation 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci#include "qla_def.h" 78c2ecf20Sopenharmony_ci#include "qla_target.h" 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 108c2ecf20Sopenharmony_ci#include <linux/delay.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <scsi/scsi_tcq.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/** 158c2ecf20Sopenharmony_ci * qla2x00_get_cmd_direction() - Determine control_flag data direction. 168c2ecf20Sopenharmony_ci * @sp: SCSI command 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * Returns the proper CF_* direction based on CDB. 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_cistatic inline uint16_t 218c2ecf20Sopenharmony_ciqla2x00_get_cmd_direction(srb_t *sp) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci uint16_t cflags; 248c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd = GET_CMD_SP(sp); 258c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = sp->vha; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci cflags = 0; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci /* Set transfer direction */ 308c2ecf20Sopenharmony_ci if (cmd->sc_data_direction == DMA_TO_DEVICE) { 318c2ecf20Sopenharmony_ci cflags = CF_WRITE; 328c2ecf20Sopenharmony_ci vha->qla_stats.output_bytes += scsi_bufflen(cmd); 338c2ecf20Sopenharmony_ci vha->qla_stats.output_requests++; 348c2ecf20Sopenharmony_ci } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) { 358c2ecf20Sopenharmony_ci cflags = CF_READ; 368c2ecf20Sopenharmony_ci vha->qla_stats.input_bytes += scsi_bufflen(cmd); 378c2ecf20Sopenharmony_ci vha->qla_stats.input_requests++; 388c2ecf20Sopenharmony_ci } 398c2ecf20Sopenharmony_ci return (cflags); 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/** 438c2ecf20Sopenharmony_ci * qla2x00_calc_iocbs_32() - Determine number of Command Type 2 and 448c2ecf20Sopenharmony_ci * Continuation Type 0 IOCBs to allocate. 458c2ecf20Sopenharmony_ci * 468c2ecf20Sopenharmony_ci * @dsds: number of data segment descriptors needed 478c2ecf20Sopenharmony_ci * 488c2ecf20Sopenharmony_ci * Returns the number of IOCB entries needed to store @dsds. 498c2ecf20Sopenharmony_ci */ 508c2ecf20Sopenharmony_ciuint16_t 518c2ecf20Sopenharmony_ciqla2x00_calc_iocbs_32(uint16_t dsds) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci uint16_t iocbs; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci iocbs = 1; 568c2ecf20Sopenharmony_ci if (dsds > 3) { 578c2ecf20Sopenharmony_ci iocbs += (dsds - 3) / 7; 588c2ecf20Sopenharmony_ci if ((dsds - 3) % 7) 598c2ecf20Sopenharmony_ci iocbs++; 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci return (iocbs); 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/** 658c2ecf20Sopenharmony_ci * qla2x00_calc_iocbs_64() - Determine number of Command Type 3 and 668c2ecf20Sopenharmony_ci * Continuation Type 1 IOCBs to allocate. 678c2ecf20Sopenharmony_ci * 688c2ecf20Sopenharmony_ci * @dsds: number of data segment descriptors needed 698c2ecf20Sopenharmony_ci * 708c2ecf20Sopenharmony_ci * Returns the number of IOCB entries needed to store @dsds. 718c2ecf20Sopenharmony_ci */ 728c2ecf20Sopenharmony_ciuint16_t 738c2ecf20Sopenharmony_ciqla2x00_calc_iocbs_64(uint16_t dsds) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci uint16_t iocbs; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci iocbs = 1; 788c2ecf20Sopenharmony_ci if (dsds > 2) { 798c2ecf20Sopenharmony_ci iocbs += (dsds - 2) / 5; 808c2ecf20Sopenharmony_ci if ((dsds - 2) % 5) 818c2ecf20Sopenharmony_ci iocbs++; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci return (iocbs); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci/** 878c2ecf20Sopenharmony_ci * qla2x00_prep_cont_type0_iocb() - Initialize a Continuation Type 0 IOCB. 888c2ecf20Sopenharmony_ci * @vha: HA context 898c2ecf20Sopenharmony_ci * 908c2ecf20Sopenharmony_ci * Returns a pointer to the Continuation Type 0 IOCB packet. 918c2ecf20Sopenharmony_ci */ 928c2ecf20Sopenharmony_cistatic inline cont_entry_t * 938c2ecf20Sopenharmony_ciqla2x00_prep_cont_type0_iocb(struct scsi_qla_host *vha) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci cont_entry_t *cont_pkt; 968c2ecf20Sopenharmony_ci struct req_que *req = vha->req; 978c2ecf20Sopenharmony_ci /* Adjust ring index. */ 988c2ecf20Sopenharmony_ci req->ring_index++; 998c2ecf20Sopenharmony_ci if (req->ring_index == req->length) { 1008c2ecf20Sopenharmony_ci req->ring_index = 0; 1018c2ecf20Sopenharmony_ci req->ring_ptr = req->ring; 1028c2ecf20Sopenharmony_ci } else { 1038c2ecf20Sopenharmony_ci req->ring_ptr++; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci cont_pkt = (cont_entry_t *)req->ring_ptr; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci /* Load packet defaults. */ 1098c2ecf20Sopenharmony_ci put_unaligned_le32(CONTINUE_TYPE, &cont_pkt->entry_type); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci return (cont_pkt); 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci/** 1158c2ecf20Sopenharmony_ci * qla2x00_prep_cont_type1_iocb() - Initialize a Continuation Type 1 IOCB. 1168c2ecf20Sopenharmony_ci * @vha: HA context 1178c2ecf20Sopenharmony_ci * @req: request queue 1188c2ecf20Sopenharmony_ci * 1198c2ecf20Sopenharmony_ci * Returns a pointer to the continuation type 1 IOCB packet. 1208c2ecf20Sopenharmony_ci */ 1218c2ecf20Sopenharmony_cistatic inline cont_a64_entry_t * 1228c2ecf20Sopenharmony_ciqla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha, struct req_que *req) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci cont_a64_entry_t *cont_pkt; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci /* Adjust ring index. */ 1278c2ecf20Sopenharmony_ci req->ring_index++; 1288c2ecf20Sopenharmony_ci if (req->ring_index == req->length) { 1298c2ecf20Sopenharmony_ci req->ring_index = 0; 1308c2ecf20Sopenharmony_ci req->ring_ptr = req->ring; 1318c2ecf20Sopenharmony_ci } else { 1328c2ecf20Sopenharmony_ci req->ring_ptr++; 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci cont_pkt = (cont_a64_entry_t *)req->ring_ptr; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* Load packet defaults. */ 1388c2ecf20Sopenharmony_ci put_unaligned_le32(IS_QLAFX00(vha->hw) ? CONTINUE_A64_TYPE_FX00 : 1398c2ecf20Sopenharmony_ci CONTINUE_A64_TYPE, &cont_pkt->entry_type); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci return (cont_pkt); 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ciinline int 1458c2ecf20Sopenharmony_ciqla24xx_configure_prot_mode(srb_t *sp, uint16_t *fw_prot_opts) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd = GET_CMD_SP(sp); 1488c2ecf20Sopenharmony_ci uint8_t guard = scsi_host_get_guard(cmd->device->host); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci /* We always use DIFF Bundling for best performance */ 1518c2ecf20Sopenharmony_ci *fw_prot_opts = 0; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci /* Translate SCSI opcode to a protection opcode */ 1548c2ecf20Sopenharmony_ci switch (scsi_get_prot_op(cmd)) { 1558c2ecf20Sopenharmony_ci case SCSI_PROT_READ_STRIP: 1568c2ecf20Sopenharmony_ci *fw_prot_opts |= PO_MODE_DIF_REMOVE; 1578c2ecf20Sopenharmony_ci break; 1588c2ecf20Sopenharmony_ci case SCSI_PROT_WRITE_INSERT: 1598c2ecf20Sopenharmony_ci *fw_prot_opts |= PO_MODE_DIF_INSERT; 1608c2ecf20Sopenharmony_ci break; 1618c2ecf20Sopenharmony_ci case SCSI_PROT_READ_INSERT: 1628c2ecf20Sopenharmony_ci *fw_prot_opts |= PO_MODE_DIF_INSERT; 1638c2ecf20Sopenharmony_ci break; 1648c2ecf20Sopenharmony_ci case SCSI_PROT_WRITE_STRIP: 1658c2ecf20Sopenharmony_ci *fw_prot_opts |= PO_MODE_DIF_REMOVE; 1668c2ecf20Sopenharmony_ci break; 1678c2ecf20Sopenharmony_ci case SCSI_PROT_READ_PASS: 1688c2ecf20Sopenharmony_ci case SCSI_PROT_WRITE_PASS: 1698c2ecf20Sopenharmony_ci if (guard & SHOST_DIX_GUARD_IP) 1708c2ecf20Sopenharmony_ci *fw_prot_opts |= PO_MODE_DIF_TCP_CKSUM; 1718c2ecf20Sopenharmony_ci else 1728c2ecf20Sopenharmony_ci *fw_prot_opts |= PO_MODE_DIF_PASS; 1738c2ecf20Sopenharmony_ci break; 1748c2ecf20Sopenharmony_ci default: /* Normal Request */ 1758c2ecf20Sopenharmony_ci *fw_prot_opts |= PO_MODE_DIF_PASS; 1768c2ecf20Sopenharmony_ci break; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci return scsi_prot_sg_count(cmd); 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/* 1838c2ecf20Sopenharmony_ci * qla2x00_build_scsi_iocbs_32() - Build IOCB command utilizing 32bit 1848c2ecf20Sopenharmony_ci * capable IOCB types. 1858c2ecf20Sopenharmony_ci * 1868c2ecf20Sopenharmony_ci * @sp: SRB command to process 1878c2ecf20Sopenharmony_ci * @cmd_pkt: Command type 2 IOCB 1888c2ecf20Sopenharmony_ci * @tot_dsds: Total number of segments to transfer 1898c2ecf20Sopenharmony_ci */ 1908c2ecf20Sopenharmony_civoid qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt, 1918c2ecf20Sopenharmony_ci uint16_t tot_dsds) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci uint16_t avail_dsds; 1948c2ecf20Sopenharmony_ci struct dsd32 *cur_dsd; 1958c2ecf20Sopenharmony_ci scsi_qla_host_t *vha; 1968c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd; 1978c2ecf20Sopenharmony_ci struct scatterlist *sg; 1988c2ecf20Sopenharmony_ci int i; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci cmd = GET_CMD_SP(sp); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* Update entry type to indicate Command Type 2 IOCB */ 2038c2ecf20Sopenharmony_ci put_unaligned_le32(COMMAND_TYPE, &cmd_pkt->entry_type); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci /* No data transfer */ 2068c2ecf20Sopenharmony_ci if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { 2078c2ecf20Sopenharmony_ci cmd_pkt->byte_count = cpu_to_le32(0); 2088c2ecf20Sopenharmony_ci return; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci vha = sp->vha; 2128c2ecf20Sopenharmony_ci cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp)); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci /* Three DSDs are available in the Command Type 2 IOCB */ 2158c2ecf20Sopenharmony_ci avail_dsds = ARRAY_SIZE(cmd_pkt->dsd32); 2168c2ecf20Sopenharmony_ci cur_dsd = cmd_pkt->dsd32; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci /* Load data segments */ 2198c2ecf20Sopenharmony_ci scsi_for_each_sg(cmd, sg, tot_dsds, i) { 2208c2ecf20Sopenharmony_ci cont_entry_t *cont_pkt; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci /* Allocate additional continuation packets? */ 2238c2ecf20Sopenharmony_ci if (avail_dsds == 0) { 2248c2ecf20Sopenharmony_ci /* 2258c2ecf20Sopenharmony_ci * Seven DSDs are available in the Continuation 2268c2ecf20Sopenharmony_ci * Type 0 IOCB. 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_ci cont_pkt = qla2x00_prep_cont_type0_iocb(vha); 2298c2ecf20Sopenharmony_ci cur_dsd = cont_pkt->dsd; 2308c2ecf20Sopenharmony_ci avail_dsds = ARRAY_SIZE(cont_pkt->dsd); 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci append_dsd32(&cur_dsd, sg); 2348c2ecf20Sopenharmony_ci avail_dsds--; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci/** 2398c2ecf20Sopenharmony_ci * qla2x00_build_scsi_iocbs_64() - Build IOCB command utilizing 64bit 2408c2ecf20Sopenharmony_ci * capable IOCB types. 2418c2ecf20Sopenharmony_ci * 2428c2ecf20Sopenharmony_ci * @sp: SRB command to process 2438c2ecf20Sopenharmony_ci * @cmd_pkt: Command type 3 IOCB 2448c2ecf20Sopenharmony_ci * @tot_dsds: Total number of segments to transfer 2458c2ecf20Sopenharmony_ci */ 2468c2ecf20Sopenharmony_civoid qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt, 2478c2ecf20Sopenharmony_ci uint16_t tot_dsds) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci uint16_t avail_dsds; 2508c2ecf20Sopenharmony_ci struct dsd64 *cur_dsd; 2518c2ecf20Sopenharmony_ci scsi_qla_host_t *vha; 2528c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd; 2538c2ecf20Sopenharmony_ci struct scatterlist *sg; 2548c2ecf20Sopenharmony_ci int i; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci cmd = GET_CMD_SP(sp); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci /* Update entry type to indicate Command Type 3 IOCB */ 2598c2ecf20Sopenharmony_ci put_unaligned_le32(COMMAND_A64_TYPE, &cmd_pkt->entry_type); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci /* No data transfer */ 2628c2ecf20Sopenharmony_ci if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { 2638c2ecf20Sopenharmony_ci cmd_pkt->byte_count = cpu_to_le32(0); 2648c2ecf20Sopenharmony_ci return; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci vha = sp->vha; 2688c2ecf20Sopenharmony_ci cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp)); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci /* Two DSDs are available in the Command Type 3 IOCB */ 2718c2ecf20Sopenharmony_ci avail_dsds = ARRAY_SIZE(cmd_pkt->dsd64); 2728c2ecf20Sopenharmony_ci cur_dsd = cmd_pkt->dsd64; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci /* Load data segments */ 2758c2ecf20Sopenharmony_ci scsi_for_each_sg(cmd, sg, tot_dsds, i) { 2768c2ecf20Sopenharmony_ci cont_a64_entry_t *cont_pkt; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* Allocate additional continuation packets? */ 2798c2ecf20Sopenharmony_ci if (avail_dsds == 0) { 2808c2ecf20Sopenharmony_ci /* 2818c2ecf20Sopenharmony_ci * Five DSDs are available in the Continuation 2828c2ecf20Sopenharmony_ci * Type 1 IOCB. 2838c2ecf20Sopenharmony_ci */ 2848c2ecf20Sopenharmony_ci cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->req); 2858c2ecf20Sopenharmony_ci cur_dsd = cont_pkt->dsd; 2868c2ecf20Sopenharmony_ci avail_dsds = ARRAY_SIZE(cont_pkt->dsd); 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci append_dsd64(&cur_dsd, sg); 2908c2ecf20Sopenharmony_ci avail_dsds--; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci/* 2958c2ecf20Sopenharmony_ci * Find the first handle that is not in use, starting from 2968c2ecf20Sopenharmony_ci * req->current_outstanding_cmd + 1. The caller must hold the lock that is 2978c2ecf20Sopenharmony_ci * associated with @req. 2988c2ecf20Sopenharmony_ci */ 2998c2ecf20Sopenharmony_ciuint32_t qla2xxx_get_next_handle(struct req_que *req) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci uint32_t index, handle = req->current_outstanding_cmd; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci for (index = 1; index < req->num_outstanding_cmds; index++) { 3048c2ecf20Sopenharmony_ci handle++; 3058c2ecf20Sopenharmony_ci if (handle == req->num_outstanding_cmds) 3068c2ecf20Sopenharmony_ci handle = 1; 3078c2ecf20Sopenharmony_ci if (!req->outstanding_cmds[handle]) 3088c2ecf20Sopenharmony_ci return handle; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci return 0; 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci/** 3158c2ecf20Sopenharmony_ci * qla2x00_start_scsi() - Send a SCSI command to the ISP 3168c2ecf20Sopenharmony_ci * @sp: command to send to the ISP 3178c2ecf20Sopenharmony_ci * 3188c2ecf20Sopenharmony_ci * Returns non-zero if a failure occurred, else zero. 3198c2ecf20Sopenharmony_ci */ 3208c2ecf20Sopenharmony_ciint 3218c2ecf20Sopenharmony_ciqla2x00_start_scsi(srb_t *sp) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci int nseg; 3248c2ecf20Sopenharmony_ci unsigned long flags; 3258c2ecf20Sopenharmony_ci scsi_qla_host_t *vha; 3268c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd; 3278c2ecf20Sopenharmony_ci uint32_t *clr_ptr; 3288c2ecf20Sopenharmony_ci uint32_t handle; 3298c2ecf20Sopenharmony_ci cmd_entry_t *cmd_pkt; 3308c2ecf20Sopenharmony_ci uint16_t cnt; 3318c2ecf20Sopenharmony_ci uint16_t req_cnt; 3328c2ecf20Sopenharmony_ci uint16_t tot_dsds; 3338c2ecf20Sopenharmony_ci struct device_reg_2xxx __iomem *reg; 3348c2ecf20Sopenharmony_ci struct qla_hw_data *ha; 3358c2ecf20Sopenharmony_ci struct req_que *req; 3368c2ecf20Sopenharmony_ci struct rsp_que *rsp; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci /* Setup device pointers. */ 3398c2ecf20Sopenharmony_ci vha = sp->vha; 3408c2ecf20Sopenharmony_ci ha = vha->hw; 3418c2ecf20Sopenharmony_ci reg = &ha->iobase->isp; 3428c2ecf20Sopenharmony_ci cmd = GET_CMD_SP(sp); 3438c2ecf20Sopenharmony_ci req = ha->req_q_map[0]; 3448c2ecf20Sopenharmony_ci rsp = ha->rsp_q_map[0]; 3458c2ecf20Sopenharmony_ci /* So we know we haven't pci_map'ed anything yet */ 3468c2ecf20Sopenharmony_ci tot_dsds = 0; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci /* Send marker if required */ 3498c2ecf20Sopenharmony_ci if (vha->marker_needed != 0) { 3508c2ecf20Sopenharmony_ci if (qla2x00_marker(vha, ha->base_qpair, 0, 0, MK_SYNC_ALL) != 3518c2ecf20Sopenharmony_ci QLA_SUCCESS) { 3528c2ecf20Sopenharmony_ci return (QLA_FUNCTION_FAILED); 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci vha->marker_needed = 0; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* Acquire ring specific lock */ 3588c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci handle = qla2xxx_get_next_handle(req); 3618c2ecf20Sopenharmony_ci if (handle == 0) 3628c2ecf20Sopenharmony_ci goto queuing_error; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci /* Map the sg table so we have an accurate count of sg entries needed */ 3658c2ecf20Sopenharmony_ci if (scsi_sg_count(cmd)) { 3668c2ecf20Sopenharmony_ci nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd), 3678c2ecf20Sopenharmony_ci scsi_sg_count(cmd), cmd->sc_data_direction); 3688c2ecf20Sopenharmony_ci if (unlikely(!nseg)) 3698c2ecf20Sopenharmony_ci goto queuing_error; 3708c2ecf20Sopenharmony_ci } else 3718c2ecf20Sopenharmony_ci nseg = 0; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci tot_dsds = nseg; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* Calculate the number of request entries needed. */ 3768c2ecf20Sopenharmony_ci req_cnt = ha->isp_ops->calc_req_entries(tot_dsds); 3778c2ecf20Sopenharmony_ci if (req->cnt < (req_cnt + 2)) { 3788c2ecf20Sopenharmony_ci cnt = rd_reg_word_relaxed(ISP_REQ_Q_OUT(ha, reg)); 3798c2ecf20Sopenharmony_ci if (req->ring_index < cnt) 3808c2ecf20Sopenharmony_ci req->cnt = cnt - req->ring_index; 3818c2ecf20Sopenharmony_ci else 3828c2ecf20Sopenharmony_ci req->cnt = req->length - 3838c2ecf20Sopenharmony_ci (req->ring_index - cnt); 3848c2ecf20Sopenharmony_ci /* If still no head room then bail out */ 3858c2ecf20Sopenharmony_ci if (req->cnt < (req_cnt + 2)) 3868c2ecf20Sopenharmony_ci goto queuing_error; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* Build command packet */ 3908c2ecf20Sopenharmony_ci req->current_outstanding_cmd = handle; 3918c2ecf20Sopenharmony_ci req->outstanding_cmds[handle] = sp; 3928c2ecf20Sopenharmony_ci sp->handle = handle; 3938c2ecf20Sopenharmony_ci cmd->host_scribble = (unsigned char *)(unsigned long)handle; 3948c2ecf20Sopenharmony_ci req->cnt -= req_cnt; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci cmd_pkt = (cmd_entry_t *)req->ring_ptr; 3978c2ecf20Sopenharmony_ci cmd_pkt->handle = handle; 3988c2ecf20Sopenharmony_ci /* Zero out remaining portion of packet. */ 3998c2ecf20Sopenharmony_ci clr_ptr = (uint32_t *)cmd_pkt + 2; 4008c2ecf20Sopenharmony_ci memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); 4018c2ecf20Sopenharmony_ci cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci /* Set target ID and LUN number*/ 4048c2ecf20Sopenharmony_ci SET_TARGET_ID(ha, cmd_pkt->target, sp->fcport->loop_id); 4058c2ecf20Sopenharmony_ci cmd_pkt->lun = cpu_to_le16(cmd->device->lun); 4068c2ecf20Sopenharmony_ci cmd_pkt->control_flags = cpu_to_le16(CF_SIMPLE_TAG); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci /* Load SCSI command packet. */ 4098c2ecf20Sopenharmony_ci memcpy(cmd_pkt->scsi_cdb, cmd->cmnd, cmd->cmd_len); 4108c2ecf20Sopenharmony_ci cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci /* Build IOCB segments */ 4138c2ecf20Sopenharmony_ci ha->isp_ops->build_iocbs(sp, cmd_pkt, tot_dsds); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci /* Set total data segment count. */ 4168c2ecf20Sopenharmony_ci cmd_pkt->entry_count = (uint8_t)req_cnt; 4178c2ecf20Sopenharmony_ci wmb(); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci /* Adjust ring index. */ 4208c2ecf20Sopenharmony_ci req->ring_index++; 4218c2ecf20Sopenharmony_ci if (req->ring_index == req->length) { 4228c2ecf20Sopenharmony_ci req->ring_index = 0; 4238c2ecf20Sopenharmony_ci req->ring_ptr = req->ring; 4248c2ecf20Sopenharmony_ci } else 4258c2ecf20Sopenharmony_ci req->ring_ptr++; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci sp->flags |= SRB_DMA_VALID; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci /* Set chip new ring index. */ 4308c2ecf20Sopenharmony_ci wrt_reg_word(ISP_REQ_Q_IN(ha, reg), req->ring_index); 4318c2ecf20Sopenharmony_ci rd_reg_word_relaxed(ISP_REQ_Q_IN(ha, reg)); /* PCI Posting. */ 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci /* Manage unprocessed RIO/ZIO commands in response queue. */ 4348c2ecf20Sopenharmony_ci if (vha->flags.process_response_queue && 4358c2ecf20Sopenharmony_ci rsp->ring_ptr->signature != RESPONSE_PROCESSED) 4368c2ecf20Sopenharmony_ci qla2x00_process_response_queue(rsp); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 4398c2ecf20Sopenharmony_ci return (QLA_SUCCESS); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ciqueuing_error: 4428c2ecf20Sopenharmony_ci if (tot_dsds) 4438c2ecf20Sopenharmony_ci scsi_dma_unmap(cmd); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci return (QLA_FUNCTION_FAILED); 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci/** 4518c2ecf20Sopenharmony_ci * qla2x00_start_iocbs() - Execute the IOCB command 4528c2ecf20Sopenharmony_ci * @vha: HA context 4538c2ecf20Sopenharmony_ci * @req: request queue 4548c2ecf20Sopenharmony_ci */ 4558c2ecf20Sopenharmony_civoid 4568c2ecf20Sopenharmony_ciqla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 4598c2ecf20Sopenharmony_ci device_reg_t *reg = ISP_QUE_REG(ha, req->id); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (IS_P3P_TYPE(ha)) { 4628c2ecf20Sopenharmony_ci qla82xx_start_iocbs(vha); 4638c2ecf20Sopenharmony_ci } else { 4648c2ecf20Sopenharmony_ci /* Adjust ring index. */ 4658c2ecf20Sopenharmony_ci req->ring_index++; 4668c2ecf20Sopenharmony_ci if (req->ring_index == req->length) { 4678c2ecf20Sopenharmony_ci req->ring_index = 0; 4688c2ecf20Sopenharmony_ci req->ring_ptr = req->ring; 4698c2ecf20Sopenharmony_ci } else 4708c2ecf20Sopenharmony_ci req->ring_ptr++; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci /* Set chip new ring index. */ 4738c2ecf20Sopenharmony_ci if (ha->mqenable || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { 4748c2ecf20Sopenharmony_ci wrt_reg_dword(req->req_q_in, req->ring_index); 4758c2ecf20Sopenharmony_ci } else if (IS_QLA83XX(ha)) { 4768c2ecf20Sopenharmony_ci wrt_reg_dword(req->req_q_in, req->ring_index); 4778c2ecf20Sopenharmony_ci rd_reg_dword_relaxed(&ha->iobase->isp24.hccr); 4788c2ecf20Sopenharmony_ci } else if (IS_QLAFX00(ha)) { 4798c2ecf20Sopenharmony_ci wrt_reg_dword(®->ispfx00.req_q_in, req->ring_index); 4808c2ecf20Sopenharmony_ci rd_reg_dword_relaxed(®->ispfx00.req_q_in); 4818c2ecf20Sopenharmony_ci QLAFX00_SET_HST_INTR(ha, ha->rqstq_intr_code); 4828c2ecf20Sopenharmony_ci } else if (IS_FWI2_CAPABLE(ha)) { 4838c2ecf20Sopenharmony_ci wrt_reg_dword(®->isp24.req_q_in, req->ring_index); 4848c2ecf20Sopenharmony_ci rd_reg_dword_relaxed(®->isp24.req_q_in); 4858c2ecf20Sopenharmony_ci } else { 4868c2ecf20Sopenharmony_ci wrt_reg_word(ISP_REQ_Q_IN(ha, ®->isp), 4878c2ecf20Sopenharmony_ci req->ring_index); 4888c2ecf20Sopenharmony_ci rd_reg_word_relaxed(ISP_REQ_Q_IN(ha, ®->isp)); 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci/** 4948c2ecf20Sopenharmony_ci * qla2x00_marker() - Send a marker IOCB to the firmware. 4958c2ecf20Sopenharmony_ci * @vha: HA context 4968c2ecf20Sopenharmony_ci * @qpair: queue pair pointer 4978c2ecf20Sopenharmony_ci * @loop_id: loop ID 4988c2ecf20Sopenharmony_ci * @lun: LUN 4998c2ecf20Sopenharmony_ci * @type: marker modifier 5008c2ecf20Sopenharmony_ci * 5018c2ecf20Sopenharmony_ci * Can be called from both normal and interrupt context. 5028c2ecf20Sopenharmony_ci * 5038c2ecf20Sopenharmony_ci * Returns non-zero if a failure occurred, else zero. 5048c2ecf20Sopenharmony_ci */ 5058c2ecf20Sopenharmony_cistatic int 5068c2ecf20Sopenharmony_ci__qla2x00_marker(struct scsi_qla_host *vha, struct qla_qpair *qpair, 5078c2ecf20Sopenharmony_ci uint16_t loop_id, uint64_t lun, uint8_t type) 5088c2ecf20Sopenharmony_ci{ 5098c2ecf20Sopenharmony_ci mrk_entry_t *mrk; 5108c2ecf20Sopenharmony_ci struct mrk_entry_24xx *mrk24 = NULL; 5118c2ecf20Sopenharmony_ci struct req_que *req = qpair->req; 5128c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 5138c2ecf20Sopenharmony_ci scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci mrk = (mrk_entry_t *)__qla2x00_alloc_iocbs(qpair, NULL); 5168c2ecf20Sopenharmony_ci if (mrk == NULL) { 5178c2ecf20Sopenharmony_ci ql_log(ql_log_warn, base_vha, 0x3026, 5188c2ecf20Sopenharmony_ci "Failed to allocate Marker IOCB.\n"); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci return (QLA_FUNCTION_FAILED); 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci mrk->entry_type = MARKER_TYPE; 5248c2ecf20Sopenharmony_ci mrk->modifier = type; 5258c2ecf20Sopenharmony_ci if (type != MK_SYNC_ALL) { 5268c2ecf20Sopenharmony_ci if (IS_FWI2_CAPABLE(ha)) { 5278c2ecf20Sopenharmony_ci mrk24 = (struct mrk_entry_24xx *) mrk; 5288c2ecf20Sopenharmony_ci mrk24->nport_handle = cpu_to_le16(loop_id); 5298c2ecf20Sopenharmony_ci int_to_scsilun(lun, (struct scsi_lun *)&mrk24->lun); 5308c2ecf20Sopenharmony_ci host_to_fcp_swap(mrk24->lun, sizeof(mrk24->lun)); 5318c2ecf20Sopenharmony_ci mrk24->vp_index = vha->vp_idx; 5328c2ecf20Sopenharmony_ci mrk24->handle = make_handle(req->id, mrk24->handle); 5338c2ecf20Sopenharmony_ci } else { 5348c2ecf20Sopenharmony_ci SET_TARGET_ID(ha, mrk->target, loop_id); 5358c2ecf20Sopenharmony_ci mrk->lun = cpu_to_le16((uint16_t)lun); 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci wmb(); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci qla2x00_start_iocbs(vha, req); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci return (QLA_SUCCESS); 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ciint 5468c2ecf20Sopenharmony_ciqla2x00_marker(struct scsi_qla_host *vha, struct qla_qpair *qpair, 5478c2ecf20Sopenharmony_ci uint16_t loop_id, uint64_t lun, uint8_t type) 5488c2ecf20Sopenharmony_ci{ 5498c2ecf20Sopenharmony_ci int ret; 5508c2ecf20Sopenharmony_ci unsigned long flags = 0; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci spin_lock_irqsave(qpair->qp_lock_ptr, flags); 5538c2ecf20Sopenharmony_ci ret = __qla2x00_marker(vha, qpair, loop_id, lun, type); 5548c2ecf20Sopenharmony_ci spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci return (ret); 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci/* 5608c2ecf20Sopenharmony_ci * qla2x00_issue_marker 5618c2ecf20Sopenharmony_ci * 5628c2ecf20Sopenharmony_ci * Issue marker 5638c2ecf20Sopenharmony_ci * Caller CAN have hardware lock held as specified by ha_locked parameter. 5648c2ecf20Sopenharmony_ci * Might release it, then reaquire. 5658c2ecf20Sopenharmony_ci */ 5668c2ecf20Sopenharmony_ciint qla2x00_issue_marker(scsi_qla_host_t *vha, int ha_locked) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci if (ha_locked) { 5698c2ecf20Sopenharmony_ci if (__qla2x00_marker(vha, vha->hw->base_qpair, 0, 0, 5708c2ecf20Sopenharmony_ci MK_SYNC_ALL) != QLA_SUCCESS) 5718c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 5728c2ecf20Sopenharmony_ci } else { 5738c2ecf20Sopenharmony_ci if (qla2x00_marker(vha, vha->hw->base_qpair, 0, 0, 5748c2ecf20Sopenharmony_ci MK_SYNC_ALL) != QLA_SUCCESS) 5758c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci vha->marker_needed = 0; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci return QLA_SUCCESS; 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_cistatic inline int 5838c2ecf20Sopenharmony_ciqla24xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt, 5848c2ecf20Sopenharmony_ci uint16_t tot_dsds) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci struct dsd64 *cur_dsd = NULL, *next_dsd; 5878c2ecf20Sopenharmony_ci scsi_qla_host_t *vha; 5888c2ecf20Sopenharmony_ci struct qla_hw_data *ha; 5898c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd; 5908c2ecf20Sopenharmony_ci struct scatterlist *cur_seg; 5918c2ecf20Sopenharmony_ci uint8_t avail_dsds; 5928c2ecf20Sopenharmony_ci uint8_t first_iocb = 1; 5938c2ecf20Sopenharmony_ci uint32_t dsd_list_len; 5948c2ecf20Sopenharmony_ci struct dsd_dma *dsd_ptr; 5958c2ecf20Sopenharmony_ci struct ct6_dsd *ctx; 5968c2ecf20Sopenharmony_ci struct qla_qpair *qpair = sp->qpair; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci cmd = GET_CMD_SP(sp); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci /* Update entry type to indicate Command Type 3 IOCB */ 6018c2ecf20Sopenharmony_ci put_unaligned_le32(COMMAND_TYPE_6, &cmd_pkt->entry_type); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci /* No data transfer */ 6048c2ecf20Sopenharmony_ci if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE || 6058c2ecf20Sopenharmony_ci tot_dsds == 0) { 6068c2ecf20Sopenharmony_ci cmd_pkt->byte_count = cpu_to_le32(0); 6078c2ecf20Sopenharmony_ci return 0; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci vha = sp->vha; 6118c2ecf20Sopenharmony_ci ha = vha->hw; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci /* Set transfer direction */ 6148c2ecf20Sopenharmony_ci if (cmd->sc_data_direction == DMA_TO_DEVICE) { 6158c2ecf20Sopenharmony_ci cmd_pkt->control_flags = cpu_to_le16(CF_WRITE_DATA); 6168c2ecf20Sopenharmony_ci qpair->counters.output_bytes += scsi_bufflen(cmd); 6178c2ecf20Sopenharmony_ci qpair->counters.output_requests++; 6188c2ecf20Sopenharmony_ci } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) { 6198c2ecf20Sopenharmony_ci cmd_pkt->control_flags = cpu_to_le16(CF_READ_DATA); 6208c2ecf20Sopenharmony_ci qpair->counters.input_bytes += scsi_bufflen(cmd); 6218c2ecf20Sopenharmony_ci qpair->counters.input_requests++; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci cur_seg = scsi_sglist(cmd); 6258c2ecf20Sopenharmony_ci ctx = sp->u.scmd.ct6_ctx; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci while (tot_dsds) { 6288c2ecf20Sopenharmony_ci avail_dsds = (tot_dsds > QLA_DSDS_PER_IOCB) ? 6298c2ecf20Sopenharmony_ci QLA_DSDS_PER_IOCB : tot_dsds; 6308c2ecf20Sopenharmony_ci tot_dsds -= avail_dsds; 6318c2ecf20Sopenharmony_ci dsd_list_len = (avail_dsds + 1) * QLA_DSD_SIZE; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci dsd_ptr = list_first_entry(&ha->gbl_dsd_list, 6348c2ecf20Sopenharmony_ci struct dsd_dma, list); 6358c2ecf20Sopenharmony_ci next_dsd = dsd_ptr->dsd_addr; 6368c2ecf20Sopenharmony_ci list_del(&dsd_ptr->list); 6378c2ecf20Sopenharmony_ci ha->gbl_dsd_avail--; 6388c2ecf20Sopenharmony_ci list_add_tail(&dsd_ptr->list, &ctx->dsd_list); 6398c2ecf20Sopenharmony_ci ctx->dsd_use_cnt++; 6408c2ecf20Sopenharmony_ci ha->gbl_dsd_inuse++; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (first_iocb) { 6438c2ecf20Sopenharmony_ci first_iocb = 0; 6448c2ecf20Sopenharmony_ci put_unaligned_le64(dsd_ptr->dsd_list_dma, 6458c2ecf20Sopenharmony_ci &cmd_pkt->fcp_dsd.address); 6468c2ecf20Sopenharmony_ci cmd_pkt->fcp_dsd.length = cpu_to_le32(dsd_list_len); 6478c2ecf20Sopenharmony_ci } else { 6488c2ecf20Sopenharmony_ci put_unaligned_le64(dsd_ptr->dsd_list_dma, 6498c2ecf20Sopenharmony_ci &cur_dsd->address); 6508c2ecf20Sopenharmony_ci cur_dsd->length = cpu_to_le32(dsd_list_len); 6518c2ecf20Sopenharmony_ci cur_dsd++; 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci cur_dsd = next_dsd; 6548c2ecf20Sopenharmony_ci while (avail_dsds) { 6558c2ecf20Sopenharmony_ci append_dsd64(&cur_dsd, cur_seg); 6568c2ecf20Sopenharmony_ci cur_seg = sg_next(cur_seg); 6578c2ecf20Sopenharmony_ci avail_dsds--; 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci /* Null termination */ 6628c2ecf20Sopenharmony_ci cur_dsd->address = 0; 6638c2ecf20Sopenharmony_ci cur_dsd->length = 0; 6648c2ecf20Sopenharmony_ci cur_dsd++; 6658c2ecf20Sopenharmony_ci cmd_pkt->control_flags |= cpu_to_le16(CF_DATA_SEG_DESCR_ENABLE); 6668c2ecf20Sopenharmony_ci return 0; 6678c2ecf20Sopenharmony_ci} 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci/* 6708c2ecf20Sopenharmony_ci * qla24xx_calc_dsd_lists() - Determine number of DSD list required 6718c2ecf20Sopenharmony_ci * for Command Type 6. 6728c2ecf20Sopenharmony_ci * 6738c2ecf20Sopenharmony_ci * @dsds: number of data segment descriptors needed 6748c2ecf20Sopenharmony_ci * 6758c2ecf20Sopenharmony_ci * Returns the number of dsd list needed to store @dsds. 6768c2ecf20Sopenharmony_ci */ 6778c2ecf20Sopenharmony_cistatic inline uint16_t 6788c2ecf20Sopenharmony_ciqla24xx_calc_dsd_lists(uint16_t dsds) 6798c2ecf20Sopenharmony_ci{ 6808c2ecf20Sopenharmony_ci uint16_t dsd_lists = 0; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci dsd_lists = (dsds/QLA_DSDS_PER_IOCB); 6838c2ecf20Sopenharmony_ci if (dsds % QLA_DSDS_PER_IOCB) 6848c2ecf20Sopenharmony_ci dsd_lists++; 6858c2ecf20Sopenharmony_ci return dsd_lists; 6868c2ecf20Sopenharmony_ci} 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci/** 6908c2ecf20Sopenharmony_ci * qla24xx_build_scsi_iocbs() - Build IOCB command utilizing Command Type 7 6918c2ecf20Sopenharmony_ci * IOCB types. 6928c2ecf20Sopenharmony_ci * 6938c2ecf20Sopenharmony_ci * @sp: SRB command to process 6948c2ecf20Sopenharmony_ci * @cmd_pkt: Command type 3 IOCB 6958c2ecf20Sopenharmony_ci * @tot_dsds: Total number of segments to transfer 6968c2ecf20Sopenharmony_ci * @req: pointer to request queue 6978c2ecf20Sopenharmony_ci */ 6988c2ecf20Sopenharmony_ciinline void 6998c2ecf20Sopenharmony_ciqla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt, 7008c2ecf20Sopenharmony_ci uint16_t tot_dsds, struct req_que *req) 7018c2ecf20Sopenharmony_ci{ 7028c2ecf20Sopenharmony_ci uint16_t avail_dsds; 7038c2ecf20Sopenharmony_ci struct dsd64 *cur_dsd; 7048c2ecf20Sopenharmony_ci scsi_qla_host_t *vha; 7058c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd; 7068c2ecf20Sopenharmony_ci struct scatterlist *sg; 7078c2ecf20Sopenharmony_ci int i; 7088c2ecf20Sopenharmony_ci struct qla_qpair *qpair = sp->qpair; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci cmd = GET_CMD_SP(sp); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci /* Update entry type to indicate Command Type 3 IOCB */ 7138c2ecf20Sopenharmony_ci put_unaligned_le32(COMMAND_TYPE_7, &cmd_pkt->entry_type); 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci /* No data transfer */ 7168c2ecf20Sopenharmony_ci if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { 7178c2ecf20Sopenharmony_ci cmd_pkt->byte_count = cpu_to_le32(0); 7188c2ecf20Sopenharmony_ci return; 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci vha = sp->vha; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci /* Set transfer direction */ 7248c2ecf20Sopenharmony_ci if (cmd->sc_data_direction == DMA_TO_DEVICE) { 7258c2ecf20Sopenharmony_ci cmd_pkt->task_mgmt_flags = cpu_to_le16(TMF_WRITE_DATA); 7268c2ecf20Sopenharmony_ci qpair->counters.output_bytes += scsi_bufflen(cmd); 7278c2ecf20Sopenharmony_ci qpair->counters.output_requests++; 7288c2ecf20Sopenharmony_ci } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) { 7298c2ecf20Sopenharmony_ci cmd_pkt->task_mgmt_flags = cpu_to_le16(TMF_READ_DATA); 7308c2ecf20Sopenharmony_ci qpair->counters.input_bytes += scsi_bufflen(cmd); 7318c2ecf20Sopenharmony_ci qpair->counters.input_requests++; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci /* One DSD is available in the Command Type 3 IOCB */ 7358c2ecf20Sopenharmony_ci avail_dsds = 1; 7368c2ecf20Sopenharmony_ci cur_dsd = &cmd_pkt->dsd; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci /* Load data segments */ 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci scsi_for_each_sg(cmd, sg, tot_dsds, i) { 7418c2ecf20Sopenharmony_ci cont_a64_entry_t *cont_pkt; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci /* Allocate additional continuation packets? */ 7448c2ecf20Sopenharmony_ci if (avail_dsds == 0) { 7458c2ecf20Sopenharmony_ci /* 7468c2ecf20Sopenharmony_ci * Five DSDs are available in the Continuation 7478c2ecf20Sopenharmony_ci * Type 1 IOCB. 7488c2ecf20Sopenharmony_ci */ 7498c2ecf20Sopenharmony_ci cont_pkt = qla2x00_prep_cont_type1_iocb(vha, req); 7508c2ecf20Sopenharmony_ci cur_dsd = cont_pkt->dsd; 7518c2ecf20Sopenharmony_ci avail_dsds = ARRAY_SIZE(cont_pkt->dsd); 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci append_dsd64(&cur_dsd, sg); 7558c2ecf20Sopenharmony_ci avail_dsds--; 7568c2ecf20Sopenharmony_ci } 7578c2ecf20Sopenharmony_ci} 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_cistruct fw_dif_context { 7608c2ecf20Sopenharmony_ci __le32 ref_tag; 7618c2ecf20Sopenharmony_ci __le16 app_tag; 7628c2ecf20Sopenharmony_ci uint8_t ref_tag_mask[4]; /* Validation/Replacement Mask*/ 7638c2ecf20Sopenharmony_ci uint8_t app_tag_mask[2]; /* Validation/Replacement Mask*/ 7648c2ecf20Sopenharmony_ci}; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci/* 7678c2ecf20Sopenharmony_ci * qla24xx_set_t10dif_tags_from_cmd - Extract Ref and App tags from SCSI command 7688c2ecf20Sopenharmony_ci * 7698c2ecf20Sopenharmony_ci */ 7708c2ecf20Sopenharmony_cistatic inline void 7718c2ecf20Sopenharmony_ciqla24xx_set_t10dif_tags(srb_t *sp, struct fw_dif_context *pkt, 7728c2ecf20Sopenharmony_ci unsigned int protcnt) 7738c2ecf20Sopenharmony_ci{ 7748c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd = GET_CMD_SP(sp); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci switch (scsi_get_prot_type(cmd)) { 7778c2ecf20Sopenharmony_ci case SCSI_PROT_DIF_TYPE0: 7788c2ecf20Sopenharmony_ci /* 7798c2ecf20Sopenharmony_ci * No check for ql2xenablehba_err_chk, as it would be an 7808c2ecf20Sopenharmony_ci * I/O error if hba tag generation is not done. 7818c2ecf20Sopenharmony_ci */ 7828c2ecf20Sopenharmony_ci pkt->ref_tag = cpu_to_le32((uint32_t) 7838c2ecf20Sopenharmony_ci (0xffffffff & scsi_get_lba(cmd))); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci if (!qla2x00_hba_err_chk_enabled(sp)) 7868c2ecf20Sopenharmony_ci break; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci pkt->ref_tag_mask[0] = 0xff; 7898c2ecf20Sopenharmony_ci pkt->ref_tag_mask[1] = 0xff; 7908c2ecf20Sopenharmony_ci pkt->ref_tag_mask[2] = 0xff; 7918c2ecf20Sopenharmony_ci pkt->ref_tag_mask[3] = 0xff; 7928c2ecf20Sopenharmony_ci break; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci /* 7958c2ecf20Sopenharmony_ci * For TYPE 2 protection: 16 bit GUARD + 32 bit REF tag has to 7968c2ecf20Sopenharmony_ci * match LBA in CDB + N 7978c2ecf20Sopenharmony_ci */ 7988c2ecf20Sopenharmony_ci case SCSI_PROT_DIF_TYPE2: 7998c2ecf20Sopenharmony_ci pkt->app_tag = cpu_to_le16(0); 8008c2ecf20Sopenharmony_ci pkt->app_tag_mask[0] = 0x0; 8018c2ecf20Sopenharmony_ci pkt->app_tag_mask[1] = 0x0; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci pkt->ref_tag = cpu_to_le32((uint32_t) 8048c2ecf20Sopenharmony_ci (0xffffffff & scsi_get_lba(cmd))); 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci if (!qla2x00_hba_err_chk_enabled(sp)) 8078c2ecf20Sopenharmony_ci break; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci /* enable ALL bytes of the ref tag */ 8108c2ecf20Sopenharmony_ci pkt->ref_tag_mask[0] = 0xff; 8118c2ecf20Sopenharmony_ci pkt->ref_tag_mask[1] = 0xff; 8128c2ecf20Sopenharmony_ci pkt->ref_tag_mask[2] = 0xff; 8138c2ecf20Sopenharmony_ci pkt->ref_tag_mask[3] = 0xff; 8148c2ecf20Sopenharmony_ci break; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci /* For Type 3 protection: 16 bit GUARD only */ 8178c2ecf20Sopenharmony_ci case SCSI_PROT_DIF_TYPE3: 8188c2ecf20Sopenharmony_ci pkt->ref_tag_mask[0] = pkt->ref_tag_mask[1] = 8198c2ecf20Sopenharmony_ci pkt->ref_tag_mask[2] = pkt->ref_tag_mask[3] = 8208c2ecf20Sopenharmony_ci 0x00; 8218c2ecf20Sopenharmony_ci break; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci /* 8248c2ecf20Sopenharmony_ci * For TYpe 1 protection: 16 bit GUARD tag, 32 bit REF tag, and 8258c2ecf20Sopenharmony_ci * 16 bit app tag. 8268c2ecf20Sopenharmony_ci */ 8278c2ecf20Sopenharmony_ci case SCSI_PROT_DIF_TYPE1: 8288c2ecf20Sopenharmony_ci pkt->ref_tag = cpu_to_le32((uint32_t) 8298c2ecf20Sopenharmony_ci (0xffffffff & scsi_get_lba(cmd))); 8308c2ecf20Sopenharmony_ci pkt->app_tag = cpu_to_le16(0); 8318c2ecf20Sopenharmony_ci pkt->app_tag_mask[0] = 0x0; 8328c2ecf20Sopenharmony_ci pkt->app_tag_mask[1] = 0x0; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci if (!qla2x00_hba_err_chk_enabled(sp)) 8358c2ecf20Sopenharmony_ci break; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci /* enable ALL bytes of the ref tag */ 8388c2ecf20Sopenharmony_ci pkt->ref_tag_mask[0] = 0xff; 8398c2ecf20Sopenharmony_ci pkt->ref_tag_mask[1] = 0xff; 8408c2ecf20Sopenharmony_ci pkt->ref_tag_mask[2] = 0xff; 8418c2ecf20Sopenharmony_ci pkt->ref_tag_mask[3] = 0xff; 8428c2ecf20Sopenharmony_ci break; 8438c2ecf20Sopenharmony_ci } 8448c2ecf20Sopenharmony_ci} 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ciint 8478c2ecf20Sopenharmony_ciqla24xx_get_one_block_sg(uint32_t blk_sz, struct qla2_sgx *sgx, 8488c2ecf20Sopenharmony_ci uint32_t *partial) 8498c2ecf20Sopenharmony_ci{ 8508c2ecf20Sopenharmony_ci struct scatterlist *sg; 8518c2ecf20Sopenharmony_ci uint32_t cumulative_partial, sg_len; 8528c2ecf20Sopenharmony_ci dma_addr_t sg_dma_addr; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci if (sgx->num_bytes == sgx->tot_bytes) 8558c2ecf20Sopenharmony_ci return 0; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci sg = sgx->cur_sg; 8588c2ecf20Sopenharmony_ci cumulative_partial = sgx->tot_partial; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci sg_dma_addr = sg_dma_address(sg); 8618c2ecf20Sopenharmony_ci sg_len = sg_dma_len(sg); 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci sgx->dma_addr = sg_dma_addr + sgx->bytes_consumed; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci if ((cumulative_partial + (sg_len - sgx->bytes_consumed)) >= blk_sz) { 8668c2ecf20Sopenharmony_ci sgx->dma_len = (blk_sz - cumulative_partial); 8678c2ecf20Sopenharmony_ci sgx->tot_partial = 0; 8688c2ecf20Sopenharmony_ci sgx->num_bytes += blk_sz; 8698c2ecf20Sopenharmony_ci *partial = 0; 8708c2ecf20Sopenharmony_ci } else { 8718c2ecf20Sopenharmony_ci sgx->dma_len = sg_len - sgx->bytes_consumed; 8728c2ecf20Sopenharmony_ci sgx->tot_partial += sgx->dma_len; 8738c2ecf20Sopenharmony_ci *partial = 1; 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci sgx->bytes_consumed += sgx->dma_len; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci if (sg_len == sgx->bytes_consumed) { 8798c2ecf20Sopenharmony_ci sg = sg_next(sg); 8808c2ecf20Sopenharmony_ci sgx->num_sg++; 8818c2ecf20Sopenharmony_ci sgx->cur_sg = sg; 8828c2ecf20Sopenharmony_ci sgx->bytes_consumed = 0; 8838c2ecf20Sopenharmony_ci } 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci return 1; 8868c2ecf20Sopenharmony_ci} 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ciint 8898c2ecf20Sopenharmony_ciqla24xx_walk_and_build_sglist_no_difb(struct qla_hw_data *ha, srb_t *sp, 8908c2ecf20Sopenharmony_ci struct dsd64 *dsd, uint16_t tot_dsds, struct qla_tc_param *tc) 8918c2ecf20Sopenharmony_ci{ 8928c2ecf20Sopenharmony_ci void *next_dsd; 8938c2ecf20Sopenharmony_ci uint8_t avail_dsds = 0; 8948c2ecf20Sopenharmony_ci uint32_t dsd_list_len; 8958c2ecf20Sopenharmony_ci struct dsd_dma *dsd_ptr; 8968c2ecf20Sopenharmony_ci struct scatterlist *sg_prot; 8978c2ecf20Sopenharmony_ci struct dsd64 *cur_dsd = dsd; 8988c2ecf20Sopenharmony_ci uint16_t used_dsds = tot_dsds; 8998c2ecf20Sopenharmony_ci uint32_t prot_int; /* protection interval */ 9008c2ecf20Sopenharmony_ci uint32_t partial; 9018c2ecf20Sopenharmony_ci struct qla2_sgx sgx; 9028c2ecf20Sopenharmony_ci dma_addr_t sle_dma; 9038c2ecf20Sopenharmony_ci uint32_t sle_dma_len, tot_prot_dma_len = 0; 9048c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci memset(&sgx, 0, sizeof(struct qla2_sgx)); 9078c2ecf20Sopenharmony_ci if (sp) { 9088c2ecf20Sopenharmony_ci cmd = GET_CMD_SP(sp); 9098c2ecf20Sopenharmony_ci prot_int = cmd->device->sector_size; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci sgx.tot_bytes = scsi_bufflen(cmd); 9128c2ecf20Sopenharmony_ci sgx.cur_sg = scsi_sglist(cmd); 9138c2ecf20Sopenharmony_ci sgx.sp = sp; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci sg_prot = scsi_prot_sglist(cmd); 9168c2ecf20Sopenharmony_ci } else if (tc) { 9178c2ecf20Sopenharmony_ci prot_int = tc->blk_sz; 9188c2ecf20Sopenharmony_ci sgx.tot_bytes = tc->bufflen; 9198c2ecf20Sopenharmony_ci sgx.cur_sg = tc->sg; 9208c2ecf20Sopenharmony_ci sg_prot = tc->prot_sg; 9218c2ecf20Sopenharmony_ci } else { 9228c2ecf20Sopenharmony_ci BUG(); 9238c2ecf20Sopenharmony_ci return 1; 9248c2ecf20Sopenharmony_ci } 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci while (qla24xx_get_one_block_sg(prot_int, &sgx, &partial)) { 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci sle_dma = sgx.dma_addr; 9298c2ecf20Sopenharmony_ci sle_dma_len = sgx.dma_len; 9308c2ecf20Sopenharmony_cialloc_and_fill: 9318c2ecf20Sopenharmony_ci /* Allocate additional continuation packets? */ 9328c2ecf20Sopenharmony_ci if (avail_dsds == 0) { 9338c2ecf20Sopenharmony_ci avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ? 9348c2ecf20Sopenharmony_ci QLA_DSDS_PER_IOCB : used_dsds; 9358c2ecf20Sopenharmony_ci dsd_list_len = (avail_dsds + 1) * 12; 9368c2ecf20Sopenharmony_ci used_dsds -= avail_dsds; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci /* allocate tracking DS */ 9398c2ecf20Sopenharmony_ci dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC); 9408c2ecf20Sopenharmony_ci if (!dsd_ptr) 9418c2ecf20Sopenharmony_ci return 1; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci /* allocate new list */ 9448c2ecf20Sopenharmony_ci dsd_ptr->dsd_addr = next_dsd = 9458c2ecf20Sopenharmony_ci dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC, 9468c2ecf20Sopenharmony_ci &dsd_ptr->dsd_list_dma); 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci if (!next_dsd) { 9498c2ecf20Sopenharmony_ci /* 9508c2ecf20Sopenharmony_ci * Need to cleanup only this dsd_ptr, rest 9518c2ecf20Sopenharmony_ci * will be done by sp_free_dma() 9528c2ecf20Sopenharmony_ci */ 9538c2ecf20Sopenharmony_ci kfree(dsd_ptr); 9548c2ecf20Sopenharmony_ci return 1; 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci if (sp) { 9588c2ecf20Sopenharmony_ci list_add_tail(&dsd_ptr->list, 9598c2ecf20Sopenharmony_ci &sp->u.scmd.crc_ctx->dsd_list); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci sp->flags |= SRB_CRC_CTX_DSD_VALID; 9628c2ecf20Sopenharmony_ci } else { 9638c2ecf20Sopenharmony_ci list_add_tail(&dsd_ptr->list, 9648c2ecf20Sopenharmony_ci &(tc->ctx->dsd_list)); 9658c2ecf20Sopenharmony_ci *tc->ctx_dsd_alloced = 1; 9668c2ecf20Sopenharmony_ci } 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci /* add new list to cmd iocb or last list */ 9708c2ecf20Sopenharmony_ci put_unaligned_le64(dsd_ptr->dsd_list_dma, 9718c2ecf20Sopenharmony_ci &cur_dsd->address); 9728c2ecf20Sopenharmony_ci cur_dsd->length = cpu_to_le32(dsd_list_len); 9738c2ecf20Sopenharmony_ci cur_dsd = next_dsd; 9748c2ecf20Sopenharmony_ci } 9758c2ecf20Sopenharmony_ci put_unaligned_le64(sle_dma, &cur_dsd->address); 9768c2ecf20Sopenharmony_ci cur_dsd->length = cpu_to_le32(sle_dma_len); 9778c2ecf20Sopenharmony_ci cur_dsd++; 9788c2ecf20Sopenharmony_ci avail_dsds--; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci if (partial == 0) { 9818c2ecf20Sopenharmony_ci /* Got a full protection interval */ 9828c2ecf20Sopenharmony_ci sle_dma = sg_dma_address(sg_prot) + tot_prot_dma_len; 9838c2ecf20Sopenharmony_ci sle_dma_len = 8; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci tot_prot_dma_len += sle_dma_len; 9868c2ecf20Sopenharmony_ci if (tot_prot_dma_len == sg_dma_len(sg_prot)) { 9878c2ecf20Sopenharmony_ci tot_prot_dma_len = 0; 9888c2ecf20Sopenharmony_ci sg_prot = sg_next(sg_prot); 9898c2ecf20Sopenharmony_ci } 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci partial = 1; /* So as to not re-enter this block */ 9928c2ecf20Sopenharmony_ci goto alloc_and_fill; 9938c2ecf20Sopenharmony_ci } 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci /* Null termination */ 9968c2ecf20Sopenharmony_ci cur_dsd->address = 0; 9978c2ecf20Sopenharmony_ci cur_dsd->length = 0; 9988c2ecf20Sopenharmony_ci cur_dsd++; 9998c2ecf20Sopenharmony_ci return 0; 10008c2ecf20Sopenharmony_ci} 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ciint 10038c2ecf20Sopenharmony_ciqla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, 10048c2ecf20Sopenharmony_ci struct dsd64 *dsd, uint16_t tot_dsds, struct qla_tc_param *tc) 10058c2ecf20Sopenharmony_ci{ 10068c2ecf20Sopenharmony_ci void *next_dsd; 10078c2ecf20Sopenharmony_ci uint8_t avail_dsds = 0; 10088c2ecf20Sopenharmony_ci uint32_t dsd_list_len; 10098c2ecf20Sopenharmony_ci struct dsd_dma *dsd_ptr; 10108c2ecf20Sopenharmony_ci struct scatterlist *sg, *sgl; 10118c2ecf20Sopenharmony_ci struct dsd64 *cur_dsd = dsd; 10128c2ecf20Sopenharmony_ci int i; 10138c2ecf20Sopenharmony_ci uint16_t used_dsds = tot_dsds; 10148c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci if (sp) { 10178c2ecf20Sopenharmony_ci cmd = GET_CMD_SP(sp); 10188c2ecf20Sopenharmony_ci sgl = scsi_sglist(cmd); 10198c2ecf20Sopenharmony_ci } else if (tc) { 10208c2ecf20Sopenharmony_ci sgl = tc->sg; 10218c2ecf20Sopenharmony_ci } else { 10228c2ecf20Sopenharmony_ci BUG(); 10238c2ecf20Sopenharmony_ci return 1; 10248c2ecf20Sopenharmony_ci } 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci for_each_sg(sgl, sg, tot_dsds, i) { 10288c2ecf20Sopenharmony_ci /* Allocate additional continuation packets? */ 10298c2ecf20Sopenharmony_ci if (avail_dsds == 0) { 10308c2ecf20Sopenharmony_ci avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ? 10318c2ecf20Sopenharmony_ci QLA_DSDS_PER_IOCB : used_dsds; 10328c2ecf20Sopenharmony_ci dsd_list_len = (avail_dsds + 1) * 12; 10338c2ecf20Sopenharmony_ci used_dsds -= avail_dsds; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci /* allocate tracking DS */ 10368c2ecf20Sopenharmony_ci dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC); 10378c2ecf20Sopenharmony_ci if (!dsd_ptr) 10388c2ecf20Sopenharmony_ci return 1; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci /* allocate new list */ 10418c2ecf20Sopenharmony_ci dsd_ptr->dsd_addr = next_dsd = 10428c2ecf20Sopenharmony_ci dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC, 10438c2ecf20Sopenharmony_ci &dsd_ptr->dsd_list_dma); 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci if (!next_dsd) { 10468c2ecf20Sopenharmony_ci /* 10478c2ecf20Sopenharmony_ci * Need to cleanup only this dsd_ptr, rest 10488c2ecf20Sopenharmony_ci * will be done by sp_free_dma() 10498c2ecf20Sopenharmony_ci */ 10508c2ecf20Sopenharmony_ci kfree(dsd_ptr); 10518c2ecf20Sopenharmony_ci return 1; 10528c2ecf20Sopenharmony_ci } 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci if (sp) { 10558c2ecf20Sopenharmony_ci list_add_tail(&dsd_ptr->list, 10568c2ecf20Sopenharmony_ci &sp->u.scmd.crc_ctx->dsd_list); 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci sp->flags |= SRB_CRC_CTX_DSD_VALID; 10598c2ecf20Sopenharmony_ci } else { 10608c2ecf20Sopenharmony_ci list_add_tail(&dsd_ptr->list, 10618c2ecf20Sopenharmony_ci &(tc->ctx->dsd_list)); 10628c2ecf20Sopenharmony_ci *tc->ctx_dsd_alloced = 1; 10638c2ecf20Sopenharmony_ci } 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci /* add new list to cmd iocb or last list */ 10668c2ecf20Sopenharmony_ci put_unaligned_le64(dsd_ptr->dsd_list_dma, 10678c2ecf20Sopenharmony_ci &cur_dsd->address); 10688c2ecf20Sopenharmony_ci cur_dsd->length = cpu_to_le32(dsd_list_len); 10698c2ecf20Sopenharmony_ci cur_dsd = next_dsd; 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci append_dsd64(&cur_dsd, sg); 10728c2ecf20Sopenharmony_ci avail_dsds--; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci } 10758c2ecf20Sopenharmony_ci /* Null termination */ 10768c2ecf20Sopenharmony_ci cur_dsd->address = 0; 10778c2ecf20Sopenharmony_ci cur_dsd->length = 0; 10788c2ecf20Sopenharmony_ci cur_dsd++; 10798c2ecf20Sopenharmony_ci return 0; 10808c2ecf20Sopenharmony_ci} 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ciint 10838c2ecf20Sopenharmony_ciqla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp, 10848c2ecf20Sopenharmony_ci struct dsd64 *cur_dsd, uint16_t tot_dsds, struct qla_tgt_cmd *tc) 10858c2ecf20Sopenharmony_ci{ 10868c2ecf20Sopenharmony_ci struct dsd_dma *dsd_ptr = NULL, *dif_dsd, *nxt_dsd; 10878c2ecf20Sopenharmony_ci struct scatterlist *sg, *sgl; 10888c2ecf20Sopenharmony_ci struct crc_context *difctx = NULL; 10898c2ecf20Sopenharmony_ci struct scsi_qla_host *vha; 10908c2ecf20Sopenharmony_ci uint dsd_list_len; 10918c2ecf20Sopenharmony_ci uint avail_dsds = 0; 10928c2ecf20Sopenharmony_ci uint used_dsds = tot_dsds; 10938c2ecf20Sopenharmony_ci bool dif_local_dma_alloc = false; 10948c2ecf20Sopenharmony_ci bool direction_to_device = false; 10958c2ecf20Sopenharmony_ci int i; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci if (sp) { 10988c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd = GET_CMD_SP(sp); 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci sgl = scsi_prot_sglist(cmd); 11018c2ecf20Sopenharmony_ci vha = sp->vha; 11028c2ecf20Sopenharmony_ci difctx = sp->u.scmd.crc_ctx; 11038c2ecf20Sopenharmony_ci direction_to_device = cmd->sc_data_direction == DMA_TO_DEVICE; 11048c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe021, 11058c2ecf20Sopenharmony_ci "%s: scsi_cmnd: %p, crc_ctx: %p, sp: %p\n", 11068c2ecf20Sopenharmony_ci __func__, cmd, difctx, sp); 11078c2ecf20Sopenharmony_ci } else if (tc) { 11088c2ecf20Sopenharmony_ci vha = tc->vha; 11098c2ecf20Sopenharmony_ci sgl = tc->prot_sg; 11108c2ecf20Sopenharmony_ci difctx = tc->ctx; 11118c2ecf20Sopenharmony_ci direction_to_device = tc->dma_data_direction == DMA_TO_DEVICE; 11128c2ecf20Sopenharmony_ci } else { 11138c2ecf20Sopenharmony_ci BUG(); 11148c2ecf20Sopenharmony_ci return 1; 11158c2ecf20Sopenharmony_ci } 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe021, 11188c2ecf20Sopenharmony_ci "%s: enter (write=%u)\n", __func__, direction_to_device); 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci /* if initiator doing write or target doing read */ 11218c2ecf20Sopenharmony_ci if (direction_to_device) { 11228c2ecf20Sopenharmony_ci for_each_sg(sgl, sg, tot_dsds, i) { 11238c2ecf20Sopenharmony_ci u64 sle_phys = sg_phys(sg); 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci /* If SGE addr + len flips bits in upper 32-bits */ 11268c2ecf20Sopenharmony_ci if (MSD(sle_phys + sg->length) ^ MSD(sle_phys)) { 11278c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe022, 11288c2ecf20Sopenharmony_ci "%s: page boundary crossing (phys=%llx len=%x)\n", 11298c2ecf20Sopenharmony_ci __func__, sle_phys, sg->length); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci if (difctx) { 11328c2ecf20Sopenharmony_ci ha->dif_bundle_crossed_pages++; 11338c2ecf20Sopenharmony_ci dif_local_dma_alloc = true; 11348c2ecf20Sopenharmony_ci } else { 11358c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt + ql_dbg_verbose, 11368c2ecf20Sopenharmony_ci vha, 0xe022, 11378c2ecf20Sopenharmony_ci "%s: difctx pointer is NULL\n", 11388c2ecf20Sopenharmony_ci __func__); 11398c2ecf20Sopenharmony_ci } 11408c2ecf20Sopenharmony_ci break; 11418c2ecf20Sopenharmony_ci } 11428c2ecf20Sopenharmony_ci } 11438c2ecf20Sopenharmony_ci ha->dif_bundle_writes++; 11448c2ecf20Sopenharmony_ci } else { 11458c2ecf20Sopenharmony_ci ha->dif_bundle_reads++; 11468c2ecf20Sopenharmony_ci } 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci if (ql2xdifbundlinginternalbuffers) 11498c2ecf20Sopenharmony_ci dif_local_dma_alloc = direction_to_device; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci if (dif_local_dma_alloc) { 11528c2ecf20Sopenharmony_ci u32 track_difbundl_buf = 0; 11538c2ecf20Sopenharmony_ci u32 ldma_sg_len = 0; 11548c2ecf20Sopenharmony_ci u8 ldma_needed = 1; 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci difctx->no_dif_bundl = 0; 11578c2ecf20Sopenharmony_ci difctx->dif_bundl_len = 0; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci /* Track DSD buffers */ 11608c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&difctx->ldif_dsd_list); 11618c2ecf20Sopenharmony_ci /* Track local DMA buffers */ 11628c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&difctx->ldif_dma_hndl_list); 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci for_each_sg(sgl, sg, tot_dsds, i) { 11658c2ecf20Sopenharmony_ci u32 sglen = sg_dma_len(sg); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe023, 11688c2ecf20Sopenharmony_ci "%s: sg[%x] (phys=%llx sglen=%x) ldma_sg_len: %x dif_bundl_len: %x ldma_needed: %x\n", 11698c2ecf20Sopenharmony_ci __func__, i, (u64)sg_phys(sg), sglen, ldma_sg_len, 11708c2ecf20Sopenharmony_ci difctx->dif_bundl_len, ldma_needed); 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci while (sglen) { 11738c2ecf20Sopenharmony_ci u32 xfrlen = 0; 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci if (ldma_needed) { 11768c2ecf20Sopenharmony_ci /* 11778c2ecf20Sopenharmony_ci * Allocate list item to store 11788c2ecf20Sopenharmony_ci * the DMA buffers 11798c2ecf20Sopenharmony_ci */ 11808c2ecf20Sopenharmony_ci dsd_ptr = kzalloc(sizeof(*dsd_ptr), 11818c2ecf20Sopenharmony_ci GFP_ATOMIC); 11828c2ecf20Sopenharmony_ci if (!dsd_ptr) { 11838c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe024, 11848c2ecf20Sopenharmony_ci "%s: failed alloc dsd_ptr\n", 11858c2ecf20Sopenharmony_ci __func__); 11868c2ecf20Sopenharmony_ci return 1; 11878c2ecf20Sopenharmony_ci } 11888c2ecf20Sopenharmony_ci ha->dif_bundle_kallocs++; 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci /* allocate dma buffer */ 11918c2ecf20Sopenharmony_ci dsd_ptr->dsd_addr = dma_pool_alloc 11928c2ecf20Sopenharmony_ci (ha->dif_bundl_pool, GFP_ATOMIC, 11938c2ecf20Sopenharmony_ci &dsd_ptr->dsd_list_dma); 11948c2ecf20Sopenharmony_ci if (!dsd_ptr->dsd_addr) { 11958c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe024, 11968c2ecf20Sopenharmony_ci "%s: failed alloc ->dsd_ptr\n", 11978c2ecf20Sopenharmony_ci __func__); 11988c2ecf20Sopenharmony_ci /* 11998c2ecf20Sopenharmony_ci * need to cleanup only this 12008c2ecf20Sopenharmony_ci * dsd_ptr rest will be done 12018c2ecf20Sopenharmony_ci * by sp_free_dma() 12028c2ecf20Sopenharmony_ci */ 12038c2ecf20Sopenharmony_ci kfree(dsd_ptr); 12048c2ecf20Sopenharmony_ci ha->dif_bundle_kallocs--; 12058c2ecf20Sopenharmony_ci return 1; 12068c2ecf20Sopenharmony_ci } 12078c2ecf20Sopenharmony_ci ha->dif_bundle_dma_allocs++; 12088c2ecf20Sopenharmony_ci ldma_needed = 0; 12098c2ecf20Sopenharmony_ci difctx->no_dif_bundl++; 12108c2ecf20Sopenharmony_ci list_add_tail(&dsd_ptr->list, 12118c2ecf20Sopenharmony_ci &difctx->ldif_dma_hndl_list); 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci /* xfrlen is min of dma pool size and sglen */ 12158c2ecf20Sopenharmony_ci xfrlen = (sglen > 12168c2ecf20Sopenharmony_ci (DIF_BUNDLING_DMA_POOL_SIZE - ldma_sg_len)) ? 12178c2ecf20Sopenharmony_ci DIF_BUNDLING_DMA_POOL_SIZE - ldma_sg_len : 12188c2ecf20Sopenharmony_ci sglen; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci /* replace with local allocated dma buffer */ 12218c2ecf20Sopenharmony_ci sg_pcopy_to_buffer(sgl, sg_nents(sgl), 12228c2ecf20Sopenharmony_ci dsd_ptr->dsd_addr + ldma_sg_len, xfrlen, 12238c2ecf20Sopenharmony_ci difctx->dif_bundl_len); 12248c2ecf20Sopenharmony_ci difctx->dif_bundl_len += xfrlen; 12258c2ecf20Sopenharmony_ci sglen -= xfrlen; 12268c2ecf20Sopenharmony_ci ldma_sg_len += xfrlen; 12278c2ecf20Sopenharmony_ci if (ldma_sg_len == DIF_BUNDLING_DMA_POOL_SIZE || 12288c2ecf20Sopenharmony_ci sg_is_last(sg)) { 12298c2ecf20Sopenharmony_ci ldma_needed = 1; 12308c2ecf20Sopenharmony_ci ldma_sg_len = 0; 12318c2ecf20Sopenharmony_ci } 12328c2ecf20Sopenharmony_ci } 12338c2ecf20Sopenharmony_ci } 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci track_difbundl_buf = used_dsds = difctx->no_dif_bundl; 12368c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe025, 12378c2ecf20Sopenharmony_ci "dif_bundl_len=%x, no_dif_bundl=%x track_difbundl_buf: %x\n", 12388c2ecf20Sopenharmony_ci difctx->dif_bundl_len, difctx->no_dif_bundl, 12398c2ecf20Sopenharmony_ci track_difbundl_buf); 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci if (sp) 12428c2ecf20Sopenharmony_ci sp->flags |= SRB_DIF_BUNDL_DMA_VALID; 12438c2ecf20Sopenharmony_ci else 12448c2ecf20Sopenharmony_ci tc->prot_flags = DIF_BUNDL_DMA_VALID; 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci list_for_each_entry_safe(dif_dsd, nxt_dsd, 12478c2ecf20Sopenharmony_ci &difctx->ldif_dma_hndl_list, list) { 12488c2ecf20Sopenharmony_ci u32 sglen = (difctx->dif_bundl_len > 12498c2ecf20Sopenharmony_ci DIF_BUNDLING_DMA_POOL_SIZE) ? 12508c2ecf20Sopenharmony_ci DIF_BUNDLING_DMA_POOL_SIZE : difctx->dif_bundl_len; 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci BUG_ON(track_difbundl_buf == 0); 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci /* Allocate additional continuation packets? */ 12558c2ecf20Sopenharmony_ci if (avail_dsds == 0) { 12568c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 12578c2ecf20Sopenharmony_ci 0xe024, 12588c2ecf20Sopenharmony_ci "%s: adding continuation iocb's\n", 12598c2ecf20Sopenharmony_ci __func__); 12608c2ecf20Sopenharmony_ci avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ? 12618c2ecf20Sopenharmony_ci QLA_DSDS_PER_IOCB : used_dsds; 12628c2ecf20Sopenharmony_ci dsd_list_len = (avail_dsds + 1) * 12; 12638c2ecf20Sopenharmony_ci used_dsds -= avail_dsds; 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci /* allocate tracking DS */ 12668c2ecf20Sopenharmony_ci dsd_ptr = kzalloc(sizeof(*dsd_ptr), GFP_ATOMIC); 12678c2ecf20Sopenharmony_ci if (!dsd_ptr) { 12688c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe026, 12698c2ecf20Sopenharmony_ci "%s: failed alloc dsd_ptr\n", 12708c2ecf20Sopenharmony_ci __func__); 12718c2ecf20Sopenharmony_ci return 1; 12728c2ecf20Sopenharmony_ci } 12738c2ecf20Sopenharmony_ci ha->dif_bundle_kallocs++; 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci difctx->no_ldif_dsd++; 12768c2ecf20Sopenharmony_ci /* allocate new list */ 12778c2ecf20Sopenharmony_ci dsd_ptr->dsd_addr = 12788c2ecf20Sopenharmony_ci dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC, 12798c2ecf20Sopenharmony_ci &dsd_ptr->dsd_list_dma); 12808c2ecf20Sopenharmony_ci if (!dsd_ptr->dsd_addr) { 12818c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe026, 12828c2ecf20Sopenharmony_ci "%s: failed alloc ->dsd_addr\n", 12838c2ecf20Sopenharmony_ci __func__); 12848c2ecf20Sopenharmony_ci /* 12858c2ecf20Sopenharmony_ci * need to cleanup only this dsd_ptr 12868c2ecf20Sopenharmony_ci * rest will be done by sp_free_dma() 12878c2ecf20Sopenharmony_ci */ 12888c2ecf20Sopenharmony_ci kfree(dsd_ptr); 12898c2ecf20Sopenharmony_ci ha->dif_bundle_kallocs--; 12908c2ecf20Sopenharmony_ci return 1; 12918c2ecf20Sopenharmony_ci } 12928c2ecf20Sopenharmony_ci ha->dif_bundle_dma_allocs++; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci if (sp) { 12958c2ecf20Sopenharmony_ci list_add_tail(&dsd_ptr->list, 12968c2ecf20Sopenharmony_ci &difctx->ldif_dsd_list); 12978c2ecf20Sopenharmony_ci sp->flags |= SRB_CRC_CTX_DSD_VALID; 12988c2ecf20Sopenharmony_ci } else { 12998c2ecf20Sopenharmony_ci list_add_tail(&dsd_ptr->list, 13008c2ecf20Sopenharmony_ci &difctx->ldif_dsd_list); 13018c2ecf20Sopenharmony_ci tc->ctx_dsd_alloced = 1; 13028c2ecf20Sopenharmony_ci } 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci /* add new list to cmd iocb or last list */ 13058c2ecf20Sopenharmony_ci put_unaligned_le64(dsd_ptr->dsd_list_dma, 13068c2ecf20Sopenharmony_ci &cur_dsd->address); 13078c2ecf20Sopenharmony_ci cur_dsd->length = cpu_to_le32(dsd_list_len); 13088c2ecf20Sopenharmony_ci cur_dsd = dsd_ptr->dsd_addr; 13098c2ecf20Sopenharmony_ci } 13108c2ecf20Sopenharmony_ci put_unaligned_le64(dif_dsd->dsd_list_dma, 13118c2ecf20Sopenharmony_ci &cur_dsd->address); 13128c2ecf20Sopenharmony_ci cur_dsd->length = cpu_to_le32(sglen); 13138c2ecf20Sopenharmony_ci cur_dsd++; 13148c2ecf20Sopenharmony_ci avail_dsds--; 13158c2ecf20Sopenharmony_ci difctx->dif_bundl_len -= sglen; 13168c2ecf20Sopenharmony_ci track_difbundl_buf--; 13178c2ecf20Sopenharmony_ci } 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe026, 13208c2ecf20Sopenharmony_ci "%s: no_ldif_dsd:%x, no_dif_bundl:%x\n", __func__, 13218c2ecf20Sopenharmony_ci difctx->no_ldif_dsd, difctx->no_dif_bundl); 13228c2ecf20Sopenharmony_ci } else { 13238c2ecf20Sopenharmony_ci for_each_sg(sgl, sg, tot_dsds, i) { 13248c2ecf20Sopenharmony_ci /* Allocate additional continuation packets? */ 13258c2ecf20Sopenharmony_ci if (avail_dsds == 0) { 13268c2ecf20Sopenharmony_ci avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ? 13278c2ecf20Sopenharmony_ci QLA_DSDS_PER_IOCB : used_dsds; 13288c2ecf20Sopenharmony_ci dsd_list_len = (avail_dsds + 1) * 12; 13298c2ecf20Sopenharmony_ci used_dsds -= avail_dsds; 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci /* allocate tracking DS */ 13328c2ecf20Sopenharmony_ci dsd_ptr = kzalloc(sizeof(*dsd_ptr), GFP_ATOMIC); 13338c2ecf20Sopenharmony_ci if (!dsd_ptr) { 13348c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_tgt + ql_dbg_verbose, 13358c2ecf20Sopenharmony_ci vha, 0xe027, 13368c2ecf20Sopenharmony_ci "%s: failed alloc dsd_dma...\n", 13378c2ecf20Sopenharmony_ci __func__); 13388c2ecf20Sopenharmony_ci return 1; 13398c2ecf20Sopenharmony_ci } 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci /* allocate new list */ 13428c2ecf20Sopenharmony_ci dsd_ptr->dsd_addr = 13438c2ecf20Sopenharmony_ci dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC, 13448c2ecf20Sopenharmony_ci &dsd_ptr->dsd_list_dma); 13458c2ecf20Sopenharmony_ci if (!dsd_ptr->dsd_addr) { 13468c2ecf20Sopenharmony_ci /* need to cleanup only this dsd_ptr */ 13478c2ecf20Sopenharmony_ci /* rest will be done by sp_free_dma() */ 13488c2ecf20Sopenharmony_ci kfree(dsd_ptr); 13498c2ecf20Sopenharmony_ci return 1; 13508c2ecf20Sopenharmony_ci } 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci if (sp) { 13538c2ecf20Sopenharmony_ci list_add_tail(&dsd_ptr->list, 13548c2ecf20Sopenharmony_ci &difctx->dsd_list); 13558c2ecf20Sopenharmony_ci sp->flags |= SRB_CRC_CTX_DSD_VALID; 13568c2ecf20Sopenharmony_ci } else { 13578c2ecf20Sopenharmony_ci list_add_tail(&dsd_ptr->list, 13588c2ecf20Sopenharmony_ci &difctx->dsd_list); 13598c2ecf20Sopenharmony_ci tc->ctx_dsd_alloced = 1; 13608c2ecf20Sopenharmony_ci } 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci /* add new list to cmd iocb or last list */ 13638c2ecf20Sopenharmony_ci put_unaligned_le64(dsd_ptr->dsd_list_dma, 13648c2ecf20Sopenharmony_ci &cur_dsd->address); 13658c2ecf20Sopenharmony_ci cur_dsd->length = cpu_to_le32(dsd_list_len); 13668c2ecf20Sopenharmony_ci cur_dsd = dsd_ptr->dsd_addr; 13678c2ecf20Sopenharmony_ci } 13688c2ecf20Sopenharmony_ci append_dsd64(&cur_dsd, sg); 13698c2ecf20Sopenharmony_ci avail_dsds--; 13708c2ecf20Sopenharmony_ci } 13718c2ecf20Sopenharmony_ci } 13728c2ecf20Sopenharmony_ci /* Null termination */ 13738c2ecf20Sopenharmony_ci cur_dsd->address = 0; 13748c2ecf20Sopenharmony_ci cur_dsd->length = 0; 13758c2ecf20Sopenharmony_ci cur_dsd++; 13768c2ecf20Sopenharmony_ci return 0; 13778c2ecf20Sopenharmony_ci} 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci/** 13808c2ecf20Sopenharmony_ci * qla24xx_build_scsi_crc_2_iocbs() - Build IOCB command utilizing Command 13818c2ecf20Sopenharmony_ci * Type 6 IOCB types. 13828c2ecf20Sopenharmony_ci * 13838c2ecf20Sopenharmony_ci * @sp: SRB command to process 13848c2ecf20Sopenharmony_ci * @cmd_pkt: Command type 3 IOCB 13858c2ecf20Sopenharmony_ci * @tot_dsds: Total number of segments to transfer 13868c2ecf20Sopenharmony_ci * @tot_prot_dsds: Total number of segments with protection information 13878c2ecf20Sopenharmony_ci * @fw_prot_opts: Protection options to be passed to firmware 13888c2ecf20Sopenharmony_ci */ 13898c2ecf20Sopenharmony_cistatic inline int 13908c2ecf20Sopenharmony_ciqla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, 13918c2ecf20Sopenharmony_ci uint16_t tot_dsds, uint16_t tot_prot_dsds, uint16_t fw_prot_opts) 13928c2ecf20Sopenharmony_ci{ 13938c2ecf20Sopenharmony_ci struct dsd64 *cur_dsd; 13948c2ecf20Sopenharmony_ci __be32 *fcp_dl; 13958c2ecf20Sopenharmony_ci scsi_qla_host_t *vha; 13968c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd; 13978c2ecf20Sopenharmony_ci uint32_t total_bytes = 0; 13988c2ecf20Sopenharmony_ci uint32_t data_bytes; 13998c2ecf20Sopenharmony_ci uint32_t dif_bytes; 14008c2ecf20Sopenharmony_ci uint8_t bundling = 1; 14018c2ecf20Sopenharmony_ci uint16_t blk_size; 14028c2ecf20Sopenharmony_ci struct crc_context *crc_ctx_pkt = NULL; 14038c2ecf20Sopenharmony_ci struct qla_hw_data *ha; 14048c2ecf20Sopenharmony_ci uint8_t additional_fcpcdb_len; 14058c2ecf20Sopenharmony_ci uint16_t fcp_cmnd_len; 14068c2ecf20Sopenharmony_ci struct fcp_cmnd *fcp_cmnd; 14078c2ecf20Sopenharmony_ci dma_addr_t crc_ctx_dma; 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci cmd = GET_CMD_SP(sp); 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci /* Update entry type to indicate Command Type CRC_2 IOCB */ 14128c2ecf20Sopenharmony_ci put_unaligned_le32(COMMAND_TYPE_CRC_2, &cmd_pkt->entry_type); 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci vha = sp->vha; 14158c2ecf20Sopenharmony_ci ha = vha->hw; 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci /* No data transfer */ 14188c2ecf20Sopenharmony_ci data_bytes = scsi_bufflen(cmd); 14198c2ecf20Sopenharmony_ci if (!data_bytes || cmd->sc_data_direction == DMA_NONE) { 14208c2ecf20Sopenharmony_ci cmd_pkt->byte_count = cpu_to_le32(0); 14218c2ecf20Sopenharmony_ci return QLA_SUCCESS; 14228c2ecf20Sopenharmony_ci } 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci cmd_pkt->vp_index = sp->vha->vp_idx; 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci /* Set transfer direction */ 14278c2ecf20Sopenharmony_ci if (cmd->sc_data_direction == DMA_TO_DEVICE) { 14288c2ecf20Sopenharmony_ci cmd_pkt->control_flags = 14298c2ecf20Sopenharmony_ci cpu_to_le16(CF_WRITE_DATA); 14308c2ecf20Sopenharmony_ci } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) { 14318c2ecf20Sopenharmony_ci cmd_pkt->control_flags = 14328c2ecf20Sopenharmony_ci cpu_to_le16(CF_READ_DATA); 14338c2ecf20Sopenharmony_ci } 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) || 14368c2ecf20Sopenharmony_ci (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_STRIP) || 14378c2ecf20Sopenharmony_ci (scsi_get_prot_op(cmd) == SCSI_PROT_READ_STRIP) || 14388c2ecf20Sopenharmony_ci (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_INSERT)) 14398c2ecf20Sopenharmony_ci bundling = 0; 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci /* Allocate CRC context from global pool */ 14428c2ecf20Sopenharmony_ci crc_ctx_pkt = sp->u.scmd.crc_ctx = 14438c2ecf20Sopenharmony_ci dma_pool_zalloc(ha->dl_dma_pool, GFP_ATOMIC, &crc_ctx_dma); 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci if (!crc_ctx_pkt) 14468c2ecf20Sopenharmony_ci goto crc_queuing_error; 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci crc_ctx_pkt->crc_ctx_dma = crc_ctx_dma; 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci sp->flags |= SRB_CRC_CTX_DMA_VALID; 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci /* Set handle */ 14538c2ecf20Sopenharmony_ci crc_ctx_pkt->handle = cmd_pkt->handle; 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&crc_ctx_pkt->dsd_list); 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci qla24xx_set_t10dif_tags(sp, (struct fw_dif_context *) 14588c2ecf20Sopenharmony_ci &crc_ctx_pkt->ref_tag, tot_prot_dsds); 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci put_unaligned_le64(crc_ctx_dma, &cmd_pkt->crc_context_address); 14618c2ecf20Sopenharmony_ci cmd_pkt->crc_context_len = cpu_to_le16(CRC_CONTEXT_LEN_FW); 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci /* Determine SCSI command length -- align to 4 byte boundary */ 14648c2ecf20Sopenharmony_ci if (cmd->cmd_len > 16) { 14658c2ecf20Sopenharmony_ci additional_fcpcdb_len = cmd->cmd_len - 16; 14668c2ecf20Sopenharmony_ci if ((cmd->cmd_len % 4) != 0) { 14678c2ecf20Sopenharmony_ci /* SCSI cmd > 16 bytes must be multiple of 4 */ 14688c2ecf20Sopenharmony_ci goto crc_queuing_error; 14698c2ecf20Sopenharmony_ci } 14708c2ecf20Sopenharmony_ci fcp_cmnd_len = 12 + cmd->cmd_len + 4; 14718c2ecf20Sopenharmony_ci } else { 14728c2ecf20Sopenharmony_ci additional_fcpcdb_len = 0; 14738c2ecf20Sopenharmony_ci fcp_cmnd_len = 12 + 16 + 4; 14748c2ecf20Sopenharmony_ci } 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci fcp_cmnd = &crc_ctx_pkt->fcp_cmnd; 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci fcp_cmnd->additional_cdb_len = additional_fcpcdb_len; 14798c2ecf20Sopenharmony_ci if (cmd->sc_data_direction == DMA_TO_DEVICE) 14808c2ecf20Sopenharmony_ci fcp_cmnd->additional_cdb_len |= 1; 14818c2ecf20Sopenharmony_ci else if (cmd->sc_data_direction == DMA_FROM_DEVICE) 14828c2ecf20Sopenharmony_ci fcp_cmnd->additional_cdb_len |= 2; 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci int_to_scsilun(cmd->device->lun, &fcp_cmnd->lun); 14858c2ecf20Sopenharmony_ci memcpy(fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len); 14868c2ecf20Sopenharmony_ci cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(fcp_cmnd_len); 14878c2ecf20Sopenharmony_ci put_unaligned_le64(crc_ctx_dma + CRC_CONTEXT_FCPCMND_OFF, 14888c2ecf20Sopenharmony_ci &cmd_pkt->fcp_cmnd_dseg_address); 14898c2ecf20Sopenharmony_ci fcp_cmnd->task_management = 0; 14908c2ecf20Sopenharmony_ci fcp_cmnd->task_attribute = TSK_SIMPLE; 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci cmd_pkt->fcp_rsp_dseg_len = 0; /* Let response come in status iocb */ 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci /* Compute dif len and adjust data len to incude protection */ 14958c2ecf20Sopenharmony_ci dif_bytes = 0; 14968c2ecf20Sopenharmony_ci blk_size = cmd->device->sector_size; 14978c2ecf20Sopenharmony_ci dif_bytes = (data_bytes / blk_size) * 8; 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci switch (scsi_get_prot_op(GET_CMD_SP(sp))) { 15008c2ecf20Sopenharmony_ci case SCSI_PROT_READ_INSERT: 15018c2ecf20Sopenharmony_ci case SCSI_PROT_WRITE_STRIP: 15028c2ecf20Sopenharmony_ci total_bytes = data_bytes; 15038c2ecf20Sopenharmony_ci data_bytes += dif_bytes; 15048c2ecf20Sopenharmony_ci break; 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci case SCSI_PROT_READ_STRIP: 15078c2ecf20Sopenharmony_ci case SCSI_PROT_WRITE_INSERT: 15088c2ecf20Sopenharmony_ci case SCSI_PROT_READ_PASS: 15098c2ecf20Sopenharmony_ci case SCSI_PROT_WRITE_PASS: 15108c2ecf20Sopenharmony_ci total_bytes = data_bytes + dif_bytes; 15118c2ecf20Sopenharmony_ci break; 15128c2ecf20Sopenharmony_ci default: 15138c2ecf20Sopenharmony_ci BUG(); 15148c2ecf20Sopenharmony_ci } 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci if (!qla2x00_hba_err_chk_enabled(sp)) 15178c2ecf20Sopenharmony_ci fw_prot_opts |= 0x10; /* Disable Guard tag checking */ 15188c2ecf20Sopenharmony_ci /* HBA error checking enabled */ 15198c2ecf20Sopenharmony_ci else if (IS_PI_UNINIT_CAPABLE(ha)) { 15208c2ecf20Sopenharmony_ci if ((scsi_get_prot_type(GET_CMD_SP(sp)) == SCSI_PROT_DIF_TYPE1) 15218c2ecf20Sopenharmony_ci || (scsi_get_prot_type(GET_CMD_SP(sp)) == 15228c2ecf20Sopenharmony_ci SCSI_PROT_DIF_TYPE2)) 15238c2ecf20Sopenharmony_ci fw_prot_opts |= BIT_10; 15248c2ecf20Sopenharmony_ci else if (scsi_get_prot_type(GET_CMD_SP(sp)) == 15258c2ecf20Sopenharmony_ci SCSI_PROT_DIF_TYPE3) 15268c2ecf20Sopenharmony_ci fw_prot_opts |= BIT_11; 15278c2ecf20Sopenharmony_ci } 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci if (!bundling) { 15308c2ecf20Sopenharmony_ci cur_dsd = &crc_ctx_pkt->u.nobundling.data_dsd[0]; 15318c2ecf20Sopenharmony_ci } else { 15328c2ecf20Sopenharmony_ci /* 15338c2ecf20Sopenharmony_ci * Configure Bundling if we need to fetch interlaving 15348c2ecf20Sopenharmony_ci * protection PCI accesses 15358c2ecf20Sopenharmony_ci */ 15368c2ecf20Sopenharmony_ci fw_prot_opts |= PO_ENABLE_DIF_BUNDLING; 15378c2ecf20Sopenharmony_ci crc_ctx_pkt->u.bundling.dif_byte_count = cpu_to_le32(dif_bytes); 15388c2ecf20Sopenharmony_ci crc_ctx_pkt->u.bundling.dseg_count = cpu_to_le16(tot_dsds - 15398c2ecf20Sopenharmony_ci tot_prot_dsds); 15408c2ecf20Sopenharmony_ci cur_dsd = &crc_ctx_pkt->u.bundling.data_dsd[0]; 15418c2ecf20Sopenharmony_ci } 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci /* Finish the common fields of CRC pkt */ 15448c2ecf20Sopenharmony_ci crc_ctx_pkt->blk_size = cpu_to_le16(blk_size); 15458c2ecf20Sopenharmony_ci crc_ctx_pkt->prot_opts = cpu_to_le16(fw_prot_opts); 15468c2ecf20Sopenharmony_ci crc_ctx_pkt->byte_count = cpu_to_le32(data_bytes); 15478c2ecf20Sopenharmony_ci crc_ctx_pkt->guard_seed = cpu_to_le16(0); 15488c2ecf20Sopenharmony_ci /* Fibre channel byte count */ 15498c2ecf20Sopenharmony_ci cmd_pkt->byte_count = cpu_to_le32(total_bytes); 15508c2ecf20Sopenharmony_ci fcp_dl = (__be32 *)(crc_ctx_pkt->fcp_cmnd.cdb + 16 + 15518c2ecf20Sopenharmony_ci additional_fcpcdb_len); 15528c2ecf20Sopenharmony_ci *fcp_dl = htonl(total_bytes); 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci if (!data_bytes || cmd->sc_data_direction == DMA_NONE) { 15558c2ecf20Sopenharmony_ci cmd_pkt->byte_count = cpu_to_le32(0); 15568c2ecf20Sopenharmony_ci return QLA_SUCCESS; 15578c2ecf20Sopenharmony_ci } 15588c2ecf20Sopenharmony_ci /* Walks data segments */ 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci cmd_pkt->control_flags |= cpu_to_le16(CF_DATA_SEG_DESCR_ENABLE); 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci if (!bundling && tot_prot_dsds) { 15638c2ecf20Sopenharmony_ci if (qla24xx_walk_and_build_sglist_no_difb(ha, sp, 15648c2ecf20Sopenharmony_ci cur_dsd, tot_dsds, NULL)) 15658c2ecf20Sopenharmony_ci goto crc_queuing_error; 15668c2ecf20Sopenharmony_ci } else if (qla24xx_walk_and_build_sglist(ha, sp, cur_dsd, 15678c2ecf20Sopenharmony_ci (tot_dsds - tot_prot_dsds), NULL)) 15688c2ecf20Sopenharmony_ci goto crc_queuing_error; 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci if (bundling && tot_prot_dsds) { 15718c2ecf20Sopenharmony_ci /* Walks dif segments */ 15728c2ecf20Sopenharmony_ci cmd_pkt->control_flags |= cpu_to_le16(CF_DIF_SEG_DESCR_ENABLE); 15738c2ecf20Sopenharmony_ci cur_dsd = &crc_ctx_pkt->u.bundling.dif_dsd; 15748c2ecf20Sopenharmony_ci if (qla24xx_walk_and_build_prot_sglist(ha, sp, cur_dsd, 15758c2ecf20Sopenharmony_ci tot_prot_dsds, NULL)) 15768c2ecf20Sopenharmony_ci goto crc_queuing_error; 15778c2ecf20Sopenharmony_ci } 15788c2ecf20Sopenharmony_ci return QLA_SUCCESS; 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_cicrc_queuing_error: 15818c2ecf20Sopenharmony_ci /* Cleanup will be performed by the caller */ 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 15848c2ecf20Sopenharmony_ci} 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci/** 15878c2ecf20Sopenharmony_ci * qla24xx_start_scsi() - Send a SCSI command to the ISP 15888c2ecf20Sopenharmony_ci * @sp: command to send to the ISP 15898c2ecf20Sopenharmony_ci * 15908c2ecf20Sopenharmony_ci * Returns non-zero if a failure occurred, else zero. 15918c2ecf20Sopenharmony_ci */ 15928c2ecf20Sopenharmony_ciint 15938c2ecf20Sopenharmony_ciqla24xx_start_scsi(srb_t *sp) 15948c2ecf20Sopenharmony_ci{ 15958c2ecf20Sopenharmony_ci int nseg; 15968c2ecf20Sopenharmony_ci unsigned long flags; 15978c2ecf20Sopenharmony_ci uint32_t *clr_ptr; 15988c2ecf20Sopenharmony_ci uint32_t handle; 15998c2ecf20Sopenharmony_ci struct cmd_type_7 *cmd_pkt; 16008c2ecf20Sopenharmony_ci uint16_t cnt; 16018c2ecf20Sopenharmony_ci uint16_t req_cnt; 16028c2ecf20Sopenharmony_ci uint16_t tot_dsds; 16038c2ecf20Sopenharmony_ci struct req_que *req = NULL; 16048c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd = GET_CMD_SP(sp); 16058c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = sp->vha; 16068c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci /* Setup device pointers. */ 16098c2ecf20Sopenharmony_ci req = vha->req; 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci /* So we know we haven't pci_map'ed anything yet */ 16128c2ecf20Sopenharmony_ci tot_dsds = 0; 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci /* Send marker if required */ 16158c2ecf20Sopenharmony_ci if (vha->marker_needed != 0) { 16168c2ecf20Sopenharmony_ci if (qla2x00_marker(vha, ha->base_qpair, 0, 0, MK_SYNC_ALL) != 16178c2ecf20Sopenharmony_ci QLA_SUCCESS) 16188c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 16198c2ecf20Sopenharmony_ci vha->marker_needed = 0; 16208c2ecf20Sopenharmony_ci } 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci /* Acquire ring specific lock */ 16238c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci handle = qla2xxx_get_next_handle(req); 16268c2ecf20Sopenharmony_ci if (handle == 0) 16278c2ecf20Sopenharmony_ci goto queuing_error; 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci /* Map the sg table so we have an accurate count of sg entries needed */ 16308c2ecf20Sopenharmony_ci if (scsi_sg_count(cmd)) { 16318c2ecf20Sopenharmony_ci nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd), 16328c2ecf20Sopenharmony_ci scsi_sg_count(cmd), cmd->sc_data_direction); 16338c2ecf20Sopenharmony_ci if (unlikely(!nseg)) 16348c2ecf20Sopenharmony_ci goto queuing_error; 16358c2ecf20Sopenharmony_ci } else 16368c2ecf20Sopenharmony_ci nseg = 0; 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci tot_dsds = nseg; 16398c2ecf20Sopenharmony_ci req_cnt = qla24xx_calc_iocbs(vha, tot_dsds); 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci sp->iores.res_type = RESOURCE_INI; 16428c2ecf20Sopenharmony_ci sp->iores.iocb_cnt = req_cnt; 16438c2ecf20Sopenharmony_ci if (qla_get_iocbs(sp->qpair, &sp->iores)) 16448c2ecf20Sopenharmony_ci goto queuing_error; 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci if (req->cnt < (req_cnt + 2)) { 16478c2ecf20Sopenharmony_ci if (IS_SHADOW_REG_CAPABLE(ha)) { 16488c2ecf20Sopenharmony_ci cnt = *req->out_ptr; 16498c2ecf20Sopenharmony_ci } else { 16508c2ecf20Sopenharmony_ci cnt = rd_reg_dword_relaxed(req->req_q_out); 16518c2ecf20Sopenharmony_ci if (qla2x00_check_reg16_for_disconnect(vha, cnt)) 16528c2ecf20Sopenharmony_ci goto queuing_error; 16538c2ecf20Sopenharmony_ci } 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_ci if (req->ring_index < cnt) 16568c2ecf20Sopenharmony_ci req->cnt = cnt - req->ring_index; 16578c2ecf20Sopenharmony_ci else 16588c2ecf20Sopenharmony_ci req->cnt = req->length - 16598c2ecf20Sopenharmony_ci (req->ring_index - cnt); 16608c2ecf20Sopenharmony_ci if (req->cnt < (req_cnt + 2)) 16618c2ecf20Sopenharmony_ci goto queuing_error; 16628c2ecf20Sopenharmony_ci } 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci /* Build command packet. */ 16658c2ecf20Sopenharmony_ci req->current_outstanding_cmd = handle; 16668c2ecf20Sopenharmony_ci req->outstanding_cmds[handle] = sp; 16678c2ecf20Sopenharmony_ci sp->handle = handle; 16688c2ecf20Sopenharmony_ci cmd->host_scribble = (unsigned char *)(unsigned long)handle; 16698c2ecf20Sopenharmony_ci req->cnt -= req_cnt; 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci cmd_pkt = (struct cmd_type_7 *)req->ring_ptr; 16728c2ecf20Sopenharmony_ci cmd_pkt->handle = make_handle(req->id, handle); 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci /* Zero out remaining portion of packet. */ 16758c2ecf20Sopenharmony_ci /* tagged queuing modifier -- default is TSK_SIMPLE (0). */ 16768c2ecf20Sopenharmony_ci clr_ptr = (uint32_t *)cmd_pkt + 2; 16778c2ecf20Sopenharmony_ci memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); 16788c2ecf20Sopenharmony_ci cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci /* Set NPORT-ID and LUN number*/ 16818c2ecf20Sopenharmony_ci cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); 16828c2ecf20Sopenharmony_ci cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; 16838c2ecf20Sopenharmony_ci cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; 16848c2ecf20Sopenharmony_ci cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; 16858c2ecf20Sopenharmony_ci cmd_pkt->vp_index = sp->vha->vp_idx; 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci int_to_scsilun(cmd->device->lun, &cmd_pkt->lun); 16888c2ecf20Sopenharmony_ci host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci cmd_pkt->task = TSK_SIMPLE; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci /* Load SCSI command packet. */ 16938c2ecf20Sopenharmony_ci memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len); 16948c2ecf20Sopenharmony_ci host_to_fcp_swap(cmd_pkt->fcp_cdb, sizeof(cmd_pkt->fcp_cdb)); 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci /* Build IOCB segments */ 16998c2ecf20Sopenharmony_ci qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds, req); 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci /* Set total data segment count. */ 17028c2ecf20Sopenharmony_ci cmd_pkt->entry_count = (uint8_t)req_cnt; 17038c2ecf20Sopenharmony_ci wmb(); 17048c2ecf20Sopenharmony_ci /* Adjust ring index. */ 17058c2ecf20Sopenharmony_ci req->ring_index++; 17068c2ecf20Sopenharmony_ci if (req->ring_index == req->length) { 17078c2ecf20Sopenharmony_ci req->ring_index = 0; 17088c2ecf20Sopenharmony_ci req->ring_ptr = req->ring; 17098c2ecf20Sopenharmony_ci } else 17108c2ecf20Sopenharmony_ci req->ring_ptr++; 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci sp->flags |= SRB_DMA_VALID; 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_ci /* Set chip new ring index. */ 17158c2ecf20Sopenharmony_ci wrt_reg_dword(req->req_q_in, req->ring_index); 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 17188c2ecf20Sopenharmony_ci return QLA_SUCCESS; 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ciqueuing_error: 17218c2ecf20Sopenharmony_ci if (tot_dsds) 17228c2ecf20Sopenharmony_ci scsi_dma_unmap(cmd); 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci qla_put_iocbs(sp->qpair, &sp->iores); 17258c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 17288c2ecf20Sopenharmony_ci} 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci/** 17318c2ecf20Sopenharmony_ci * qla24xx_dif_start_scsi() - Send a SCSI command to the ISP 17328c2ecf20Sopenharmony_ci * @sp: command to send to the ISP 17338c2ecf20Sopenharmony_ci * 17348c2ecf20Sopenharmony_ci * Returns non-zero if a failure occurred, else zero. 17358c2ecf20Sopenharmony_ci */ 17368c2ecf20Sopenharmony_ciint 17378c2ecf20Sopenharmony_ciqla24xx_dif_start_scsi(srb_t *sp) 17388c2ecf20Sopenharmony_ci{ 17398c2ecf20Sopenharmony_ci int nseg; 17408c2ecf20Sopenharmony_ci unsigned long flags; 17418c2ecf20Sopenharmony_ci uint32_t *clr_ptr; 17428c2ecf20Sopenharmony_ci uint32_t handle; 17438c2ecf20Sopenharmony_ci uint16_t cnt; 17448c2ecf20Sopenharmony_ci uint16_t req_cnt = 0; 17458c2ecf20Sopenharmony_ci uint16_t tot_dsds; 17468c2ecf20Sopenharmony_ci uint16_t tot_prot_dsds; 17478c2ecf20Sopenharmony_ci uint16_t fw_prot_opts = 0; 17488c2ecf20Sopenharmony_ci struct req_que *req = NULL; 17498c2ecf20Sopenharmony_ci struct rsp_que *rsp = NULL; 17508c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd = GET_CMD_SP(sp); 17518c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = sp->vha; 17528c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 17538c2ecf20Sopenharmony_ci struct cmd_type_crc_2 *cmd_pkt; 17548c2ecf20Sopenharmony_ci uint32_t status = 0; 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ci#define QDSS_GOT_Q_SPACE BIT_0 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci /* Only process protection or >16 cdb in this routine */ 17598c2ecf20Sopenharmony_ci if (scsi_get_prot_op(cmd) == SCSI_PROT_NORMAL) { 17608c2ecf20Sopenharmony_ci if (cmd->cmd_len <= 16) 17618c2ecf20Sopenharmony_ci return qla24xx_start_scsi(sp); 17628c2ecf20Sopenharmony_ci } 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci /* Setup device pointers. */ 17658c2ecf20Sopenharmony_ci req = vha->req; 17668c2ecf20Sopenharmony_ci rsp = req->rsp; 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci /* So we know we haven't pci_map'ed anything yet */ 17698c2ecf20Sopenharmony_ci tot_dsds = 0; 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci /* Send marker if required */ 17728c2ecf20Sopenharmony_ci if (vha->marker_needed != 0) { 17738c2ecf20Sopenharmony_ci if (qla2x00_marker(vha, ha->base_qpair, 0, 0, MK_SYNC_ALL) != 17748c2ecf20Sopenharmony_ci QLA_SUCCESS) 17758c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 17768c2ecf20Sopenharmony_ci vha->marker_needed = 0; 17778c2ecf20Sopenharmony_ci } 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci /* Acquire ring specific lock */ 17808c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci handle = qla2xxx_get_next_handle(req); 17838c2ecf20Sopenharmony_ci if (handle == 0) 17848c2ecf20Sopenharmony_ci goto queuing_error; 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci /* Compute number of required data segments */ 17878c2ecf20Sopenharmony_ci /* Map the sg table so we have an accurate count of sg entries needed */ 17888c2ecf20Sopenharmony_ci if (scsi_sg_count(cmd)) { 17898c2ecf20Sopenharmony_ci nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd), 17908c2ecf20Sopenharmony_ci scsi_sg_count(cmd), cmd->sc_data_direction); 17918c2ecf20Sopenharmony_ci if (unlikely(!nseg)) 17928c2ecf20Sopenharmony_ci goto queuing_error; 17938c2ecf20Sopenharmony_ci else 17948c2ecf20Sopenharmony_ci sp->flags |= SRB_DMA_VALID; 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) || 17978c2ecf20Sopenharmony_ci (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_STRIP)) { 17988c2ecf20Sopenharmony_ci struct qla2_sgx sgx; 17998c2ecf20Sopenharmony_ci uint32_t partial; 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci memset(&sgx, 0, sizeof(struct qla2_sgx)); 18028c2ecf20Sopenharmony_ci sgx.tot_bytes = scsi_bufflen(cmd); 18038c2ecf20Sopenharmony_ci sgx.cur_sg = scsi_sglist(cmd); 18048c2ecf20Sopenharmony_ci sgx.sp = sp; 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci nseg = 0; 18078c2ecf20Sopenharmony_ci while (qla24xx_get_one_block_sg( 18088c2ecf20Sopenharmony_ci cmd->device->sector_size, &sgx, &partial)) 18098c2ecf20Sopenharmony_ci nseg++; 18108c2ecf20Sopenharmony_ci } 18118c2ecf20Sopenharmony_ci } else 18128c2ecf20Sopenharmony_ci nseg = 0; 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_ci /* number of required data segments */ 18158c2ecf20Sopenharmony_ci tot_dsds = nseg; 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci /* Compute number of required protection segments */ 18188c2ecf20Sopenharmony_ci if (qla24xx_configure_prot_mode(sp, &fw_prot_opts)) { 18198c2ecf20Sopenharmony_ci nseg = dma_map_sg(&ha->pdev->dev, scsi_prot_sglist(cmd), 18208c2ecf20Sopenharmony_ci scsi_prot_sg_count(cmd), cmd->sc_data_direction); 18218c2ecf20Sopenharmony_ci if (unlikely(!nseg)) 18228c2ecf20Sopenharmony_ci goto queuing_error; 18238c2ecf20Sopenharmony_ci else 18248c2ecf20Sopenharmony_ci sp->flags |= SRB_CRC_PROT_DMA_VALID; 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) || 18278c2ecf20Sopenharmony_ci (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_STRIP)) { 18288c2ecf20Sopenharmony_ci nseg = scsi_bufflen(cmd) / cmd->device->sector_size; 18298c2ecf20Sopenharmony_ci } 18308c2ecf20Sopenharmony_ci } else { 18318c2ecf20Sopenharmony_ci nseg = 0; 18328c2ecf20Sopenharmony_ci } 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci req_cnt = 1; 18358c2ecf20Sopenharmony_ci /* Total Data and protection sg segment(s) */ 18368c2ecf20Sopenharmony_ci tot_prot_dsds = nseg; 18378c2ecf20Sopenharmony_ci tot_dsds += nseg; 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci sp->iores.res_type = RESOURCE_INI; 18408c2ecf20Sopenharmony_ci sp->iores.iocb_cnt = qla24xx_calc_iocbs(vha, tot_dsds); 18418c2ecf20Sopenharmony_ci if (qla_get_iocbs(sp->qpair, &sp->iores)) 18428c2ecf20Sopenharmony_ci goto queuing_error; 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci if (req->cnt < (req_cnt + 2)) { 18458c2ecf20Sopenharmony_ci if (IS_SHADOW_REG_CAPABLE(ha)) { 18468c2ecf20Sopenharmony_ci cnt = *req->out_ptr; 18478c2ecf20Sopenharmony_ci } else { 18488c2ecf20Sopenharmony_ci cnt = rd_reg_dword_relaxed(req->req_q_out); 18498c2ecf20Sopenharmony_ci if (qla2x00_check_reg16_for_disconnect(vha, cnt)) 18508c2ecf20Sopenharmony_ci goto queuing_error; 18518c2ecf20Sopenharmony_ci } 18528c2ecf20Sopenharmony_ci if (req->ring_index < cnt) 18538c2ecf20Sopenharmony_ci req->cnt = cnt - req->ring_index; 18548c2ecf20Sopenharmony_ci else 18558c2ecf20Sopenharmony_ci req->cnt = req->length - 18568c2ecf20Sopenharmony_ci (req->ring_index - cnt); 18578c2ecf20Sopenharmony_ci if (req->cnt < (req_cnt + 2)) 18588c2ecf20Sopenharmony_ci goto queuing_error; 18598c2ecf20Sopenharmony_ci } 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci status |= QDSS_GOT_Q_SPACE; 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci /* Build header part of command packet (excluding the OPCODE). */ 18648c2ecf20Sopenharmony_ci req->current_outstanding_cmd = handle; 18658c2ecf20Sopenharmony_ci req->outstanding_cmds[handle] = sp; 18668c2ecf20Sopenharmony_ci sp->handle = handle; 18678c2ecf20Sopenharmony_ci cmd->host_scribble = (unsigned char *)(unsigned long)handle; 18688c2ecf20Sopenharmony_ci req->cnt -= req_cnt; 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci /* Fill-in common area */ 18718c2ecf20Sopenharmony_ci cmd_pkt = (struct cmd_type_crc_2 *)req->ring_ptr; 18728c2ecf20Sopenharmony_ci cmd_pkt->handle = make_handle(req->id, handle); 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci clr_ptr = (uint32_t *)cmd_pkt + 2; 18758c2ecf20Sopenharmony_ci memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci /* Set NPORT-ID and LUN number*/ 18788c2ecf20Sopenharmony_ci cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); 18798c2ecf20Sopenharmony_ci cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; 18808c2ecf20Sopenharmony_ci cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; 18818c2ecf20Sopenharmony_ci cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci int_to_scsilun(cmd->device->lun, &cmd_pkt->lun); 18848c2ecf20Sopenharmony_ci host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci /* Total Data and protection segment(s) */ 18878c2ecf20Sopenharmony_ci cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci /* Build IOCB segments and adjust for data protection segments */ 18908c2ecf20Sopenharmony_ci if (qla24xx_build_scsi_crc_2_iocbs(sp, (struct cmd_type_crc_2 *) 18918c2ecf20Sopenharmony_ci req->ring_ptr, tot_dsds, tot_prot_dsds, fw_prot_opts) != 18928c2ecf20Sopenharmony_ci QLA_SUCCESS) 18938c2ecf20Sopenharmony_ci goto queuing_error; 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci cmd_pkt->entry_count = (uint8_t)req_cnt; 18968c2ecf20Sopenharmony_ci /* Specify response queue number where completion should happen */ 18978c2ecf20Sopenharmony_ci cmd_pkt->entry_status = (uint8_t) rsp->id; 18988c2ecf20Sopenharmony_ci cmd_pkt->timeout = cpu_to_le16(0); 18998c2ecf20Sopenharmony_ci wmb(); 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci /* Adjust ring index. */ 19028c2ecf20Sopenharmony_ci req->ring_index++; 19038c2ecf20Sopenharmony_ci if (req->ring_index == req->length) { 19048c2ecf20Sopenharmony_ci req->ring_index = 0; 19058c2ecf20Sopenharmony_ci req->ring_ptr = req->ring; 19068c2ecf20Sopenharmony_ci } else 19078c2ecf20Sopenharmony_ci req->ring_ptr++; 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci /* Set chip new ring index. */ 19108c2ecf20Sopenharmony_ci wrt_reg_dword(req->req_q_in, req->ring_index); 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ci return QLA_SUCCESS; 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ciqueuing_error: 19178c2ecf20Sopenharmony_ci if (status & QDSS_GOT_Q_SPACE) { 19188c2ecf20Sopenharmony_ci req->outstanding_cmds[handle] = NULL; 19198c2ecf20Sopenharmony_ci req->cnt += req_cnt; 19208c2ecf20Sopenharmony_ci } 19218c2ecf20Sopenharmony_ci /* Cleanup will be performed by the caller (queuecommand) */ 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci qla_put_iocbs(sp->qpair, &sp->iores); 19248c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 19278c2ecf20Sopenharmony_ci} 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci/** 19308c2ecf20Sopenharmony_ci * qla2xxx_start_scsi_mq() - Send a SCSI command to the ISP 19318c2ecf20Sopenharmony_ci * @sp: command to send to the ISP 19328c2ecf20Sopenharmony_ci * 19338c2ecf20Sopenharmony_ci * Returns non-zero if a failure occurred, else zero. 19348c2ecf20Sopenharmony_ci */ 19358c2ecf20Sopenharmony_cistatic int 19368c2ecf20Sopenharmony_ciqla2xxx_start_scsi_mq(srb_t *sp) 19378c2ecf20Sopenharmony_ci{ 19388c2ecf20Sopenharmony_ci int nseg; 19398c2ecf20Sopenharmony_ci unsigned long flags; 19408c2ecf20Sopenharmony_ci uint32_t *clr_ptr; 19418c2ecf20Sopenharmony_ci uint32_t handle; 19428c2ecf20Sopenharmony_ci struct cmd_type_7 *cmd_pkt; 19438c2ecf20Sopenharmony_ci uint16_t cnt; 19448c2ecf20Sopenharmony_ci uint16_t req_cnt; 19458c2ecf20Sopenharmony_ci uint16_t tot_dsds; 19468c2ecf20Sopenharmony_ci struct req_que *req = NULL; 19478c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd = GET_CMD_SP(sp); 19488c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = sp->fcport->vha; 19498c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 19508c2ecf20Sopenharmony_ci struct qla_qpair *qpair = sp->qpair; 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_ci /* Acquire qpair specific lock */ 19538c2ecf20Sopenharmony_ci spin_lock_irqsave(&qpair->qp_lock, flags); 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci /* Setup qpair pointers */ 19568c2ecf20Sopenharmony_ci req = qpair->req; 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci /* So we know we haven't pci_map'ed anything yet */ 19598c2ecf20Sopenharmony_ci tot_dsds = 0; 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci /* Send marker if required */ 19628c2ecf20Sopenharmony_ci if (vha->marker_needed != 0) { 19638c2ecf20Sopenharmony_ci if (__qla2x00_marker(vha, qpair, 0, 0, MK_SYNC_ALL) != 19648c2ecf20Sopenharmony_ci QLA_SUCCESS) { 19658c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qpair->qp_lock, flags); 19668c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 19678c2ecf20Sopenharmony_ci } 19688c2ecf20Sopenharmony_ci vha->marker_needed = 0; 19698c2ecf20Sopenharmony_ci } 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci handle = qla2xxx_get_next_handle(req); 19728c2ecf20Sopenharmony_ci if (handle == 0) 19738c2ecf20Sopenharmony_ci goto queuing_error; 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_ci /* Map the sg table so we have an accurate count of sg entries needed */ 19768c2ecf20Sopenharmony_ci if (scsi_sg_count(cmd)) { 19778c2ecf20Sopenharmony_ci nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd), 19788c2ecf20Sopenharmony_ci scsi_sg_count(cmd), cmd->sc_data_direction); 19798c2ecf20Sopenharmony_ci if (unlikely(!nseg)) 19808c2ecf20Sopenharmony_ci goto queuing_error; 19818c2ecf20Sopenharmony_ci } else 19828c2ecf20Sopenharmony_ci nseg = 0; 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci tot_dsds = nseg; 19858c2ecf20Sopenharmony_ci req_cnt = qla24xx_calc_iocbs(vha, tot_dsds); 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci sp->iores.res_type = RESOURCE_INI; 19888c2ecf20Sopenharmony_ci sp->iores.iocb_cnt = req_cnt; 19898c2ecf20Sopenharmony_ci if (qla_get_iocbs(sp->qpair, &sp->iores)) 19908c2ecf20Sopenharmony_ci goto queuing_error; 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci if (req->cnt < (req_cnt + 2)) { 19938c2ecf20Sopenharmony_ci if (IS_SHADOW_REG_CAPABLE(ha)) { 19948c2ecf20Sopenharmony_ci cnt = *req->out_ptr; 19958c2ecf20Sopenharmony_ci } else { 19968c2ecf20Sopenharmony_ci cnt = rd_reg_dword_relaxed(req->req_q_out); 19978c2ecf20Sopenharmony_ci if (qla2x00_check_reg16_for_disconnect(vha, cnt)) 19988c2ecf20Sopenharmony_ci goto queuing_error; 19998c2ecf20Sopenharmony_ci } 20008c2ecf20Sopenharmony_ci 20018c2ecf20Sopenharmony_ci if (req->ring_index < cnt) 20028c2ecf20Sopenharmony_ci req->cnt = cnt - req->ring_index; 20038c2ecf20Sopenharmony_ci else 20048c2ecf20Sopenharmony_ci req->cnt = req->length - 20058c2ecf20Sopenharmony_ci (req->ring_index - cnt); 20068c2ecf20Sopenharmony_ci if (req->cnt < (req_cnt + 2)) 20078c2ecf20Sopenharmony_ci goto queuing_error; 20088c2ecf20Sopenharmony_ci } 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ci /* Build command packet. */ 20118c2ecf20Sopenharmony_ci req->current_outstanding_cmd = handle; 20128c2ecf20Sopenharmony_ci req->outstanding_cmds[handle] = sp; 20138c2ecf20Sopenharmony_ci sp->handle = handle; 20148c2ecf20Sopenharmony_ci cmd->host_scribble = (unsigned char *)(unsigned long)handle; 20158c2ecf20Sopenharmony_ci req->cnt -= req_cnt; 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci cmd_pkt = (struct cmd_type_7 *)req->ring_ptr; 20188c2ecf20Sopenharmony_ci cmd_pkt->handle = make_handle(req->id, handle); 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci /* Zero out remaining portion of packet. */ 20218c2ecf20Sopenharmony_ci /* tagged queuing modifier -- default is TSK_SIMPLE (0). */ 20228c2ecf20Sopenharmony_ci clr_ptr = (uint32_t *)cmd_pkt + 2; 20238c2ecf20Sopenharmony_ci memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); 20248c2ecf20Sopenharmony_ci cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci /* Set NPORT-ID and LUN number*/ 20278c2ecf20Sopenharmony_ci cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); 20288c2ecf20Sopenharmony_ci cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; 20298c2ecf20Sopenharmony_ci cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; 20308c2ecf20Sopenharmony_ci cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; 20318c2ecf20Sopenharmony_ci cmd_pkt->vp_index = sp->fcport->vha->vp_idx; 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci int_to_scsilun(cmd->device->lun, &cmd_pkt->lun); 20348c2ecf20Sopenharmony_ci host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci cmd_pkt->task = TSK_SIMPLE; 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci /* Load SCSI command packet. */ 20398c2ecf20Sopenharmony_ci memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len); 20408c2ecf20Sopenharmony_ci host_to_fcp_swap(cmd_pkt->fcp_cdb, sizeof(cmd_pkt->fcp_cdb)); 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_ci /* Build IOCB segments */ 20458c2ecf20Sopenharmony_ci qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds, req); 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci /* Set total data segment count. */ 20488c2ecf20Sopenharmony_ci cmd_pkt->entry_count = (uint8_t)req_cnt; 20498c2ecf20Sopenharmony_ci wmb(); 20508c2ecf20Sopenharmony_ci /* Adjust ring index. */ 20518c2ecf20Sopenharmony_ci req->ring_index++; 20528c2ecf20Sopenharmony_ci if (req->ring_index == req->length) { 20538c2ecf20Sopenharmony_ci req->ring_index = 0; 20548c2ecf20Sopenharmony_ci req->ring_ptr = req->ring; 20558c2ecf20Sopenharmony_ci } else 20568c2ecf20Sopenharmony_ci req->ring_ptr++; 20578c2ecf20Sopenharmony_ci 20588c2ecf20Sopenharmony_ci sp->flags |= SRB_DMA_VALID; 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci /* Set chip new ring index. */ 20618c2ecf20Sopenharmony_ci wrt_reg_dword(req->req_q_in, req->ring_index); 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qpair->qp_lock, flags); 20648c2ecf20Sopenharmony_ci return QLA_SUCCESS; 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ciqueuing_error: 20678c2ecf20Sopenharmony_ci if (tot_dsds) 20688c2ecf20Sopenharmony_ci scsi_dma_unmap(cmd); 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci qla_put_iocbs(sp->qpair, &sp->iores); 20718c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qpair->qp_lock, flags); 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 20748c2ecf20Sopenharmony_ci} 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci/** 20788c2ecf20Sopenharmony_ci * qla2xxx_dif_start_scsi_mq() - Send a SCSI command to the ISP 20798c2ecf20Sopenharmony_ci * @sp: command to send to the ISP 20808c2ecf20Sopenharmony_ci * 20818c2ecf20Sopenharmony_ci * Returns non-zero if a failure occurred, else zero. 20828c2ecf20Sopenharmony_ci */ 20838c2ecf20Sopenharmony_ciint 20848c2ecf20Sopenharmony_ciqla2xxx_dif_start_scsi_mq(srb_t *sp) 20858c2ecf20Sopenharmony_ci{ 20868c2ecf20Sopenharmony_ci int nseg; 20878c2ecf20Sopenharmony_ci unsigned long flags; 20888c2ecf20Sopenharmony_ci uint32_t *clr_ptr; 20898c2ecf20Sopenharmony_ci uint32_t handle; 20908c2ecf20Sopenharmony_ci uint16_t cnt; 20918c2ecf20Sopenharmony_ci uint16_t req_cnt = 0; 20928c2ecf20Sopenharmony_ci uint16_t tot_dsds; 20938c2ecf20Sopenharmony_ci uint16_t tot_prot_dsds; 20948c2ecf20Sopenharmony_ci uint16_t fw_prot_opts = 0; 20958c2ecf20Sopenharmony_ci struct req_que *req = NULL; 20968c2ecf20Sopenharmony_ci struct rsp_que *rsp = NULL; 20978c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd = GET_CMD_SP(sp); 20988c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = sp->fcport->vha; 20998c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 21008c2ecf20Sopenharmony_ci struct cmd_type_crc_2 *cmd_pkt; 21018c2ecf20Sopenharmony_ci uint32_t status = 0; 21028c2ecf20Sopenharmony_ci struct qla_qpair *qpair = sp->qpair; 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_ci#define QDSS_GOT_Q_SPACE BIT_0 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci /* Check for host side state */ 21078c2ecf20Sopenharmony_ci if (!qpair->online) { 21088c2ecf20Sopenharmony_ci cmd->result = DID_NO_CONNECT << 16; 21098c2ecf20Sopenharmony_ci return QLA_INTERFACE_ERROR; 21108c2ecf20Sopenharmony_ci } 21118c2ecf20Sopenharmony_ci 21128c2ecf20Sopenharmony_ci if (!qpair->difdix_supported && 21138c2ecf20Sopenharmony_ci scsi_get_prot_op(cmd) != SCSI_PROT_NORMAL) { 21148c2ecf20Sopenharmony_ci cmd->result = DID_NO_CONNECT << 16; 21158c2ecf20Sopenharmony_ci return QLA_INTERFACE_ERROR; 21168c2ecf20Sopenharmony_ci } 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci /* Only process protection or >16 cdb in this routine */ 21198c2ecf20Sopenharmony_ci if (scsi_get_prot_op(cmd) == SCSI_PROT_NORMAL) { 21208c2ecf20Sopenharmony_ci if (cmd->cmd_len <= 16) 21218c2ecf20Sopenharmony_ci return qla2xxx_start_scsi_mq(sp); 21228c2ecf20Sopenharmony_ci } 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_ci spin_lock_irqsave(&qpair->qp_lock, flags); 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_ci /* Setup qpair pointers */ 21278c2ecf20Sopenharmony_ci rsp = qpair->rsp; 21288c2ecf20Sopenharmony_ci req = qpair->req; 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci /* So we know we haven't pci_map'ed anything yet */ 21318c2ecf20Sopenharmony_ci tot_dsds = 0; 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci /* Send marker if required */ 21348c2ecf20Sopenharmony_ci if (vha->marker_needed != 0) { 21358c2ecf20Sopenharmony_ci if (__qla2x00_marker(vha, qpair, 0, 0, MK_SYNC_ALL) != 21368c2ecf20Sopenharmony_ci QLA_SUCCESS) { 21378c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qpair->qp_lock, flags); 21388c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 21398c2ecf20Sopenharmony_ci } 21408c2ecf20Sopenharmony_ci vha->marker_needed = 0; 21418c2ecf20Sopenharmony_ci } 21428c2ecf20Sopenharmony_ci 21438c2ecf20Sopenharmony_ci handle = qla2xxx_get_next_handle(req); 21448c2ecf20Sopenharmony_ci if (handle == 0) 21458c2ecf20Sopenharmony_ci goto queuing_error; 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci /* Compute number of required data segments */ 21488c2ecf20Sopenharmony_ci /* Map the sg table so we have an accurate count of sg entries needed */ 21498c2ecf20Sopenharmony_ci if (scsi_sg_count(cmd)) { 21508c2ecf20Sopenharmony_ci nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd), 21518c2ecf20Sopenharmony_ci scsi_sg_count(cmd), cmd->sc_data_direction); 21528c2ecf20Sopenharmony_ci if (unlikely(!nseg)) 21538c2ecf20Sopenharmony_ci goto queuing_error; 21548c2ecf20Sopenharmony_ci else 21558c2ecf20Sopenharmony_ci sp->flags |= SRB_DMA_VALID; 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ci if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) || 21588c2ecf20Sopenharmony_ci (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_STRIP)) { 21598c2ecf20Sopenharmony_ci struct qla2_sgx sgx; 21608c2ecf20Sopenharmony_ci uint32_t partial; 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci memset(&sgx, 0, sizeof(struct qla2_sgx)); 21638c2ecf20Sopenharmony_ci sgx.tot_bytes = scsi_bufflen(cmd); 21648c2ecf20Sopenharmony_ci sgx.cur_sg = scsi_sglist(cmd); 21658c2ecf20Sopenharmony_ci sgx.sp = sp; 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci nseg = 0; 21688c2ecf20Sopenharmony_ci while (qla24xx_get_one_block_sg( 21698c2ecf20Sopenharmony_ci cmd->device->sector_size, &sgx, &partial)) 21708c2ecf20Sopenharmony_ci nseg++; 21718c2ecf20Sopenharmony_ci } 21728c2ecf20Sopenharmony_ci } else 21738c2ecf20Sopenharmony_ci nseg = 0; 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_ci /* number of required data segments */ 21768c2ecf20Sopenharmony_ci tot_dsds = nseg; 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci /* Compute number of required protection segments */ 21798c2ecf20Sopenharmony_ci if (qla24xx_configure_prot_mode(sp, &fw_prot_opts)) { 21808c2ecf20Sopenharmony_ci nseg = dma_map_sg(&ha->pdev->dev, scsi_prot_sglist(cmd), 21818c2ecf20Sopenharmony_ci scsi_prot_sg_count(cmd), cmd->sc_data_direction); 21828c2ecf20Sopenharmony_ci if (unlikely(!nseg)) 21838c2ecf20Sopenharmony_ci goto queuing_error; 21848c2ecf20Sopenharmony_ci else 21858c2ecf20Sopenharmony_ci sp->flags |= SRB_CRC_PROT_DMA_VALID; 21868c2ecf20Sopenharmony_ci 21878c2ecf20Sopenharmony_ci if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) || 21888c2ecf20Sopenharmony_ci (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_STRIP)) { 21898c2ecf20Sopenharmony_ci nseg = scsi_bufflen(cmd) / cmd->device->sector_size; 21908c2ecf20Sopenharmony_ci } 21918c2ecf20Sopenharmony_ci } else { 21928c2ecf20Sopenharmony_ci nseg = 0; 21938c2ecf20Sopenharmony_ci } 21948c2ecf20Sopenharmony_ci 21958c2ecf20Sopenharmony_ci req_cnt = 1; 21968c2ecf20Sopenharmony_ci /* Total Data and protection sg segment(s) */ 21978c2ecf20Sopenharmony_ci tot_prot_dsds = nseg; 21988c2ecf20Sopenharmony_ci tot_dsds += nseg; 21998c2ecf20Sopenharmony_ci 22008c2ecf20Sopenharmony_ci sp->iores.res_type = RESOURCE_INI; 22018c2ecf20Sopenharmony_ci sp->iores.iocb_cnt = qla24xx_calc_iocbs(vha, tot_dsds); 22028c2ecf20Sopenharmony_ci if (qla_get_iocbs(sp->qpair, &sp->iores)) 22038c2ecf20Sopenharmony_ci goto queuing_error; 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_ci if (req->cnt < (req_cnt + 2)) { 22068c2ecf20Sopenharmony_ci if (IS_SHADOW_REG_CAPABLE(ha)) { 22078c2ecf20Sopenharmony_ci cnt = *req->out_ptr; 22088c2ecf20Sopenharmony_ci } else { 22098c2ecf20Sopenharmony_ci cnt = rd_reg_dword_relaxed(req->req_q_out); 22108c2ecf20Sopenharmony_ci if (qla2x00_check_reg16_for_disconnect(vha, cnt)) 22118c2ecf20Sopenharmony_ci goto queuing_error; 22128c2ecf20Sopenharmony_ci } 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci if (req->ring_index < cnt) 22158c2ecf20Sopenharmony_ci req->cnt = cnt - req->ring_index; 22168c2ecf20Sopenharmony_ci else 22178c2ecf20Sopenharmony_ci req->cnt = req->length - 22188c2ecf20Sopenharmony_ci (req->ring_index - cnt); 22198c2ecf20Sopenharmony_ci if (req->cnt < (req_cnt + 2)) 22208c2ecf20Sopenharmony_ci goto queuing_error; 22218c2ecf20Sopenharmony_ci } 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ci status |= QDSS_GOT_Q_SPACE; 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci /* Build header part of command packet (excluding the OPCODE). */ 22268c2ecf20Sopenharmony_ci req->current_outstanding_cmd = handle; 22278c2ecf20Sopenharmony_ci req->outstanding_cmds[handle] = sp; 22288c2ecf20Sopenharmony_ci sp->handle = handle; 22298c2ecf20Sopenharmony_ci cmd->host_scribble = (unsigned char *)(unsigned long)handle; 22308c2ecf20Sopenharmony_ci req->cnt -= req_cnt; 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci /* Fill-in common area */ 22338c2ecf20Sopenharmony_ci cmd_pkt = (struct cmd_type_crc_2 *)req->ring_ptr; 22348c2ecf20Sopenharmony_ci cmd_pkt->handle = make_handle(req->id, handle); 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_ci clr_ptr = (uint32_t *)cmd_pkt + 2; 22378c2ecf20Sopenharmony_ci memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci /* Set NPORT-ID and LUN number*/ 22408c2ecf20Sopenharmony_ci cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); 22418c2ecf20Sopenharmony_ci cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; 22428c2ecf20Sopenharmony_ci cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; 22438c2ecf20Sopenharmony_ci cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci int_to_scsilun(cmd->device->lun, &cmd_pkt->lun); 22468c2ecf20Sopenharmony_ci host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_ci /* Total Data and protection segment(s) */ 22498c2ecf20Sopenharmony_ci cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci /* Build IOCB segments and adjust for data protection segments */ 22528c2ecf20Sopenharmony_ci if (qla24xx_build_scsi_crc_2_iocbs(sp, (struct cmd_type_crc_2 *) 22538c2ecf20Sopenharmony_ci req->ring_ptr, tot_dsds, tot_prot_dsds, fw_prot_opts) != 22548c2ecf20Sopenharmony_ci QLA_SUCCESS) 22558c2ecf20Sopenharmony_ci goto queuing_error; 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_ci cmd_pkt->entry_count = (uint8_t)req_cnt; 22588c2ecf20Sopenharmony_ci cmd_pkt->timeout = cpu_to_le16(0); 22598c2ecf20Sopenharmony_ci wmb(); 22608c2ecf20Sopenharmony_ci 22618c2ecf20Sopenharmony_ci /* Adjust ring index. */ 22628c2ecf20Sopenharmony_ci req->ring_index++; 22638c2ecf20Sopenharmony_ci if (req->ring_index == req->length) { 22648c2ecf20Sopenharmony_ci req->ring_index = 0; 22658c2ecf20Sopenharmony_ci req->ring_ptr = req->ring; 22668c2ecf20Sopenharmony_ci } else 22678c2ecf20Sopenharmony_ci req->ring_ptr++; 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci /* Set chip new ring index. */ 22708c2ecf20Sopenharmony_ci wrt_reg_dword(req->req_q_in, req->ring_index); 22718c2ecf20Sopenharmony_ci 22728c2ecf20Sopenharmony_ci /* Manage unprocessed RIO/ZIO commands in response queue. */ 22738c2ecf20Sopenharmony_ci if (vha->flags.process_response_queue && 22748c2ecf20Sopenharmony_ci rsp->ring_ptr->signature != RESPONSE_PROCESSED) 22758c2ecf20Sopenharmony_ci qla24xx_process_response_queue(vha, rsp); 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qpair->qp_lock, flags); 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_ci return QLA_SUCCESS; 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_ciqueuing_error: 22828c2ecf20Sopenharmony_ci if (status & QDSS_GOT_Q_SPACE) { 22838c2ecf20Sopenharmony_ci req->outstanding_cmds[handle] = NULL; 22848c2ecf20Sopenharmony_ci req->cnt += req_cnt; 22858c2ecf20Sopenharmony_ci } 22868c2ecf20Sopenharmony_ci /* Cleanup will be performed by the caller (queuecommand) */ 22878c2ecf20Sopenharmony_ci 22888c2ecf20Sopenharmony_ci qla_put_iocbs(sp->qpair, &sp->iores); 22898c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qpair->qp_lock, flags); 22908c2ecf20Sopenharmony_ci 22918c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 22928c2ecf20Sopenharmony_ci} 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_ci/* Generic Control-SRB manipulation functions. */ 22958c2ecf20Sopenharmony_ci 22968c2ecf20Sopenharmony_ci/* hardware_lock assumed to be held. */ 22978c2ecf20Sopenharmony_ci 22988c2ecf20Sopenharmony_civoid * 22998c2ecf20Sopenharmony_ci__qla2x00_alloc_iocbs(struct qla_qpair *qpair, srb_t *sp) 23008c2ecf20Sopenharmony_ci{ 23018c2ecf20Sopenharmony_ci scsi_qla_host_t *vha = qpair->vha; 23028c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 23038c2ecf20Sopenharmony_ci struct req_que *req = qpair->req; 23048c2ecf20Sopenharmony_ci device_reg_t *reg = ISP_QUE_REG(ha, req->id); 23058c2ecf20Sopenharmony_ci uint32_t handle; 23068c2ecf20Sopenharmony_ci request_t *pkt; 23078c2ecf20Sopenharmony_ci uint16_t cnt, req_cnt; 23088c2ecf20Sopenharmony_ci 23098c2ecf20Sopenharmony_ci pkt = NULL; 23108c2ecf20Sopenharmony_ci req_cnt = 1; 23118c2ecf20Sopenharmony_ci handle = 0; 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_ci if (sp && (sp->type != SRB_SCSI_CMD)) { 23148c2ecf20Sopenharmony_ci /* Adjust entry-counts as needed. */ 23158c2ecf20Sopenharmony_ci req_cnt = sp->iocbs; 23168c2ecf20Sopenharmony_ci } 23178c2ecf20Sopenharmony_ci 23188c2ecf20Sopenharmony_ci /* Check for room on request queue. */ 23198c2ecf20Sopenharmony_ci if (req->cnt < req_cnt + 2) { 23208c2ecf20Sopenharmony_ci if (qpair->use_shadow_reg) 23218c2ecf20Sopenharmony_ci cnt = *req->out_ptr; 23228c2ecf20Sopenharmony_ci else if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha) || 23238c2ecf20Sopenharmony_ci IS_QLA28XX(ha)) 23248c2ecf20Sopenharmony_ci cnt = rd_reg_dword(®->isp25mq.req_q_out); 23258c2ecf20Sopenharmony_ci else if (IS_P3P_TYPE(ha)) 23268c2ecf20Sopenharmony_ci cnt = rd_reg_dword(reg->isp82.req_q_out); 23278c2ecf20Sopenharmony_ci else if (IS_FWI2_CAPABLE(ha)) 23288c2ecf20Sopenharmony_ci cnt = rd_reg_dword(®->isp24.req_q_out); 23298c2ecf20Sopenharmony_ci else if (IS_QLAFX00(ha)) 23308c2ecf20Sopenharmony_ci cnt = rd_reg_dword(®->ispfx00.req_q_out); 23318c2ecf20Sopenharmony_ci else 23328c2ecf20Sopenharmony_ci cnt = qla2x00_debounce_register( 23338c2ecf20Sopenharmony_ci ISP_REQ_Q_OUT(ha, ®->isp)); 23348c2ecf20Sopenharmony_ci 23358c2ecf20Sopenharmony_ci if (!qpair->use_shadow_reg && cnt == ISP_REG16_DISCONNECT) { 23368c2ecf20Sopenharmony_ci qla_schedule_eeh_work(vha); 23378c2ecf20Sopenharmony_ci return NULL; 23388c2ecf20Sopenharmony_ci } 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_ci if (req->ring_index < cnt) 23418c2ecf20Sopenharmony_ci req->cnt = cnt - req->ring_index; 23428c2ecf20Sopenharmony_ci else 23438c2ecf20Sopenharmony_ci req->cnt = req->length - 23448c2ecf20Sopenharmony_ci (req->ring_index - cnt); 23458c2ecf20Sopenharmony_ci } 23468c2ecf20Sopenharmony_ci if (req->cnt < req_cnt + 2) 23478c2ecf20Sopenharmony_ci goto queuing_error; 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_ci if (sp) { 23508c2ecf20Sopenharmony_ci handle = qla2xxx_get_next_handle(req); 23518c2ecf20Sopenharmony_ci if (handle == 0) { 23528c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0x700b, 23538c2ecf20Sopenharmony_ci "No room on outstanding cmd array.\n"); 23548c2ecf20Sopenharmony_ci goto queuing_error; 23558c2ecf20Sopenharmony_ci } 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci /* Prep command array. */ 23588c2ecf20Sopenharmony_ci req->current_outstanding_cmd = handle; 23598c2ecf20Sopenharmony_ci req->outstanding_cmds[handle] = sp; 23608c2ecf20Sopenharmony_ci sp->handle = handle; 23618c2ecf20Sopenharmony_ci } 23628c2ecf20Sopenharmony_ci 23638c2ecf20Sopenharmony_ci /* Prep packet */ 23648c2ecf20Sopenharmony_ci req->cnt -= req_cnt; 23658c2ecf20Sopenharmony_ci pkt = req->ring_ptr; 23668c2ecf20Sopenharmony_ci memset(pkt, 0, REQUEST_ENTRY_SIZE); 23678c2ecf20Sopenharmony_ci if (IS_QLAFX00(ha)) { 23688c2ecf20Sopenharmony_ci wrt_reg_byte((u8 __force __iomem *)&pkt->entry_count, req_cnt); 23698c2ecf20Sopenharmony_ci wrt_reg_dword((__le32 __force __iomem *)&pkt->handle, handle); 23708c2ecf20Sopenharmony_ci } else { 23718c2ecf20Sopenharmony_ci pkt->entry_count = req_cnt; 23728c2ecf20Sopenharmony_ci pkt->handle = handle; 23738c2ecf20Sopenharmony_ci } 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_ci return pkt; 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_ciqueuing_error: 23788c2ecf20Sopenharmony_ci qpair->tgt_counters.num_alloc_iocb_failed++; 23798c2ecf20Sopenharmony_ci return pkt; 23808c2ecf20Sopenharmony_ci} 23818c2ecf20Sopenharmony_ci 23828c2ecf20Sopenharmony_civoid * 23838c2ecf20Sopenharmony_ciqla2x00_alloc_iocbs_ready(struct qla_qpair *qpair, srb_t *sp) 23848c2ecf20Sopenharmony_ci{ 23858c2ecf20Sopenharmony_ci scsi_qla_host_t *vha = qpair->vha; 23868c2ecf20Sopenharmony_ci 23878c2ecf20Sopenharmony_ci if (qla2x00_reset_active(vha)) 23888c2ecf20Sopenharmony_ci return NULL; 23898c2ecf20Sopenharmony_ci 23908c2ecf20Sopenharmony_ci return __qla2x00_alloc_iocbs(qpair, sp); 23918c2ecf20Sopenharmony_ci} 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_civoid * 23948c2ecf20Sopenharmony_ciqla2x00_alloc_iocbs(struct scsi_qla_host *vha, srb_t *sp) 23958c2ecf20Sopenharmony_ci{ 23968c2ecf20Sopenharmony_ci return __qla2x00_alloc_iocbs(vha->hw->base_qpair, sp); 23978c2ecf20Sopenharmony_ci} 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_cistatic void 24008c2ecf20Sopenharmony_ciqla24xx_prli_iocb(srb_t *sp, struct logio_entry_24xx *logio) 24018c2ecf20Sopenharmony_ci{ 24028c2ecf20Sopenharmony_ci struct srb_iocb *lio = &sp->u.iocb_cmd; 24038c2ecf20Sopenharmony_ci 24048c2ecf20Sopenharmony_ci logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; 24058c2ecf20Sopenharmony_ci logio->control_flags = cpu_to_le16(LCF_COMMAND_PRLI); 24068c2ecf20Sopenharmony_ci if (lio->u.logio.flags & SRB_LOGIN_NVME_PRLI) { 24078c2ecf20Sopenharmony_ci logio->control_flags |= cpu_to_le16(LCF_NVME_PRLI); 24088c2ecf20Sopenharmony_ci if (sp->vha->flags.nvme_first_burst) 24098c2ecf20Sopenharmony_ci logio->io_parameter[0] = 24108c2ecf20Sopenharmony_ci cpu_to_le32(NVME_PRLI_SP_FIRST_BURST); 24118c2ecf20Sopenharmony_ci if (sp->vha->flags.nvme2_enabled) { 24128c2ecf20Sopenharmony_ci /* Set service parameter BIT_8 for SLER support */ 24138c2ecf20Sopenharmony_ci logio->io_parameter[0] |= 24148c2ecf20Sopenharmony_ci cpu_to_le32(NVME_PRLI_SP_SLER); 24158c2ecf20Sopenharmony_ci /* Set service parameter BIT_9 for PI control support */ 24168c2ecf20Sopenharmony_ci logio->io_parameter[0] |= 24178c2ecf20Sopenharmony_ci cpu_to_le32(NVME_PRLI_SP_PI_CTRL); 24188c2ecf20Sopenharmony_ci } 24198c2ecf20Sopenharmony_ci } 24208c2ecf20Sopenharmony_ci 24218c2ecf20Sopenharmony_ci logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); 24228c2ecf20Sopenharmony_ci logio->port_id[0] = sp->fcport->d_id.b.al_pa; 24238c2ecf20Sopenharmony_ci logio->port_id[1] = sp->fcport->d_id.b.area; 24248c2ecf20Sopenharmony_ci logio->port_id[2] = sp->fcport->d_id.b.domain; 24258c2ecf20Sopenharmony_ci logio->vp_index = sp->vha->vp_idx; 24268c2ecf20Sopenharmony_ci} 24278c2ecf20Sopenharmony_ci 24288c2ecf20Sopenharmony_cistatic void 24298c2ecf20Sopenharmony_ciqla24xx_login_iocb(srb_t *sp, struct logio_entry_24xx *logio) 24308c2ecf20Sopenharmony_ci{ 24318c2ecf20Sopenharmony_ci struct srb_iocb *lio = &sp->u.iocb_cmd; 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_ci logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; 24348c2ecf20Sopenharmony_ci logio->control_flags = cpu_to_le16(LCF_COMMAND_PLOGI); 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_ci if (lio->u.logio.flags & SRB_LOGIN_PRLI_ONLY) { 24378c2ecf20Sopenharmony_ci logio->control_flags = cpu_to_le16(LCF_COMMAND_PRLI); 24388c2ecf20Sopenharmony_ci } else { 24398c2ecf20Sopenharmony_ci logio->control_flags = cpu_to_le16(LCF_COMMAND_PLOGI); 24408c2ecf20Sopenharmony_ci if (lio->u.logio.flags & SRB_LOGIN_COND_PLOGI) 24418c2ecf20Sopenharmony_ci logio->control_flags |= cpu_to_le16(LCF_COND_PLOGI); 24428c2ecf20Sopenharmony_ci if (lio->u.logio.flags & SRB_LOGIN_SKIP_PRLI) 24438c2ecf20Sopenharmony_ci logio->control_flags |= cpu_to_le16(LCF_SKIP_PRLI); 24448c2ecf20Sopenharmony_ci } 24458c2ecf20Sopenharmony_ci logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); 24468c2ecf20Sopenharmony_ci logio->port_id[0] = sp->fcport->d_id.b.al_pa; 24478c2ecf20Sopenharmony_ci logio->port_id[1] = sp->fcport->d_id.b.area; 24488c2ecf20Sopenharmony_ci logio->port_id[2] = sp->fcport->d_id.b.domain; 24498c2ecf20Sopenharmony_ci logio->vp_index = sp->vha->vp_idx; 24508c2ecf20Sopenharmony_ci} 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_cistatic void 24538c2ecf20Sopenharmony_ciqla2x00_login_iocb(srb_t *sp, struct mbx_entry *mbx) 24548c2ecf20Sopenharmony_ci{ 24558c2ecf20Sopenharmony_ci struct qla_hw_data *ha = sp->vha->hw; 24568c2ecf20Sopenharmony_ci struct srb_iocb *lio = &sp->u.iocb_cmd; 24578c2ecf20Sopenharmony_ci uint16_t opts; 24588c2ecf20Sopenharmony_ci 24598c2ecf20Sopenharmony_ci mbx->entry_type = MBX_IOCB_TYPE; 24608c2ecf20Sopenharmony_ci SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id); 24618c2ecf20Sopenharmony_ci mbx->mb0 = cpu_to_le16(MBC_LOGIN_FABRIC_PORT); 24628c2ecf20Sopenharmony_ci opts = lio->u.logio.flags & SRB_LOGIN_COND_PLOGI ? BIT_0 : 0; 24638c2ecf20Sopenharmony_ci opts |= lio->u.logio.flags & SRB_LOGIN_SKIP_PRLI ? BIT_1 : 0; 24648c2ecf20Sopenharmony_ci if (HAS_EXTENDED_IDS(ha)) { 24658c2ecf20Sopenharmony_ci mbx->mb1 = cpu_to_le16(sp->fcport->loop_id); 24668c2ecf20Sopenharmony_ci mbx->mb10 = cpu_to_le16(opts); 24678c2ecf20Sopenharmony_ci } else { 24688c2ecf20Sopenharmony_ci mbx->mb1 = cpu_to_le16((sp->fcport->loop_id << 8) | opts); 24698c2ecf20Sopenharmony_ci } 24708c2ecf20Sopenharmony_ci mbx->mb2 = cpu_to_le16(sp->fcport->d_id.b.domain); 24718c2ecf20Sopenharmony_ci mbx->mb3 = cpu_to_le16(sp->fcport->d_id.b.area << 8 | 24728c2ecf20Sopenharmony_ci sp->fcport->d_id.b.al_pa); 24738c2ecf20Sopenharmony_ci mbx->mb9 = cpu_to_le16(sp->vha->vp_idx); 24748c2ecf20Sopenharmony_ci} 24758c2ecf20Sopenharmony_ci 24768c2ecf20Sopenharmony_cistatic void 24778c2ecf20Sopenharmony_ciqla24xx_logout_iocb(srb_t *sp, struct logio_entry_24xx *logio) 24788c2ecf20Sopenharmony_ci{ 24798c2ecf20Sopenharmony_ci u16 control_flags = LCF_COMMAND_LOGO; 24808c2ecf20Sopenharmony_ci logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci if (sp->fcport->explicit_logout) { 24838c2ecf20Sopenharmony_ci control_flags |= LCF_EXPL_LOGO|LCF_FREE_NPORT; 24848c2ecf20Sopenharmony_ci } else { 24858c2ecf20Sopenharmony_ci control_flags |= LCF_IMPL_LOGO; 24868c2ecf20Sopenharmony_ci 24878c2ecf20Sopenharmony_ci if (!sp->fcport->keep_nport_handle) 24888c2ecf20Sopenharmony_ci control_flags |= LCF_FREE_NPORT; 24898c2ecf20Sopenharmony_ci } 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_ci logio->control_flags = cpu_to_le16(control_flags); 24928c2ecf20Sopenharmony_ci logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); 24938c2ecf20Sopenharmony_ci logio->port_id[0] = sp->fcport->d_id.b.al_pa; 24948c2ecf20Sopenharmony_ci logio->port_id[1] = sp->fcport->d_id.b.area; 24958c2ecf20Sopenharmony_ci logio->port_id[2] = sp->fcport->d_id.b.domain; 24968c2ecf20Sopenharmony_ci logio->vp_index = sp->vha->vp_idx; 24978c2ecf20Sopenharmony_ci} 24988c2ecf20Sopenharmony_ci 24998c2ecf20Sopenharmony_cistatic void 25008c2ecf20Sopenharmony_ciqla2x00_logout_iocb(srb_t *sp, struct mbx_entry *mbx) 25018c2ecf20Sopenharmony_ci{ 25028c2ecf20Sopenharmony_ci struct qla_hw_data *ha = sp->vha->hw; 25038c2ecf20Sopenharmony_ci 25048c2ecf20Sopenharmony_ci mbx->entry_type = MBX_IOCB_TYPE; 25058c2ecf20Sopenharmony_ci SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id); 25068c2ecf20Sopenharmony_ci mbx->mb0 = cpu_to_le16(MBC_LOGOUT_FABRIC_PORT); 25078c2ecf20Sopenharmony_ci mbx->mb1 = HAS_EXTENDED_IDS(ha) ? 25088c2ecf20Sopenharmony_ci cpu_to_le16(sp->fcport->loop_id) : 25098c2ecf20Sopenharmony_ci cpu_to_le16(sp->fcport->loop_id << 8); 25108c2ecf20Sopenharmony_ci mbx->mb2 = cpu_to_le16(sp->fcport->d_id.b.domain); 25118c2ecf20Sopenharmony_ci mbx->mb3 = cpu_to_le16(sp->fcport->d_id.b.area << 8 | 25128c2ecf20Sopenharmony_ci sp->fcport->d_id.b.al_pa); 25138c2ecf20Sopenharmony_ci mbx->mb9 = cpu_to_le16(sp->vha->vp_idx); 25148c2ecf20Sopenharmony_ci /* Implicit: mbx->mbx10 = 0. */ 25158c2ecf20Sopenharmony_ci} 25168c2ecf20Sopenharmony_ci 25178c2ecf20Sopenharmony_cistatic void 25188c2ecf20Sopenharmony_ciqla24xx_adisc_iocb(srb_t *sp, struct logio_entry_24xx *logio) 25198c2ecf20Sopenharmony_ci{ 25208c2ecf20Sopenharmony_ci logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; 25218c2ecf20Sopenharmony_ci logio->control_flags = cpu_to_le16(LCF_COMMAND_ADISC); 25228c2ecf20Sopenharmony_ci logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); 25238c2ecf20Sopenharmony_ci logio->vp_index = sp->vha->vp_idx; 25248c2ecf20Sopenharmony_ci} 25258c2ecf20Sopenharmony_ci 25268c2ecf20Sopenharmony_cistatic void 25278c2ecf20Sopenharmony_ciqla2x00_adisc_iocb(srb_t *sp, struct mbx_entry *mbx) 25288c2ecf20Sopenharmony_ci{ 25298c2ecf20Sopenharmony_ci struct qla_hw_data *ha = sp->vha->hw; 25308c2ecf20Sopenharmony_ci 25318c2ecf20Sopenharmony_ci mbx->entry_type = MBX_IOCB_TYPE; 25328c2ecf20Sopenharmony_ci SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id); 25338c2ecf20Sopenharmony_ci mbx->mb0 = cpu_to_le16(MBC_GET_PORT_DATABASE); 25348c2ecf20Sopenharmony_ci if (HAS_EXTENDED_IDS(ha)) { 25358c2ecf20Sopenharmony_ci mbx->mb1 = cpu_to_le16(sp->fcport->loop_id); 25368c2ecf20Sopenharmony_ci mbx->mb10 = cpu_to_le16(BIT_0); 25378c2ecf20Sopenharmony_ci } else { 25388c2ecf20Sopenharmony_ci mbx->mb1 = cpu_to_le16((sp->fcport->loop_id << 8) | BIT_0); 25398c2ecf20Sopenharmony_ci } 25408c2ecf20Sopenharmony_ci mbx->mb2 = cpu_to_le16(MSW(ha->async_pd_dma)); 25418c2ecf20Sopenharmony_ci mbx->mb3 = cpu_to_le16(LSW(ha->async_pd_dma)); 25428c2ecf20Sopenharmony_ci mbx->mb6 = cpu_to_le16(MSW(MSD(ha->async_pd_dma))); 25438c2ecf20Sopenharmony_ci mbx->mb7 = cpu_to_le16(LSW(MSD(ha->async_pd_dma))); 25448c2ecf20Sopenharmony_ci mbx->mb9 = cpu_to_le16(sp->vha->vp_idx); 25458c2ecf20Sopenharmony_ci} 25468c2ecf20Sopenharmony_ci 25478c2ecf20Sopenharmony_cistatic void 25488c2ecf20Sopenharmony_ciqla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk) 25498c2ecf20Sopenharmony_ci{ 25508c2ecf20Sopenharmony_ci uint32_t flags; 25518c2ecf20Sopenharmony_ci uint64_t lun; 25528c2ecf20Sopenharmony_ci struct fc_port *fcport = sp->fcport; 25538c2ecf20Sopenharmony_ci scsi_qla_host_t *vha = fcport->vha; 25548c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 25558c2ecf20Sopenharmony_ci struct srb_iocb *iocb = &sp->u.iocb_cmd; 25568c2ecf20Sopenharmony_ci struct req_que *req = vha->req; 25578c2ecf20Sopenharmony_ci 25588c2ecf20Sopenharmony_ci flags = iocb->u.tmf.flags; 25598c2ecf20Sopenharmony_ci lun = iocb->u.tmf.lun; 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_ci tsk->entry_type = TSK_MGMT_IOCB_TYPE; 25628c2ecf20Sopenharmony_ci tsk->entry_count = 1; 25638c2ecf20Sopenharmony_ci tsk->handle = make_handle(req->id, tsk->handle); 25648c2ecf20Sopenharmony_ci tsk->nport_handle = cpu_to_le16(fcport->loop_id); 25658c2ecf20Sopenharmony_ci tsk->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); 25668c2ecf20Sopenharmony_ci tsk->control_flags = cpu_to_le32(flags); 25678c2ecf20Sopenharmony_ci tsk->port_id[0] = fcport->d_id.b.al_pa; 25688c2ecf20Sopenharmony_ci tsk->port_id[1] = fcport->d_id.b.area; 25698c2ecf20Sopenharmony_ci tsk->port_id[2] = fcport->d_id.b.domain; 25708c2ecf20Sopenharmony_ci tsk->vp_index = fcport->vha->vp_idx; 25718c2ecf20Sopenharmony_ci 25728c2ecf20Sopenharmony_ci if (flags == TCF_LUN_RESET) { 25738c2ecf20Sopenharmony_ci int_to_scsilun(lun, &tsk->lun); 25748c2ecf20Sopenharmony_ci host_to_fcp_swap((uint8_t *)&tsk->lun, 25758c2ecf20Sopenharmony_ci sizeof(tsk->lun)); 25768c2ecf20Sopenharmony_ci } 25778c2ecf20Sopenharmony_ci} 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_civoid qla2x00_init_timer(srb_t *sp, unsigned long tmo) 25808c2ecf20Sopenharmony_ci{ 25818c2ecf20Sopenharmony_ci timer_setup(&sp->u.iocb_cmd.timer, qla2x00_sp_timeout, 0); 25828c2ecf20Sopenharmony_ci sp->u.iocb_cmd.timer.expires = jiffies + tmo * HZ; 25838c2ecf20Sopenharmony_ci sp->free = qla2x00_sp_free; 25848c2ecf20Sopenharmony_ci if (IS_QLAFX00(sp->vha->hw) && sp->type == SRB_FXIOCB_DCMD) 25858c2ecf20Sopenharmony_ci init_completion(&sp->u.iocb_cmd.u.fxiocb.fxiocb_comp); 25868c2ecf20Sopenharmony_ci sp->start_timer = 1; 25878c2ecf20Sopenharmony_ci} 25888c2ecf20Sopenharmony_ci 25898c2ecf20Sopenharmony_cistatic void qla2x00_els_dcmd_sp_free(srb_t *sp) 25908c2ecf20Sopenharmony_ci{ 25918c2ecf20Sopenharmony_ci struct srb_iocb *elsio = &sp->u.iocb_cmd; 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_ci kfree(sp->fcport); 25948c2ecf20Sopenharmony_ci 25958c2ecf20Sopenharmony_ci if (elsio->u.els_logo.els_logo_pyld) 25968c2ecf20Sopenharmony_ci dma_free_coherent(&sp->vha->hw->pdev->dev, DMA_POOL_SIZE, 25978c2ecf20Sopenharmony_ci elsio->u.els_logo.els_logo_pyld, 25988c2ecf20Sopenharmony_ci elsio->u.els_logo.els_logo_pyld_dma); 25998c2ecf20Sopenharmony_ci 26008c2ecf20Sopenharmony_ci del_timer(&elsio->timer); 26018c2ecf20Sopenharmony_ci qla2x00_rel_sp(sp); 26028c2ecf20Sopenharmony_ci} 26038c2ecf20Sopenharmony_ci 26048c2ecf20Sopenharmony_cistatic void 26058c2ecf20Sopenharmony_ciqla2x00_els_dcmd_iocb_timeout(void *data) 26068c2ecf20Sopenharmony_ci{ 26078c2ecf20Sopenharmony_ci srb_t *sp = data; 26088c2ecf20Sopenharmony_ci fc_port_t *fcport = sp->fcport; 26098c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = sp->vha; 26108c2ecf20Sopenharmony_ci struct srb_iocb *lio = &sp->u.iocb_cmd; 26118c2ecf20Sopenharmony_ci unsigned long flags = 0; 26128c2ecf20Sopenharmony_ci int res, h; 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3069, 26158c2ecf20Sopenharmony_ci "%s Timeout, hdl=%x, portid=%02x%02x%02x\n", 26168c2ecf20Sopenharmony_ci sp->name, sp->handle, fcport->d_id.b.domain, fcport->d_id.b.area, 26178c2ecf20Sopenharmony_ci fcport->d_id.b.al_pa); 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci /* Abort the exchange */ 26208c2ecf20Sopenharmony_ci res = qla24xx_async_abort_cmd(sp, false); 26218c2ecf20Sopenharmony_ci if (res) { 26228c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3070, 26238c2ecf20Sopenharmony_ci "mbx abort_command failed.\n"); 26248c2ecf20Sopenharmony_ci spin_lock_irqsave(sp->qpair->qp_lock_ptr, flags); 26258c2ecf20Sopenharmony_ci for (h = 1; h < sp->qpair->req->num_outstanding_cmds; h++) { 26268c2ecf20Sopenharmony_ci if (sp->qpair->req->outstanding_cmds[h] == sp) { 26278c2ecf20Sopenharmony_ci sp->qpair->req->outstanding_cmds[h] = NULL; 26288c2ecf20Sopenharmony_ci break; 26298c2ecf20Sopenharmony_ci } 26308c2ecf20Sopenharmony_ci } 26318c2ecf20Sopenharmony_ci spin_unlock_irqrestore(sp->qpair->qp_lock_ptr, flags); 26328c2ecf20Sopenharmony_ci complete(&lio->u.els_logo.comp); 26338c2ecf20Sopenharmony_ci } else { 26348c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3071, 26358c2ecf20Sopenharmony_ci "mbx abort_command success.\n"); 26368c2ecf20Sopenharmony_ci } 26378c2ecf20Sopenharmony_ci} 26388c2ecf20Sopenharmony_ci 26398c2ecf20Sopenharmony_cistatic void qla2x00_els_dcmd_sp_done(srb_t *sp, int res) 26408c2ecf20Sopenharmony_ci{ 26418c2ecf20Sopenharmony_ci fc_port_t *fcport = sp->fcport; 26428c2ecf20Sopenharmony_ci struct srb_iocb *lio = &sp->u.iocb_cmd; 26438c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = sp->vha; 26448c2ecf20Sopenharmony_ci 26458c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3072, 26468c2ecf20Sopenharmony_ci "%s hdl=%x, portid=%02x%02x%02x done\n", 26478c2ecf20Sopenharmony_ci sp->name, sp->handle, fcport->d_id.b.domain, 26488c2ecf20Sopenharmony_ci fcport->d_id.b.area, fcport->d_id.b.al_pa); 26498c2ecf20Sopenharmony_ci 26508c2ecf20Sopenharmony_ci complete(&lio->u.els_logo.comp); 26518c2ecf20Sopenharmony_ci} 26528c2ecf20Sopenharmony_ci 26538c2ecf20Sopenharmony_ciint 26548c2ecf20Sopenharmony_ciqla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode, 26558c2ecf20Sopenharmony_ci port_id_t remote_did) 26568c2ecf20Sopenharmony_ci{ 26578c2ecf20Sopenharmony_ci srb_t *sp; 26588c2ecf20Sopenharmony_ci fc_port_t *fcport = NULL; 26598c2ecf20Sopenharmony_ci struct srb_iocb *elsio = NULL; 26608c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 26618c2ecf20Sopenharmony_ci struct els_logo_payload logo_pyld; 26628c2ecf20Sopenharmony_ci int rval = QLA_SUCCESS; 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_ci fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); 26658c2ecf20Sopenharmony_ci if (!fcport) { 26668c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0x70e5, "fcport allocation failed\n"); 26678c2ecf20Sopenharmony_ci return -ENOMEM; 26688c2ecf20Sopenharmony_ci } 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_ci /* Alloc SRB structure */ 26718c2ecf20Sopenharmony_ci sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); 26728c2ecf20Sopenharmony_ci if (!sp) { 26738c2ecf20Sopenharmony_ci kfree(fcport); 26748c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0x70e6, 26758c2ecf20Sopenharmony_ci "SRB allocation failed\n"); 26768c2ecf20Sopenharmony_ci return -ENOMEM; 26778c2ecf20Sopenharmony_ci } 26788c2ecf20Sopenharmony_ci 26798c2ecf20Sopenharmony_ci elsio = &sp->u.iocb_cmd; 26808c2ecf20Sopenharmony_ci fcport->loop_id = 0xFFFF; 26818c2ecf20Sopenharmony_ci fcport->d_id.b.domain = remote_did.b.domain; 26828c2ecf20Sopenharmony_ci fcport->d_id.b.area = remote_did.b.area; 26838c2ecf20Sopenharmony_ci fcport->d_id.b.al_pa = remote_did.b.al_pa; 26848c2ecf20Sopenharmony_ci 26858c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3073, "portid=%02x%02x%02x done\n", 26868c2ecf20Sopenharmony_ci fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa); 26878c2ecf20Sopenharmony_ci 26888c2ecf20Sopenharmony_ci sp->type = SRB_ELS_DCMD; 26898c2ecf20Sopenharmony_ci sp->name = "ELS_DCMD"; 26908c2ecf20Sopenharmony_ci sp->fcport = fcport; 26918c2ecf20Sopenharmony_ci elsio->timeout = qla2x00_els_dcmd_iocb_timeout; 26928c2ecf20Sopenharmony_ci qla2x00_init_timer(sp, ELS_DCMD_TIMEOUT); 26938c2ecf20Sopenharmony_ci init_completion(&sp->u.iocb_cmd.u.els_logo.comp); 26948c2ecf20Sopenharmony_ci sp->done = qla2x00_els_dcmd_sp_done; 26958c2ecf20Sopenharmony_ci sp->free = qla2x00_els_dcmd_sp_free; 26968c2ecf20Sopenharmony_ci 26978c2ecf20Sopenharmony_ci elsio->u.els_logo.els_logo_pyld = dma_alloc_coherent(&ha->pdev->dev, 26988c2ecf20Sopenharmony_ci DMA_POOL_SIZE, &elsio->u.els_logo.els_logo_pyld_dma, 26998c2ecf20Sopenharmony_ci GFP_KERNEL); 27008c2ecf20Sopenharmony_ci 27018c2ecf20Sopenharmony_ci if (!elsio->u.els_logo.els_logo_pyld) { 27028c2ecf20Sopenharmony_ci sp->free(sp); 27038c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 27048c2ecf20Sopenharmony_ci } 27058c2ecf20Sopenharmony_ci 27068c2ecf20Sopenharmony_ci memset(&logo_pyld, 0, sizeof(struct els_logo_payload)); 27078c2ecf20Sopenharmony_ci 27088c2ecf20Sopenharmony_ci elsio->u.els_logo.els_cmd = els_opcode; 27098c2ecf20Sopenharmony_ci logo_pyld.opcode = els_opcode; 27108c2ecf20Sopenharmony_ci logo_pyld.s_id[0] = vha->d_id.b.al_pa; 27118c2ecf20Sopenharmony_ci logo_pyld.s_id[1] = vha->d_id.b.area; 27128c2ecf20Sopenharmony_ci logo_pyld.s_id[2] = vha->d_id.b.domain; 27138c2ecf20Sopenharmony_ci host_to_fcp_swap(logo_pyld.s_id, sizeof(uint32_t)); 27148c2ecf20Sopenharmony_ci memcpy(&logo_pyld.wwpn, vha->port_name, WWN_SIZE); 27158c2ecf20Sopenharmony_ci 27168c2ecf20Sopenharmony_ci memcpy(elsio->u.els_logo.els_logo_pyld, &logo_pyld, 27178c2ecf20Sopenharmony_ci sizeof(struct els_logo_payload)); 27188c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x3075, "LOGO buffer:"); 27198c2ecf20Sopenharmony_ci ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x010a, 27208c2ecf20Sopenharmony_ci elsio->u.els_logo.els_logo_pyld, 27218c2ecf20Sopenharmony_ci sizeof(*elsio->u.els_logo.els_logo_pyld)); 27228c2ecf20Sopenharmony_ci 27238c2ecf20Sopenharmony_ci rval = qla2x00_start_sp(sp); 27248c2ecf20Sopenharmony_ci if (rval != QLA_SUCCESS) { 27258c2ecf20Sopenharmony_ci sp->free(sp); 27268c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 27278c2ecf20Sopenharmony_ci } 27288c2ecf20Sopenharmony_ci 27298c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3074, 27308c2ecf20Sopenharmony_ci "%s LOGO sent, hdl=%x, loopid=%x, portid=%02x%02x%02x.\n", 27318c2ecf20Sopenharmony_ci sp->name, sp->handle, fcport->loop_id, fcport->d_id.b.domain, 27328c2ecf20Sopenharmony_ci fcport->d_id.b.area, fcport->d_id.b.al_pa); 27338c2ecf20Sopenharmony_ci 27348c2ecf20Sopenharmony_ci wait_for_completion(&elsio->u.els_logo.comp); 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_ci sp->free(sp); 27378c2ecf20Sopenharmony_ci return rval; 27388c2ecf20Sopenharmony_ci} 27398c2ecf20Sopenharmony_ci 27408c2ecf20Sopenharmony_cistatic void 27418c2ecf20Sopenharmony_ciqla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) 27428c2ecf20Sopenharmony_ci{ 27438c2ecf20Sopenharmony_ci scsi_qla_host_t *vha = sp->vha; 27448c2ecf20Sopenharmony_ci struct srb_iocb *elsio = &sp->u.iocb_cmd; 27458c2ecf20Sopenharmony_ci 27468c2ecf20Sopenharmony_ci els_iocb->entry_type = ELS_IOCB_TYPE; 27478c2ecf20Sopenharmony_ci els_iocb->entry_count = 1; 27488c2ecf20Sopenharmony_ci els_iocb->sys_define = 0; 27498c2ecf20Sopenharmony_ci els_iocb->entry_status = 0; 27508c2ecf20Sopenharmony_ci els_iocb->handle = sp->handle; 27518c2ecf20Sopenharmony_ci els_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id); 27528c2ecf20Sopenharmony_ci els_iocb->tx_dsd_count = cpu_to_le16(1); 27538c2ecf20Sopenharmony_ci els_iocb->vp_index = vha->vp_idx; 27548c2ecf20Sopenharmony_ci els_iocb->sof_type = EST_SOFI3; 27558c2ecf20Sopenharmony_ci els_iocb->rx_dsd_count = 0; 27568c2ecf20Sopenharmony_ci els_iocb->opcode = elsio->u.els_logo.els_cmd; 27578c2ecf20Sopenharmony_ci 27588c2ecf20Sopenharmony_ci els_iocb->d_id[0] = sp->fcport->d_id.b.al_pa; 27598c2ecf20Sopenharmony_ci els_iocb->d_id[1] = sp->fcport->d_id.b.area; 27608c2ecf20Sopenharmony_ci els_iocb->d_id[2] = sp->fcport->d_id.b.domain; 27618c2ecf20Sopenharmony_ci /* For SID the byte order is different than DID */ 27628c2ecf20Sopenharmony_ci els_iocb->s_id[1] = vha->d_id.b.al_pa; 27638c2ecf20Sopenharmony_ci els_iocb->s_id[2] = vha->d_id.b.area; 27648c2ecf20Sopenharmony_ci els_iocb->s_id[0] = vha->d_id.b.domain; 27658c2ecf20Sopenharmony_ci 27668c2ecf20Sopenharmony_ci if (elsio->u.els_logo.els_cmd == ELS_DCMD_PLOGI) { 27678c2ecf20Sopenharmony_ci els_iocb->control_flags = 0; 27688c2ecf20Sopenharmony_ci els_iocb->tx_byte_count = els_iocb->tx_len = 27698c2ecf20Sopenharmony_ci cpu_to_le32(sizeof(struct els_plogi_payload)); 27708c2ecf20Sopenharmony_ci put_unaligned_le64(elsio->u.els_plogi.els_plogi_pyld_dma, 27718c2ecf20Sopenharmony_ci &els_iocb->tx_address); 27728c2ecf20Sopenharmony_ci els_iocb->rx_dsd_count = cpu_to_le16(1); 27738c2ecf20Sopenharmony_ci els_iocb->rx_byte_count = els_iocb->rx_len = 27748c2ecf20Sopenharmony_ci cpu_to_le32(sizeof(struct els_plogi_payload)); 27758c2ecf20Sopenharmony_ci put_unaligned_le64(elsio->u.els_plogi.els_resp_pyld_dma, 27768c2ecf20Sopenharmony_ci &els_iocb->rx_address); 27778c2ecf20Sopenharmony_ci 27788c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x3073, 27798c2ecf20Sopenharmony_ci "PLOGI ELS IOCB:\n"); 27808c2ecf20Sopenharmony_ci ql_dump_buffer(ql_log_info, vha, 0x0109, 27818c2ecf20Sopenharmony_ci (uint8_t *)els_iocb, 27828c2ecf20Sopenharmony_ci sizeof(*els_iocb)); 27838c2ecf20Sopenharmony_ci } else { 27848c2ecf20Sopenharmony_ci els_iocb->control_flags = cpu_to_le16(1 << 13); 27858c2ecf20Sopenharmony_ci els_iocb->tx_byte_count = 27868c2ecf20Sopenharmony_ci cpu_to_le32(sizeof(struct els_logo_payload)); 27878c2ecf20Sopenharmony_ci put_unaligned_le64(elsio->u.els_logo.els_logo_pyld_dma, 27888c2ecf20Sopenharmony_ci &els_iocb->tx_address); 27898c2ecf20Sopenharmony_ci els_iocb->tx_len = cpu_to_le32(sizeof(struct els_logo_payload)); 27908c2ecf20Sopenharmony_ci 27918c2ecf20Sopenharmony_ci els_iocb->rx_byte_count = 0; 27928c2ecf20Sopenharmony_ci els_iocb->rx_address = 0; 27938c2ecf20Sopenharmony_ci els_iocb->rx_len = 0; 27948c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x3076, 27958c2ecf20Sopenharmony_ci "LOGO ELS IOCB:"); 27968c2ecf20Sopenharmony_ci ql_dump_buffer(ql_log_info, vha, 0x010b, 27978c2ecf20Sopenharmony_ci els_iocb, 27988c2ecf20Sopenharmony_ci sizeof(*els_iocb)); 27998c2ecf20Sopenharmony_ci } 28008c2ecf20Sopenharmony_ci 28018c2ecf20Sopenharmony_ci sp->vha->qla_stats.control_requests++; 28028c2ecf20Sopenharmony_ci} 28038c2ecf20Sopenharmony_ci 28048c2ecf20Sopenharmony_cistatic void 28058c2ecf20Sopenharmony_ciqla2x00_els_dcmd2_iocb_timeout(void *data) 28068c2ecf20Sopenharmony_ci{ 28078c2ecf20Sopenharmony_ci srb_t *sp = data; 28088c2ecf20Sopenharmony_ci fc_port_t *fcport = sp->fcport; 28098c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = sp->vha; 28108c2ecf20Sopenharmony_ci unsigned long flags = 0; 28118c2ecf20Sopenharmony_ci int res, h; 28128c2ecf20Sopenharmony_ci 28138c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io + ql_dbg_disc, vha, 0x3069, 28148c2ecf20Sopenharmony_ci "%s hdl=%x ELS Timeout, %8phC portid=%06x\n", 28158c2ecf20Sopenharmony_ci sp->name, sp->handle, fcport->port_name, fcport->d_id.b24); 28168c2ecf20Sopenharmony_ci 28178c2ecf20Sopenharmony_ci /* Abort the exchange */ 28188c2ecf20Sopenharmony_ci res = qla24xx_async_abort_cmd(sp, false); 28198c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3070, 28208c2ecf20Sopenharmony_ci "mbx abort_command %s\n", 28218c2ecf20Sopenharmony_ci (res == QLA_SUCCESS) ? "successful" : "failed"); 28228c2ecf20Sopenharmony_ci if (res) { 28238c2ecf20Sopenharmony_ci spin_lock_irqsave(sp->qpair->qp_lock_ptr, flags); 28248c2ecf20Sopenharmony_ci for (h = 1; h < sp->qpair->req->num_outstanding_cmds; h++) { 28258c2ecf20Sopenharmony_ci if (sp->qpair->req->outstanding_cmds[h] == sp) { 28268c2ecf20Sopenharmony_ci sp->qpair->req->outstanding_cmds[h] = NULL; 28278c2ecf20Sopenharmony_ci break; 28288c2ecf20Sopenharmony_ci } 28298c2ecf20Sopenharmony_ci } 28308c2ecf20Sopenharmony_ci spin_unlock_irqrestore(sp->qpair->qp_lock_ptr, flags); 28318c2ecf20Sopenharmony_ci sp->done(sp, QLA_FUNCTION_TIMEOUT); 28328c2ecf20Sopenharmony_ci } 28338c2ecf20Sopenharmony_ci} 28348c2ecf20Sopenharmony_ci 28358c2ecf20Sopenharmony_civoid qla2x00_els_dcmd2_free(scsi_qla_host_t *vha, struct els_plogi *els_plogi) 28368c2ecf20Sopenharmony_ci{ 28378c2ecf20Sopenharmony_ci if (els_plogi->els_plogi_pyld) 28388c2ecf20Sopenharmony_ci dma_free_coherent(&vha->hw->pdev->dev, 28398c2ecf20Sopenharmony_ci els_plogi->tx_size, 28408c2ecf20Sopenharmony_ci els_plogi->els_plogi_pyld, 28418c2ecf20Sopenharmony_ci els_plogi->els_plogi_pyld_dma); 28428c2ecf20Sopenharmony_ci 28438c2ecf20Sopenharmony_ci if (els_plogi->els_resp_pyld) 28448c2ecf20Sopenharmony_ci dma_free_coherent(&vha->hw->pdev->dev, 28458c2ecf20Sopenharmony_ci els_plogi->rx_size, 28468c2ecf20Sopenharmony_ci els_plogi->els_resp_pyld, 28478c2ecf20Sopenharmony_ci els_plogi->els_resp_pyld_dma); 28488c2ecf20Sopenharmony_ci} 28498c2ecf20Sopenharmony_ci 28508c2ecf20Sopenharmony_cistatic void qla2x00_els_dcmd2_sp_done(srb_t *sp, int res) 28518c2ecf20Sopenharmony_ci{ 28528c2ecf20Sopenharmony_ci fc_port_t *fcport = sp->fcport; 28538c2ecf20Sopenharmony_ci struct srb_iocb *lio = &sp->u.iocb_cmd; 28548c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = sp->vha; 28558c2ecf20Sopenharmony_ci struct event_arg ea; 28568c2ecf20Sopenharmony_ci struct qla_work_evt *e; 28578c2ecf20Sopenharmony_ci struct fc_port *conflict_fcport; 28588c2ecf20Sopenharmony_ci port_id_t cid; /* conflict Nport id */ 28598c2ecf20Sopenharmony_ci const __le32 *fw_status = sp->u.iocb_cmd.u.els_plogi.fw_status; 28608c2ecf20Sopenharmony_ci u16 lid; 28618c2ecf20Sopenharmony_ci 28628c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x3072, 28638c2ecf20Sopenharmony_ci "%s ELS done rc %d hdl=%x, portid=%06x %8phC\n", 28648c2ecf20Sopenharmony_ci sp->name, res, sp->handle, fcport->d_id.b24, fcport->port_name); 28658c2ecf20Sopenharmony_ci 28668c2ecf20Sopenharmony_ci fcport->flags &= ~(FCF_ASYNC_SENT|FCF_ASYNC_ACTIVE); 28678c2ecf20Sopenharmony_ci del_timer(&sp->u.iocb_cmd.timer); 28688c2ecf20Sopenharmony_ci 28698c2ecf20Sopenharmony_ci if (sp->flags & SRB_WAKEUP_ON_COMP) 28708c2ecf20Sopenharmony_ci complete(&lio->u.els_plogi.comp); 28718c2ecf20Sopenharmony_ci else { 28728c2ecf20Sopenharmony_ci switch (le32_to_cpu(fw_status[0])) { 28738c2ecf20Sopenharmony_ci case CS_DATA_UNDERRUN: 28748c2ecf20Sopenharmony_ci case CS_COMPLETE: 28758c2ecf20Sopenharmony_ci memset(&ea, 0, sizeof(ea)); 28768c2ecf20Sopenharmony_ci ea.fcport = fcport; 28778c2ecf20Sopenharmony_ci ea.rc = res; 28788c2ecf20Sopenharmony_ci qla_handle_els_plogi_done(vha, &ea); 28798c2ecf20Sopenharmony_ci break; 28808c2ecf20Sopenharmony_ci 28818c2ecf20Sopenharmony_ci case CS_IOCB_ERROR: 28828c2ecf20Sopenharmony_ci switch (le32_to_cpu(fw_status[1])) { 28838c2ecf20Sopenharmony_ci case LSC_SCODE_PORTID_USED: 28848c2ecf20Sopenharmony_ci lid = le32_to_cpu(fw_status[2]) & 0xffff; 28858c2ecf20Sopenharmony_ci qlt_find_sess_invalidate_other(vha, 28868c2ecf20Sopenharmony_ci wwn_to_u64(fcport->port_name), 28878c2ecf20Sopenharmony_ci fcport->d_id, lid, &conflict_fcport); 28888c2ecf20Sopenharmony_ci if (conflict_fcport) { 28898c2ecf20Sopenharmony_ci /* 28908c2ecf20Sopenharmony_ci * Another fcport shares the same 28918c2ecf20Sopenharmony_ci * loop_id & nport id; conflict 28928c2ecf20Sopenharmony_ci * fcport needs to finish cleanup 28938c2ecf20Sopenharmony_ci * before this fcport can proceed 28948c2ecf20Sopenharmony_ci * to login. 28958c2ecf20Sopenharmony_ci */ 28968c2ecf20Sopenharmony_ci conflict_fcport->conflict = fcport; 28978c2ecf20Sopenharmony_ci fcport->login_pause = 1; 28988c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20ed, 28998c2ecf20Sopenharmony_ci "%s %d %8phC pid %06x inuse with lid %#x post gidpn\n", 29008c2ecf20Sopenharmony_ci __func__, __LINE__, 29018c2ecf20Sopenharmony_ci fcport->port_name, 29028c2ecf20Sopenharmony_ci fcport->d_id.b24, lid); 29038c2ecf20Sopenharmony_ci } else { 29048c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20ed, 29058c2ecf20Sopenharmony_ci "%s %d %8phC pid %06x inuse with lid %#x sched del\n", 29068c2ecf20Sopenharmony_ci __func__, __LINE__, 29078c2ecf20Sopenharmony_ci fcport->port_name, 29088c2ecf20Sopenharmony_ci fcport->d_id.b24, lid); 29098c2ecf20Sopenharmony_ci qla2x00_clear_loop_id(fcport); 29108c2ecf20Sopenharmony_ci set_bit(lid, vha->hw->loop_id_map); 29118c2ecf20Sopenharmony_ci fcport->loop_id = lid; 29128c2ecf20Sopenharmony_ci fcport->keep_nport_handle = 0; 29138c2ecf20Sopenharmony_ci qlt_schedule_sess_for_deletion(fcport); 29148c2ecf20Sopenharmony_ci } 29158c2ecf20Sopenharmony_ci break; 29168c2ecf20Sopenharmony_ci 29178c2ecf20Sopenharmony_ci case LSC_SCODE_NPORT_USED: 29188c2ecf20Sopenharmony_ci cid.b.domain = (le32_to_cpu(fw_status[2]) >> 16) 29198c2ecf20Sopenharmony_ci & 0xff; 29208c2ecf20Sopenharmony_ci cid.b.area = (le32_to_cpu(fw_status[2]) >> 8) 29218c2ecf20Sopenharmony_ci & 0xff; 29228c2ecf20Sopenharmony_ci cid.b.al_pa = le32_to_cpu(fw_status[2]) & 0xff; 29238c2ecf20Sopenharmony_ci cid.b.rsvd_1 = 0; 29248c2ecf20Sopenharmony_ci 29258c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20ec, 29268c2ecf20Sopenharmony_ci "%s %d %8phC lid %#x in use with pid %06x post gnl\n", 29278c2ecf20Sopenharmony_ci __func__, __LINE__, fcport->port_name, 29288c2ecf20Sopenharmony_ci fcport->loop_id, cid.b24); 29298c2ecf20Sopenharmony_ci set_bit(fcport->loop_id, 29308c2ecf20Sopenharmony_ci vha->hw->loop_id_map); 29318c2ecf20Sopenharmony_ci fcport->loop_id = FC_NO_LOOP_ID; 29328c2ecf20Sopenharmony_ci qla24xx_post_gnl_work(vha, fcport); 29338c2ecf20Sopenharmony_ci break; 29348c2ecf20Sopenharmony_ci 29358c2ecf20Sopenharmony_ci case LSC_SCODE_NOXCB: 29368c2ecf20Sopenharmony_ci vha->hw->exch_starvation++; 29378c2ecf20Sopenharmony_ci if (vha->hw->exch_starvation > 5) { 29388c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xd046, 29398c2ecf20Sopenharmony_ci "Exchange starvation. Resetting RISC\n"); 29408c2ecf20Sopenharmony_ci vha->hw->exch_starvation = 0; 29418c2ecf20Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, 29428c2ecf20Sopenharmony_ci &vha->dpc_flags); 29438c2ecf20Sopenharmony_ci qla2xxx_wake_dpc(vha); 29448c2ecf20Sopenharmony_ci break; 29458c2ecf20Sopenharmony_ci } 29468c2ecf20Sopenharmony_ci fallthrough; 29478c2ecf20Sopenharmony_ci default: 29488c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20eb, 29498c2ecf20Sopenharmony_ci "%s %8phC cmd error fw_status 0x%x 0x%x 0x%x\n", 29508c2ecf20Sopenharmony_ci __func__, sp->fcport->port_name, 29518c2ecf20Sopenharmony_ci fw_status[0], fw_status[1], fw_status[2]); 29528c2ecf20Sopenharmony_ci 29538c2ecf20Sopenharmony_ci fcport->flags &= ~FCF_ASYNC_SENT; 29548c2ecf20Sopenharmony_ci qlt_schedule_sess_for_deletion(fcport); 29558c2ecf20Sopenharmony_ci break; 29568c2ecf20Sopenharmony_ci } 29578c2ecf20Sopenharmony_ci break; 29588c2ecf20Sopenharmony_ci 29598c2ecf20Sopenharmony_ci default: 29608c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20eb, 29618c2ecf20Sopenharmony_ci "%s %8phC cmd error 2 fw_status 0x%x 0x%x 0x%x\n", 29628c2ecf20Sopenharmony_ci __func__, sp->fcport->port_name, 29638c2ecf20Sopenharmony_ci fw_status[0], fw_status[1], fw_status[2]); 29648c2ecf20Sopenharmony_ci 29658c2ecf20Sopenharmony_ci sp->fcport->flags &= ~FCF_ASYNC_SENT; 29668c2ecf20Sopenharmony_ci qlt_schedule_sess_for_deletion(fcport); 29678c2ecf20Sopenharmony_ci break; 29688c2ecf20Sopenharmony_ci } 29698c2ecf20Sopenharmony_ci 29708c2ecf20Sopenharmony_ci e = qla2x00_alloc_work(vha, QLA_EVT_UNMAP); 29718c2ecf20Sopenharmony_ci if (!e) { 29728c2ecf20Sopenharmony_ci struct srb_iocb *elsio = &sp->u.iocb_cmd; 29738c2ecf20Sopenharmony_ci 29748c2ecf20Sopenharmony_ci qla2x00_els_dcmd2_free(vha, &elsio->u.els_plogi); 29758c2ecf20Sopenharmony_ci sp->free(sp); 29768c2ecf20Sopenharmony_ci return; 29778c2ecf20Sopenharmony_ci } 29788c2ecf20Sopenharmony_ci e->u.iosb.sp = sp; 29798c2ecf20Sopenharmony_ci qla2x00_post_work(vha, e); 29808c2ecf20Sopenharmony_ci } 29818c2ecf20Sopenharmony_ci} 29828c2ecf20Sopenharmony_ci 29838c2ecf20Sopenharmony_ciint 29848c2ecf20Sopenharmony_ciqla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode, 29858c2ecf20Sopenharmony_ci fc_port_t *fcport, bool wait) 29868c2ecf20Sopenharmony_ci{ 29878c2ecf20Sopenharmony_ci srb_t *sp; 29888c2ecf20Sopenharmony_ci struct srb_iocb *elsio = NULL; 29898c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 29908c2ecf20Sopenharmony_ci int rval = QLA_SUCCESS; 29918c2ecf20Sopenharmony_ci void *ptr, *resp_ptr; 29928c2ecf20Sopenharmony_ci 29938c2ecf20Sopenharmony_ci /* Alloc SRB structure */ 29948c2ecf20Sopenharmony_ci sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); 29958c2ecf20Sopenharmony_ci if (!sp) { 29968c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0x70e6, 29978c2ecf20Sopenharmony_ci "SRB allocation failed\n"); 29988c2ecf20Sopenharmony_ci fcport->flags &= ~FCF_ASYNC_ACTIVE; 29998c2ecf20Sopenharmony_ci return -ENOMEM; 30008c2ecf20Sopenharmony_ci } 30018c2ecf20Sopenharmony_ci 30028c2ecf20Sopenharmony_ci fcport->flags |= FCF_ASYNC_SENT; 30038c2ecf20Sopenharmony_ci qla2x00_set_fcport_disc_state(fcport, DSC_LOGIN_PEND); 30048c2ecf20Sopenharmony_ci elsio = &sp->u.iocb_cmd; 30058c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3073, 30068c2ecf20Sopenharmony_ci "Enter: PLOGI portid=%06x\n", fcport->d_id.b24); 30078c2ecf20Sopenharmony_ci 30088c2ecf20Sopenharmony_ci sp->type = SRB_ELS_DCMD; 30098c2ecf20Sopenharmony_ci sp->name = "ELS_DCMD"; 30108c2ecf20Sopenharmony_ci sp->fcport = fcport; 30118c2ecf20Sopenharmony_ci 30128c2ecf20Sopenharmony_ci elsio->timeout = qla2x00_els_dcmd2_iocb_timeout; 30138c2ecf20Sopenharmony_ci if (wait) 30148c2ecf20Sopenharmony_ci sp->flags = SRB_WAKEUP_ON_COMP; 30158c2ecf20Sopenharmony_ci 30168c2ecf20Sopenharmony_ci qla2x00_init_timer(sp, ELS_DCMD_TIMEOUT + 2); 30178c2ecf20Sopenharmony_ci 30188c2ecf20Sopenharmony_ci sp->done = qla2x00_els_dcmd2_sp_done; 30198c2ecf20Sopenharmony_ci elsio->u.els_plogi.tx_size = elsio->u.els_plogi.rx_size = DMA_POOL_SIZE; 30208c2ecf20Sopenharmony_ci 30218c2ecf20Sopenharmony_ci ptr = elsio->u.els_plogi.els_plogi_pyld = 30228c2ecf20Sopenharmony_ci dma_alloc_coherent(&ha->pdev->dev, elsio->u.els_plogi.tx_size, 30238c2ecf20Sopenharmony_ci &elsio->u.els_plogi.els_plogi_pyld_dma, GFP_KERNEL); 30248c2ecf20Sopenharmony_ci 30258c2ecf20Sopenharmony_ci if (!elsio->u.els_plogi.els_plogi_pyld) { 30268c2ecf20Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 30278c2ecf20Sopenharmony_ci goto out; 30288c2ecf20Sopenharmony_ci } 30298c2ecf20Sopenharmony_ci 30308c2ecf20Sopenharmony_ci resp_ptr = elsio->u.els_plogi.els_resp_pyld = 30318c2ecf20Sopenharmony_ci dma_alloc_coherent(&ha->pdev->dev, elsio->u.els_plogi.rx_size, 30328c2ecf20Sopenharmony_ci &elsio->u.els_plogi.els_resp_pyld_dma, GFP_KERNEL); 30338c2ecf20Sopenharmony_ci 30348c2ecf20Sopenharmony_ci if (!elsio->u.els_plogi.els_resp_pyld) { 30358c2ecf20Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 30368c2ecf20Sopenharmony_ci goto out; 30378c2ecf20Sopenharmony_ci } 30388c2ecf20Sopenharmony_ci 30398c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3073, "PLOGI %p %p\n", ptr, resp_ptr); 30408c2ecf20Sopenharmony_ci 30418c2ecf20Sopenharmony_ci memset(ptr, 0, sizeof(struct els_plogi_payload)); 30428c2ecf20Sopenharmony_ci memset(resp_ptr, 0, sizeof(struct els_plogi_payload)); 30438c2ecf20Sopenharmony_ci memcpy(elsio->u.els_plogi.els_plogi_pyld->data, 30448c2ecf20Sopenharmony_ci &ha->plogi_els_payld.fl_csp, LOGIN_TEMPLATE_SIZE); 30458c2ecf20Sopenharmony_ci 30468c2ecf20Sopenharmony_ci elsio->u.els_plogi.els_cmd = els_opcode; 30478c2ecf20Sopenharmony_ci elsio->u.els_plogi.els_plogi_pyld->opcode = els_opcode; 30488c2ecf20Sopenharmony_ci 30498c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x3073, "PLOGI buffer:\n"); 30508c2ecf20Sopenharmony_ci ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x0109, 30518c2ecf20Sopenharmony_ci (uint8_t *)elsio->u.els_plogi.els_plogi_pyld, 30528c2ecf20Sopenharmony_ci sizeof(*elsio->u.els_plogi.els_plogi_pyld)); 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_ci init_completion(&elsio->u.els_plogi.comp); 30558c2ecf20Sopenharmony_ci rval = qla2x00_start_sp(sp); 30568c2ecf20Sopenharmony_ci if (rval != QLA_SUCCESS) { 30578c2ecf20Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 30588c2ecf20Sopenharmony_ci } else { 30598c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x3074, 30608c2ecf20Sopenharmony_ci "%s PLOGI sent, hdl=%x, loopid=%x, to port_id %06x from port_id %06x\n", 30618c2ecf20Sopenharmony_ci sp->name, sp->handle, fcport->loop_id, 30628c2ecf20Sopenharmony_ci fcport->d_id.b24, vha->d_id.b24); 30638c2ecf20Sopenharmony_ci } 30648c2ecf20Sopenharmony_ci 30658c2ecf20Sopenharmony_ci if (wait) { 30668c2ecf20Sopenharmony_ci wait_for_completion(&elsio->u.els_plogi.comp); 30678c2ecf20Sopenharmony_ci 30688c2ecf20Sopenharmony_ci if (elsio->u.els_plogi.comp_status != CS_COMPLETE) 30698c2ecf20Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 30708c2ecf20Sopenharmony_ci } else { 30718c2ecf20Sopenharmony_ci goto done; 30728c2ecf20Sopenharmony_ci } 30738c2ecf20Sopenharmony_ci 30748c2ecf20Sopenharmony_ciout: 30758c2ecf20Sopenharmony_ci fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); 30768c2ecf20Sopenharmony_ci qla2x00_els_dcmd2_free(vha, &elsio->u.els_plogi); 30778c2ecf20Sopenharmony_ci sp->free(sp); 30788c2ecf20Sopenharmony_cidone: 30798c2ecf20Sopenharmony_ci return rval; 30808c2ecf20Sopenharmony_ci} 30818c2ecf20Sopenharmony_ci 30828c2ecf20Sopenharmony_cistatic void 30838c2ecf20Sopenharmony_ciqla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) 30848c2ecf20Sopenharmony_ci{ 30858c2ecf20Sopenharmony_ci struct bsg_job *bsg_job = sp->u.bsg_job; 30868c2ecf20Sopenharmony_ci struct fc_bsg_request *bsg_request = bsg_job->request; 30878c2ecf20Sopenharmony_ci 30888c2ecf20Sopenharmony_ci els_iocb->entry_type = ELS_IOCB_TYPE; 30898c2ecf20Sopenharmony_ci els_iocb->entry_count = 1; 30908c2ecf20Sopenharmony_ci els_iocb->sys_define = 0; 30918c2ecf20Sopenharmony_ci els_iocb->entry_status = 0; 30928c2ecf20Sopenharmony_ci els_iocb->handle = sp->handle; 30938c2ecf20Sopenharmony_ci els_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id); 30948c2ecf20Sopenharmony_ci els_iocb->tx_dsd_count = cpu_to_le16(bsg_job->request_payload.sg_cnt); 30958c2ecf20Sopenharmony_ci els_iocb->vp_index = sp->vha->vp_idx; 30968c2ecf20Sopenharmony_ci els_iocb->sof_type = EST_SOFI3; 30978c2ecf20Sopenharmony_ci els_iocb->rx_dsd_count = cpu_to_le16(bsg_job->reply_payload.sg_cnt); 30988c2ecf20Sopenharmony_ci 30998c2ecf20Sopenharmony_ci els_iocb->opcode = 31008c2ecf20Sopenharmony_ci sp->type == SRB_ELS_CMD_RPT ? 31018c2ecf20Sopenharmony_ci bsg_request->rqst_data.r_els.els_code : 31028c2ecf20Sopenharmony_ci bsg_request->rqst_data.h_els.command_code; 31038c2ecf20Sopenharmony_ci els_iocb->d_id[0] = sp->fcport->d_id.b.al_pa; 31048c2ecf20Sopenharmony_ci els_iocb->d_id[1] = sp->fcport->d_id.b.area; 31058c2ecf20Sopenharmony_ci els_iocb->d_id[2] = sp->fcport->d_id.b.domain; 31068c2ecf20Sopenharmony_ci els_iocb->control_flags = 0; 31078c2ecf20Sopenharmony_ci els_iocb->rx_byte_count = 31088c2ecf20Sopenharmony_ci cpu_to_le32(bsg_job->reply_payload.payload_len); 31098c2ecf20Sopenharmony_ci els_iocb->tx_byte_count = 31108c2ecf20Sopenharmony_ci cpu_to_le32(bsg_job->request_payload.payload_len); 31118c2ecf20Sopenharmony_ci 31128c2ecf20Sopenharmony_ci put_unaligned_le64(sg_dma_address(bsg_job->request_payload.sg_list), 31138c2ecf20Sopenharmony_ci &els_iocb->tx_address); 31148c2ecf20Sopenharmony_ci els_iocb->tx_len = cpu_to_le32(sg_dma_len 31158c2ecf20Sopenharmony_ci (bsg_job->request_payload.sg_list)); 31168c2ecf20Sopenharmony_ci 31178c2ecf20Sopenharmony_ci put_unaligned_le64(sg_dma_address(bsg_job->reply_payload.sg_list), 31188c2ecf20Sopenharmony_ci &els_iocb->rx_address); 31198c2ecf20Sopenharmony_ci els_iocb->rx_len = cpu_to_le32(sg_dma_len 31208c2ecf20Sopenharmony_ci (bsg_job->reply_payload.sg_list)); 31218c2ecf20Sopenharmony_ci 31228c2ecf20Sopenharmony_ci sp->vha->qla_stats.control_requests++; 31238c2ecf20Sopenharmony_ci} 31248c2ecf20Sopenharmony_ci 31258c2ecf20Sopenharmony_cistatic void 31268c2ecf20Sopenharmony_ciqla2x00_ct_iocb(srb_t *sp, ms_iocb_entry_t *ct_iocb) 31278c2ecf20Sopenharmony_ci{ 31288c2ecf20Sopenharmony_ci uint16_t avail_dsds; 31298c2ecf20Sopenharmony_ci struct dsd64 *cur_dsd; 31308c2ecf20Sopenharmony_ci struct scatterlist *sg; 31318c2ecf20Sopenharmony_ci int index; 31328c2ecf20Sopenharmony_ci uint16_t tot_dsds; 31338c2ecf20Sopenharmony_ci scsi_qla_host_t *vha = sp->vha; 31348c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 31358c2ecf20Sopenharmony_ci struct bsg_job *bsg_job = sp->u.bsg_job; 31368c2ecf20Sopenharmony_ci int entry_count = 1; 31378c2ecf20Sopenharmony_ci 31388c2ecf20Sopenharmony_ci memset(ct_iocb, 0, sizeof(ms_iocb_entry_t)); 31398c2ecf20Sopenharmony_ci ct_iocb->entry_type = CT_IOCB_TYPE; 31408c2ecf20Sopenharmony_ci ct_iocb->entry_status = 0; 31418c2ecf20Sopenharmony_ci ct_iocb->handle1 = sp->handle; 31428c2ecf20Sopenharmony_ci SET_TARGET_ID(ha, ct_iocb->loop_id, sp->fcport->loop_id); 31438c2ecf20Sopenharmony_ci ct_iocb->status = cpu_to_le16(0); 31448c2ecf20Sopenharmony_ci ct_iocb->control_flags = cpu_to_le16(0); 31458c2ecf20Sopenharmony_ci ct_iocb->timeout = 0; 31468c2ecf20Sopenharmony_ci ct_iocb->cmd_dsd_count = 31478c2ecf20Sopenharmony_ci cpu_to_le16(bsg_job->request_payload.sg_cnt); 31488c2ecf20Sopenharmony_ci ct_iocb->total_dsd_count = 31498c2ecf20Sopenharmony_ci cpu_to_le16(bsg_job->request_payload.sg_cnt + 1); 31508c2ecf20Sopenharmony_ci ct_iocb->req_bytecount = 31518c2ecf20Sopenharmony_ci cpu_to_le32(bsg_job->request_payload.payload_len); 31528c2ecf20Sopenharmony_ci ct_iocb->rsp_bytecount = 31538c2ecf20Sopenharmony_ci cpu_to_le32(bsg_job->reply_payload.payload_len); 31548c2ecf20Sopenharmony_ci 31558c2ecf20Sopenharmony_ci put_unaligned_le64(sg_dma_address(bsg_job->request_payload.sg_list), 31568c2ecf20Sopenharmony_ci &ct_iocb->req_dsd.address); 31578c2ecf20Sopenharmony_ci ct_iocb->req_dsd.length = ct_iocb->req_bytecount; 31588c2ecf20Sopenharmony_ci 31598c2ecf20Sopenharmony_ci put_unaligned_le64(sg_dma_address(bsg_job->reply_payload.sg_list), 31608c2ecf20Sopenharmony_ci &ct_iocb->rsp_dsd.address); 31618c2ecf20Sopenharmony_ci ct_iocb->rsp_dsd.length = ct_iocb->rsp_bytecount; 31628c2ecf20Sopenharmony_ci 31638c2ecf20Sopenharmony_ci avail_dsds = 1; 31648c2ecf20Sopenharmony_ci cur_dsd = &ct_iocb->rsp_dsd; 31658c2ecf20Sopenharmony_ci index = 0; 31668c2ecf20Sopenharmony_ci tot_dsds = bsg_job->reply_payload.sg_cnt; 31678c2ecf20Sopenharmony_ci 31688c2ecf20Sopenharmony_ci for_each_sg(bsg_job->reply_payload.sg_list, sg, tot_dsds, index) { 31698c2ecf20Sopenharmony_ci cont_a64_entry_t *cont_pkt; 31708c2ecf20Sopenharmony_ci 31718c2ecf20Sopenharmony_ci /* Allocate additional continuation packets? */ 31728c2ecf20Sopenharmony_ci if (avail_dsds == 0) { 31738c2ecf20Sopenharmony_ci /* 31748c2ecf20Sopenharmony_ci * Five DSDs are available in the Cont. 31758c2ecf20Sopenharmony_ci * Type 1 IOCB. 31768c2ecf20Sopenharmony_ci */ 31778c2ecf20Sopenharmony_ci cont_pkt = qla2x00_prep_cont_type1_iocb(vha, 31788c2ecf20Sopenharmony_ci vha->hw->req_q_map[0]); 31798c2ecf20Sopenharmony_ci cur_dsd = cont_pkt->dsd; 31808c2ecf20Sopenharmony_ci avail_dsds = 5; 31818c2ecf20Sopenharmony_ci entry_count++; 31828c2ecf20Sopenharmony_ci } 31838c2ecf20Sopenharmony_ci 31848c2ecf20Sopenharmony_ci append_dsd64(&cur_dsd, sg); 31858c2ecf20Sopenharmony_ci avail_dsds--; 31868c2ecf20Sopenharmony_ci } 31878c2ecf20Sopenharmony_ci ct_iocb->entry_count = entry_count; 31888c2ecf20Sopenharmony_ci 31898c2ecf20Sopenharmony_ci sp->vha->qla_stats.control_requests++; 31908c2ecf20Sopenharmony_ci} 31918c2ecf20Sopenharmony_ci 31928c2ecf20Sopenharmony_cistatic void 31938c2ecf20Sopenharmony_ciqla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb) 31948c2ecf20Sopenharmony_ci{ 31958c2ecf20Sopenharmony_ci uint16_t avail_dsds; 31968c2ecf20Sopenharmony_ci struct dsd64 *cur_dsd; 31978c2ecf20Sopenharmony_ci struct scatterlist *sg; 31988c2ecf20Sopenharmony_ci int index; 31998c2ecf20Sopenharmony_ci uint16_t cmd_dsds, rsp_dsds; 32008c2ecf20Sopenharmony_ci scsi_qla_host_t *vha = sp->vha; 32018c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 32028c2ecf20Sopenharmony_ci struct bsg_job *bsg_job = sp->u.bsg_job; 32038c2ecf20Sopenharmony_ci int entry_count = 1; 32048c2ecf20Sopenharmony_ci cont_a64_entry_t *cont_pkt = NULL; 32058c2ecf20Sopenharmony_ci 32068c2ecf20Sopenharmony_ci ct_iocb->entry_type = CT_IOCB_TYPE; 32078c2ecf20Sopenharmony_ci ct_iocb->entry_status = 0; 32088c2ecf20Sopenharmony_ci ct_iocb->sys_define = 0; 32098c2ecf20Sopenharmony_ci ct_iocb->handle = sp->handle; 32108c2ecf20Sopenharmony_ci 32118c2ecf20Sopenharmony_ci ct_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id); 32128c2ecf20Sopenharmony_ci ct_iocb->vp_index = sp->vha->vp_idx; 32138c2ecf20Sopenharmony_ci ct_iocb->comp_status = cpu_to_le16(0); 32148c2ecf20Sopenharmony_ci 32158c2ecf20Sopenharmony_ci cmd_dsds = bsg_job->request_payload.sg_cnt; 32168c2ecf20Sopenharmony_ci rsp_dsds = bsg_job->reply_payload.sg_cnt; 32178c2ecf20Sopenharmony_ci 32188c2ecf20Sopenharmony_ci ct_iocb->cmd_dsd_count = cpu_to_le16(cmd_dsds); 32198c2ecf20Sopenharmony_ci ct_iocb->timeout = 0; 32208c2ecf20Sopenharmony_ci ct_iocb->rsp_dsd_count = cpu_to_le16(rsp_dsds); 32218c2ecf20Sopenharmony_ci ct_iocb->cmd_byte_count = 32228c2ecf20Sopenharmony_ci cpu_to_le32(bsg_job->request_payload.payload_len); 32238c2ecf20Sopenharmony_ci 32248c2ecf20Sopenharmony_ci avail_dsds = 2; 32258c2ecf20Sopenharmony_ci cur_dsd = ct_iocb->dsd; 32268c2ecf20Sopenharmony_ci index = 0; 32278c2ecf20Sopenharmony_ci 32288c2ecf20Sopenharmony_ci for_each_sg(bsg_job->request_payload.sg_list, sg, cmd_dsds, index) { 32298c2ecf20Sopenharmony_ci /* Allocate additional continuation packets? */ 32308c2ecf20Sopenharmony_ci if (avail_dsds == 0) { 32318c2ecf20Sopenharmony_ci /* 32328c2ecf20Sopenharmony_ci * Five DSDs are available in the Cont. 32338c2ecf20Sopenharmony_ci * Type 1 IOCB. 32348c2ecf20Sopenharmony_ci */ 32358c2ecf20Sopenharmony_ci cont_pkt = qla2x00_prep_cont_type1_iocb( 32368c2ecf20Sopenharmony_ci vha, ha->req_q_map[0]); 32378c2ecf20Sopenharmony_ci cur_dsd = cont_pkt->dsd; 32388c2ecf20Sopenharmony_ci avail_dsds = 5; 32398c2ecf20Sopenharmony_ci entry_count++; 32408c2ecf20Sopenharmony_ci } 32418c2ecf20Sopenharmony_ci 32428c2ecf20Sopenharmony_ci append_dsd64(&cur_dsd, sg); 32438c2ecf20Sopenharmony_ci avail_dsds--; 32448c2ecf20Sopenharmony_ci } 32458c2ecf20Sopenharmony_ci 32468c2ecf20Sopenharmony_ci index = 0; 32478c2ecf20Sopenharmony_ci 32488c2ecf20Sopenharmony_ci for_each_sg(bsg_job->reply_payload.sg_list, sg, rsp_dsds, index) { 32498c2ecf20Sopenharmony_ci /* Allocate additional continuation packets? */ 32508c2ecf20Sopenharmony_ci if (avail_dsds == 0) { 32518c2ecf20Sopenharmony_ci /* 32528c2ecf20Sopenharmony_ci * Five DSDs are available in the Cont. 32538c2ecf20Sopenharmony_ci * Type 1 IOCB. 32548c2ecf20Sopenharmony_ci */ 32558c2ecf20Sopenharmony_ci cont_pkt = qla2x00_prep_cont_type1_iocb(vha, 32568c2ecf20Sopenharmony_ci ha->req_q_map[0]); 32578c2ecf20Sopenharmony_ci cur_dsd = cont_pkt->dsd; 32588c2ecf20Sopenharmony_ci avail_dsds = 5; 32598c2ecf20Sopenharmony_ci entry_count++; 32608c2ecf20Sopenharmony_ci } 32618c2ecf20Sopenharmony_ci 32628c2ecf20Sopenharmony_ci append_dsd64(&cur_dsd, sg); 32638c2ecf20Sopenharmony_ci avail_dsds--; 32648c2ecf20Sopenharmony_ci } 32658c2ecf20Sopenharmony_ci ct_iocb->entry_count = entry_count; 32668c2ecf20Sopenharmony_ci} 32678c2ecf20Sopenharmony_ci 32688c2ecf20Sopenharmony_ci/* 32698c2ecf20Sopenharmony_ci * qla82xx_start_scsi() - Send a SCSI command to the ISP 32708c2ecf20Sopenharmony_ci * @sp: command to send to the ISP 32718c2ecf20Sopenharmony_ci * 32728c2ecf20Sopenharmony_ci * Returns non-zero if a failure occurred, else zero. 32738c2ecf20Sopenharmony_ci */ 32748c2ecf20Sopenharmony_ciint 32758c2ecf20Sopenharmony_ciqla82xx_start_scsi(srb_t *sp) 32768c2ecf20Sopenharmony_ci{ 32778c2ecf20Sopenharmony_ci int nseg; 32788c2ecf20Sopenharmony_ci unsigned long flags; 32798c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd; 32808c2ecf20Sopenharmony_ci uint32_t *clr_ptr; 32818c2ecf20Sopenharmony_ci uint32_t handle; 32828c2ecf20Sopenharmony_ci uint16_t cnt; 32838c2ecf20Sopenharmony_ci uint16_t req_cnt; 32848c2ecf20Sopenharmony_ci uint16_t tot_dsds; 32858c2ecf20Sopenharmony_ci struct device_reg_82xx __iomem *reg; 32868c2ecf20Sopenharmony_ci uint32_t dbval; 32878c2ecf20Sopenharmony_ci __be32 *fcp_dl; 32888c2ecf20Sopenharmony_ci uint8_t additional_cdb_len; 32898c2ecf20Sopenharmony_ci struct ct6_dsd *ctx; 32908c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = sp->vha; 32918c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 32928c2ecf20Sopenharmony_ci struct req_que *req = NULL; 32938c2ecf20Sopenharmony_ci struct rsp_que *rsp = NULL; 32948c2ecf20Sopenharmony_ci 32958c2ecf20Sopenharmony_ci /* Setup device pointers. */ 32968c2ecf20Sopenharmony_ci reg = &ha->iobase->isp82; 32978c2ecf20Sopenharmony_ci cmd = GET_CMD_SP(sp); 32988c2ecf20Sopenharmony_ci req = vha->req; 32998c2ecf20Sopenharmony_ci rsp = ha->rsp_q_map[0]; 33008c2ecf20Sopenharmony_ci 33018c2ecf20Sopenharmony_ci /* So we know we haven't pci_map'ed anything yet */ 33028c2ecf20Sopenharmony_ci tot_dsds = 0; 33038c2ecf20Sopenharmony_ci 33048c2ecf20Sopenharmony_ci dbval = 0x04 | (ha->portnum << 5); 33058c2ecf20Sopenharmony_ci 33068c2ecf20Sopenharmony_ci /* Send marker if required */ 33078c2ecf20Sopenharmony_ci if (vha->marker_needed != 0) { 33088c2ecf20Sopenharmony_ci if (qla2x00_marker(vha, ha->base_qpair, 33098c2ecf20Sopenharmony_ci 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) { 33108c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0x300c, 33118c2ecf20Sopenharmony_ci "qla2x00_marker failed for cmd=%p.\n", cmd); 33128c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 33138c2ecf20Sopenharmony_ci } 33148c2ecf20Sopenharmony_ci vha->marker_needed = 0; 33158c2ecf20Sopenharmony_ci } 33168c2ecf20Sopenharmony_ci 33178c2ecf20Sopenharmony_ci /* Acquire ring specific lock */ 33188c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 33198c2ecf20Sopenharmony_ci 33208c2ecf20Sopenharmony_ci handle = qla2xxx_get_next_handle(req); 33218c2ecf20Sopenharmony_ci if (handle == 0) 33228c2ecf20Sopenharmony_ci goto queuing_error; 33238c2ecf20Sopenharmony_ci 33248c2ecf20Sopenharmony_ci /* Map the sg table so we have an accurate count of sg entries needed */ 33258c2ecf20Sopenharmony_ci if (scsi_sg_count(cmd)) { 33268c2ecf20Sopenharmony_ci nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd), 33278c2ecf20Sopenharmony_ci scsi_sg_count(cmd), cmd->sc_data_direction); 33288c2ecf20Sopenharmony_ci if (unlikely(!nseg)) 33298c2ecf20Sopenharmony_ci goto queuing_error; 33308c2ecf20Sopenharmony_ci } else 33318c2ecf20Sopenharmony_ci nseg = 0; 33328c2ecf20Sopenharmony_ci 33338c2ecf20Sopenharmony_ci tot_dsds = nseg; 33348c2ecf20Sopenharmony_ci 33358c2ecf20Sopenharmony_ci if (tot_dsds > ql2xshiftctondsd) { 33368c2ecf20Sopenharmony_ci struct cmd_type_6 *cmd_pkt; 33378c2ecf20Sopenharmony_ci uint16_t more_dsd_lists = 0; 33388c2ecf20Sopenharmony_ci struct dsd_dma *dsd_ptr; 33398c2ecf20Sopenharmony_ci uint16_t i; 33408c2ecf20Sopenharmony_ci 33418c2ecf20Sopenharmony_ci more_dsd_lists = qla24xx_calc_dsd_lists(tot_dsds); 33428c2ecf20Sopenharmony_ci if ((more_dsd_lists + ha->gbl_dsd_inuse) >= NUM_DSD_CHAIN) { 33438c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x300d, 33448c2ecf20Sopenharmony_ci "Num of DSD list %d is than %d for cmd=%p.\n", 33458c2ecf20Sopenharmony_ci more_dsd_lists + ha->gbl_dsd_inuse, NUM_DSD_CHAIN, 33468c2ecf20Sopenharmony_ci cmd); 33478c2ecf20Sopenharmony_ci goto queuing_error; 33488c2ecf20Sopenharmony_ci } 33498c2ecf20Sopenharmony_ci 33508c2ecf20Sopenharmony_ci if (more_dsd_lists <= ha->gbl_dsd_avail) 33518c2ecf20Sopenharmony_ci goto sufficient_dsds; 33528c2ecf20Sopenharmony_ci else 33538c2ecf20Sopenharmony_ci more_dsd_lists -= ha->gbl_dsd_avail; 33548c2ecf20Sopenharmony_ci 33558c2ecf20Sopenharmony_ci for (i = 0; i < more_dsd_lists; i++) { 33568c2ecf20Sopenharmony_ci dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC); 33578c2ecf20Sopenharmony_ci if (!dsd_ptr) { 33588c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0x300e, 33598c2ecf20Sopenharmony_ci "Failed to allocate memory for dsd_dma " 33608c2ecf20Sopenharmony_ci "for cmd=%p.\n", cmd); 33618c2ecf20Sopenharmony_ci goto queuing_error; 33628c2ecf20Sopenharmony_ci } 33638c2ecf20Sopenharmony_ci 33648c2ecf20Sopenharmony_ci dsd_ptr->dsd_addr = dma_pool_alloc(ha->dl_dma_pool, 33658c2ecf20Sopenharmony_ci GFP_ATOMIC, &dsd_ptr->dsd_list_dma); 33668c2ecf20Sopenharmony_ci if (!dsd_ptr->dsd_addr) { 33678c2ecf20Sopenharmony_ci kfree(dsd_ptr); 33688c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0x300f, 33698c2ecf20Sopenharmony_ci "Failed to allocate memory for dsd_addr " 33708c2ecf20Sopenharmony_ci "for cmd=%p.\n", cmd); 33718c2ecf20Sopenharmony_ci goto queuing_error; 33728c2ecf20Sopenharmony_ci } 33738c2ecf20Sopenharmony_ci list_add_tail(&dsd_ptr->list, &ha->gbl_dsd_list); 33748c2ecf20Sopenharmony_ci ha->gbl_dsd_avail++; 33758c2ecf20Sopenharmony_ci } 33768c2ecf20Sopenharmony_ci 33778c2ecf20Sopenharmony_cisufficient_dsds: 33788c2ecf20Sopenharmony_ci req_cnt = 1; 33798c2ecf20Sopenharmony_ci 33808c2ecf20Sopenharmony_ci if (req->cnt < (req_cnt + 2)) { 33818c2ecf20Sopenharmony_ci cnt = (uint16_t)rd_reg_dword_relaxed( 33828c2ecf20Sopenharmony_ci ®->req_q_out[0]); 33838c2ecf20Sopenharmony_ci if (req->ring_index < cnt) 33848c2ecf20Sopenharmony_ci req->cnt = cnt - req->ring_index; 33858c2ecf20Sopenharmony_ci else 33868c2ecf20Sopenharmony_ci req->cnt = req->length - 33878c2ecf20Sopenharmony_ci (req->ring_index - cnt); 33888c2ecf20Sopenharmony_ci if (req->cnt < (req_cnt + 2)) 33898c2ecf20Sopenharmony_ci goto queuing_error; 33908c2ecf20Sopenharmony_ci } 33918c2ecf20Sopenharmony_ci 33928c2ecf20Sopenharmony_ci ctx = sp->u.scmd.ct6_ctx = 33938c2ecf20Sopenharmony_ci mempool_alloc(ha->ctx_mempool, GFP_ATOMIC); 33948c2ecf20Sopenharmony_ci if (!ctx) { 33958c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0x3010, 33968c2ecf20Sopenharmony_ci "Failed to allocate ctx for cmd=%p.\n", cmd); 33978c2ecf20Sopenharmony_ci goto queuing_error; 33988c2ecf20Sopenharmony_ci } 33998c2ecf20Sopenharmony_ci 34008c2ecf20Sopenharmony_ci memset(ctx, 0, sizeof(struct ct6_dsd)); 34018c2ecf20Sopenharmony_ci ctx->fcp_cmnd = dma_pool_zalloc(ha->fcp_cmnd_dma_pool, 34028c2ecf20Sopenharmony_ci GFP_ATOMIC, &ctx->fcp_cmnd_dma); 34038c2ecf20Sopenharmony_ci if (!ctx->fcp_cmnd) { 34048c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0x3011, 34058c2ecf20Sopenharmony_ci "Failed to allocate fcp_cmnd for cmd=%p.\n", cmd); 34068c2ecf20Sopenharmony_ci goto queuing_error; 34078c2ecf20Sopenharmony_ci } 34088c2ecf20Sopenharmony_ci 34098c2ecf20Sopenharmony_ci /* Initialize the DSD list and dma handle */ 34108c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ctx->dsd_list); 34118c2ecf20Sopenharmony_ci ctx->dsd_use_cnt = 0; 34128c2ecf20Sopenharmony_ci 34138c2ecf20Sopenharmony_ci if (cmd->cmd_len > 16) { 34148c2ecf20Sopenharmony_ci additional_cdb_len = cmd->cmd_len - 16; 34158c2ecf20Sopenharmony_ci if ((cmd->cmd_len % 4) != 0) { 34168c2ecf20Sopenharmony_ci /* SCSI command bigger than 16 bytes must be 34178c2ecf20Sopenharmony_ci * multiple of 4 34188c2ecf20Sopenharmony_ci */ 34198c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0x3012, 34208c2ecf20Sopenharmony_ci "scsi cmd len %d not multiple of 4 " 34218c2ecf20Sopenharmony_ci "for cmd=%p.\n", cmd->cmd_len, cmd); 34228c2ecf20Sopenharmony_ci goto queuing_error_fcp_cmnd; 34238c2ecf20Sopenharmony_ci } 34248c2ecf20Sopenharmony_ci ctx->fcp_cmnd_len = 12 + cmd->cmd_len + 4; 34258c2ecf20Sopenharmony_ci } else { 34268c2ecf20Sopenharmony_ci additional_cdb_len = 0; 34278c2ecf20Sopenharmony_ci ctx->fcp_cmnd_len = 12 + 16 + 4; 34288c2ecf20Sopenharmony_ci } 34298c2ecf20Sopenharmony_ci 34308c2ecf20Sopenharmony_ci cmd_pkt = (struct cmd_type_6 *)req->ring_ptr; 34318c2ecf20Sopenharmony_ci cmd_pkt->handle = make_handle(req->id, handle); 34328c2ecf20Sopenharmony_ci 34338c2ecf20Sopenharmony_ci /* Zero out remaining portion of packet. */ 34348c2ecf20Sopenharmony_ci /* tagged queuing modifier -- default is TSK_SIMPLE (0). */ 34358c2ecf20Sopenharmony_ci clr_ptr = (uint32_t *)cmd_pkt + 2; 34368c2ecf20Sopenharmony_ci memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); 34378c2ecf20Sopenharmony_ci cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); 34388c2ecf20Sopenharmony_ci 34398c2ecf20Sopenharmony_ci /* Set NPORT-ID and LUN number*/ 34408c2ecf20Sopenharmony_ci cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); 34418c2ecf20Sopenharmony_ci cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; 34428c2ecf20Sopenharmony_ci cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; 34438c2ecf20Sopenharmony_ci cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; 34448c2ecf20Sopenharmony_ci cmd_pkt->vp_index = sp->vha->vp_idx; 34458c2ecf20Sopenharmony_ci 34468c2ecf20Sopenharmony_ci /* Build IOCB segments */ 34478c2ecf20Sopenharmony_ci if (qla24xx_build_scsi_type_6_iocbs(sp, cmd_pkt, tot_dsds)) 34488c2ecf20Sopenharmony_ci goto queuing_error_fcp_cmnd; 34498c2ecf20Sopenharmony_ci 34508c2ecf20Sopenharmony_ci int_to_scsilun(cmd->device->lun, &cmd_pkt->lun); 34518c2ecf20Sopenharmony_ci host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); 34528c2ecf20Sopenharmony_ci 34538c2ecf20Sopenharmony_ci /* build FCP_CMND IU */ 34548c2ecf20Sopenharmony_ci int_to_scsilun(cmd->device->lun, &ctx->fcp_cmnd->lun); 34558c2ecf20Sopenharmony_ci ctx->fcp_cmnd->additional_cdb_len = additional_cdb_len; 34568c2ecf20Sopenharmony_ci 34578c2ecf20Sopenharmony_ci if (cmd->sc_data_direction == DMA_TO_DEVICE) 34588c2ecf20Sopenharmony_ci ctx->fcp_cmnd->additional_cdb_len |= 1; 34598c2ecf20Sopenharmony_ci else if (cmd->sc_data_direction == DMA_FROM_DEVICE) 34608c2ecf20Sopenharmony_ci ctx->fcp_cmnd->additional_cdb_len |= 2; 34618c2ecf20Sopenharmony_ci 34628c2ecf20Sopenharmony_ci /* Populate the FCP_PRIO. */ 34638c2ecf20Sopenharmony_ci if (ha->flags.fcp_prio_enabled) 34648c2ecf20Sopenharmony_ci ctx->fcp_cmnd->task_attribute |= 34658c2ecf20Sopenharmony_ci sp->fcport->fcp_prio << 3; 34668c2ecf20Sopenharmony_ci 34678c2ecf20Sopenharmony_ci memcpy(ctx->fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len); 34688c2ecf20Sopenharmony_ci 34698c2ecf20Sopenharmony_ci fcp_dl = (__be32 *)(ctx->fcp_cmnd->cdb + 16 + 34708c2ecf20Sopenharmony_ci additional_cdb_len); 34718c2ecf20Sopenharmony_ci *fcp_dl = htonl((uint32_t)scsi_bufflen(cmd)); 34728c2ecf20Sopenharmony_ci 34738c2ecf20Sopenharmony_ci cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(ctx->fcp_cmnd_len); 34748c2ecf20Sopenharmony_ci put_unaligned_le64(ctx->fcp_cmnd_dma, 34758c2ecf20Sopenharmony_ci &cmd_pkt->fcp_cmnd_dseg_address); 34768c2ecf20Sopenharmony_ci 34778c2ecf20Sopenharmony_ci sp->flags |= SRB_FCP_CMND_DMA_VALID; 34788c2ecf20Sopenharmony_ci cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); 34798c2ecf20Sopenharmony_ci /* Set total data segment count. */ 34808c2ecf20Sopenharmony_ci cmd_pkt->entry_count = (uint8_t)req_cnt; 34818c2ecf20Sopenharmony_ci /* Specify response queue number where 34828c2ecf20Sopenharmony_ci * completion should happen 34838c2ecf20Sopenharmony_ci */ 34848c2ecf20Sopenharmony_ci cmd_pkt->entry_status = (uint8_t) rsp->id; 34858c2ecf20Sopenharmony_ci } else { 34868c2ecf20Sopenharmony_ci struct cmd_type_7 *cmd_pkt; 34878c2ecf20Sopenharmony_ci 34888c2ecf20Sopenharmony_ci req_cnt = qla24xx_calc_iocbs(vha, tot_dsds); 34898c2ecf20Sopenharmony_ci if (req->cnt < (req_cnt + 2)) { 34908c2ecf20Sopenharmony_ci cnt = (uint16_t)rd_reg_dword_relaxed( 34918c2ecf20Sopenharmony_ci ®->req_q_out[0]); 34928c2ecf20Sopenharmony_ci if (req->ring_index < cnt) 34938c2ecf20Sopenharmony_ci req->cnt = cnt - req->ring_index; 34948c2ecf20Sopenharmony_ci else 34958c2ecf20Sopenharmony_ci req->cnt = req->length - 34968c2ecf20Sopenharmony_ci (req->ring_index - cnt); 34978c2ecf20Sopenharmony_ci } 34988c2ecf20Sopenharmony_ci if (req->cnt < (req_cnt + 2)) 34998c2ecf20Sopenharmony_ci goto queuing_error; 35008c2ecf20Sopenharmony_ci 35018c2ecf20Sopenharmony_ci cmd_pkt = (struct cmd_type_7 *)req->ring_ptr; 35028c2ecf20Sopenharmony_ci cmd_pkt->handle = make_handle(req->id, handle); 35038c2ecf20Sopenharmony_ci 35048c2ecf20Sopenharmony_ci /* Zero out remaining portion of packet. */ 35058c2ecf20Sopenharmony_ci /* tagged queuing modifier -- default is TSK_SIMPLE (0).*/ 35068c2ecf20Sopenharmony_ci clr_ptr = (uint32_t *)cmd_pkt + 2; 35078c2ecf20Sopenharmony_ci memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); 35088c2ecf20Sopenharmony_ci cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); 35098c2ecf20Sopenharmony_ci 35108c2ecf20Sopenharmony_ci /* Set NPORT-ID and LUN number*/ 35118c2ecf20Sopenharmony_ci cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); 35128c2ecf20Sopenharmony_ci cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; 35138c2ecf20Sopenharmony_ci cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; 35148c2ecf20Sopenharmony_ci cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; 35158c2ecf20Sopenharmony_ci cmd_pkt->vp_index = sp->vha->vp_idx; 35168c2ecf20Sopenharmony_ci 35178c2ecf20Sopenharmony_ci int_to_scsilun(cmd->device->lun, &cmd_pkt->lun); 35188c2ecf20Sopenharmony_ci host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, 35198c2ecf20Sopenharmony_ci sizeof(cmd_pkt->lun)); 35208c2ecf20Sopenharmony_ci 35218c2ecf20Sopenharmony_ci /* Populate the FCP_PRIO. */ 35228c2ecf20Sopenharmony_ci if (ha->flags.fcp_prio_enabled) 35238c2ecf20Sopenharmony_ci cmd_pkt->task |= sp->fcport->fcp_prio << 3; 35248c2ecf20Sopenharmony_ci 35258c2ecf20Sopenharmony_ci /* Load SCSI command packet. */ 35268c2ecf20Sopenharmony_ci memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len); 35278c2ecf20Sopenharmony_ci host_to_fcp_swap(cmd_pkt->fcp_cdb, sizeof(cmd_pkt->fcp_cdb)); 35288c2ecf20Sopenharmony_ci 35298c2ecf20Sopenharmony_ci cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); 35308c2ecf20Sopenharmony_ci 35318c2ecf20Sopenharmony_ci /* Build IOCB segments */ 35328c2ecf20Sopenharmony_ci qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds, req); 35338c2ecf20Sopenharmony_ci 35348c2ecf20Sopenharmony_ci /* Set total data segment count. */ 35358c2ecf20Sopenharmony_ci cmd_pkt->entry_count = (uint8_t)req_cnt; 35368c2ecf20Sopenharmony_ci /* Specify response queue number where 35378c2ecf20Sopenharmony_ci * completion should happen. 35388c2ecf20Sopenharmony_ci */ 35398c2ecf20Sopenharmony_ci cmd_pkt->entry_status = (uint8_t) rsp->id; 35408c2ecf20Sopenharmony_ci 35418c2ecf20Sopenharmony_ci } 35428c2ecf20Sopenharmony_ci /* Build command packet. */ 35438c2ecf20Sopenharmony_ci req->current_outstanding_cmd = handle; 35448c2ecf20Sopenharmony_ci req->outstanding_cmds[handle] = sp; 35458c2ecf20Sopenharmony_ci sp->handle = handle; 35468c2ecf20Sopenharmony_ci cmd->host_scribble = (unsigned char *)(unsigned long)handle; 35478c2ecf20Sopenharmony_ci req->cnt -= req_cnt; 35488c2ecf20Sopenharmony_ci wmb(); 35498c2ecf20Sopenharmony_ci 35508c2ecf20Sopenharmony_ci /* Adjust ring index. */ 35518c2ecf20Sopenharmony_ci req->ring_index++; 35528c2ecf20Sopenharmony_ci if (req->ring_index == req->length) { 35538c2ecf20Sopenharmony_ci req->ring_index = 0; 35548c2ecf20Sopenharmony_ci req->ring_ptr = req->ring; 35558c2ecf20Sopenharmony_ci } else 35568c2ecf20Sopenharmony_ci req->ring_ptr++; 35578c2ecf20Sopenharmony_ci 35588c2ecf20Sopenharmony_ci sp->flags |= SRB_DMA_VALID; 35598c2ecf20Sopenharmony_ci 35608c2ecf20Sopenharmony_ci /* Set chip new ring index. */ 35618c2ecf20Sopenharmony_ci /* write, read and verify logic */ 35628c2ecf20Sopenharmony_ci dbval = dbval | (req->id << 8) | (req->ring_index << 16); 35638c2ecf20Sopenharmony_ci if (ql2xdbwr) 35648c2ecf20Sopenharmony_ci qla82xx_wr_32(ha, (uintptr_t __force)ha->nxdb_wr_ptr, dbval); 35658c2ecf20Sopenharmony_ci else { 35668c2ecf20Sopenharmony_ci wrt_reg_dword(ha->nxdb_wr_ptr, dbval); 35678c2ecf20Sopenharmony_ci wmb(); 35688c2ecf20Sopenharmony_ci while (rd_reg_dword(ha->nxdb_rd_ptr) != dbval) { 35698c2ecf20Sopenharmony_ci wrt_reg_dword(ha->nxdb_wr_ptr, dbval); 35708c2ecf20Sopenharmony_ci wmb(); 35718c2ecf20Sopenharmony_ci } 35728c2ecf20Sopenharmony_ci } 35738c2ecf20Sopenharmony_ci 35748c2ecf20Sopenharmony_ci /* Manage unprocessed RIO/ZIO commands in response queue. */ 35758c2ecf20Sopenharmony_ci if (vha->flags.process_response_queue && 35768c2ecf20Sopenharmony_ci rsp->ring_ptr->signature != RESPONSE_PROCESSED) 35778c2ecf20Sopenharmony_ci qla24xx_process_response_queue(vha, rsp); 35788c2ecf20Sopenharmony_ci 35798c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 35808c2ecf20Sopenharmony_ci return QLA_SUCCESS; 35818c2ecf20Sopenharmony_ci 35828c2ecf20Sopenharmony_ciqueuing_error_fcp_cmnd: 35838c2ecf20Sopenharmony_ci dma_pool_free(ha->fcp_cmnd_dma_pool, ctx->fcp_cmnd, ctx->fcp_cmnd_dma); 35848c2ecf20Sopenharmony_ciqueuing_error: 35858c2ecf20Sopenharmony_ci if (tot_dsds) 35868c2ecf20Sopenharmony_ci scsi_dma_unmap(cmd); 35878c2ecf20Sopenharmony_ci 35888c2ecf20Sopenharmony_ci if (sp->u.scmd.crc_ctx) { 35898c2ecf20Sopenharmony_ci mempool_free(sp->u.scmd.crc_ctx, ha->ctx_mempool); 35908c2ecf20Sopenharmony_ci sp->u.scmd.crc_ctx = NULL; 35918c2ecf20Sopenharmony_ci } 35928c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 35938c2ecf20Sopenharmony_ci 35948c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 35958c2ecf20Sopenharmony_ci} 35968c2ecf20Sopenharmony_ci 35978c2ecf20Sopenharmony_cistatic void 35988c2ecf20Sopenharmony_ciqla24xx_abort_iocb(srb_t *sp, struct abort_entry_24xx *abt_iocb) 35998c2ecf20Sopenharmony_ci{ 36008c2ecf20Sopenharmony_ci struct srb_iocb *aio = &sp->u.iocb_cmd; 36018c2ecf20Sopenharmony_ci scsi_qla_host_t *vha = sp->vha; 36028c2ecf20Sopenharmony_ci struct req_que *req = sp->qpair->req; 36038c2ecf20Sopenharmony_ci 36048c2ecf20Sopenharmony_ci memset(abt_iocb, 0, sizeof(struct abort_entry_24xx)); 36058c2ecf20Sopenharmony_ci abt_iocb->entry_type = ABORT_IOCB_TYPE; 36068c2ecf20Sopenharmony_ci abt_iocb->entry_count = 1; 36078c2ecf20Sopenharmony_ci abt_iocb->handle = make_handle(req->id, sp->handle); 36088c2ecf20Sopenharmony_ci if (sp->fcport) { 36098c2ecf20Sopenharmony_ci abt_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id); 36108c2ecf20Sopenharmony_ci abt_iocb->port_id[0] = sp->fcport->d_id.b.al_pa; 36118c2ecf20Sopenharmony_ci abt_iocb->port_id[1] = sp->fcport->d_id.b.area; 36128c2ecf20Sopenharmony_ci abt_iocb->port_id[2] = sp->fcport->d_id.b.domain; 36138c2ecf20Sopenharmony_ci } 36148c2ecf20Sopenharmony_ci abt_iocb->handle_to_abort = 36158c2ecf20Sopenharmony_ci make_handle(le16_to_cpu(aio->u.abt.req_que_no), 36168c2ecf20Sopenharmony_ci aio->u.abt.cmd_hndl); 36178c2ecf20Sopenharmony_ci abt_iocb->vp_index = vha->vp_idx; 36188c2ecf20Sopenharmony_ci abt_iocb->req_que_no = aio->u.abt.req_que_no; 36198c2ecf20Sopenharmony_ci /* Send the command to the firmware */ 36208c2ecf20Sopenharmony_ci wmb(); 36218c2ecf20Sopenharmony_ci} 36228c2ecf20Sopenharmony_ci 36238c2ecf20Sopenharmony_cistatic void 36248c2ecf20Sopenharmony_ciqla2x00_mb_iocb(srb_t *sp, struct mbx_24xx_entry *mbx) 36258c2ecf20Sopenharmony_ci{ 36268c2ecf20Sopenharmony_ci int i, sz; 36278c2ecf20Sopenharmony_ci 36288c2ecf20Sopenharmony_ci mbx->entry_type = MBX_IOCB_TYPE; 36298c2ecf20Sopenharmony_ci mbx->handle = sp->handle; 36308c2ecf20Sopenharmony_ci sz = min(ARRAY_SIZE(mbx->mb), ARRAY_SIZE(sp->u.iocb_cmd.u.mbx.out_mb)); 36318c2ecf20Sopenharmony_ci 36328c2ecf20Sopenharmony_ci for (i = 0; i < sz; i++) 36338c2ecf20Sopenharmony_ci mbx->mb[i] = sp->u.iocb_cmd.u.mbx.out_mb[i]; 36348c2ecf20Sopenharmony_ci} 36358c2ecf20Sopenharmony_ci 36368c2ecf20Sopenharmony_cistatic void 36378c2ecf20Sopenharmony_ciqla2x00_ctpthru_cmd_iocb(srb_t *sp, struct ct_entry_24xx *ct_pkt) 36388c2ecf20Sopenharmony_ci{ 36398c2ecf20Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.iocb = ct_pkt; 36408c2ecf20Sopenharmony_ci qla24xx_prep_ms_iocb(sp->vha, &sp->u.iocb_cmd.u.ctarg); 36418c2ecf20Sopenharmony_ci ct_pkt->handle = sp->handle; 36428c2ecf20Sopenharmony_ci} 36438c2ecf20Sopenharmony_ci 36448c2ecf20Sopenharmony_cistatic void qla2x00_send_notify_ack_iocb(srb_t *sp, 36458c2ecf20Sopenharmony_ci struct nack_to_isp *nack) 36468c2ecf20Sopenharmony_ci{ 36478c2ecf20Sopenharmony_ci struct imm_ntfy_from_isp *ntfy = sp->u.iocb_cmd.u.nack.ntfy; 36488c2ecf20Sopenharmony_ci 36498c2ecf20Sopenharmony_ci nack->entry_type = NOTIFY_ACK_TYPE; 36508c2ecf20Sopenharmony_ci nack->entry_count = 1; 36518c2ecf20Sopenharmony_ci nack->ox_id = ntfy->ox_id; 36528c2ecf20Sopenharmony_ci 36538c2ecf20Sopenharmony_ci nack->u.isp24.handle = sp->handle; 36548c2ecf20Sopenharmony_ci nack->u.isp24.nport_handle = ntfy->u.isp24.nport_handle; 36558c2ecf20Sopenharmony_ci if (le16_to_cpu(ntfy->u.isp24.status) == IMM_NTFY_ELS) { 36568c2ecf20Sopenharmony_ci nack->u.isp24.flags = ntfy->u.isp24.flags & 36578c2ecf20Sopenharmony_ci cpu_to_le16(NOTIFY24XX_FLAGS_PUREX_IOCB); 36588c2ecf20Sopenharmony_ci } 36598c2ecf20Sopenharmony_ci nack->u.isp24.srr_rx_id = ntfy->u.isp24.srr_rx_id; 36608c2ecf20Sopenharmony_ci nack->u.isp24.status = ntfy->u.isp24.status; 36618c2ecf20Sopenharmony_ci nack->u.isp24.status_subcode = ntfy->u.isp24.status_subcode; 36628c2ecf20Sopenharmony_ci nack->u.isp24.fw_handle = ntfy->u.isp24.fw_handle; 36638c2ecf20Sopenharmony_ci nack->u.isp24.exchange_address = ntfy->u.isp24.exchange_address; 36648c2ecf20Sopenharmony_ci nack->u.isp24.srr_rel_offs = ntfy->u.isp24.srr_rel_offs; 36658c2ecf20Sopenharmony_ci nack->u.isp24.srr_ui = ntfy->u.isp24.srr_ui; 36668c2ecf20Sopenharmony_ci nack->u.isp24.srr_flags = 0; 36678c2ecf20Sopenharmony_ci nack->u.isp24.srr_reject_code = 0; 36688c2ecf20Sopenharmony_ci nack->u.isp24.srr_reject_code_expl = 0; 36698c2ecf20Sopenharmony_ci nack->u.isp24.vp_index = ntfy->u.isp24.vp_index; 36708c2ecf20Sopenharmony_ci} 36718c2ecf20Sopenharmony_ci 36728c2ecf20Sopenharmony_ci/* 36738c2ecf20Sopenharmony_ci * Build NVME LS request 36748c2ecf20Sopenharmony_ci */ 36758c2ecf20Sopenharmony_cistatic void 36768c2ecf20Sopenharmony_ciqla_nvme_ls(srb_t *sp, struct pt_ls4_request *cmd_pkt) 36778c2ecf20Sopenharmony_ci{ 36788c2ecf20Sopenharmony_ci struct srb_iocb *nvme; 36798c2ecf20Sopenharmony_ci 36808c2ecf20Sopenharmony_ci nvme = &sp->u.iocb_cmd; 36818c2ecf20Sopenharmony_ci cmd_pkt->entry_type = PT_LS4_REQUEST; 36828c2ecf20Sopenharmony_ci cmd_pkt->entry_count = 1; 36838c2ecf20Sopenharmony_ci cmd_pkt->control_flags = cpu_to_le16(CF_LS4_ORIGINATOR << CF_LS4_SHIFT); 36848c2ecf20Sopenharmony_ci 36858c2ecf20Sopenharmony_ci cmd_pkt->timeout = cpu_to_le16(nvme->u.nvme.timeout_sec); 36868c2ecf20Sopenharmony_ci cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); 36878c2ecf20Sopenharmony_ci cmd_pkt->vp_index = sp->fcport->vha->vp_idx; 36888c2ecf20Sopenharmony_ci 36898c2ecf20Sopenharmony_ci cmd_pkt->tx_dseg_count = cpu_to_le16(1); 36908c2ecf20Sopenharmony_ci cmd_pkt->tx_byte_count = cpu_to_le32(nvme->u.nvme.cmd_len); 36918c2ecf20Sopenharmony_ci cmd_pkt->dsd[0].length = cpu_to_le32(nvme->u.nvme.cmd_len); 36928c2ecf20Sopenharmony_ci put_unaligned_le64(nvme->u.nvme.cmd_dma, &cmd_pkt->dsd[0].address); 36938c2ecf20Sopenharmony_ci 36948c2ecf20Sopenharmony_ci cmd_pkt->rx_dseg_count = cpu_to_le16(1); 36958c2ecf20Sopenharmony_ci cmd_pkt->rx_byte_count = cpu_to_le32(nvme->u.nvme.rsp_len); 36968c2ecf20Sopenharmony_ci cmd_pkt->dsd[1].length = cpu_to_le32(nvme->u.nvme.rsp_len); 36978c2ecf20Sopenharmony_ci put_unaligned_le64(nvme->u.nvme.rsp_dma, &cmd_pkt->dsd[1].address); 36988c2ecf20Sopenharmony_ci} 36998c2ecf20Sopenharmony_ci 37008c2ecf20Sopenharmony_cistatic void 37018c2ecf20Sopenharmony_ciqla25xx_ctrlvp_iocb(srb_t *sp, struct vp_ctrl_entry_24xx *vce) 37028c2ecf20Sopenharmony_ci{ 37038c2ecf20Sopenharmony_ci int map, pos; 37048c2ecf20Sopenharmony_ci 37058c2ecf20Sopenharmony_ci vce->entry_type = VP_CTRL_IOCB_TYPE; 37068c2ecf20Sopenharmony_ci vce->handle = sp->handle; 37078c2ecf20Sopenharmony_ci vce->entry_count = 1; 37088c2ecf20Sopenharmony_ci vce->command = cpu_to_le16(sp->u.iocb_cmd.u.ctrlvp.cmd); 37098c2ecf20Sopenharmony_ci vce->vp_count = cpu_to_le16(1); 37108c2ecf20Sopenharmony_ci 37118c2ecf20Sopenharmony_ci /* 37128c2ecf20Sopenharmony_ci * index map in firmware starts with 1; decrement index 37138c2ecf20Sopenharmony_ci * this is ok as we never use index 0 37148c2ecf20Sopenharmony_ci */ 37158c2ecf20Sopenharmony_ci map = (sp->u.iocb_cmd.u.ctrlvp.vp_index - 1) / 8; 37168c2ecf20Sopenharmony_ci pos = (sp->u.iocb_cmd.u.ctrlvp.vp_index - 1) & 7; 37178c2ecf20Sopenharmony_ci vce->vp_idx_map[map] |= 1 << pos; 37188c2ecf20Sopenharmony_ci} 37198c2ecf20Sopenharmony_ci 37208c2ecf20Sopenharmony_cistatic void 37218c2ecf20Sopenharmony_ciqla24xx_prlo_iocb(srb_t *sp, struct logio_entry_24xx *logio) 37228c2ecf20Sopenharmony_ci{ 37238c2ecf20Sopenharmony_ci logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; 37248c2ecf20Sopenharmony_ci logio->control_flags = 37258c2ecf20Sopenharmony_ci cpu_to_le16(LCF_COMMAND_PRLO|LCF_IMPL_PRLO); 37268c2ecf20Sopenharmony_ci 37278c2ecf20Sopenharmony_ci logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); 37288c2ecf20Sopenharmony_ci logio->port_id[0] = sp->fcport->d_id.b.al_pa; 37298c2ecf20Sopenharmony_ci logio->port_id[1] = sp->fcport->d_id.b.area; 37308c2ecf20Sopenharmony_ci logio->port_id[2] = sp->fcport->d_id.b.domain; 37318c2ecf20Sopenharmony_ci logio->vp_index = sp->fcport->vha->vp_idx; 37328c2ecf20Sopenharmony_ci} 37338c2ecf20Sopenharmony_ci 37348c2ecf20Sopenharmony_ciint 37358c2ecf20Sopenharmony_ciqla2x00_start_sp(srb_t *sp) 37368c2ecf20Sopenharmony_ci{ 37378c2ecf20Sopenharmony_ci int rval = QLA_SUCCESS; 37388c2ecf20Sopenharmony_ci scsi_qla_host_t *vha = sp->vha; 37398c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 37408c2ecf20Sopenharmony_ci struct qla_qpair *qp = sp->qpair; 37418c2ecf20Sopenharmony_ci void *pkt; 37428c2ecf20Sopenharmony_ci unsigned long flags; 37438c2ecf20Sopenharmony_ci 37448c2ecf20Sopenharmony_ci if (vha->hw->flags.eeh_busy) 37458c2ecf20Sopenharmony_ci return -EIO; 37468c2ecf20Sopenharmony_ci 37478c2ecf20Sopenharmony_ci spin_lock_irqsave(qp->qp_lock_ptr, flags); 37488c2ecf20Sopenharmony_ci pkt = __qla2x00_alloc_iocbs(sp->qpair, sp); 37498c2ecf20Sopenharmony_ci if (!pkt) { 37508c2ecf20Sopenharmony_ci rval = -EAGAIN; 37518c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0x700c, 37528c2ecf20Sopenharmony_ci "qla2x00_alloc_iocbs failed.\n"); 37538c2ecf20Sopenharmony_ci goto done; 37548c2ecf20Sopenharmony_ci } 37558c2ecf20Sopenharmony_ci 37568c2ecf20Sopenharmony_ci switch (sp->type) { 37578c2ecf20Sopenharmony_ci case SRB_LOGIN_CMD: 37588c2ecf20Sopenharmony_ci IS_FWI2_CAPABLE(ha) ? 37598c2ecf20Sopenharmony_ci qla24xx_login_iocb(sp, pkt) : 37608c2ecf20Sopenharmony_ci qla2x00_login_iocb(sp, pkt); 37618c2ecf20Sopenharmony_ci break; 37628c2ecf20Sopenharmony_ci case SRB_PRLI_CMD: 37638c2ecf20Sopenharmony_ci qla24xx_prli_iocb(sp, pkt); 37648c2ecf20Sopenharmony_ci break; 37658c2ecf20Sopenharmony_ci case SRB_LOGOUT_CMD: 37668c2ecf20Sopenharmony_ci IS_FWI2_CAPABLE(ha) ? 37678c2ecf20Sopenharmony_ci qla24xx_logout_iocb(sp, pkt) : 37688c2ecf20Sopenharmony_ci qla2x00_logout_iocb(sp, pkt); 37698c2ecf20Sopenharmony_ci break; 37708c2ecf20Sopenharmony_ci case SRB_ELS_CMD_RPT: 37718c2ecf20Sopenharmony_ci case SRB_ELS_CMD_HST: 37728c2ecf20Sopenharmony_ci qla24xx_els_iocb(sp, pkt); 37738c2ecf20Sopenharmony_ci break; 37748c2ecf20Sopenharmony_ci case SRB_CT_CMD: 37758c2ecf20Sopenharmony_ci IS_FWI2_CAPABLE(ha) ? 37768c2ecf20Sopenharmony_ci qla24xx_ct_iocb(sp, pkt) : 37778c2ecf20Sopenharmony_ci qla2x00_ct_iocb(sp, pkt); 37788c2ecf20Sopenharmony_ci break; 37798c2ecf20Sopenharmony_ci case SRB_ADISC_CMD: 37808c2ecf20Sopenharmony_ci IS_FWI2_CAPABLE(ha) ? 37818c2ecf20Sopenharmony_ci qla24xx_adisc_iocb(sp, pkt) : 37828c2ecf20Sopenharmony_ci qla2x00_adisc_iocb(sp, pkt); 37838c2ecf20Sopenharmony_ci break; 37848c2ecf20Sopenharmony_ci case SRB_TM_CMD: 37858c2ecf20Sopenharmony_ci IS_QLAFX00(ha) ? 37868c2ecf20Sopenharmony_ci qlafx00_tm_iocb(sp, pkt) : 37878c2ecf20Sopenharmony_ci qla24xx_tm_iocb(sp, pkt); 37888c2ecf20Sopenharmony_ci break; 37898c2ecf20Sopenharmony_ci case SRB_FXIOCB_DCMD: 37908c2ecf20Sopenharmony_ci case SRB_FXIOCB_BCMD: 37918c2ecf20Sopenharmony_ci qlafx00_fxdisc_iocb(sp, pkt); 37928c2ecf20Sopenharmony_ci break; 37938c2ecf20Sopenharmony_ci case SRB_NVME_LS: 37948c2ecf20Sopenharmony_ci qla_nvme_ls(sp, pkt); 37958c2ecf20Sopenharmony_ci break; 37968c2ecf20Sopenharmony_ci case SRB_ABT_CMD: 37978c2ecf20Sopenharmony_ci IS_QLAFX00(ha) ? 37988c2ecf20Sopenharmony_ci qlafx00_abort_iocb(sp, pkt) : 37998c2ecf20Sopenharmony_ci qla24xx_abort_iocb(sp, pkt); 38008c2ecf20Sopenharmony_ci break; 38018c2ecf20Sopenharmony_ci case SRB_ELS_DCMD: 38028c2ecf20Sopenharmony_ci qla24xx_els_logo_iocb(sp, pkt); 38038c2ecf20Sopenharmony_ci break; 38048c2ecf20Sopenharmony_ci case SRB_CT_PTHRU_CMD: 38058c2ecf20Sopenharmony_ci qla2x00_ctpthru_cmd_iocb(sp, pkt); 38068c2ecf20Sopenharmony_ci break; 38078c2ecf20Sopenharmony_ci case SRB_MB_IOCB: 38088c2ecf20Sopenharmony_ci qla2x00_mb_iocb(sp, pkt); 38098c2ecf20Sopenharmony_ci break; 38108c2ecf20Sopenharmony_ci case SRB_NACK_PLOGI: 38118c2ecf20Sopenharmony_ci case SRB_NACK_PRLI: 38128c2ecf20Sopenharmony_ci case SRB_NACK_LOGO: 38138c2ecf20Sopenharmony_ci qla2x00_send_notify_ack_iocb(sp, pkt); 38148c2ecf20Sopenharmony_ci break; 38158c2ecf20Sopenharmony_ci case SRB_CTRL_VP: 38168c2ecf20Sopenharmony_ci qla25xx_ctrlvp_iocb(sp, pkt); 38178c2ecf20Sopenharmony_ci break; 38188c2ecf20Sopenharmony_ci case SRB_PRLO_CMD: 38198c2ecf20Sopenharmony_ci qla24xx_prlo_iocb(sp, pkt); 38208c2ecf20Sopenharmony_ci break; 38218c2ecf20Sopenharmony_ci default: 38228c2ecf20Sopenharmony_ci break; 38238c2ecf20Sopenharmony_ci } 38248c2ecf20Sopenharmony_ci 38258c2ecf20Sopenharmony_ci if (sp->start_timer) 38268c2ecf20Sopenharmony_ci add_timer(&sp->u.iocb_cmd.timer); 38278c2ecf20Sopenharmony_ci 38288c2ecf20Sopenharmony_ci wmb(); 38298c2ecf20Sopenharmony_ci qla2x00_start_iocbs(vha, qp->req); 38308c2ecf20Sopenharmony_cidone: 38318c2ecf20Sopenharmony_ci spin_unlock_irqrestore(qp->qp_lock_ptr, flags); 38328c2ecf20Sopenharmony_ci return rval; 38338c2ecf20Sopenharmony_ci} 38348c2ecf20Sopenharmony_ci 38358c2ecf20Sopenharmony_cistatic void 38368c2ecf20Sopenharmony_ciqla25xx_build_bidir_iocb(srb_t *sp, struct scsi_qla_host *vha, 38378c2ecf20Sopenharmony_ci struct cmd_bidir *cmd_pkt, uint32_t tot_dsds) 38388c2ecf20Sopenharmony_ci{ 38398c2ecf20Sopenharmony_ci uint16_t avail_dsds; 38408c2ecf20Sopenharmony_ci struct dsd64 *cur_dsd; 38418c2ecf20Sopenharmony_ci uint32_t req_data_len = 0; 38428c2ecf20Sopenharmony_ci uint32_t rsp_data_len = 0; 38438c2ecf20Sopenharmony_ci struct scatterlist *sg; 38448c2ecf20Sopenharmony_ci int index; 38458c2ecf20Sopenharmony_ci int entry_count = 1; 38468c2ecf20Sopenharmony_ci struct bsg_job *bsg_job = sp->u.bsg_job; 38478c2ecf20Sopenharmony_ci 38488c2ecf20Sopenharmony_ci /*Update entry type to indicate bidir command */ 38498c2ecf20Sopenharmony_ci put_unaligned_le32(COMMAND_BIDIRECTIONAL, &cmd_pkt->entry_type); 38508c2ecf20Sopenharmony_ci 38518c2ecf20Sopenharmony_ci /* Set the transfer direction, in this set both flags 38528c2ecf20Sopenharmony_ci * Also set the BD_WRAP_BACK flag, firmware will take care 38538c2ecf20Sopenharmony_ci * assigning DID=SID for outgoing pkts. 38548c2ecf20Sopenharmony_ci */ 38558c2ecf20Sopenharmony_ci cmd_pkt->wr_dseg_count = cpu_to_le16(bsg_job->request_payload.sg_cnt); 38568c2ecf20Sopenharmony_ci cmd_pkt->rd_dseg_count = cpu_to_le16(bsg_job->reply_payload.sg_cnt); 38578c2ecf20Sopenharmony_ci cmd_pkt->control_flags = cpu_to_le16(BD_WRITE_DATA | BD_READ_DATA | 38588c2ecf20Sopenharmony_ci BD_WRAP_BACK); 38598c2ecf20Sopenharmony_ci 38608c2ecf20Sopenharmony_ci req_data_len = rsp_data_len = bsg_job->request_payload.payload_len; 38618c2ecf20Sopenharmony_ci cmd_pkt->wr_byte_count = cpu_to_le32(req_data_len); 38628c2ecf20Sopenharmony_ci cmd_pkt->rd_byte_count = cpu_to_le32(rsp_data_len); 38638c2ecf20Sopenharmony_ci cmd_pkt->timeout = cpu_to_le16(qla2x00_get_async_timeout(vha) + 2); 38648c2ecf20Sopenharmony_ci 38658c2ecf20Sopenharmony_ci vha->bidi_stats.transfer_bytes += req_data_len; 38668c2ecf20Sopenharmony_ci vha->bidi_stats.io_count++; 38678c2ecf20Sopenharmony_ci 38688c2ecf20Sopenharmony_ci vha->qla_stats.output_bytes += req_data_len; 38698c2ecf20Sopenharmony_ci vha->qla_stats.output_requests++; 38708c2ecf20Sopenharmony_ci 38718c2ecf20Sopenharmony_ci /* Only one dsd is available for bidirectional IOCB, remaining dsds 38728c2ecf20Sopenharmony_ci * are bundled in continuation iocb 38738c2ecf20Sopenharmony_ci */ 38748c2ecf20Sopenharmony_ci avail_dsds = 1; 38758c2ecf20Sopenharmony_ci cur_dsd = &cmd_pkt->fcp_dsd; 38768c2ecf20Sopenharmony_ci 38778c2ecf20Sopenharmony_ci index = 0; 38788c2ecf20Sopenharmony_ci 38798c2ecf20Sopenharmony_ci for_each_sg(bsg_job->request_payload.sg_list, sg, 38808c2ecf20Sopenharmony_ci bsg_job->request_payload.sg_cnt, index) { 38818c2ecf20Sopenharmony_ci cont_a64_entry_t *cont_pkt; 38828c2ecf20Sopenharmony_ci 38838c2ecf20Sopenharmony_ci /* Allocate additional continuation packets */ 38848c2ecf20Sopenharmony_ci if (avail_dsds == 0) { 38858c2ecf20Sopenharmony_ci /* Continuation type 1 IOCB can accomodate 38868c2ecf20Sopenharmony_ci * 5 DSDS 38878c2ecf20Sopenharmony_ci */ 38888c2ecf20Sopenharmony_ci cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->req); 38898c2ecf20Sopenharmony_ci cur_dsd = cont_pkt->dsd; 38908c2ecf20Sopenharmony_ci avail_dsds = 5; 38918c2ecf20Sopenharmony_ci entry_count++; 38928c2ecf20Sopenharmony_ci } 38938c2ecf20Sopenharmony_ci append_dsd64(&cur_dsd, sg); 38948c2ecf20Sopenharmony_ci avail_dsds--; 38958c2ecf20Sopenharmony_ci } 38968c2ecf20Sopenharmony_ci /* For read request DSD will always goes to continuation IOCB 38978c2ecf20Sopenharmony_ci * and follow the write DSD. If there is room on the current IOCB 38988c2ecf20Sopenharmony_ci * then it is added to that IOCB else new continuation IOCB is 38998c2ecf20Sopenharmony_ci * allocated. 39008c2ecf20Sopenharmony_ci */ 39018c2ecf20Sopenharmony_ci for_each_sg(bsg_job->reply_payload.sg_list, sg, 39028c2ecf20Sopenharmony_ci bsg_job->reply_payload.sg_cnt, index) { 39038c2ecf20Sopenharmony_ci cont_a64_entry_t *cont_pkt; 39048c2ecf20Sopenharmony_ci 39058c2ecf20Sopenharmony_ci /* Allocate additional continuation packets */ 39068c2ecf20Sopenharmony_ci if (avail_dsds == 0) { 39078c2ecf20Sopenharmony_ci /* Continuation type 1 IOCB can accomodate 39088c2ecf20Sopenharmony_ci * 5 DSDS 39098c2ecf20Sopenharmony_ci */ 39108c2ecf20Sopenharmony_ci cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->req); 39118c2ecf20Sopenharmony_ci cur_dsd = cont_pkt->dsd; 39128c2ecf20Sopenharmony_ci avail_dsds = 5; 39138c2ecf20Sopenharmony_ci entry_count++; 39148c2ecf20Sopenharmony_ci } 39158c2ecf20Sopenharmony_ci append_dsd64(&cur_dsd, sg); 39168c2ecf20Sopenharmony_ci avail_dsds--; 39178c2ecf20Sopenharmony_ci } 39188c2ecf20Sopenharmony_ci /* This value should be same as number of IOCB required for this cmd */ 39198c2ecf20Sopenharmony_ci cmd_pkt->entry_count = entry_count; 39208c2ecf20Sopenharmony_ci} 39218c2ecf20Sopenharmony_ci 39228c2ecf20Sopenharmony_ciint 39238c2ecf20Sopenharmony_ciqla2x00_start_bidir(srb_t *sp, struct scsi_qla_host *vha, uint32_t tot_dsds) 39248c2ecf20Sopenharmony_ci{ 39258c2ecf20Sopenharmony_ci 39268c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 39278c2ecf20Sopenharmony_ci unsigned long flags; 39288c2ecf20Sopenharmony_ci uint32_t handle; 39298c2ecf20Sopenharmony_ci uint16_t req_cnt; 39308c2ecf20Sopenharmony_ci uint16_t cnt; 39318c2ecf20Sopenharmony_ci uint32_t *clr_ptr; 39328c2ecf20Sopenharmony_ci struct cmd_bidir *cmd_pkt = NULL; 39338c2ecf20Sopenharmony_ci struct rsp_que *rsp; 39348c2ecf20Sopenharmony_ci struct req_que *req; 39358c2ecf20Sopenharmony_ci int rval = EXT_STATUS_OK; 39368c2ecf20Sopenharmony_ci 39378c2ecf20Sopenharmony_ci rval = QLA_SUCCESS; 39388c2ecf20Sopenharmony_ci 39398c2ecf20Sopenharmony_ci rsp = ha->rsp_q_map[0]; 39408c2ecf20Sopenharmony_ci req = vha->req; 39418c2ecf20Sopenharmony_ci 39428c2ecf20Sopenharmony_ci /* Send marker if required */ 39438c2ecf20Sopenharmony_ci if (vha->marker_needed != 0) { 39448c2ecf20Sopenharmony_ci if (qla2x00_marker(vha, ha->base_qpair, 39458c2ecf20Sopenharmony_ci 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) 39468c2ecf20Sopenharmony_ci return EXT_STATUS_MAILBOX; 39478c2ecf20Sopenharmony_ci vha->marker_needed = 0; 39488c2ecf20Sopenharmony_ci } 39498c2ecf20Sopenharmony_ci 39508c2ecf20Sopenharmony_ci /* Acquire ring specific lock */ 39518c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 39528c2ecf20Sopenharmony_ci 39538c2ecf20Sopenharmony_ci handle = qla2xxx_get_next_handle(req); 39548c2ecf20Sopenharmony_ci if (handle == 0) { 39558c2ecf20Sopenharmony_ci rval = EXT_STATUS_BUSY; 39568c2ecf20Sopenharmony_ci goto queuing_error; 39578c2ecf20Sopenharmony_ci } 39588c2ecf20Sopenharmony_ci 39598c2ecf20Sopenharmony_ci /* Calculate number of IOCB required */ 39608c2ecf20Sopenharmony_ci req_cnt = qla24xx_calc_iocbs(vha, tot_dsds); 39618c2ecf20Sopenharmony_ci 39628c2ecf20Sopenharmony_ci /* Check for room on request queue. */ 39638c2ecf20Sopenharmony_ci if (req->cnt < req_cnt + 2) { 39648c2ecf20Sopenharmony_ci if (IS_SHADOW_REG_CAPABLE(ha)) { 39658c2ecf20Sopenharmony_ci cnt = *req->out_ptr; 39668c2ecf20Sopenharmony_ci } else { 39678c2ecf20Sopenharmony_ci cnt = rd_reg_dword_relaxed(req->req_q_out); 39688c2ecf20Sopenharmony_ci if (qla2x00_check_reg16_for_disconnect(vha, cnt)) 39698c2ecf20Sopenharmony_ci goto queuing_error; 39708c2ecf20Sopenharmony_ci } 39718c2ecf20Sopenharmony_ci 39728c2ecf20Sopenharmony_ci if (req->ring_index < cnt) 39738c2ecf20Sopenharmony_ci req->cnt = cnt - req->ring_index; 39748c2ecf20Sopenharmony_ci else 39758c2ecf20Sopenharmony_ci req->cnt = req->length - 39768c2ecf20Sopenharmony_ci (req->ring_index - cnt); 39778c2ecf20Sopenharmony_ci } 39788c2ecf20Sopenharmony_ci if (req->cnt < req_cnt + 2) { 39798c2ecf20Sopenharmony_ci rval = EXT_STATUS_BUSY; 39808c2ecf20Sopenharmony_ci goto queuing_error; 39818c2ecf20Sopenharmony_ci } 39828c2ecf20Sopenharmony_ci 39838c2ecf20Sopenharmony_ci cmd_pkt = (struct cmd_bidir *)req->ring_ptr; 39848c2ecf20Sopenharmony_ci cmd_pkt->handle = make_handle(req->id, handle); 39858c2ecf20Sopenharmony_ci 39868c2ecf20Sopenharmony_ci /* Zero out remaining portion of packet. */ 39878c2ecf20Sopenharmony_ci /* tagged queuing modifier -- default is TSK_SIMPLE (0).*/ 39888c2ecf20Sopenharmony_ci clr_ptr = (uint32_t *)cmd_pkt + 2; 39898c2ecf20Sopenharmony_ci memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); 39908c2ecf20Sopenharmony_ci 39918c2ecf20Sopenharmony_ci /* Set NPORT-ID (of vha)*/ 39928c2ecf20Sopenharmony_ci cmd_pkt->nport_handle = cpu_to_le16(vha->self_login_loop_id); 39938c2ecf20Sopenharmony_ci cmd_pkt->port_id[0] = vha->d_id.b.al_pa; 39948c2ecf20Sopenharmony_ci cmd_pkt->port_id[1] = vha->d_id.b.area; 39958c2ecf20Sopenharmony_ci cmd_pkt->port_id[2] = vha->d_id.b.domain; 39968c2ecf20Sopenharmony_ci 39978c2ecf20Sopenharmony_ci qla25xx_build_bidir_iocb(sp, vha, cmd_pkt, tot_dsds); 39988c2ecf20Sopenharmony_ci cmd_pkt->entry_status = (uint8_t) rsp->id; 39998c2ecf20Sopenharmony_ci /* Build command packet. */ 40008c2ecf20Sopenharmony_ci req->current_outstanding_cmd = handle; 40018c2ecf20Sopenharmony_ci req->outstanding_cmds[handle] = sp; 40028c2ecf20Sopenharmony_ci sp->handle = handle; 40038c2ecf20Sopenharmony_ci req->cnt -= req_cnt; 40048c2ecf20Sopenharmony_ci 40058c2ecf20Sopenharmony_ci /* Send the command to the firmware */ 40068c2ecf20Sopenharmony_ci wmb(); 40078c2ecf20Sopenharmony_ci qla2x00_start_iocbs(vha, req); 40088c2ecf20Sopenharmony_ciqueuing_error: 40098c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 40108c2ecf20Sopenharmony_ci 40118c2ecf20Sopenharmony_ci return rval; 40128c2ecf20Sopenharmony_ci} 4013