162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * QLogic Fibre Channel HBA Driver 462306a36Sopenharmony_ci * Copyright (c) 2003-2014 QLogic Corporation 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include "qla_def.h" 762306a36Sopenharmony_ci#include "qla_target.h" 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/blkdev.h> 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <scsi/scsi_tcq.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic int qla_start_scsi_type6(srb_t *sp); 1562306a36Sopenharmony_ci/** 1662306a36Sopenharmony_ci * qla2x00_get_cmd_direction() - Determine control_flag data direction. 1762306a36Sopenharmony_ci * @sp: SCSI command 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * Returns the proper CF_* direction based on CDB. 2062306a36Sopenharmony_ci */ 2162306a36Sopenharmony_cistatic inline uint16_t 2262306a36Sopenharmony_ciqla2x00_get_cmd_direction(srb_t *sp) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci uint16_t cflags; 2562306a36Sopenharmony_ci struct scsi_cmnd *cmd = GET_CMD_SP(sp); 2662306a36Sopenharmony_ci struct scsi_qla_host *vha = sp->vha; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci cflags = 0; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci /* Set transfer direction */ 3162306a36Sopenharmony_ci if (cmd->sc_data_direction == DMA_TO_DEVICE) { 3262306a36Sopenharmony_ci cflags = CF_WRITE; 3362306a36Sopenharmony_ci vha->qla_stats.output_bytes += scsi_bufflen(cmd); 3462306a36Sopenharmony_ci vha->qla_stats.output_requests++; 3562306a36Sopenharmony_ci } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) { 3662306a36Sopenharmony_ci cflags = CF_READ; 3762306a36Sopenharmony_ci vha->qla_stats.input_bytes += scsi_bufflen(cmd); 3862306a36Sopenharmony_ci vha->qla_stats.input_requests++; 3962306a36Sopenharmony_ci } 4062306a36Sopenharmony_ci return (cflags); 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/** 4462306a36Sopenharmony_ci * qla2x00_calc_iocbs_32() - Determine number of Command Type 2 and 4562306a36Sopenharmony_ci * Continuation Type 0 IOCBs to allocate. 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * @dsds: number of data segment descriptors needed 4862306a36Sopenharmony_ci * 4962306a36Sopenharmony_ci * Returns the number of IOCB entries needed to store @dsds. 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_ciuint16_t 5262306a36Sopenharmony_ciqla2x00_calc_iocbs_32(uint16_t dsds) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci uint16_t iocbs; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci iocbs = 1; 5762306a36Sopenharmony_ci if (dsds > 3) { 5862306a36Sopenharmony_ci iocbs += (dsds - 3) / 7; 5962306a36Sopenharmony_ci if ((dsds - 3) % 7) 6062306a36Sopenharmony_ci iocbs++; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci return (iocbs); 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/** 6662306a36Sopenharmony_ci * qla2x00_calc_iocbs_64() - Determine number of Command Type 3 and 6762306a36Sopenharmony_ci * Continuation Type 1 IOCBs to allocate. 6862306a36Sopenharmony_ci * 6962306a36Sopenharmony_ci * @dsds: number of data segment descriptors needed 7062306a36Sopenharmony_ci * 7162306a36Sopenharmony_ci * Returns the number of IOCB entries needed to store @dsds. 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_ciuint16_t 7462306a36Sopenharmony_ciqla2x00_calc_iocbs_64(uint16_t dsds) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci uint16_t iocbs; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci iocbs = 1; 7962306a36Sopenharmony_ci if (dsds > 2) { 8062306a36Sopenharmony_ci iocbs += (dsds - 2) / 5; 8162306a36Sopenharmony_ci if ((dsds - 2) % 5) 8262306a36Sopenharmony_ci iocbs++; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci return (iocbs); 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/** 8862306a36Sopenharmony_ci * qla2x00_prep_cont_type0_iocb() - Initialize a Continuation Type 0 IOCB. 8962306a36Sopenharmony_ci * @vha: HA context 9062306a36Sopenharmony_ci * 9162306a36Sopenharmony_ci * Returns a pointer to the Continuation Type 0 IOCB packet. 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_cistatic inline cont_entry_t * 9462306a36Sopenharmony_ciqla2x00_prep_cont_type0_iocb(struct scsi_qla_host *vha) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci cont_entry_t *cont_pkt; 9762306a36Sopenharmony_ci struct req_que *req = vha->req; 9862306a36Sopenharmony_ci /* Adjust ring index. */ 9962306a36Sopenharmony_ci req->ring_index++; 10062306a36Sopenharmony_ci if (req->ring_index == req->length) { 10162306a36Sopenharmony_ci req->ring_index = 0; 10262306a36Sopenharmony_ci req->ring_ptr = req->ring; 10362306a36Sopenharmony_ci } else { 10462306a36Sopenharmony_ci req->ring_ptr++; 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci cont_pkt = (cont_entry_t *)req->ring_ptr; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* Load packet defaults. */ 11062306a36Sopenharmony_ci put_unaligned_le32(CONTINUE_TYPE, &cont_pkt->entry_type); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci return (cont_pkt); 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci/** 11662306a36Sopenharmony_ci * qla2x00_prep_cont_type1_iocb() - Initialize a Continuation Type 1 IOCB. 11762306a36Sopenharmony_ci * @vha: HA context 11862306a36Sopenharmony_ci * @req: request queue 11962306a36Sopenharmony_ci * 12062306a36Sopenharmony_ci * Returns a pointer to the continuation type 1 IOCB packet. 12162306a36Sopenharmony_ci */ 12262306a36Sopenharmony_cicont_a64_entry_t * 12362306a36Sopenharmony_ciqla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha, struct req_que *req) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci cont_a64_entry_t *cont_pkt; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci /* Adjust ring index. */ 12862306a36Sopenharmony_ci req->ring_index++; 12962306a36Sopenharmony_ci if (req->ring_index == req->length) { 13062306a36Sopenharmony_ci req->ring_index = 0; 13162306a36Sopenharmony_ci req->ring_ptr = req->ring; 13262306a36Sopenharmony_ci } else { 13362306a36Sopenharmony_ci req->ring_ptr++; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci cont_pkt = (cont_a64_entry_t *)req->ring_ptr; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci /* Load packet defaults. */ 13962306a36Sopenharmony_ci put_unaligned_le32(IS_QLAFX00(vha->hw) ? CONTINUE_A64_TYPE_FX00 : 14062306a36Sopenharmony_ci CONTINUE_A64_TYPE, &cont_pkt->entry_type); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci return (cont_pkt); 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ciinline int 14662306a36Sopenharmony_ciqla24xx_configure_prot_mode(srb_t *sp, uint16_t *fw_prot_opts) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci struct scsi_cmnd *cmd = GET_CMD_SP(sp); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* We always use DIFF Bundling for best performance */ 15162306a36Sopenharmony_ci *fw_prot_opts = 0; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* Translate SCSI opcode to a protection opcode */ 15462306a36Sopenharmony_ci switch (scsi_get_prot_op(cmd)) { 15562306a36Sopenharmony_ci case SCSI_PROT_READ_STRIP: 15662306a36Sopenharmony_ci *fw_prot_opts |= PO_MODE_DIF_REMOVE; 15762306a36Sopenharmony_ci break; 15862306a36Sopenharmony_ci case SCSI_PROT_WRITE_INSERT: 15962306a36Sopenharmony_ci *fw_prot_opts |= PO_MODE_DIF_INSERT; 16062306a36Sopenharmony_ci break; 16162306a36Sopenharmony_ci case SCSI_PROT_READ_INSERT: 16262306a36Sopenharmony_ci *fw_prot_opts |= PO_MODE_DIF_INSERT; 16362306a36Sopenharmony_ci break; 16462306a36Sopenharmony_ci case SCSI_PROT_WRITE_STRIP: 16562306a36Sopenharmony_ci *fw_prot_opts |= PO_MODE_DIF_REMOVE; 16662306a36Sopenharmony_ci break; 16762306a36Sopenharmony_ci case SCSI_PROT_READ_PASS: 16862306a36Sopenharmony_ci case SCSI_PROT_WRITE_PASS: 16962306a36Sopenharmony_ci if (cmd->prot_flags & SCSI_PROT_IP_CHECKSUM) 17062306a36Sopenharmony_ci *fw_prot_opts |= PO_MODE_DIF_TCP_CKSUM; 17162306a36Sopenharmony_ci else 17262306a36Sopenharmony_ci *fw_prot_opts |= PO_MODE_DIF_PASS; 17362306a36Sopenharmony_ci break; 17462306a36Sopenharmony_ci default: /* Normal Request */ 17562306a36Sopenharmony_ci *fw_prot_opts |= PO_MODE_DIF_PASS; 17662306a36Sopenharmony_ci break; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci if (!(cmd->prot_flags & SCSI_PROT_GUARD_CHECK)) 18062306a36Sopenharmony_ci *fw_prot_opts |= PO_DISABLE_GUARD_CHECK; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci return scsi_prot_sg_count(cmd); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci/* 18662306a36Sopenharmony_ci * qla2x00_build_scsi_iocbs_32() - Build IOCB command utilizing 32bit 18762306a36Sopenharmony_ci * capable IOCB types. 18862306a36Sopenharmony_ci * 18962306a36Sopenharmony_ci * @sp: SRB command to process 19062306a36Sopenharmony_ci * @cmd_pkt: Command type 2 IOCB 19162306a36Sopenharmony_ci * @tot_dsds: Total number of segments to transfer 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_civoid qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt, 19462306a36Sopenharmony_ci uint16_t tot_dsds) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci uint16_t avail_dsds; 19762306a36Sopenharmony_ci struct dsd32 *cur_dsd; 19862306a36Sopenharmony_ci scsi_qla_host_t *vha; 19962306a36Sopenharmony_ci struct scsi_cmnd *cmd; 20062306a36Sopenharmony_ci struct scatterlist *sg; 20162306a36Sopenharmony_ci int i; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci cmd = GET_CMD_SP(sp); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci /* Update entry type to indicate Command Type 2 IOCB */ 20662306a36Sopenharmony_ci put_unaligned_le32(COMMAND_TYPE, &cmd_pkt->entry_type); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci /* No data transfer */ 20962306a36Sopenharmony_ci if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { 21062306a36Sopenharmony_ci cmd_pkt->byte_count = cpu_to_le32(0); 21162306a36Sopenharmony_ci return; 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci vha = sp->vha; 21562306a36Sopenharmony_ci cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp)); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci /* Three DSDs are available in the Command Type 2 IOCB */ 21862306a36Sopenharmony_ci avail_dsds = ARRAY_SIZE(cmd_pkt->dsd32); 21962306a36Sopenharmony_ci cur_dsd = cmd_pkt->dsd32; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci /* Load data segments */ 22262306a36Sopenharmony_ci scsi_for_each_sg(cmd, sg, tot_dsds, i) { 22362306a36Sopenharmony_ci cont_entry_t *cont_pkt; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci /* Allocate additional continuation packets? */ 22662306a36Sopenharmony_ci if (avail_dsds == 0) { 22762306a36Sopenharmony_ci /* 22862306a36Sopenharmony_ci * Seven DSDs are available in the Continuation 22962306a36Sopenharmony_ci * Type 0 IOCB. 23062306a36Sopenharmony_ci */ 23162306a36Sopenharmony_ci cont_pkt = qla2x00_prep_cont_type0_iocb(vha); 23262306a36Sopenharmony_ci cur_dsd = cont_pkt->dsd; 23362306a36Sopenharmony_ci avail_dsds = ARRAY_SIZE(cont_pkt->dsd); 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci append_dsd32(&cur_dsd, sg); 23762306a36Sopenharmony_ci avail_dsds--; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci/** 24262306a36Sopenharmony_ci * qla2x00_build_scsi_iocbs_64() - Build IOCB command utilizing 64bit 24362306a36Sopenharmony_ci * capable IOCB types. 24462306a36Sopenharmony_ci * 24562306a36Sopenharmony_ci * @sp: SRB command to process 24662306a36Sopenharmony_ci * @cmd_pkt: Command type 3 IOCB 24762306a36Sopenharmony_ci * @tot_dsds: Total number of segments to transfer 24862306a36Sopenharmony_ci */ 24962306a36Sopenharmony_civoid qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt, 25062306a36Sopenharmony_ci uint16_t tot_dsds) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci uint16_t avail_dsds; 25362306a36Sopenharmony_ci struct dsd64 *cur_dsd; 25462306a36Sopenharmony_ci scsi_qla_host_t *vha; 25562306a36Sopenharmony_ci struct scsi_cmnd *cmd; 25662306a36Sopenharmony_ci struct scatterlist *sg; 25762306a36Sopenharmony_ci int i; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci cmd = GET_CMD_SP(sp); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci /* Update entry type to indicate Command Type 3 IOCB */ 26262306a36Sopenharmony_ci put_unaligned_le32(COMMAND_A64_TYPE, &cmd_pkt->entry_type); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci /* No data transfer */ 26562306a36Sopenharmony_ci if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { 26662306a36Sopenharmony_ci cmd_pkt->byte_count = cpu_to_le32(0); 26762306a36Sopenharmony_ci return; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci vha = sp->vha; 27162306a36Sopenharmony_ci cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp)); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci /* Two DSDs are available in the Command Type 3 IOCB */ 27462306a36Sopenharmony_ci avail_dsds = ARRAY_SIZE(cmd_pkt->dsd64); 27562306a36Sopenharmony_ci cur_dsd = cmd_pkt->dsd64; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci /* Load data segments */ 27862306a36Sopenharmony_ci scsi_for_each_sg(cmd, sg, tot_dsds, i) { 27962306a36Sopenharmony_ci cont_a64_entry_t *cont_pkt; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* Allocate additional continuation packets? */ 28262306a36Sopenharmony_ci if (avail_dsds == 0) { 28362306a36Sopenharmony_ci /* 28462306a36Sopenharmony_ci * Five DSDs are available in the Continuation 28562306a36Sopenharmony_ci * Type 1 IOCB. 28662306a36Sopenharmony_ci */ 28762306a36Sopenharmony_ci cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->req); 28862306a36Sopenharmony_ci cur_dsd = cont_pkt->dsd; 28962306a36Sopenharmony_ci avail_dsds = ARRAY_SIZE(cont_pkt->dsd); 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci append_dsd64(&cur_dsd, sg); 29362306a36Sopenharmony_ci avail_dsds--; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci/* 29862306a36Sopenharmony_ci * Find the first handle that is not in use, starting from 29962306a36Sopenharmony_ci * req->current_outstanding_cmd + 1. The caller must hold the lock that is 30062306a36Sopenharmony_ci * associated with @req. 30162306a36Sopenharmony_ci */ 30262306a36Sopenharmony_ciuint32_t qla2xxx_get_next_handle(struct req_que *req) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci uint32_t index, handle = req->current_outstanding_cmd; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci for (index = 1; index < req->num_outstanding_cmds; index++) { 30762306a36Sopenharmony_ci handle++; 30862306a36Sopenharmony_ci if (handle == req->num_outstanding_cmds) 30962306a36Sopenharmony_ci handle = 1; 31062306a36Sopenharmony_ci if (!req->outstanding_cmds[handle]) 31162306a36Sopenharmony_ci return handle; 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci return 0; 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci/** 31862306a36Sopenharmony_ci * qla2x00_start_scsi() - Send a SCSI command to the ISP 31962306a36Sopenharmony_ci * @sp: command to send to the ISP 32062306a36Sopenharmony_ci * 32162306a36Sopenharmony_ci * Returns non-zero if a failure occurred, else zero. 32262306a36Sopenharmony_ci */ 32362306a36Sopenharmony_ciint 32462306a36Sopenharmony_ciqla2x00_start_scsi(srb_t *sp) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci int nseg; 32762306a36Sopenharmony_ci unsigned long flags; 32862306a36Sopenharmony_ci scsi_qla_host_t *vha; 32962306a36Sopenharmony_ci struct scsi_cmnd *cmd; 33062306a36Sopenharmony_ci uint32_t *clr_ptr; 33162306a36Sopenharmony_ci uint32_t handle; 33262306a36Sopenharmony_ci cmd_entry_t *cmd_pkt; 33362306a36Sopenharmony_ci uint16_t cnt; 33462306a36Sopenharmony_ci uint16_t req_cnt; 33562306a36Sopenharmony_ci uint16_t tot_dsds; 33662306a36Sopenharmony_ci struct device_reg_2xxx __iomem *reg; 33762306a36Sopenharmony_ci struct qla_hw_data *ha; 33862306a36Sopenharmony_ci struct req_que *req; 33962306a36Sopenharmony_ci struct rsp_que *rsp; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci /* Setup device pointers. */ 34262306a36Sopenharmony_ci vha = sp->vha; 34362306a36Sopenharmony_ci ha = vha->hw; 34462306a36Sopenharmony_ci reg = &ha->iobase->isp; 34562306a36Sopenharmony_ci cmd = GET_CMD_SP(sp); 34662306a36Sopenharmony_ci req = ha->req_q_map[0]; 34762306a36Sopenharmony_ci rsp = ha->rsp_q_map[0]; 34862306a36Sopenharmony_ci /* So we know we haven't pci_map'ed anything yet */ 34962306a36Sopenharmony_ci tot_dsds = 0; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci /* Send marker if required */ 35262306a36Sopenharmony_ci if (vha->marker_needed != 0) { 35362306a36Sopenharmony_ci if (qla2x00_marker(vha, ha->base_qpair, 0, 0, MK_SYNC_ALL) != 35462306a36Sopenharmony_ci QLA_SUCCESS) { 35562306a36Sopenharmony_ci return (QLA_FUNCTION_FAILED); 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci vha->marker_needed = 0; 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci /* Acquire ring specific lock */ 36162306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci handle = qla2xxx_get_next_handle(req); 36462306a36Sopenharmony_ci if (handle == 0) 36562306a36Sopenharmony_ci goto queuing_error; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci /* Map the sg table so we have an accurate count of sg entries needed */ 36862306a36Sopenharmony_ci if (scsi_sg_count(cmd)) { 36962306a36Sopenharmony_ci nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd), 37062306a36Sopenharmony_ci scsi_sg_count(cmd), cmd->sc_data_direction); 37162306a36Sopenharmony_ci if (unlikely(!nseg)) 37262306a36Sopenharmony_ci goto queuing_error; 37362306a36Sopenharmony_ci } else 37462306a36Sopenharmony_ci nseg = 0; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci tot_dsds = nseg; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci /* Calculate the number of request entries needed. */ 37962306a36Sopenharmony_ci req_cnt = ha->isp_ops->calc_req_entries(tot_dsds); 38062306a36Sopenharmony_ci if (req->cnt < (req_cnt + 2)) { 38162306a36Sopenharmony_ci cnt = rd_reg_word_relaxed(ISP_REQ_Q_OUT(ha, reg)); 38262306a36Sopenharmony_ci if (req->ring_index < cnt) 38362306a36Sopenharmony_ci req->cnt = cnt - req->ring_index; 38462306a36Sopenharmony_ci else 38562306a36Sopenharmony_ci req->cnt = req->length - 38662306a36Sopenharmony_ci (req->ring_index - cnt); 38762306a36Sopenharmony_ci /* If still no head room then bail out */ 38862306a36Sopenharmony_ci if (req->cnt < (req_cnt + 2)) 38962306a36Sopenharmony_ci goto queuing_error; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci /* Build command packet */ 39362306a36Sopenharmony_ci req->current_outstanding_cmd = handle; 39462306a36Sopenharmony_ci req->outstanding_cmds[handle] = sp; 39562306a36Sopenharmony_ci sp->handle = handle; 39662306a36Sopenharmony_ci cmd->host_scribble = (unsigned char *)(unsigned long)handle; 39762306a36Sopenharmony_ci req->cnt -= req_cnt; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci cmd_pkt = (cmd_entry_t *)req->ring_ptr; 40062306a36Sopenharmony_ci cmd_pkt->handle = handle; 40162306a36Sopenharmony_ci /* Zero out remaining portion of packet. */ 40262306a36Sopenharmony_ci clr_ptr = (uint32_t *)cmd_pkt + 2; 40362306a36Sopenharmony_ci memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); 40462306a36Sopenharmony_ci cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci /* Set target ID and LUN number*/ 40762306a36Sopenharmony_ci SET_TARGET_ID(ha, cmd_pkt->target, sp->fcport->loop_id); 40862306a36Sopenharmony_ci cmd_pkt->lun = cpu_to_le16(cmd->device->lun); 40962306a36Sopenharmony_ci cmd_pkt->control_flags = cpu_to_le16(CF_SIMPLE_TAG); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci /* Load SCSI command packet. */ 41262306a36Sopenharmony_ci memcpy(cmd_pkt->scsi_cdb, cmd->cmnd, cmd->cmd_len); 41362306a36Sopenharmony_ci cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* Build IOCB segments */ 41662306a36Sopenharmony_ci ha->isp_ops->build_iocbs(sp, cmd_pkt, tot_dsds); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci /* Set total data segment count. */ 41962306a36Sopenharmony_ci cmd_pkt->entry_count = (uint8_t)req_cnt; 42062306a36Sopenharmony_ci wmb(); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci /* Adjust ring index. */ 42362306a36Sopenharmony_ci req->ring_index++; 42462306a36Sopenharmony_ci if (req->ring_index == req->length) { 42562306a36Sopenharmony_ci req->ring_index = 0; 42662306a36Sopenharmony_ci req->ring_ptr = req->ring; 42762306a36Sopenharmony_ci } else 42862306a36Sopenharmony_ci req->ring_ptr++; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci sp->flags |= SRB_DMA_VALID; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci /* Set chip new ring index. */ 43362306a36Sopenharmony_ci wrt_reg_word(ISP_REQ_Q_IN(ha, reg), req->ring_index); 43462306a36Sopenharmony_ci rd_reg_word_relaxed(ISP_REQ_Q_IN(ha, reg)); /* PCI Posting. */ 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci /* Manage unprocessed RIO/ZIO commands in response queue. */ 43762306a36Sopenharmony_ci if (vha->flags.process_response_queue && 43862306a36Sopenharmony_ci rsp->ring_ptr->signature != RESPONSE_PROCESSED) 43962306a36Sopenharmony_ci qla2x00_process_response_queue(rsp); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 44262306a36Sopenharmony_ci return (QLA_SUCCESS); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ciqueuing_error: 44562306a36Sopenharmony_ci if (tot_dsds) 44662306a36Sopenharmony_ci scsi_dma_unmap(cmd); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci return (QLA_FUNCTION_FAILED); 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci/** 45462306a36Sopenharmony_ci * qla2x00_start_iocbs() - Execute the IOCB command 45562306a36Sopenharmony_ci * @vha: HA context 45662306a36Sopenharmony_ci * @req: request queue 45762306a36Sopenharmony_ci */ 45862306a36Sopenharmony_civoid 45962306a36Sopenharmony_ciqla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 46262306a36Sopenharmony_ci device_reg_t *reg = ISP_QUE_REG(ha, req->id); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci if (IS_P3P_TYPE(ha)) { 46562306a36Sopenharmony_ci qla82xx_start_iocbs(vha); 46662306a36Sopenharmony_ci } else { 46762306a36Sopenharmony_ci /* Adjust ring index. */ 46862306a36Sopenharmony_ci req->ring_index++; 46962306a36Sopenharmony_ci if (req->ring_index == req->length) { 47062306a36Sopenharmony_ci req->ring_index = 0; 47162306a36Sopenharmony_ci req->ring_ptr = req->ring; 47262306a36Sopenharmony_ci } else 47362306a36Sopenharmony_ci req->ring_ptr++; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci /* Set chip new ring index. */ 47662306a36Sopenharmony_ci if (ha->mqenable || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { 47762306a36Sopenharmony_ci wrt_reg_dword(req->req_q_in, req->ring_index); 47862306a36Sopenharmony_ci } else if (IS_QLA83XX(ha)) { 47962306a36Sopenharmony_ci wrt_reg_dword(req->req_q_in, req->ring_index); 48062306a36Sopenharmony_ci rd_reg_dword_relaxed(&ha->iobase->isp24.hccr); 48162306a36Sopenharmony_ci } else if (IS_QLAFX00(ha)) { 48262306a36Sopenharmony_ci wrt_reg_dword(®->ispfx00.req_q_in, req->ring_index); 48362306a36Sopenharmony_ci rd_reg_dword_relaxed(®->ispfx00.req_q_in); 48462306a36Sopenharmony_ci QLAFX00_SET_HST_INTR(ha, ha->rqstq_intr_code); 48562306a36Sopenharmony_ci } else if (IS_FWI2_CAPABLE(ha)) { 48662306a36Sopenharmony_ci wrt_reg_dword(®->isp24.req_q_in, req->ring_index); 48762306a36Sopenharmony_ci rd_reg_dword_relaxed(®->isp24.req_q_in); 48862306a36Sopenharmony_ci } else { 48962306a36Sopenharmony_ci wrt_reg_word(ISP_REQ_Q_IN(ha, ®->isp), 49062306a36Sopenharmony_ci req->ring_index); 49162306a36Sopenharmony_ci rd_reg_word_relaxed(ISP_REQ_Q_IN(ha, ®->isp)); 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci} 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci/** 49762306a36Sopenharmony_ci * __qla2x00_marker() - Send a marker IOCB to the firmware. 49862306a36Sopenharmony_ci * @vha: HA context 49962306a36Sopenharmony_ci * @qpair: queue pair pointer 50062306a36Sopenharmony_ci * @loop_id: loop ID 50162306a36Sopenharmony_ci * @lun: LUN 50262306a36Sopenharmony_ci * @type: marker modifier 50362306a36Sopenharmony_ci * 50462306a36Sopenharmony_ci * Can be called from both normal and interrupt context. 50562306a36Sopenharmony_ci * 50662306a36Sopenharmony_ci * Returns non-zero if a failure occurred, else zero. 50762306a36Sopenharmony_ci */ 50862306a36Sopenharmony_cistatic int 50962306a36Sopenharmony_ci__qla2x00_marker(struct scsi_qla_host *vha, struct qla_qpair *qpair, 51062306a36Sopenharmony_ci uint16_t loop_id, uint64_t lun, uint8_t type) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci mrk_entry_t *mrk; 51362306a36Sopenharmony_ci struct mrk_entry_24xx *mrk24 = NULL; 51462306a36Sopenharmony_ci struct req_que *req = qpair->req; 51562306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 51662306a36Sopenharmony_ci scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci mrk = (mrk_entry_t *)__qla2x00_alloc_iocbs(qpair, NULL); 51962306a36Sopenharmony_ci if (mrk == NULL) { 52062306a36Sopenharmony_ci ql_log(ql_log_warn, base_vha, 0x3026, 52162306a36Sopenharmony_ci "Failed to allocate Marker IOCB.\n"); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci return (QLA_FUNCTION_FAILED); 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci mrk24 = (struct mrk_entry_24xx *)mrk; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci mrk->entry_type = MARKER_TYPE; 52962306a36Sopenharmony_ci mrk->modifier = type; 53062306a36Sopenharmony_ci if (type != MK_SYNC_ALL) { 53162306a36Sopenharmony_ci if (IS_FWI2_CAPABLE(ha)) { 53262306a36Sopenharmony_ci mrk24->nport_handle = cpu_to_le16(loop_id); 53362306a36Sopenharmony_ci int_to_scsilun(lun, (struct scsi_lun *)&mrk24->lun); 53462306a36Sopenharmony_ci host_to_fcp_swap(mrk24->lun, sizeof(mrk24->lun)); 53562306a36Sopenharmony_ci mrk24->vp_index = vha->vp_idx; 53662306a36Sopenharmony_ci } else { 53762306a36Sopenharmony_ci SET_TARGET_ID(ha, mrk->target, loop_id); 53862306a36Sopenharmony_ci mrk->lun = cpu_to_le16((uint16_t)lun); 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci if (IS_FWI2_CAPABLE(ha)) 54362306a36Sopenharmony_ci mrk24->handle = QLA_SKIP_HANDLE; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci wmb(); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci qla2x00_start_iocbs(vha, req); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci return (QLA_SUCCESS); 55062306a36Sopenharmony_ci} 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ciint 55362306a36Sopenharmony_ciqla2x00_marker(struct scsi_qla_host *vha, struct qla_qpair *qpair, 55462306a36Sopenharmony_ci uint16_t loop_id, uint64_t lun, uint8_t type) 55562306a36Sopenharmony_ci{ 55662306a36Sopenharmony_ci int ret; 55762306a36Sopenharmony_ci unsigned long flags = 0; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci spin_lock_irqsave(qpair->qp_lock_ptr, flags); 56062306a36Sopenharmony_ci ret = __qla2x00_marker(vha, qpair, loop_id, lun, type); 56162306a36Sopenharmony_ci spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci return (ret); 56462306a36Sopenharmony_ci} 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci/* 56762306a36Sopenharmony_ci * qla2x00_issue_marker 56862306a36Sopenharmony_ci * 56962306a36Sopenharmony_ci * Issue marker 57062306a36Sopenharmony_ci * Caller CAN have hardware lock held as specified by ha_locked parameter. 57162306a36Sopenharmony_ci * Might release it, then reaquire. 57262306a36Sopenharmony_ci */ 57362306a36Sopenharmony_ciint qla2x00_issue_marker(scsi_qla_host_t *vha, int ha_locked) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci if (ha_locked) { 57662306a36Sopenharmony_ci if (__qla2x00_marker(vha, vha->hw->base_qpair, 0, 0, 57762306a36Sopenharmony_ci MK_SYNC_ALL) != QLA_SUCCESS) 57862306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 57962306a36Sopenharmony_ci } else { 58062306a36Sopenharmony_ci if (qla2x00_marker(vha, vha->hw->base_qpair, 0, 0, 58162306a36Sopenharmony_ci MK_SYNC_ALL) != QLA_SUCCESS) 58262306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci vha->marker_needed = 0; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci return QLA_SUCCESS; 58762306a36Sopenharmony_ci} 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_cistatic inline int 59062306a36Sopenharmony_ciqla24xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt, 59162306a36Sopenharmony_ci uint16_t tot_dsds) 59262306a36Sopenharmony_ci{ 59362306a36Sopenharmony_ci struct dsd64 *cur_dsd = NULL, *next_dsd; 59462306a36Sopenharmony_ci struct scsi_cmnd *cmd; 59562306a36Sopenharmony_ci struct scatterlist *cur_seg; 59662306a36Sopenharmony_ci uint8_t avail_dsds; 59762306a36Sopenharmony_ci uint8_t first_iocb = 1; 59862306a36Sopenharmony_ci uint32_t dsd_list_len; 59962306a36Sopenharmony_ci struct dsd_dma *dsd_ptr; 60062306a36Sopenharmony_ci struct ct6_dsd *ctx; 60162306a36Sopenharmony_ci struct qla_qpair *qpair = sp->qpair; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci cmd = GET_CMD_SP(sp); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci /* Update entry type to indicate Command Type 3 IOCB */ 60662306a36Sopenharmony_ci put_unaligned_le32(COMMAND_TYPE_6, &cmd_pkt->entry_type); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci /* No data transfer */ 60962306a36Sopenharmony_ci if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE || 61062306a36Sopenharmony_ci tot_dsds == 0) { 61162306a36Sopenharmony_ci cmd_pkt->byte_count = cpu_to_le32(0); 61262306a36Sopenharmony_ci return 0; 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci /* Set transfer direction */ 61662306a36Sopenharmony_ci if (cmd->sc_data_direction == DMA_TO_DEVICE) { 61762306a36Sopenharmony_ci cmd_pkt->control_flags = cpu_to_le16(CF_WRITE_DATA); 61862306a36Sopenharmony_ci qpair->counters.output_bytes += scsi_bufflen(cmd); 61962306a36Sopenharmony_ci qpair->counters.output_requests++; 62062306a36Sopenharmony_ci } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) { 62162306a36Sopenharmony_ci cmd_pkt->control_flags = cpu_to_le16(CF_READ_DATA); 62262306a36Sopenharmony_ci qpair->counters.input_bytes += scsi_bufflen(cmd); 62362306a36Sopenharmony_ci qpair->counters.input_requests++; 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci cur_seg = scsi_sglist(cmd); 62762306a36Sopenharmony_ci ctx = &sp->u.scmd.ct6_ctx; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci while (tot_dsds) { 63062306a36Sopenharmony_ci avail_dsds = (tot_dsds > QLA_DSDS_PER_IOCB) ? 63162306a36Sopenharmony_ci QLA_DSDS_PER_IOCB : tot_dsds; 63262306a36Sopenharmony_ci tot_dsds -= avail_dsds; 63362306a36Sopenharmony_ci dsd_list_len = (avail_dsds + 1) * QLA_DSD_SIZE; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci dsd_ptr = list_first_entry(&qpair->dsd_list, struct dsd_dma, list); 63662306a36Sopenharmony_ci next_dsd = dsd_ptr->dsd_addr; 63762306a36Sopenharmony_ci list_del(&dsd_ptr->list); 63862306a36Sopenharmony_ci qpair->dsd_avail--; 63962306a36Sopenharmony_ci list_add_tail(&dsd_ptr->list, &ctx->dsd_list); 64062306a36Sopenharmony_ci ctx->dsd_use_cnt++; 64162306a36Sopenharmony_ci qpair->dsd_inuse++; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci if (first_iocb) { 64462306a36Sopenharmony_ci first_iocb = 0; 64562306a36Sopenharmony_ci put_unaligned_le64(dsd_ptr->dsd_list_dma, 64662306a36Sopenharmony_ci &cmd_pkt->fcp_dsd.address); 64762306a36Sopenharmony_ci cmd_pkt->fcp_dsd.length = cpu_to_le32(dsd_list_len); 64862306a36Sopenharmony_ci } else { 64962306a36Sopenharmony_ci put_unaligned_le64(dsd_ptr->dsd_list_dma, 65062306a36Sopenharmony_ci &cur_dsd->address); 65162306a36Sopenharmony_ci cur_dsd->length = cpu_to_le32(dsd_list_len); 65262306a36Sopenharmony_ci cur_dsd++; 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci cur_dsd = next_dsd; 65562306a36Sopenharmony_ci while (avail_dsds) { 65662306a36Sopenharmony_ci append_dsd64(&cur_dsd, cur_seg); 65762306a36Sopenharmony_ci cur_seg = sg_next(cur_seg); 65862306a36Sopenharmony_ci avail_dsds--; 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci /* Null termination */ 66362306a36Sopenharmony_ci cur_dsd->address = 0; 66462306a36Sopenharmony_ci cur_dsd->length = 0; 66562306a36Sopenharmony_ci cur_dsd++; 66662306a36Sopenharmony_ci cmd_pkt->control_flags |= cpu_to_le16(CF_DATA_SEG_DESCR_ENABLE); 66762306a36Sopenharmony_ci return 0; 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci/* 67162306a36Sopenharmony_ci * qla24xx_calc_dsd_lists() - Determine number of DSD list required 67262306a36Sopenharmony_ci * for Command Type 6. 67362306a36Sopenharmony_ci * 67462306a36Sopenharmony_ci * @dsds: number of data segment descriptors needed 67562306a36Sopenharmony_ci * 67662306a36Sopenharmony_ci * Returns the number of dsd list needed to store @dsds. 67762306a36Sopenharmony_ci */ 67862306a36Sopenharmony_cistatic inline uint16_t 67962306a36Sopenharmony_ciqla24xx_calc_dsd_lists(uint16_t dsds) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci uint16_t dsd_lists = 0; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci dsd_lists = (dsds/QLA_DSDS_PER_IOCB); 68462306a36Sopenharmony_ci if (dsds % QLA_DSDS_PER_IOCB) 68562306a36Sopenharmony_ci dsd_lists++; 68662306a36Sopenharmony_ci return dsd_lists; 68762306a36Sopenharmony_ci} 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci/** 69162306a36Sopenharmony_ci * qla24xx_build_scsi_iocbs() - Build IOCB command utilizing Command Type 7 69262306a36Sopenharmony_ci * IOCB types. 69362306a36Sopenharmony_ci * 69462306a36Sopenharmony_ci * @sp: SRB command to process 69562306a36Sopenharmony_ci * @cmd_pkt: Command type 3 IOCB 69662306a36Sopenharmony_ci * @tot_dsds: Total number of segments to transfer 69762306a36Sopenharmony_ci * @req: pointer to request queue 69862306a36Sopenharmony_ci */ 69962306a36Sopenharmony_ciinline void 70062306a36Sopenharmony_ciqla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt, 70162306a36Sopenharmony_ci uint16_t tot_dsds, struct req_que *req) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci uint16_t avail_dsds; 70462306a36Sopenharmony_ci struct dsd64 *cur_dsd; 70562306a36Sopenharmony_ci scsi_qla_host_t *vha; 70662306a36Sopenharmony_ci struct scsi_cmnd *cmd; 70762306a36Sopenharmony_ci struct scatterlist *sg; 70862306a36Sopenharmony_ci int i; 70962306a36Sopenharmony_ci struct qla_qpair *qpair = sp->qpair; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci cmd = GET_CMD_SP(sp); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci /* Update entry type to indicate Command Type 3 IOCB */ 71462306a36Sopenharmony_ci put_unaligned_le32(COMMAND_TYPE_7, &cmd_pkt->entry_type); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci /* No data transfer */ 71762306a36Sopenharmony_ci if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { 71862306a36Sopenharmony_ci cmd_pkt->byte_count = cpu_to_le32(0); 71962306a36Sopenharmony_ci return; 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci vha = sp->vha; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci /* Set transfer direction */ 72562306a36Sopenharmony_ci if (cmd->sc_data_direction == DMA_TO_DEVICE) { 72662306a36Sopenharmony_ci cmd_pkt->task_mgmt_flags = cpu_to_le16(TMF_WRITE_DATA); 72762306a36Sopenharmony_ci qpair->counters.output_bytes += scsi_bufflen(cmd); 72862306a36Sopenharmony_ci qpair->counters.output_requests++; 72962306a36Sopenharmony_ci } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) { 73062306a36Sopenharmony_ci cmd_pkt->task_mgmt_flags = cpu_to_le16(TMF_READ_DATA); 73162306a36Sopenharmony_ci qpair->counters.input_bytes += scsi_bufflen(cmd); 73262306a36Sopenharmony_ci qpair->counters.input_requests++; 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci /* One DSD is available in the Command Type 3 IOCB */ 73662306a36Sopenharmony_ci avail_dsds = 1; 73762306a36Sopenharmony_ci cur_dsd = &cmd_pkt->dsd; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci /* Load data segments */ 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci scsi_for_each_sg(cmd, sg, tot_dsds, i) { 74262306a36Sopenharmony_ci cont_a64_entry_t *cont_pkt; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci /* Allocate additional continuation packets? */ 74562306a36Sopenharmony_ci if (avail_dsds == 0) { 74662306a36Sopenharmony_ci /* 74762306a36Sopenharmony_ci * Five DSDs are available in the Continuation 74862306a36Sopenharmony_ci * Type 1 IOCB. 74962306a36Sopenharmony_ci */ 75062306a36Sopenharmony_ci cont_pkt = qla2x00_prep_cont_type1_iocb(vha, req); 75162306a36Sopenharmony_ci cur_dsd = cont_pkt->dsd; 75262306a36Sopenharmony_ci avail_dsds = ARRAY_SIZE(cont_pkt->dsd); 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci append_dsd64(&cur_dsd, sg); 75662306a36Sopenharmony_ci avail_dsds--; 75762306a36Sopenharmony_ci } 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_cistruct fw_dif_context { 76162306a36Sopenharmony_ci __le32 ref_tag; 76262306a36Sopenharmony_ci __le16 app_tag; 76362306a36Sopenharmony_ci uint8_t ref_tag_mask[4]; /* Validation/Replacement Mask*/ 76462306a36Sopenharmony_ci uint8_t app_tag_mask[2]; /* Validation/Replacement Mask*/ 76562306a36Sopenharmony_ci}; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci/* 76862306a36Sopenharmony_ci * qla24xx_set_t10dif_tags_from_cmd - Extract Ref and App tags from SCSI command 76962306a36Sopenharmony_ci * 77062306a36Sopenharmony_ci */ 77162306a36Sopenharmony_cistatic inline void 77262306a36Sopenharmony_ciqla24xx_set_t10dif_tags(srb_t *sp, struct fw_dif_context *pkt, 77362306a36Sopenharmony_ci unsigned int protcnt) 77462306a36Sopenharmony_ci{ 77562306a36Sopenharmony_ci struct scsi_cmnd *cmd = GET_CMD_SP(sp); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci pkt->ref_tag = cpu_to_le32(scsi_prot_ref_tag(cmd)); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci if (cmd->prot_flags & SCSI_PROT_REF_CHECK && 78062306a36Sopenharmony_ci qla2x00_hba_err_chk_enabled(sp)) { 78162306a36Sopenharmony_ci pkt->ref_tag_mask[0] = 0xff; 78262306a36Sopenharmony_ci pkt->ref_tag_mask[1] = 0xff; 78362306a36Sopenharmony_ci pkt->ref_tag_mask[2] = 0xff; 78462306a36Sopenharmony_ci pkt->ref_tag_mask[3] = 0xff; 78562306a36Sopenharmony_ci } 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci pkt->app_tag = cpu_to_le16(0); 78862306a36Sopenharmony_ci pkt->app_tag_mask[0] = 0x0; 78962306a36Sopenharmony_ci pkt->app_tag_mask[1] = 0x0; 79062306a36Sopenharmony_ci} 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ciint 79362306a36Sopenharmony_ciqla24xx_get_one_block_sg(uint32_t blk_sz, struct qla2_sgx *sgx, 79462306a36Sopenharmony_ci uint32_t *partial) 79562306a36Sopenharmony_ci{ 79662306a36Sopenharmony_ci struct scatterlist *sg; 79762306a36Sopenharmony_ci uint32_t cumulative_partial, sg_len; 79862306a36Sopenharmony_ci dma_addr_t sg_dma_addr; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci if (sgx->num_bytes == sgx->tot_bytes) 80162306a36Sopenharmony_ci return 0; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci sg = sgx->cur_sg; 80462306a36Sopenharmony_ci cumulative_partial = sgx->tot_partial; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci sg_dma_addr = sg_dma_address(sg); 80762306a36Sopenharmony_ci sg_len = sg_dma_len(sg); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci sgx->dma_addr = sg_dma_addr + sgx->bytes_consumed; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci if ((cumulative_partial + (sg_len - sgx->bytes_consumed)) >= blk_sz) { 81262306a36Sopenharmony_ci sgx->dma_len = (blk_sz - cumulative_partial); 81362306a36Sopenharmony_ci sgx->tot_partial = 0; 81462306a36Sopenharmony_ci sgx->num_bytes += blk_sz; 81562306a36Sopenharmony_ci *partial = 0; 81662306a36Sopenharmony_ci } else { 81762306a36Sopenharmony_ci sgx->dma_len = sg_len - sgx->bytes_consumed; 81862306a36Sopenharmony_ci sgx->tot_partial += sgx->dma_len; 81962306a36Sopenharmony_ci *partial = 1; 82062306a36Sopenharmony_ci } 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci sgx->bytes_consumed += sgx->dma_len; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci if (sg_len == sgx->bytes_consumed) { 82562306a36Sopenharmony_ci sg = sg_next(sg); 82662306a36Sopenharmony_ci sgx->num_sg++; 82762306a36Sopenharmony_ci sgx->cur_sg = sg; 82862306a36Sopenharmony_ci sgx->bytes_consumed = 0; 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci return 1; 83262306a36Sopenharmony_ci} 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ciint 83562306a36Sopenharmony_ciqla24xx_walk_and_build_sglist_no_difb(struct qla_hw_data *ha, srb_t *sp, 83662306a36Sopenharmony_ci struct dsd64 *dsd, uint16_t tot_dsds, struct qla_tc_param *tc) 83762306a36Sopenharmony_ci{ 83862306a36Sopenharmony_ci void *next_dsd; 83962306a36Sopenharmony_ci uint8_t avail_dsds = 0; 84062306a36Sopenharmony_ci uint32_t dsd_list_len; 84162306a36Sopenharmony_ci struct dsd_dma *dsd_ptr; 84262306a36Sopenharmony_ci struct scatterlist *sg_prot; 84362306a36Sopenharmony_ci struct dsd64 *cur_dsd = dsd; 84462306a36Sopenharmony_ci uint16_t used_dsds = tot_dsds; 84562306a36Sopenharmony_ci uint32_t prot_int; /* protection interval */ 84662306a36Sopenharmony_ci uint32_t partial; 84762306a36Sopenharmony_ci struct qla2_sgx sgx; 84862306a36Sopenharmony_ci dma_addr_t sle_dma; 84962306a36Sopenharmony_ci uint32_t sle_dma_len, tot_prot_dma_len = 0; 85062306a36Sopenharmony_ci struct scsi_cmnd *cmd; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci memset(&sgx, 0, sizeof(struct qla2_sgx)); 85362306a36Sopenharmony_ci if (sp) { 85462306a36Sopenharmony_ci cmd = GET_CMD_SP(sp); 85562306a36Sopenharmony_ci prot_int = scsi_prot_interval(cmd); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci sgx.tot_bytes = scsi_bufflen(cmd); 85862306a36Sopenharmony_ci sgx.cur_sg = scsi_sglist(cmd); 85962306a36Sopenharmony_ci sgx.sp = sp; 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci sg_prot = scsi_prot_sglist(cmd); 86262306a36Sopenharmony_ci } else if (tc) { 86362306a36Sopenharmony_ci prot_int = tc->blk_sz; 86462306a36Sopenharmony_ci sgx.tot_bytes = tc->bufflen; 86562306a36Sopenharmony_ci sgx.cur_sg = tc->sg; 86662306a36Sopenharmony_ci sg_prot = tc->prot_sg; 86762306a36Sopenharmony_ci } else { 86862306a36Sopenharmony_ci BUG(); 86962306a36Sopenharmony_ci return 1; 87062306a36Sopenharmony_ci } 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci while (qla24xx_get_one_block_sg(prot_int, &sgx, &partial)) { 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci sle_dma = sgx.dma_addr; 87562306a36Sopenharmony_ci sle_dma_len = sgx.dma_len; 87662306a36Sopenharmony_cialloc_and_fill: 87762306a36Sopenharmony_ci /* Allocate additional continuation packets? */ 87862306a36Sopenharmony_ci if (avail_dsds == 0) { 87962306a36Sopenharmony_ci avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ? 88062306a36Sopenharmony_ci QLA_DSDS_PER_IOCB : used_dsds; 88162306a36Sopenharmony_ci dsd_list_len = (avail_dsds + 1) * 12; 88262306a36Sopenharmony_ci used_dsds -= avail_dsds; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci /* allocate tracking DS */ 88562306a36Sopenharmony_ci dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC); 88662306a36Sopenharmony_ci if (!dsd_ptr) 88762306a36Sopenharmony_ci return 1; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci /* allocate new list */ 89062306a36Sopenharmony_ci dsd_ptr->dsd_addr = next_dsd = 89162306a36Sopenharmony_ci dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC, 89262306a36Sopenharmony_ci &dsd_ptr->dsd_list_dma); 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci if (!next_dsd) { 89562306a36Sopenharmony_ci /* 89662306a36Sopenharmony_ci * Need to cleanup only this dsd_ptr, rest 89762306a36Sopenharmony_ci * will be done by sp_free_dma() 89862306a36Sopenharmony_ci */ 89962306a36Sopenharmony_ci kfree(dsd_ptr); 90062306a36Sopenharmony_ci return 1; 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci if (sp) { 90462306a36Sopenharmony_ci list_add_tail(&dsd_ptr->list, 90562306a36Sopenharmony_ci &sp->u.scmd.crc_ctx->dsd_list); 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci sp->flags |= SRB_CRC_CTX_DSD_VALID; 90862306a36Sopenharmony_ci } else { 90962306a36Sopenharmony_ci list_add_tail(&dsd_ptr->list, 91062306a36Sopenharmony_ci &(tc->ctx->dsd_list)); 91162306a36Sopenharmony_ci *tc->ctx_dsd_alloced = 1; 91262306a36Sopenharmony_ci } 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci /* add new list to cmd iocb or last list */ 91662306a36Sopenharmony_ci put_unaligned_le64(dsd_ptr->dsd_list_dma, 91762306a36Sopenharmony_ci &cur_dsd->address); 91862306a36Sopenharmony_ci cur_dsd->length = cpu_to_le32(dsd_list_len); 91962306a36Sopenharmony_ci cur_dsd = next_dsd; 92062306a36Sopenharmony_ci } 92162306a36Sopenharmony_ci put_unaligned_le64(sle_dma, &cur_dsd->address); 92262306a36Sopenharmony_ci cur_dsd->length = cpu_to_le32(sle_dma_len); 92362306a36Sopenharmony_ci cur_dsd++; 92462306a36Sopenharmony_ci avail_dsds--; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci if (partial == 0) { 92762306a36Sopenharmony_ci /* Got a full protection interval */ 92862306a36Sopenharmony_ci sle_dma = sg_dma_address(sg_prot) + tot_prot_dma_len; 92962306a36Sopenharmony_ci sle_dma_len = 8; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci tot_prot_dma_len += sle_dma_len; 93262306a36Sopenharmony_ci if (tot_prot_dma_len == sg_dma_len(sg_prot)) { 93362306a36Sopenharmony_ci tot_prot_dma_len = 0; 93462306a36Sopenharmony_ci sg_prot = sg_next(sg_prot); 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci partial = 1; /* So as to not re-enter this block */ 93862306a36Sopenharmony_ci goto alloc_and_fill; 93962306a36Sopenharmony_ci } 94062306a36Sopenharmony_ci } 94162306a36Sopenharmony_ci /* Null termination */ 94262306a36Sopenharmony_ci cur_dsd->address = 0; 94362306a36Sopenharmony_ci cur_dsd->length = 0; 94462306a36Sopenharmony_ci cur_dsd++; 94562306a36Sopenharmony_ci return 0; 94662306a36Sopenharmony_ci} 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ciint 94962306a36Sopenharmony_ciqla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, 95062306a36Sopenharmony_ci struct dsd64 *dsd, uint16_t tot_dsds, struct qla_tc_param *tc) 95162306a36Sopenharmony_ci{ 95262306a36Sopenharmony_ci void *next_dsd; 95362306a36Sopenharmony_ci uint8_t avail_dsds = 0; 95462306a36Sopenharmony_ci uint32_t dsd_list_len; 95562306a36Sopenharmony_ci struct dsd_dma *dsd_ptr; 95662306a36Sopenharmony_ci struct scatterlist *sg, *sgl; 95762306a36Sopenharmony_ci struct dsd64 *cur_dsd = dsd; 95862306a36Sopenharmony_ci int i; 95962306a36Sopenharmony_ci uint16_t used_dsds = tot_dsds; 96062306a36Sopenharmony_ci struct scsi_cmnd *cmd; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci if (sp) { 96362306a36Sopenharmony_ci cmd = GET_CMD_SP(sp); 96462306a36Sopenharmony_ci sgl = scsi_sglist(cmd); 96562306a36Sopenharmony_ci } else if (tc) { 96662306a36Sopenharmony_ci sgl = tc->sg; 96762306a36Sopenharmony_ci } else { 96862306a36Sopenharmony_ci BUG(); 96962306a36Sopenharmony_ci return 1; 97062306a36Sopenharmony_ci } 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci for_each_sg(sgl, sg, tot_dsds, i) { 97462306a36Sopenharmony_ci /* Allocate additional continuation packets? */ 97562306a36Sopenharmony_ci if (avail_dsds == 0) { 97662306a36Sopenharmony_ci avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ? 97762306a36Sopenharmony_ci QLA_DSDS_PER_IOCB : used_dsds; 97862306a36Sopenharmony_ci dsd_list_len = (avail_dsds + 1) * 12; 97962306a36Sopenharmony_ci used_dsds -= avail_dsds; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci /* allocate tracking DS */ 98262306a36Sopenharmony_ci dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC); 98362306a36Sopenharmony_ci if (!dsd_ptr) 98462306a36Sopenharmony_ci return 1; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci /* allocate new list */ 98762306a36Sopenharmony_ci dsd_ptr->dsd_addr = next_dsd = 98862306a36Sopenharmony_ci dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC, 98962306a36Sopenharmony_ci &dsd_ptr->dsd_list_dma); 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci if (!next_dsd) { 99262306a36Sopenharmony_ci /* 99362306a36Sopenharmony_ci * Need to cleanup only this dsd_ptr, rest 99462306a36Sopenharmony_ci * will be done by sp_free_dma() 99562306a36Sopenharmony_ci */ 99662306a36Sopenharmony_ci kfree(dsd_ptr); 99762306a36Sopenharmony_ci return 1; 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci if (sp) { 100162306a36Sopenharmony_ci list_add_tail(&dsd_ptr->list, 100262306a36Sopenharmony_ci &sp->u.scmd.crc_ctx->dsd_list); 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci sp->flags |= SRB_CRC_CTX_DSD_VALID; 100562306a36Sopenharmony_ci } else { 100662306a36Sopenharmony_ci list_add_tail(&dsd_ptr->list, 100762306a36Sopenharmony_ci &(tc->ctx->dsd_list)); 100862306a36Sopenharmony_ci *tc->ctx_dsd_alloced = 1; 100962306a36Sopenharmony_ci } 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci /* add new list to cmd iocb or last list */ 101262306a36Sopenharmony_ci put_unaligned_le64(dsd_ptr->dsd_list_dma, 101362306a36Sopenharmony_ci &cur_dsd->address); 101462306a36Sopenharmony_ci cur_dsd->length = cpu_to_le32(dsd_list_len); 101562306a36Sopenharmony_ci cur_dsd = next_dsd; 101662306a36Sopenharmony_ci } 101762306a36Sopenharmony_ci append_dsd64(&cur_dsd, sg); 101862306a36Sopenharmony_ci avail_dsds--; 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci } 102162306a36Sopenharmony_ci /* Null termination */ 102262306a36Sopenharmony_ci cur_dsd->address = 0; 102362306a36Sopenharmony_ci cur_dsd->length = 0; 102462306a36Sopenharmony_ci cur_dsd++; 102562306a36Sopenharmony_ci return 0; 102662306a36Sopenharmony_ci} 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ciint 102962306a36Sopenharmony_ciqla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp, 103062306a36Sopenharmony_ci struct dsd64 *cur_dsd, uint16_t tot_dsds, struct qla_tgt_cmd *tc) 103162306a36Sopenharmony_ci{ 103262306a36Sopenharmony_ci struct dsd_dma *dsd_ptr = NULL, *dif_dsd, *nxt_dsd; 103362306a36Sopenharmony_ci struct scatterlist *sg, *sgl; 103462306a36Sopenharmony_ci struct crc_context *difctx = NULL; 103562306a36Sopenharmony_ci struct scsi_qla_host *vha; 103662306a36Sopenharmony_ci uint dsd_list_len; 103762306a36Sopenharmony_ci uint avail_dsds = 0; 103862306a36Sopenharmony_ci uint used_dsds = tot_dsds; 103962306a36Sopenharmony_ci bool dif_local_dma_alloc = false; 104062306a36Sopenharmony_ci bool direction_to_device = false; 104162306a36Sopenharmony_ci int i; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci if (sp) { 104462306a36Sopenharmony_ci struct scsi_cmnd *cmd = GET_CMD_SP(sp); 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci sgl = scsi_prot_sglist(cmd); 104762306a36Sopenharmony_ci vha = sp->vha; 104862306a36Sopenharmony_ci difctx = sp->u.scmd.crc_ctx; 104962306a36Sopenharmony_ci direction_to_device = cmd->sc_data_direction == DMA_TO_DEVICE; 105062306a36Sopenharmony_ci ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe021, 105162306a36Sopenharmony_ci "%s: scsi_cmnd: %p, crc_ctx: %p, sp: %p\n", 105262306a36Sopenharmony_ci __func__, cmd, difctx, sp); 105362306a36Sopenharmony_ci } else if (tc) { 105462306a36Sopenharmony_ci vha = tc->vha; 105562306a36Sopenharmony_ci sgl = tc->prot_sg; 105662306a36Sopenharmony_ci difctx = tc->ctx; 105762306a36Sopenharmony_ci direction_to_device = tc->dma_data_direction == DMA_TO_DEVICE; 105862306a36Sopenharmony_ci } else { 105962306a36Sopenharmony_ci BUG(); 106062306a36Sopenharmony_ci return 1; 106162306a36Sopenharmony_ci } 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe021, 106462306a36Sopenharmony_ci "%s: enter (write=%u)\n", __func__, direction_to_device); 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci /* if initiator doing write or target doing read */ 106762306a36Sopenharmony_ci if (direction_to_device) { 106862306a36Sopenharmony_ci for_each_sg(sgl, sg, tot_dsds, i) { 106962306a36Sopenharmony_ci u64 sle_phys = sg_phys(sg); 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci /* If SGE addr + len flips bits in upper 32-bits */ 107262306a36Sopenharmony_ci if (MSD(sle_phys + sg->length) ^ MSD(sle_phys)) { 107362306a36Sopenharmony_ci ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe022, 107462306a36Sopenharmony_ci "%s: page boundary crossing (phys=%llx len=%x)\n", 107562306a36Sopenharmony_ci __func__, sle_phys, sg->length); 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci if (difctx) { 107862306a36Sopenharmony_ci ha->dif_bundle_crossed_pages++; 107962306a36Sopenharmony_ci dif_local_dma_alloc = true; 108062306a36Sopenharmony_ci } else { 108162306a36Sopenharmony_ci ql_dbg(ql_dbg_tgt + ql_dbg_verbose, 108262306a36Sopenharmony_ci vha, 0xe022, 108362306a36Sopenharmony_ci "%s: difctx pointer is NULL\n", 108462306a36Sopenharmony_ci __func__); 108562306a36Sopenharmony_ci } 108662306a36Sopenharmony_ci break; 108762306a36Sopenharmony_ci } 108862306a36Sopenharmony_ci } 108962306a36Sopenharmony_ci ha->dif_bundle_writes++; 109062306a36Sopenharmony_ci } else { 109162306a36Sopenharmony_ci ha->dif_bundle_reads++; 109262306a36Sopenharmony_ci } 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci if (ql2xdifbundlinginternalbuffers) 109562306a36Sopenharmony_ci dif_local_dma_alloc = direction_to_device; 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci if (dif_local_dma_alloc) { 109862306a36Sopenharmony_ci u32 track_difbundl_buf = 0; 109962306a36Sopenharmony_ci u32 ldma_sg_len = 0; 110062306a36Sopenharmony_ci u8 ldma_needed = 1; 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci difctx->no_dif_bundl = 0; 110362306a36Sopenharmony_ci difctx->dif_bundl_len = 0; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci /* Track DSD buffers */ 110662306a36Sopenharmony_ci INIT_LIST_HEAD(&difctx->ldif_dsd_list); 110762306a36Sopenharmony_ci /* Track local DMA buffers */ 110862306a36Sopenharmony_ci INIT_LIST_HEAD(&difctx->ldif_dma_hndl_list); 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci for_each_sg(sgl, sg, tot_dsds, i) { 111162306a36Sopenharmony_ci u32 sglen = sg_dma_len(sg); 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe023, 111462306a36Sopenharmony_ci "%s: sg[%x] (phys=%llx sglen=%x) ldma_sg_len: %x dif_bundl_len: %x ldma_needed: %x\n", 111562306a36Sopenharmony_ci __func__, i, (u64)sg_phys(sg), sglen, ldma_sg_len, 111662306a36Sopenharmony_ci difctx->dif_bundl_len, ldma_needed); 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci while (sglen) { 111962306a36Sopenharmony_ci u32 xfrlen = 0; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci if (ldma_needed) { 112262306a36Sopenharmony_ci /* 112362306a36Sopenharmony_ci * Allocate list item to store 112462306a36Sopenharmony_ci * the DMA buffers 112562306a36Sopenharmony_ci */ 112662306a36Sopenharmony_ci dsd_ptr = kzalloc(sizeof(*dsd_ptr), 112762306a36Sopenharmony_ci GFP_ATOMIC); 112862306a36Sopenharmony_ci if (!dsd_ptr) { 112962306a36Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe024, 113062306a36Sopenharmony_ci "%s: failed alloc dsd_ptr\n", 113162306a36Sopenharmony_ci __func__); 113262306a36Sopenharmony_ci return 1; 113362306a36Sopenharmony_ci } 113462306a36Sopenharmony_ci ha->dif_bundle_kallocs++; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci /* allocate dma buffer */ 113762306a36Sopenharmony_ci dsd_ptr->dsd_addr = dma_pool_alloc 113862306a36Sopenharmony_ci (ha->dif_bundl_pool, GFP_ATOMIC, 113962306a36Sopenharmony_ci &dsd_ptr->dsd_list_dma); 114062306a36Sopenharmony_ci if (!dsd_ptr->dsd_addr) { 114162306a36Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe024, 114262306a36Sopenharmony_ci "%s: failed alloc ->dsd_ptr\n", 114362306a36Sopenharmony_ci __func__); 114462306a36Sopenharmony_ci /* 114562306a36Sopenharmony_ci * need to cleanup only this 114662306a36Sopenharmony_ci * dsd_ptr rest will be done 114762306a36Sopenharmony_ci * by sp_free_dma() 114862306a36Sopenharmony_ci */ 114962306a36Sopenharmony_ci kfree(dsd_ptr); 115062306a36Sopenharmony_ci ha->dif_bundle_kallocs--; 115162306a36Sopenharmony_ci return 1; 115262306a36Sopenharmony_ci } 115362306a36Sopenharmony_ci ha->dif_bundle_dma_allocs++; 115462306a36Sopenharmony_ci ldma_needed = 0; 115562306a36Sopenharmony_ci difctx->no_dif_bundl++; 115662306a36Sopenharmony_ci list_add_tail(&dsd_ptr->list, 115762306a36Sopenharmony_ci &difctx->ldif_dma_hndl_list); 115862306a36Sopenharmony_ci } 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci /* xfrlen is min of dma pool size and sglen */ 116162306a36Sopenharmony_ci xfrlen = (sglen > 116262306a36Sopenharmony_ci (DIF_BUNDLING_DMA_POOL_SIZE - ldma_sg_len)) ? 116362306a36Sopenharmony_ci DIF_BUNDLING_DMA_POOL_SIZE - ldma_sg_len : 116462306a36Sopenharmony_ci sglen; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci /* replace with local allocated dma buffer */ 116762306a36Sopenharmony_ci sg_pcopy_to_buffer(sgl, sg_nents(sgl), 116862306a36Sopenharmony_ci dsd_ptr->dsd_addr + ldma_sg_len, xfrlen, 116962306a36Sopenharmony_ci difctx->dif_bundl_len); 117062306a36Sopenharmony_ci difctx->dif_bundl_len += xfrlen; 117162306a36Sopenharmony_ci sglen -= xfrlen; 117262306a36Sopenharmony_ci ldma_sg_len += xfrlen; 117362306a36Sopenharmony_ci if (ldma_sg_len == DIF_BUNDLING_DMA_POOL_SIZE || 117462306a36Sopenharmony_ci sg_is_last(sg)) { 117562306a36Sopenharmony_ci ldma_needed = 1; 117662306a36Sopenharmony_ci ldma_sg_len = 0; 117762306a36Sopenharmony_ci } 117862306a36Sopenharmony_ci } 117962306a36Sopenharmony_ci } 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci track_difbundl_buf = used_dsds = difctx->no_dif_bundl; 118262306a36Sopenharmony_ci ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe025, 118362306a36Sopenharmony_ci "dif_bundl_len=%x, no_dif_bundl=%x track_difbundl_buf: %x\n", 118462306a36Sopenharmony_ci difctx->dif_bundl_len, difctx->no_dif_bundl, 118562306a36Sopenharmony_ci track_difbundl_buf); 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci if (sp) 118862306a36Sopenharmony_ci sp->flags |= SRB_DIF_BUNDL_DMA_VALID; 118962306a36Sopenharmony_ci else 119062306a36Sopenharmony_ci tc->prot_flags = DIF_BUNDL_DMA_VALID; 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci list_for_each_entry_safe(dif_dsd, nxt_dsd, 119362306a36Sopenharmony_ci &difctx->ldif_dma_hndl_list, list) { 119462306a36Sopenharmony_ci u32 sglen = (difctx->dif_bundl_len > 119562306a36Sopenharmony_ci DIF_BUNDLING_DMA_POOL_SIZE) ? 119662306a36Sopenharmony_ci DIF_BUNDLING_DMA_POOL_SIZE : difctx->dif_bundl_len; 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci BUG_ON(track_difbundl_buf == 0); 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci /* Allocate additional continuation packets? */ 120162306a36Sopenharmony_ci if (avail_dsds == 0) { 120262306a36Sopenharmony_ci ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 120362306a36Sopenharmony_ci 0xe024, 120462306a36Sopenharmony_ci "%s: adding continuation iocb's\n", 120562306a36Sopenharmony_ci __func__); 120662306a36Sopenharmony_ci avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ? 120762306a36Sopenharmony_ci QLA_DSDS_PER_IOCB : used_dsds; 120862306a36Sopenharmony_ci dsd_list_len = (avail_dsds + 1) * 12; 120962306a36Sopenharmony_ci used_dsds -= avail_dsds; 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci /* allocate tracking DS */ 121262306a36Sopenharmony_ci dsd_ptr = kzalloc(sizeof(*dsd_ptr), GFP_ATOMIC); 121362306a36Sopenharmony_ci if (!dsd_ptr) { 121462306a36Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe026, 121562306a36Sopenharmony_ci "%s: failed alloc dsd_ptr\n", 121662306a36Sopenharmony_ci __func__); 121762306a36Sopenharmony_ci return 1; 121862306a36Sopenharmony_ci } 121962306a36Sopenharmony_ci ha->dif_bundle_kallocs++; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci difctx->no_ldif_dsd++; 122262306a36Sopenharmony_ci /* allocate new list */ 122362306a36Sopenharmony_ci dsd_ptr->dsd_addr = 122462306a36Sopenharmony_ci dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC, 122562306a36Sopenharmony_ci &dsd_ptr->dsd_list_dma); 122662306a36Sopenharmony_ci if (!dsd_ptr->dsd_addr) { 122762306a36Sopenharmony_ci ql_dbg(ql_dbg_tgt, vha, 0xe026, 122862306a36Sopenharmony_ci "%s: failed alloc ->dsd_addr\n", 122962306a36Sopenharmony_ci __func__); 123062306a36Sopenharmony_ci /* 123162306a36Sopenharmony_ci * need to cleanup only this dsd_ptr 123262306a36Sopenharmony_ci * rest will be done by sp_free_dma() 123362306a36Sopenharmony_ci */ 123462306a36Sopenharmony_ci kfree(dsd_ptr); 123562306a36Sopenharmony_ci ha->dif_bundle_kallocs--; 123662306a36Sopenharmony_ci return 1; 123762306a36Sopenharmony_ci } 123862306a36Sopenharmony_ci ha->dif_bundle_dma_allocs++; 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci if (sp) { 124162306a36Sopenharmony_ci list_add_tail(&dsd_ptr->list, 124262306a36Sopenharmony_ci &difctx->ldif_dsd_list); 124362306a36Sopenharmony_ci sp->flags |= SRB_CRC_CTX_DSD_VALID; 124462306a36Sopenharmony_ci } else { 124562306a36Sopenharmony_ci list_add_tail(&dsd_ptr->list, 124662306a36Sopenharmony_ci &difctx->ldif_dsd_list); 124762306a36Sopenharmony_ci tc->ctx_dsd_alloced = 1; 124862306a36Sopenharmony_ci } 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci /* add new list to cmd iocb or last list */ 125162306a36Sopenharmony_ci put_unaligned_le64(dsd_ptr->dsd_list_dma, 125262306a36Sopenharmony_ci &cur_dsd->address); 125362306a36Sopenharmony_ci cur_dsd->length = cpu_to_le32(dsd_list_len); 125462306a36Sopenharmony_ci cur_dsd = dsd_ptr->dsd_addr; 125562306a36Sopenharmony_ci } 125662306a36Sopenharmony_ci put_unaligned_le64(dif_dsd->dsd_list_dma, 125762306a36Sopenharmony_ci &cur_dsd->address); 125862306a36Sopenharmony_ci cur_dsd->length = cpu_to_le32(sglen); 125962306a36Sopenharmony_ci cur_dsd++; 126062306a36Sopenharmony_ci avail_dsds--; 126162306a36Sopenharmony_ci difctx->dif_bundl_len -= sglen; 126262306a36Sopenharmony_ci track_difbundl_buf--; 126362306a36Sopenharmony_ci } 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe026, 126662306a36Sopenharmony_ci "%s: no_ldif_dsd:%x, no_dif_bundl:%x\n", __func__, 126762306a36Sopenharmony_ci difctx->no_ldif_dsd, difctx->no_dif_bundl); 126862306a36Sopenharmony_ci } else { 126962306a36Sopenharmony_ci for_each_sg(sgl, sg, tot_dsds, i) { 127062306a36Sopenharmony_ci /* Allocate additional continuation packets? */ 127162306a36Sopenharmony_ci if (avail_dsds == 0) { 127262306a36Sopenharmony_ci avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ? 127362306a36Sopenharmony_ci QLA_DSDS_PER_IOCB : used_dsds; 127462306a36Sopenharmony_ci dsd_list_len = (avail_dsds + 1) * 12; 127562306a36Sopenharmony_ci used_dsds -= avail_dsds; 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci /* allocate tracking DS */ 127862306a36Sopenharmony_ci dsd_ptr = kzalloc(sizeof(*dsd_ptr), GFP_ATOMIC); 127962306a36Sopenharmony_ci if (!dsd_ptr) { 128062306a36Sopenharmony_ci ql_dbg(ql_dbg_tgt + ql_dbg_verbose, 128162306a36Sopenharmony_ci vha, 0xe027, 128262306a36Sopenharmony_ci "%s: failed alloc dsd_dma...\n", 128362306a36Sopenharmony_ci __func__); 128462306a36Sopenharmony_ci return 1; 128562306a36Sopenharmony_ci } 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci /* allocate new list */ 128862306a36Sopenharmony_ci dsd_ptr->dsd_addr = 128962306a36Sopenharmony_ci dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC, 129062306a36Sopenharmony_ci &dsd_ptr->dsd_list_dma); 129162306a36Sopenharmony_ci if (!dsd_ptr->dsd_addr) { 129262306a36Sopenharmony_ci /* need to cleanup only this dsd_ptr */ 129362306a36Sopenharmony_ci /* rest will be done by sp_free_dma() */ 129462306a36Sopenharmony_ci kfree(dsd_ptr); 129562306a36Sopenharmony_ci return 1; 129662306a36Sopenharmony_ci } 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci if (sp) { 129962306a36Sopenharmony_ci list_add_tail(&dsd_ptr->list, 130062306a36Sopenharmony_ci &difctx->dsd_list); 130162306a36Sopenharmony_ci sp->flags |= SRB_CRC_CTX_DSD_VALID; 130262306a36Sopenharmony_ci } else { 130362306a36Sopenharmony_ci list_add_tail(&dsd_ptr->list, 130462306a36Sopenharmony_ci &difctx->dsd_list); 130562306a36Sopenharmony_ci tc->ctx_dsd_alloced = 1; 130662306a36Sopenharmony_ci } 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci /* add new list to cmd iocb or last list */ 130962306a36Sopenharmony_ci put_unaligned_le64(dsd_ptr->dsd_list_dma, 131062306a36Sopenharmony_ci &cur_dsd->address); 131162306a36Sopenharmony_ci cur_dsd->length = cpu_to_le32(dsd_list_len); 131262306a36Sopenharmony_ci cur_dsd = dsd_ptr->dsd_addr; 131362306a36Sopenharmony_ci } 131462306a36Sopenharmony_ci append_dsd64(&cur_dsd, sg); 131562306a36Sopenharmony_ci avail_dsds--; 131662306a36Sopenharmony_ci } 131762306a36Sopenharmony_ci } 131862306a36Sopenharmony_ci /* Null termination */ 131962306a36Sopenharmony_ci cur_dsd->address = 0; 132062306a36Sopenharmony_ci cur_dsd->length = 0; 132162306a36Sopenharmony_ci cur_dsd++; 132262306a36Sopenharmony_ci return 0; 132362306a36Sopenharmony_ci} 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci/** 132662306a36Sopenharmony_ci * qla24xx_build_scsi_crc_2_iocbs() - Build IOCB command utilizing Command 132762306a36Sopenharmony_ci * Type 6 IOCB types. 132862306a36Sopenharmony_ci * 132962306a36Sopenharmony_ci * @sp: SRB command to process 133062306a36Sopenharmony_ci * @cmd_pkt: Command type 3 IOCB 133162306a36Sopenharmony_ci * @tot_dsds: Total number of segments to transfer 133262306a36Sopenharmony_ci * @tot_prot_dsds: Total number of segments with protection information 133362306a36Sopenharmony_ci * @fw_prot_opts: Protection options to be passed to firmware 133462306a36Sopenharmony_ci */ 133562306a36Sopenharmony_cistatic inline int 133662306a36Sopenharmony_ciqla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, 133762306a36Sopenharmony_ci uint16_t tot_dsds, uint16_t tot_prot_dsds, uint16_t fw_prot_opts) 133862306a36Sopenharmony_ci{ 133962306a36Sopenharmony_ci struct dsd64 *cur_dsd; 134062306a36Sopenharmony_ci __be32 *fcp_dl; 134162306a36Sopenharmony_ci scsi_qla_host_t *vha; 134262306a36Sopenharmony_ci struct scsi_cmnd *cmd; 134362306a36Sopenharmony_ci uint32_t total_bytes = 0; 134462306a36Sopenharmony_ci uint32_t data_bytes; 134562306a36Sopenharmony_ci uint32_t dif_bytes; 134662306a36Sopenharmony_ci uint8_t bundling = 1; 134762306a36Sopenharmony_ci uint16_t blk_size; 134862306a36Sopenharmony_ci struct crc_context *crc_ctx_pkt = NULL; 134962306a36Sopenharmony_ci struct qla_hw_data *ha; 135062306a36Sopenharmony_ci uint8_t additional_fcpcdb_len; 135162306a36Sopenharmony_ci uint16_t fcp_cmnd_len; 135262306a36Sopenharmony_ci struct fcp_cmnd *fcp_cmnd; 135362306a36Sopenharmony_ci dma_addr_t crc_ctx_dma; 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci cmd = GET_CMD_SP(sp); 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci /* Update entry type to indicate Command Type CRC_2 IOCB */ 135862306a36Sopenharmony_ci put_unaligned_le32(COMMAND_TYPE_CRC_2, &cmd_pkt->entry_type); 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci vha = sp->vha; 136162306a36Sopenharmony_ci ha = vha->hw; 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci /* No data transfer */ 136462306a36Sopenharmony_ci data_bytes = scsi_bufflen(cmd); 136562306a36Sopenharmony_ci if (!data_bytes || cmd->sc_data_direction == DMA_NONE) { 136662306a36Sopenharmony_ci cmd_pkt->byte_count = cpu_to_le32(0); 136762306a36Sopenharmony_ci return QLA_SUCCESS; 136862306a36Sopenharmony_ci } 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci cmd_pkt->vp_index = sp->vha->vp_idx; 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci /* Set transfer direction */ 137362306a36Sopenharmony_ci if (cmd->sc_data_direction == DMA_TO_DEVICE) { 137462306a36Sopenharmony_ci cmd_pkt->control_flags = 137562306a36Sopenharmony_ci cpu_to_le16(CF_WRITE_DATA); 137662306a36Sopenharmony_ci } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) { 137762306a36Sopenharmony_ci cmd_pkt->control_flags = 137862306a36Sopenharmony_ci cpu_to_le16(CF_READ_DATA); 137962306a36Sopenharmony_ci } 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) || 138262306a36Sopenharmony_ci (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_STRIP) || 138362306a36Sopenharmony_ci (scsi_get_prot_op(cmd) == SCSI_PROT_READ_STRIP) || 138462306a36Sopenharmony_ci (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_INSERT)) 138562306a36Sopenharmony_ci bundling = 0; 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci /* Allocate CRC context from global pool */ 138862306a36Sopenharmony_ci crc_ctx_pkt = sp->u.scmd.crc_ctx = 138962306a36Sopenharmony_ci dma_pool_zalloc(ha->dl_dma_pool, GFP_ATOMIC, &crc_ctx_dma); 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci if (!crc_ctx_pkt) 139262306a36Sopenharmony_ci goto crc_queuing_error; 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci crc_ctx_pkt->crc_ctx_dma = crc_ctx_dma; 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci sp->flags |= SRB_CRC_CTX_DMA_VALID; 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci /* Set handle */ 139962306a36Sopenharmony_ci crc_ctx_pkt->handle = cmd_pkt->handle; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci INIT_LIST_HEAD(&crc_ctx_pkt->dsd_list); 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci qla24xx_set_t10dif_tags(sp, (struct fw_dif_context *) 140462306a36Sopenharmony_ci &crc_ctx_pkt->ref_tag, tot_prot_dsds); 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci put_unaligned_le64(crc_ctx_dma, &cmd_pkt->crc_context_address); 140762306a36Sopenharmony_ci cmd_pkt->crc_context_len = cpu_to_le16(CRC_CONTEXT_LEN_FW); 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci /* Determine SCSI command length -- align to 4 byte boundary */ 141062306a36Sopenharmony_ci if (cmd->cmd_len > 16) { 141162306a36Sopenharmony_ci additional_fcpcdb_len = cmd->cmd_len - 16; 141262306a36Sopenharmony_ci if ((cmd->cmd_len % 4) != 0) { 141362306a36Sopenharmony_ci /* SCSI cmd > 16 bytes must be multiple of 4 */ 141462306a36Sopenharmony_ci goto crc_queuing_error; 141562306a36Sopenharmony_ci } 141662306a36Sopenharmony_ci fcp_cmnd_len = 12 + cmd->cmd_len + 4; 141762306a36Sopenharmony_ci } else { 141862306a36Sopenharmony_ci additional_fcpcdb_len = 0; 141962306a36Sopenharmony_ci fcp_cmnd_len = 12 + 16 + 4; 142062306a36Sopenharmony_ci } 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci fcp_cmnd = &crc_ctx_pkt->fcp_cmnd; 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci fcp_cmnd->additional_cdb_len = additional_fcpcdb_len; 142562306a36Sopenharmony_ci if (cmd->sc_data_direction == DMA_TO_DEVICE) 142662306a36Sopenharmony_ci fcp_cmnd->additional_cdb_len |= 1; 142762306a36Sopenharmony_ci else if (cmd->sc_data_direction == DMA_FROM_DEVICE) 142862306a36Sopenharmony_ci fcp_cmnd->additional_cdb_len |= 2; 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci int_to_scsilun(cmd->device->lun, &fcp_cmnd->lun); 143162306a36Sopenharmony_ci memcpy(fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len); 143262306a36Sopenharmony_ci cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(fcp_cmnd_len); 143362306a36Sopenharmony_ci put_unaligned_le64(crc_ctx_dma + CRC_CONTEXT_FCPCMND_OFF, 143462306a36Sopenharmony_ci &cmd_pkt->fcp_cmnd_dseg_address); 143562306a36Sopenharmony_ci fcp_cmnd->task_management = 0; 143662306a36Sopenharmony_ci fcp_cmnd->task_attribute = TSK_SIMPLE; 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci cmd_pkt->fcp_rsp_dseg_len = 0; /* Let response come in status iocb */ 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci /* Compute dif len and adjust data len to incude protection */ 144162306a36Sopenharmony_ci dif_bytes = 0; 144262306a36Sopenharmony_ci blk_size = cmd->device->sector_size; 144362306a36Sopenharmony_ci dif_bytes = (data_bytes / blk_size) * 8; 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci switch (scsi_get_prot_op(GET_CMD_SP(sp))) { 144662306a36Sopenharmony_ci case SCSI_PROT_READ_INSERT: 144762306a36Sopenharmony_ci case SCSI_PROT_WRITE_STRIP: 144862306a36Sopenharmony_ci total_bytes = data_bytes; 144962306a36Sopenharmony_ci data_bytes += dif_bytes; 145062306a36Sopenharmony_ci break; 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci case SCSI_PROT_READ_STRIP: 145362306a36Sopenharmony_ci case SCSI_PROT_WRITE_INSERT: 145462306a36Sopenharmony_ci case SCSI_PROT_READ_PASS: 145562306a36Sopenharmony_ci case SCSI_PROT_WRITE_PASS: 145662306a36Sopenharmony_ci total_bytes = data_bytes + dif_bytes; 145762306a36Sopenharmony_ci break; 145862306a36Sopenharmony_ci default: 145962306a36Sopenharmony_ci BUG(); 146062306a36Sopenharmony_ci } 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci if (!qla2x00_hba_err_chk_enabled(sp)) 146362306a36Sopenharmony_ci fw_prot_opts |= 0x10; /* Disable Guard tag checking */ 146462306a36Sopenharmony_ci /* HBA error checking enabled */ 146562306a36Sopenharmony_ci else if (IS_PI_UNINIT_CAPABLE(ha)) { 146662306a36Sopenharmony_ci if ((scsi_get_prot_type(GET_CMD_SP(sp)) == SCSI_PROT_DIF_TYPE1) 146762306a36Sopenharmony_ci || (scsi_get_prot_type(GET_CMD_SP(sp)) == 146862306a36Sopenharmony_ci SCSI_PROT_DIF_TYPE2)) 146962306a36Sopenharmony_ci fw_prot_opts |= BIT_10; 147062306a36Sopenharmony_ci else if (scsi_get_prot_type(GET_CMD_SP(sp)) == 147162306a36Sopenharmony_ci SCSI_PROT_DIF_TYPE3) 147262306a36Sopenharmony_ci fw_prot_opts |= BIT_11; 147362306a36Sopenharmony_ci } 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci if (!bundling) { 147662306a36Sopenharmony_ci cur_dsd = &crc_ctx_pkt->u.nobundling.data_dsd[0]; 147762306a36Sopenharmony_ci } else { 147862306a36Sopenharmony_ci /* 147962306a36Sopenharmony_ci * Configure Bundling if we need to fetch interlaving 148062306a36Sopenharmony_ci * protection PCI accesses 148162306a36Sopenharmony_ci */ 148262306a36Sopenharmony_ci fw_prot_opts |= PO_ENABLE_DIF_BUNDLING; 148362306a36Sopenharmony_ci crc_ctx_pkt->u.bundling.dif_byte_count = cpu_to_le32(dif_bytes); 148462306a36Sopenharmony_ci crc_ctx_pkt->u.bundling.dseg_count = cpu_to_le16(tot_dsds - 148562306a36Sopenharmony_ci tot_prot_dsds); 148662306a36Sopenharmony_ci cur_dsd = &crc_ctx_pkt->u.bundling.data_dsd[0]; 148762306a36Sopenharmony_ci } 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci /* Finish the common fields of CRC pkt */ 149062306a36Sopenharmony_ci crc_ctx_pkt->blk_size = cpu_to_le16(blk_size); 149162306a36Sopenharmony_ci crc_ctx_pkt->prot_opts = cpu_to_le16(fw_prot_opts); 149262306a36Sopenharmony_ci crc_ctx_pkt->byte_count = cpu_to_le32(data_bytes); 149362306a36Sopenharmony_ci crc_ctx_pkt->guard_seed = cpu_to_le16(0); 149462306a36Sopenharmony_ci /* Fibre channel byte count */ 149562306a36Sopenharmony_ci cmd_pkt->byte_count = cpu_to_le32(total_bytes); 149662306a36Sopenharmony_ci fcp_dl = (__be32 *)(crc_ctx_pkt->fcp_cmnd.cdb + 16 + 149762306a36Sopenharmony_ci additional_fcpcdb_len); 149862306a36Sopenharmony_ci *fcp_dl = htonl(total_bytes); 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci if (!data_bytes || cmd->sc_data_direction == DMA_NONE) { 150162306a36Sopenharmony_ci cmd_pkt->byte_count = cpu_to_le32(0); 150262306a36Sopenharmony_ci return QLA_SUCCESS; 150362306a36Sopenharmony_ci } 150462306a36Sopenharmony_ci /* Walks data segments */ 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci cmd_pkt->control_flags |= cpu_to_le16(CF_DATA_SEG_DESCR_ENABLE); 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci if (!bundling && tot_prot_dsds) { 150962306a36Sopenharmony_ci if (qla24xx_walk_and_build_sglist_no_difb(ha, sp, 151062306a36Sopenharmony_ci cur_dsd, tot_dsds, NULL)) 151162306a36Sopenharmony_ci goto crc_queuing_error; 151262306a36Sopenharmony_ci } else if (qla24xx_walk_and_build_sglist(ha, sp, cur_dsd, 151362306a36Sopenharmony_ci (tot_dsds - tot_prot_dsds), NULL)) 151462306a36Sopenharmony_ci goto crc_queuing_error; 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci if (bundling && tot_prot_dsds) { 151762306a36Sopenharmony_ci /* Walks dif segments */ 151862306a36Sopenharmony_ci cmd_pkt->control_flags |= cpu_to_le16(CF_DIF_SEG_DESCR_ENABLE); 151962306a36Sopenharmony_ci cur_dsd = &crc_ctx_pkt->u.bundling.dif_dsd; 152062306a36Sopenharmony_ci if (qla24xx_walk_and_build_prot_sglist(ha, sp, cur_dsd, 152162306a36Sopenharmony_ci tot_prot_dsds, NULL)) 152262306a36Sopenharmony_ci goto crc_queuing_error; 152362306a36Sopenharmony_ci } 152462306a36Sopenharmony_ci return QLA_SUCCESS; 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_cicrc_queuing_error: 152762306a36Sopenharmony_ci /* Cleanup will be performed by the caller */ 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 153062306a36Sopenharmony_ci} 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci/** 153362306a36Sopenharmony_ci * qla24xx_start_scsi() - Send a SCSI command to the ISP 153462306a36Sopenharmony_ci * @sp: command to send to the ISP 153562306a36Sopenharmony_ci * 153662306a36Sopenharmony_ci * Returns non-zero if a failure occurred, else zero. 153762306a36Sopenharmony_ci */ 153862306a36Sopenharmony_ciint 153962306a36Sopenharmony_ciqla24xx_start_scsi(srb_t *sp) 154062306a36Sopenharmony_ci{ 154162306a36Sopenharmony_ci int nseg; 154262306a36Sopenharmony_ci unsigned long flags; 154362306a36Sopenharmony_ci uint32_t *clr_ptr; 154462306a36Sopenharmony_ci uint32_t handle; 154562306a36Sopenharmony_ci struct cmd_type_7 *cmd_pkt; 154662306a36Sopenharmony_ci uint16_t cnt; 154762306a36Sopenharmony_ci uint16_t req_cnt; 154862306a36Sopenharmony_ci uint16_t tot_dsds; 154962306a36Sopenharmony_ci struct req_que *req = NULL; 155062306a36Sopenharmony_ci struct rsp_que *rsp; 155162306a36Sopenharmony_ci struct scsi_cmnd *cmd = GET_CMD_SP(sp); 155262306a36Sopenharmony_ci struct scsi_qla_host *vha = sp->vha; 155362306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci if (sp->fcport->edif.enable && (sp->fcport->flags & FCF_FCSP_DEVICE)) 155662306a36Sopenharmony_ci return qla28xx_start_scsi_edif(sp); 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci /* Setup device pointers. */ 155962306a36Sopenharmony_ci req = vha->req; 156062306a36Sopenharmony_ci rsp = req->rsp; 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci /* So we know we haven't pci_map'ed anything yet */ 156362306a36Sopenharmony_ci tot_dsds = 0; 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci /* Send marker if required */ 156662306a36Sopenharmony_ci if (vha->marker_needed != 0) { 156762306a36Sopenharmony_ci if (qla2x00_marker(vha, ha->base_qpair, 0, 0, MK_SYNC_ALL) != 156862306a36Sopenharmony_ci QLA_SUCCESS) 156962306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 157062306a36Sopenharmony_ci vha->marker_needed = 0; 157162306a36Sopenharmony_ci } 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci /* Acquire ring specific lock */ 157462306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci handle = qla2xxx_get_next_handle(req); 157762306a36Sopenharmony_ci if (handle == 0) 157862306a36Sopenharmony_ci goto queuing_error; 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci /* Map the sg table so we have an accurate count of sg entries needed */ 158162306a36Sopenharmony_ci if (scsi_sg_count(cmd)) { 158262306a36Sopenharmony_ci nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd), 158362306a36Sopenharmony_ci scsi_sg_count(cmd), cmd->sc_data_direction); 158462306a36Sopenharmony_ci if (unlikely(!nseg)) 158562306a36Sopenharmony_ci goto queuing_error; 158662306a36Sopenharmony_ci } else 158762306a36Sopenharmony_ci nseg = 0; 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci tot_dsds = nseg; 159062306a36Sopenharmony_ci req_cnt = qla24xx_calc_iocbs(vha, tot_dsds); 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH; 159362306a36Sopenharmony_ci sp->iores.exch_cnt = 1; 159462306a36Sopenharmony_ci sp->iores.iocb_cnt = req_cnt; 159562306a36Sopenharmony_ci if (qla_get_fw_resources(sp->qpair, &sp->iores)) 159662306a36Sopenharmony_ci goto queuing_error; 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci if (req->cnt < (req_cnt + 2)) { 159962306a36Sopenharmony_ci if (IS_SHADOW_REG_CAPABLE(ha)) { 160062306a36Sopenharmony_ci cnt = *req->out_ptr; 160162306a36Sopenharmony_ci } else { 160262306a36Sopenharmony_ci cnt = rd_reg_dword_relaxed(req->req_q_out); 160362306a36Sopenharmony_ci if (qla2x00_check_reg16_for_disconnect(vha, cnt)) 160462306a36Sopenharmony_ci goto queuing_error; 160562306a36Sopenharmony_ci } 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci if (req->ring_index < cnt) 160862306a36Sopenharmony_ci req->cnt = cnt - req->ring_index; 160962306a36Sopenharmony_ci else 161062306a36Sopenharmony_ci req->cnt = req->length - 161162306a36Sopenharmony_ci (req->ring_index - cnt); 161262306a36Sopenharmony_ci if (req->cnt < (req_cnt + 2)) 161362306a36Sopenharmony_ci goto queuing_error; 161462306a36Sopenharmony_ci } 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci /* Build command packet. */ 161762306a36Sopenharmony_ci req->current_outstanding_cmd = handle; 161862306a36Sopenharmony_ci req->outstanding_cmds[handle] = sp; 161962306a36Sopenharmony_ci sp->handle = handle; 162062306a36Sopenharmony_ci cmd->host_scribble = (unsigned char *)(unsigned long)handle; 162162306a36Sopenharmony_ci req->cnt -= req_cnt; 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci cmd_pkt = (struct cmd_type_7 *)req->ring_ptr; 162462306a36Sopenharmony_ci cmd_pkt->handle = make_handle(req->id, handle); 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci /* Zero out remaining portion of packet. */ 162762306a36Sopenharmony_ci /* tagged queuing modifier -- default is TSK_SIMPLE (0). */ 162862306a36Sopenharmony_ci clr_ptr = (uint32_t *)cmd_pkt + 2; 162962306a36Sopenharmony_ci memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); 163062306a36Sopenharmony_ci cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci /* Set NPORT-ID and LUN number*/ 163362306a36Sopenharmony_ci cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); 163462306a36Sopenharmony_ci cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; 163562306a36Sopenharmony_ci cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; 163662306a36Sopenharmony_ci cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; 163762306a36Sopenharmony_ci cmd_pkt->vp_index = sp->vha->vp_idx; 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci int_to_scsilun(cmd->device->lun, &cmd_pkt->lun); 164062306a36Sopenharmony_ci host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci cmd_pkt->task = TSK_SIMPLE; 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ci /* Load SCSI command packet. */ 164562306a36Sopenharmony_ci memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len); 164662306a36Sopenharmony_ci host_to_fcp_swap(cmd_pkt->fcp_cdb, sizeof(cmd_pkt->fcp_cdb)); 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci /* Build IOCB segments */ 165162306a36Sopenharmony_ci qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds, req); 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci /* Set total data segment count. */ 165462306a36Sopenharmony_ci cmd_pkt->entry_count = (uint8_t)req_cnt; 165562306a36Sopenharmony_ci wmb(); 165662306a36Sopenharmony_ci /* Adjust ring index. */ 165762306a36Sopenharmony_ci req->ring_index++; 165862306a36Sopenharmony_ci if (req->ring_index == req->length) { 165962306a36Sopenharmony_ci req->ring_index = 0; 166062306a36Sopenharmony_ci req->ring_ptr = req->ring; 166162306a36Sopenharmony_ci } else 166262306a36Sopenharmony_ci req->ring_ptr++; 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci sp->qpair->cmd_cnt++; 166562306a36Sopenharmony_ci sp->flags |= SRB_DMA_VALID; 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci /* Set chip new ring index. */ 166862306a36Sopenharmony_ci wrt_reg_dword(req->req_q_in, req->ring_index); 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci /* Manage unprocessed RIO/ZIO commands in response queue. */ 167162306a36Sopenharmony_ci if (vha->flags.process_response_queue && 167262306a36Sopenharmony_ci rsp->ring_ptr->signature != RESPONSE_PROCESSED) 167362306a36Sopenharmony_ci qla24xx_process_response_queue(vha, rsp); 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 167662306a36Sopenharmony_ci return QLA_SUCCESS; 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ciqueuing_error: 167962306a36Sopenharmony_ci if (tot_dsds) 168062306a36Sopenharmony_ci scsi_dma_unmap(cmd); 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci qla_put_fw_resources(sp->qpair, &sp->iores); 168362306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 168662306a36Sopenharmony_ci} 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci/** 168962306a36Sopenharmony_ci * qla24xx_dif_start_scsi() - Send a SCSI command to the ISP 169062306a36Sopenharmony_ci * @sp: command to send to the ISP 169162306a36Sopenharmony_ci * 169262306a36Sopenharmony_ci * Returns non-zero if a failure occurred, else zero. 169362306a36Sopenharmony_ci */ 169462306a36Sopenharmony_ciint 169562306a36Sopenharmony_ciqla24xx_dif_start_scsi(srb_t *sp) 169662306a36Sopenharmony_ci{ 169762306a36Sopenharmony_ci int nseg; 169862306a36Sopenharmony_ci unsigned long flags; 169962306a36Sopenharmony_ci uint32_t *clr_ptr; 170062306a36Sopenharmony_ci uint32_t handle; 170162306a36Sopenharmony_ci uint16_t cnt; 170262306a36Sopenharmony_ci uint16_t req_cnt = 0; 170362306a36Sopenharmony_ci uint16_t tot_dsds; 170462306a36Sopenharmony_ci uint16_t tot_prot_dsds; 170562306a36Sopenharmony_ci uint16_t fw_prot_opts = 0; 170662306a36Sopenharmony_ci struct req_que *req = NULL; 170762306a36Sopenharmony_ci struct rsp_que *rsp = NULL; 170862306a36Sopenharmony_ci struct scsi_cmnd *cmd = GET_CMD_SP(sp); 170962306a36Sopenharmony_ci struct scsi_qla_host *vha = sp->vha; 171062306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 171162306a36Sopenharmony_ci struct cmd_type_crc_2 *cmd_pkt; 171262306a36Sopenharmony_ci uint32_t status = 0; 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_ci#define QDSS_GOT_Q_SPACE BIT_0 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci /* Only process protection or >16 cdb in this routine */ 171762306a36Sopenharmony_ci if (scsi_get_prot_op(cmd) == SCSI_PROT_NORMAL) { 171862306a36Sopenharmony_ci if (cmd->cmd_len <= 16) 171962306a36Sopenharmony_ci return qla24xx_start_scsi(sp); 172062306a36Sopenharmony_ci else 172162306a36Sopenharmony_ci return qla_start_scsi_type6(sp); 172262306a36Sopenharmony_ci } 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci /* Setup device pointers. */ 172562306a36Sopenharmony_ci req = vha->req; 172662306a36Sopenharmony_ci rsp = req->rsp; 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci /* So we know we haven't pci_map'ed anything yet */ 172962306a36Sopenharmony_ci tot_dsds = 0; 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci /* Send marker if required */ 173262306a36Sopenharmony_ci if (vha->marker_needed != 0) { 173362306a36Sopenharmony_ci if (qla2x00_marker(vha, ha->base_qpair, 0, 0, MK_SYNC_ALL) != 173462306a36Sopenharmony_ci QLA_SUCCESS) 173562306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 173662306a36Sopenharmony_ci vha->marker_needed = 0; 173762306a36Sopenharmony_ci } 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ci /* Acquire ring specific lock */ 174062306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ci handle = qla2xxx_get_next_handle(req); 174362306a36Sopenharmony_ci if (handle == 0) 174462306a36Sopenharmony_ci goto queuing_error; 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci /* Compute number of required data segments */ 174762306a36Sopenharmony_ci /* Map the sg table so we have an accurate count of sg entries needed */ 174862306a36Sopenharmony_ci if (scsi_sg_count(cmd)) { 174962306a36Sopenharmony_ci nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd), 175062306a36Sopenharmony_ci scsi_sg_count(cmd), cmd->sc_data_direction); 175162306a36Sopenharmony_ci if (unlikely(!nseg)) 175262306a36Sopenharmony_ci goto queuing_error; 175362306a36Sopenharmony_ci else 175462306a36Sopenharmony_ci sp->flags |= SRB_DMA_VALID; 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_ci if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) || 175762306a36Sopenharmony_ci (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_STRIP)) { 175862306a36Sopenharmony_ci struct qla2_sgx sgx; 175962306a36Sopenharmony_ci uint32_t partial; 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci memset(&sgx, 0, sizeof(struct qla2_sgx)); 176262306a36Sopenharmony_ci sgx.tot_bytes = scsi_bufflen(cmd); 176362306a36Sopenharmony_ci sgx.cur_sg = scsi_sglist(cmd); 176462306a36Sopenharmony_ci sgx.sp = sp; 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_ci nseg = 0; 176762306a36Sopenharmony_ci while (qla24xx_get_one_block_sg( 176862306a36Sopenharmony_ci cmd->device->sector_size, &sgx, &partial)) 176962306a36Sopenharmony_ci nseg++; 177062306a36Sopenharmony_ci } 177162306a36Sopenharmony_ci } else 177262306a36Sopenharmony_ci nseg = 0; 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci /* number of required data segments */ 177562306a36Sopenharmony_ci tot_dsds = nseg; 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_ci /* Compute number of required protection segments */ 177862306a36Sopenharmony_ci if (qla24xx_configure_prot_mode(sp, &fw_prot_opts)) { 177962306a36Sopenharmony_ci nseg = dma_map_sg(&ha->pdev->dev, scsi_prot_sglist(cmd), 178062306a36Sopenharmony_ci scsi_prot_sg_count(cmd), cmd->sc_data_direction); 178162306a36Sopenharmony_ci if (unlikely(!nseg)) 178262306a36Sopenharmony_ci goto queuing_error; 178362306a36Sopenharmony_ci else 178462306a36Sopenharmony_ci sp->flags |= SRB_CRC_PROT_DMA_VALID; 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) || 178762306a36Sopenharmony_ci (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_STRIP)) { 178862306a36Sopenharmony_ci nseg = scsi_bufflen(cmd) / cmd->device->sector_size; 178962306a36Sopenharmony_ci } 179062306a36Sopenharmony_ci } else { 179162306a36Sopenharmony_ci nseg = 0; 179262306a36Sopenharmony_ci } 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci req_cnt = 1; 179562306a36Sopenharmony_ci /* Total Data and protection sg segment(s) */ 179662306a36Sopenharmony_ci tot_prot_dsds = nseg; 179762306a36Sopenharmony_ci tot_dsds += nseg; 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ci sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH; 180062306a36Sopenharmony_ci sp->iores.exch_cnt = 1; 180162306a36Sopenharmony_ci sp->iores.iocb_cnt = qla24xx_calc_iocbs(vha, tot_dsds); 180262306a36Sopenharmony_ci if (qla_get_fw_resources(sp->qpair, &sp->iores)) 180362306a36Sopenharmony_ci goto queuing_error; 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci if (req->cnt < (req_cnt + 2)) { 180662306a36Sopenharmony_ci if (IS_SHADOW_REG_CAPABLE(ha)) { 180762306a36Sopenharmony_ci cnt = *req->out_ptr; 180862306a36Sopenharmony_ci } else { 180962306a36Sopenharmony_ci cnt = rd_reg_dword_relaxed(req->req_q_out); 181062306a36Sopenharmony_ci if (qla2x00_check_reg16_for_disconnect(vha, cnt)) 181162306a36Sopenharmony_ci goto queuing_error; 181262306a36Sopenharmony_ci } 181362306a36Sopenharmony_ci if (req->ring_index < cnt) 181462306a36Sopenharmony_ci req->cnt = cnt - req->ring_index; 181562306a36Sopenharmony_ci else 181662306a36Sopenharmony_ci req->cnt = req->length - 181762306a36Sopenharmony_ci (req->ring_index - cnt); 181862306a36Sopenharmony_ci if (req->cnt < (req_cnt + 2)) 181962306a36Sopenharmony_ci goto queuing_error; 182062306a36Sopenharmony_ci } 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci status |= QDSS_GOT_Q_SPACE; 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci /* Build header part of command packet (excluding the OPCODE). */ 182562306a36Sopenharmony_ci req->current_outstanding_cmd = handle; 182662306a36Sopenharmony_ci req->outstanding_cmds[handle] = sp; 182762306a36Sopenharmony_ci sp->handle = handle; 182862306a36Sopenharmony_ci cmd->host_scribble = (unsigned char *)(unsigned long)handle; 182962306a36Sopenharmony_ci req->cnt -= req_cnt; 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci /* Fill-in common area */ 183262306a36Sopenharmony_ci cmd_pkt = (struct cmd_type_crc_2 *)req->ring_ptr; 183362306a36Sopenharmony_ci cmd_pkt->handle = make_handle(req->id, handle); 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ci clr_ptr = (uint32_t *)cmd_pkt + 2; 183662306a36Sopenharmony_ci memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_ci /* Set NPORT-ID and LUN number*/ 183962306a36Sopenharmony_ci cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); 184062306a36Sopenharmony_ci cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; 184162306a36Sopenharmony_ci cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; 184262306a36Sopenharmony_ci cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; 184362306a36Sopenharmony_ci 184462306a36Sopenharmony_ci int_to_scsilun(cmd->device->lun, &cmd_pkt->lun); 184562306a36Sopenharmony_ci host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_ci /* Total Data and protection segment(s) */ 184862306a36Sopenharmony_ci cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); 184962306a36Sopenharmony_ci 185062306a36Sopenharmony_ci /* Build IOCB segments and adjust for data protection segments */ 185162306a36Sopenharmony_ci if (qla24xx_build_scsi_crc_2_iocbs(sp, (struct cmd_type_crc_2 *) 185262306a36Sopenharmony_ci req->ring_ptr, tot_dsds, tot_prot_dsds, fw_prot_opts) != 185362306a36Sopenharmony_ci QLA_SUCCESS) 185462306a36Sopenharmony_ci goto queuing_error; 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci cmd_pkt->entry_count = (uint8_t)req_cnt; 185762306a36Sopenharmony_ci /* Specify response queue number where completion should happen */ 185862306a36Sopenharmony_ci cmd_pkt->entry_status = (uint8_t) rsp->id; 185962306a36Sopenharmony_ci cmd_pkt->timeout = cpu_to_le16(0); 186062306a36Sopenharmony_ci wmb(); 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci /* Adjust ring index. */ 186362306a36Sopenharmony_ci req->ring_index++; 186462306a36Sopenharmony_ci if (req->ring_index == req->length) { 186562306a36Sopenharmony_ci req->ring_index = 0; 186662306a36Sopenharmony_ci req->ring_ptr = req->ring; 186762306a36Sopenharmony_ci } else 186862306a36Sopenharmony_ci req->ring_ptr++; 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci sp->qpair->cmd_cnt++; 187162306a36Sopenharmony_ci /* Set chip new ring index. */ 187262306a36Sopenharmony_ci wrt_reg_dword(req->req_q_in, req->ring_index); 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci /* Manage unprocessed RIO/ZIO commands in response queue. */ 187562306a36Sopenharmony_ci if (vha->flags.process_response_queue && 187662306a36Sopenharmony_ci rsp->ring_ptr->signature != RESPONSE_PROCESSED) 187762306a36Sopenharmony_ci qla24xx_process_response_queue(vha, rsp); 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci return QLA_SUCCESS; 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ciqueuing_error: 188462306a36Sopenharmony_ci if (status & QDSS_GOT_Q_SPACE) { 188562306a36Sopenharmony_ci req->outstanding_cmds[handle] = NULL; 188662306a36Sopenharmony_ci req->cnt += req_cnt; 188762306a36Sopenharmony_ci } 188862306a36Sopenharmony_ci /* Cleanup will be performed by the caller (queuecommand) */ 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ci qla_put_fw_resources(sp->qpair, &sp->iores); 189162306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 189462306a36Sopenharmony_ci} 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_ci/** 189762306a36Sopenharmony_ci * qla2xxx_start_scsi_mq() - Send a SCSI command to the ISP 189862306a36Sopenharmony_ci * @sp: command to send to the ISP 189962306a36Sopenharmony_ci * 190062306a36Sopenharmony_ci * Returns non-zero if a failure occurred, else zero. 190162306a36Sopenharmony_ci */ 190262306a36Sopenharmony_cistatic int 190362306a36Sopenharmony_ciqla2xxx_start_scsi_mq(srb_t *sp) 190462306a36Sopenharmony_ci{ 190562306a36Sopenharmony_ci int nseg; 190662306a36Sopenharmony_ci unsigned long flags; 190762306a36Sopenharmony_ci uint32_t *clr_ptr; 190862306a36Sopenharmony_ci uint32_t handle; 190962306a36Sopenharmony_ci struct cmd_type_7 *cmd_pkt; 191062306a36Sopenharmony_ci uint16_t cnt; 191162306a36Sopenharmony_ci uint16_t req_cnt; 191262306a36Sopenharmony_ci uint16_t tot_dsds; 191362306a36Sopenharmony_ci struct req_que *req = NULL; 191462306a36Sopenharmony_ci struct rsp_que *rsp; 191562306a36Sopenharmony_ci struct scsi_cmnd *cmd = GET_CMD_SP(sp); 191662306a36Sopenharmony_ci struct scsi_qla_host *vha = sp->fcport->vha; 191762306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 191862306a36Sopenharmony_ci struct qla_qpair *qpair = sp->qpair; 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci if (sp->fcport->edif.enable && (sp->fcport->flags & FCF_FCSP_DEVICE)) 192162306a36Sopenharmony_ci return qla28xx_start_scsi_edif(sp); 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci /* Acquire qpair specific lock */ 192462306a36Sopenharmony_ci spin_lock_irqsave(&qpair->qp_lock, flags); 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci /* Setup qpair pointers */ 192762306a36Sopenharmony_ci req = qpair->req; 192862306a36Sopenharmony_ci rsp = qpair->rsp; 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci /* So we know we haven't pci_map'ed anything yet */ 193162306a36Sopenharmony_ci tot_dsds = 0; 193262306a36Sopenharmony_ci 193362306a36Sopenharmony_ci /* Send marker if required */ 193462306a36Sopenharmony_ci if (vha->marker_needed != 0) { 193562306a36Sopenharmony_ci if (__qla2x00_marker(vha, qpair, 0, 0, MK_SYNC_ALL) != 193662306a36Sopenharmony_ci QLA_SUCCESS) { 193762306a36Sopenharmony_ci spin_unlock_irqrestore(&qpair->qp_lock, flags); 193862306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 193962306a36Sopenharmony_ci } 194062306a36Sopenharmony_ci vha->marker_needed = 0; 194162306a36Sopenharmony_ci } 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_ci handle = qla2xxx_get_next_handle(req); 194462306a36Sopenharmony_ci if (handle == 0) 194562306a36Sopenharmony_ci goto queuing_error; 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci /* Map the sg table so we have an accurate count of sg entries needed */ 194862306a36Sopenharmony_ci if (scsi_sg_count(cmd)) { 194962306a36Sopenharmony_ci nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd), 195062306a36Sopenharmony_ci scsi_sg_count(cmd), cmd->sc_data_direction); 195162306a36Sopenharmony_ci if (unlikely(!nseg)) 195262306a36Sopenharmony_ci goto queuing_error; 195362306a36Sopenharmony_ci } else 195462306a36Sopenharmony_ci nseg = 0; 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_ci tot_dsds = nseg; 195762306a36Sopenharmony_ci req_cnt = qla24xx_calc_iocbs(vha, tot_dsds); 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_ci sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH; 196062306a36Sopenharmony_ci sp->iores.exch_cnt = 1; 196162306a36Sopenharmony_ci sp->iores.iocb_cnt = req_cnt; 196262306a36Sopenharmony_ci if (qla_get_fw_resources(sp->qpair, &sp->iores)) 196362306a36Sopenharmony_ci goto queuing_error; 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci if (req->cnt < (req_cnt + 2)) { 196662306a36Sopenharmony_ci if (IS_SHADOW_REG_CAPABLE(ha)) { 196762306a36Sopenharmony_ci cnt = *req->out_ptr; 196862306a36Sopenharmony_ci } else { 196962306a36Sopenharmony_ci cnt = rd_reg_dword_relaxed(req->req_q_out); 197062306a36Sopenharmony_ci if (qla2x00_check_reg16_for_disconnect(vha, cnt)) 197162306a36Sopenharmony_ci goto queuing_error; 197262306a36Sopenharmony_ci } 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_ci if (req->ring_index < cnt) 197562306a36Sopenharmony_ci req->cnt = cnt - req->ring_index; 197662306a36Sopenharmony_ci else 197762306a36Sopenharmony_ci req->cnt = req->length - 197862306a36Sopenharmony_ci (req->ring_index - cnt); 197962306a36Sopenharmony_ci if (req->cnt < (req_cnt + 2)) 198062306a36Sopenharmony_ci goto queuing_error; 198162306a36Sopenharmony_ci } 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci /* Build command packet. */ 198462306a36Sopenharmony_ci req->current_outstanding_cmd = handle; 198562306a36Sopenharmony_ci req->outstanding_cmds[handle] = sp; 198662306a36Sopenharmony_ci sp->handle = handle; 198762306a36Sopenharmony_ci cmd->host_scribble = (unsigned char *)(unsigned long)handle; 198862306a36Sopenharmony_ci req->cnt -= req_cnt; 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci cmd_pkt = (struct cmd_type_7 *)req->ring_ptr; 199162306a36Sopenharmony_ci cmd_pkt->handle = make_handle(req->id, handle); 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci /* Zero out remaining portion of packet. */ 199462306a36Sopenharmony_ci /* tagged queuing modifier -- default is TSK_SIMPLE (0). */ 199562306a36Sopenharmony_ci clr_ptr = (uint32_t *)cmd_pkt + 2; 199662306a36Sopenharmony_ci memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); 199762306a36Sopenharmony_ci cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_ci /* Set NPORT-ID and LUN number*/ 200062306a36Sopenharmony_ci cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); 200162306a36Sopenharmony_ci cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; 200262306a36Sopenharmony_ci cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; 200362306a36Sopenharmony_ci cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; 200462306a36Sopenharmony_ci cmd_pkt->vp_index = sp->fcport->vha->vp_idx; 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_ci int_to_scsilun(cmd->device->lun, &cmd_pkt->lun); 200762306a36Sopenharmony_ci host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); 200862306a36Sopenharmony_ci 200962306a36Sopenharmony_ci cmd_pkt->task = TSK_SIMPLE; 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ci /* Load SCSI command packet. */ 201262306a36Sopenharmony_ci memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len); 201362306a36Sopenharmony_ci host_to_fcp_swap(cmd_pkt->fcp_cdb, sizeof(cmd_pkt->fcp_cdb)); 201462306a36Sopenharmony_ci 201562306a36Sopenharmony_ci cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_ci /* Build IOCB segments */ 201862306a36Sopenharmony_ci qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds, req); 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_ci /* Set total data segment count. */ 202162306a36Sopenharmony_ci cmd_pkt->entry_count = (uint8_t)req_cnt; 202262306a36Sopenharmony_ci wmb(); 202362306a36Sopenharmony_ci /* Adjust ring index. */ 202462306a36Sopenharmony_ci req->ring_index++; 202562306a36Sopenharmony_ci if (req->ring_index == req->length) { 202662306a36Sopenharmony_ci req->ring_index = 0; 202762306a36Sopenharmony_ci req->ring_ptr = req->ring; 202862306a36Sopenharmony_ci } else 202962306a36Sopenharmony_ci req->ring_ptr++; 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci sp->qpair->cmd_cnt++; 203262306a36Sopenharmony_ci sp->flags |= SRB_DMA_VALID; 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci /* Set chip new ring index. */ 203562306a36Sopenharmony_ci wrt_reg_dword(req->req_q_in, req->ring_index); 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci /* Manage unprocessed RIO/ZIO commands in response queue. */ 203862306a36Sopenharmony_ci if (vha->flags.process_response_queue && 203962306a36Sopenharmony_ci rsp->ring_ptr->signature != RESPONSE_PROCESSED) 204062306a36Sopenharmony_ci qla24xx_process_response_queue(vha, rsp); 204162306a36Sopenharmony_ci 204262306a36Sopenharmony_ci spin_unlock_irqrestore(&qpair->qp_lock, flags); 204362306a36Sopenharmony_ci return QLA_SUCCESS; 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_ciqueuing_error: 204662306a36Sopenharmony_ci if (tot_dsds) 204762306a36Sopenharmony_ci scsi_dma_unmap(cmd); 204862306a36Sopenharmony_ci 204962306a36Sopenharmony_ci qla_put_fw_resources(sp->qpair, &sp->iores); 205062306a36Sopenharmony_ci spin_unlock_irqrestore(&qpair->qp_lock, flags); 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 205362306a36Sopenharmony_ci} 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_ci/** 205762306a36Sopenharmony_ci * qla2xxx_dif_start_scsi_mq() - Send a SCSI command to the ISP 205862306a36Sopenharmony_ci * @sp: command to send to the ISP 205962306a36Sopenharmony_ci * 206062306a36Sopenharmony_ci * Returns non-zero if a failure occurred, else zero. 206162306a36Sopenharmony_ci */ 206262306a36Sopenharmony_ciint 206362306a36Sopenharmony_ciqla2xxx_dif_start_scsi_mq(srb_t *sp) 206462306a36Sopenharmony_ci{ 206562306a36Sopenharmony_ci int nseg; 206662306a36Sopenharmony_ci unsigned long flags; 206762306a36Sopenharmony_ci uint32_t *clr_ptr; 206862306a36Sopenharmony_ci uint32_t handle; 206962306a36Sopenharmony_ci uint16_t cnt; 207062306a36Sopenharmony_ci uint16_t req_cnt = 0; 207162306a36Sopenharmony_ci uint16_t tot_dsds; 207262306a36Sopenharmony_ci uint16_t tot_prot_dsds; 207362306a36Sopenharmony_ci uint16_t fw_prot_opts = 0; 207462306a36Sopenharmony_ci struct req_que *req = NULL; 207562306a36Sopenharmony_ci struct rsp_que *rsp = NULL; 207662306a36Sopenharmony_ci struct scsi_cmnd *cmd = GET_CMD_SP(sp); 207762306a36Sopenharmony_ci struct scsi_qla_host *vha = sp->fcport->vha; 207862306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 207962306a36Sopenharmony_ci struct cmd_type_crc_2 *cmd_pkt; 208062306a36Sopenharmony_ci uint32_t status = 0; 208162306a36Sopenharmony_ci struct qla_qpair *qpair = sp->qpair; 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci#define QDSS_GOT_Q_SPACE BIT_0 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci /* Check for host side state */ 208662306a36Sopenharmony_ci if (!qpair->online) { 208762306a36Sopenharmony_ci cmd->result = DID_NO_CONNECT << 16; 208862306a36Sopenharmony_ci return QLA_INTERFACE_ERROR; 208962306a36Sopenharmony_ci } 209062306a36Sopenharmony_ci 209162306a36Sopenharmony_ci if (!qpair->difdix_supported && 209262306a36Sopenharmony_ci scsi_get_prot_op(cmd) != SCSI_PROT_NORMAL) { 209362306a36Sopenharmony_ci cmd->result = DID_NO_CONNECT << 16; 209462306a36Sopenharmony_ci return QLA_INTERFACE_ERROR; 209562306a36Sopenharmony_ci } 209662306a36Sopenharmony_ci 209762306a36Sopenharmony_ci /* Only process protection or >16 cdb in this routine */ 209862306a36Sopenharmony_ci if (scsi_get_prot_op(cmd) == SCSI_PROT_NORMAL) { 209962306a36Sopenharmony_ci if (cmd->cmd_len <= 16) 210062306a36Sopenharmony_ci return qla2xxx_start_scsi_mq(sp); 210162306a36Sopenharmony_ci else 210262306a36Sopenharmony_ci return qla_start_scsi_type6(sp); 210362306a36Sopenharmony_ci } 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci spin_lock_irqsave(&qpair->qp_lock, flags); 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci /* Setup qpair pointers */ 210862306a36Sopenharmony_ci rsp = qpair->rsp; 210962306a36Sopenharmony_ci req = qpair->req; 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_ci /* So we know we haven't pci_map'ed anything yet */ 211262306a36Sopenharmony_ci tot_dsds = 0; 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci /* Send marker if required */ 211562306a36Sopenharmony_ci if (vha->marker_needed != 0) { 211662306a36Sopenharmony_ci if (__qla2x00_marker(vha, qpair, 0, 0, MK_SYNC_ALL) != 211762306a36Sopenharmony_ci QLA_SUCCESS) { 211862306a36Sopenharmony_ci spin_unlock_irqrestore(&qpair->qp_lock, flags); 211962306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 212062306a36Sopenharmony_ci } 212162306a36Sopenharmony_ci vha->marker_needed = 0; 212262306a36Sopenharmony_ci } 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_ci handle = qla2xxx_get_next_handle(req); 212562306a36Sopenharmony_ci if (handle == 0) 212662306a36Sopenharmony_ci goto queuing_error; 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_ci /* Compute number of required data segments */ 212962306a36Sopenharmony_ci /* Map the sg table so we have an accurate count of sg entries needed */ 213062306a36Sopenharmony_ci if (scsi_sg_count(cmd)) { 213162306a36Sopenharmony_ci nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd), 213262306a36Sopenharmony_ci scsi_sg_count(cmd), cmd->sc_data_direction); 213362306a36Sopenharmony_ci if (unlikely(!nseg)) 213462306a36Sopenharmony_ci goto queuing_error; 213562306a36Sopenharmony_ci else 213662306a36Sopenharmony_ci sp->flags |= SRB_DMA_VALID; 213762306a36Sopenharmony_ci 213862306a36Sopenharmony_ci if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) || 213962306a36Sopenharmony_ci (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_STRIP)) { 214062306a36Sopenharmony_ci struct qla2_sgx sgx; 214162306a36Sopenharmony_ci uint32_t partial; 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_ci memset(&sgx, 0, sizeof(struct qla2_sgx)); 214462306a36Sopenharmony_ci sgx.tot_bytes = scsi_bufflen(cmd); 214562306a36Sopenharmony_ci sgx.cur_sg = scsi_sglist(cmd); 214662306a36Sopenharmony_ci sgx.sp = sp; 214762306a36Sopenharmony_ci 214862306a36Sopenharmony_ci nseg = 0; 214962306a36Sopenharmony_ci while (qla24xx_get_one_block_sg( 215062306a36Sopenharmony_ci cmd->device->sector_size, &sgx, &partial)) 215162306a36Sopenharmony_ci nseg++; 215262306a36Sopenharmony_ci } 215362306a36Sopenharmony_ci } else 215462306a36Sopenharmony_ci nseg = 0; 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci /* number of required data segments */ 215762306a36Sopenharmony_ci tot_dsds = nseg; 215862306a36Sopenharmony_ci 215962306a36Sopenharmony_ci /* Compute number of required protection segments */ 216062306a36Sopenharmony_ci if (qla24xx_configure_prot_mode(sp, &fw_prot_opts)) { 216162306a36Sopenharmony_ci nseg = dma_map_sg(&ha->pdev->dev, scsi_prot_sglist(cmd), 216262306a36Sopenharmony_ci scsi_prot_sg_count(cmd), cmd->sc_data_direction); 216362306a36Sopenharmony_ci if (unlikely(!nseg)) 216462306a36Sopenharmony_ci goto queuing_error; 216562306a36Sopenharmony_ci else 216662306a36Sopenharmony_ci sp->flags |= SRB_CRC_PROT_DMA_VALID; 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) || 216962306a36Sopenharmony_ci (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_STRIP)) { 217062306a36Sopenharmony_ci nseg = scsi_bufflen(cmd) / cmd->device->sector_size; 217162306a36Sopenharmony_ci } 217262306a36Sopenharmony_ci } else { 217362306a36Sopenharmony_ci nseg = 0; 217462306a36Sopenharmony_ci } 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci req_cnt = 1; 217762306a36Sopenharmony_ci /* Total Data and protection sg segment(s) */ 217862306a36Sopenharmony_ci tot_prot_dsds = nseg; 217962306a36Sopenharmony_ci tot_dsds += nseg; 218062306a36Sopenharmony_ci 218162306a36Sopenharmony_ci sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH; 218262306a36Sopenharmony_ci sp->iores.exch_cnt = 1; 218362306a36Sopenharmony_ci sp->iores.iocb_cnt = qla24xx_calc_iocbs(vha, tot_dsds); 218462306a36Sopenharmony_ci if (qla_get_fw_resources(sp->qpair, &sp->iores)) 218562306a36Sopenharmony_ci goto queuing_error; 218662306a36Sopenharmony_ci 218762306a36Sopenharmony_ci if (req->cnt < (req_cnt + 2)) { 218862306a36Sopenharmony_ci if (IS_SHADOW_REG_CAPABLE(ha)) { 218962306a36Sopenharmony_ci cnt = *req->out_ptr; 219062306a36Sopenharmony_ci } else { 219162306a36Sopenharmony_ci cnt = rd_reg_dword_relaxed(req->req_q_out); 219262306a36Sopenharmony_ci if (qla2x00_check_reg16_for_disconnect(vha, cnt)) 219362306a36Sopenharmony_ci goto queuing_error; 219462306a36Sopenharmony_ci } 219562306a36Sopenharmony_ci 219662306a36Sopenharmony_ci if (req->ring_index < cnt) 219762306a36Sopenharmony_ci req->cnt = cnt - req->ring_index; 219862306a36Sopenharmony_ci else 219962306a36Sopenharmony_ci req->cnt = req->length - 220062306a36Sopenharmony_ci (req->ring_index - cnt); 220162306a36Sopenharmony_ci if (req->cnt < (req_cnt + 2)) 220262306a36Sopenharmony_ci goto queuing_error; 220362306a36Sopenharmony_ci } 220462306a36Sopenharmony_ci 220562306a36Sopenharmony_ci status |= QDSS_GOT_Q_SPACE; 220662306a36Sopenharmony_ci 220762306a36Sopenharmony_ci /* Build header part of command packet (excluding the OPCODE). */ 220862306a36Sopenharmony_ci req->current_outstanding_cmd = handle; 220962306a36Sopenharmony_ci req->outstanding_cmds[handle] = sp; 221062306a36Sopenharmony_ci sp->handle = handle; 221162306a36Sopenharmony_ci cmd->host_scribble = (unsigned char *)(unsigned long)handle; 221262306a36Sopenharmony_ci req->cnt -= req_cnt; 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_ci /* Fill-in common area */ 221562306a36Sopenharmony_ci cmd_pkt = (struct cmd_type_crc_2 *)req->ring_ptr; 221662306a36Sopenharmony_ci cmd_pkt->handle = make_handle(req->id, handle); 221762306a36Sopenharmony_ci 221862306a36Sopenharmony_ci clr_ptr = (uint32_t *)cmd_pkt + 2; 221962306a36Sopenharmony_ci memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); 222062306a36Sopenharmony_ci 222162306a36Sopenharmony_ci /* Set NPORT-ID and LUN number*/ 222262306a36Sopenharmony_ci cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); 222362306a36Sopenharmony_ci cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; 222462306a36Sopenharmony_ci cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; 222562306a36Sopenharmony_ci cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; 222662306a36Sopenharmony_ci 222762306a36Sopenharmony_ci int_to_scsilun(cmd->device->lun, &cmd_pkt->lun); 222862306a36Sopenharmony_ci host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); 222962306a36Sopenharmony_ci 223062306a36Sopenharmony_ci /* Total Data and protection segment(s) */ 223162306a36Sopenharmony_ci cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); 223262306a36Sopenharmony_ci 223362306a36Sopenharmony_ci /* Build IOCB segments and adjust for data protection segments */ 223462306a36Sopenharmony_ci if (qla24xx_build_scsi_crc_2_iocbs(sp, (struct cmd_type_crc_2 *) 223562306a36Sopenharmony_ci req->ring_ptr, tot_dsds, tot_prot_dsds, fw_prot_opts) != 223662306a36Sopenharmony_ci QLA_SUCCESS) 223762306a36Sopenharmony_ci goto queuing_error; 223862306a36Sopenharmony_ci 223962306a36Sopenharmony_ci cmd_pkt->entry_count = (uint8_t)req_cnt; 224062306a36Sopenharmony_ci cmd_pkt->timeout = cpu_to_le16(0); 224162306a36Sopenharmony_ci wmb(); 224262306a36Sopenharmony_ci 224362306a36Sopenharmony_ci /* Adjust ring index. */ 224462306a36Sopenharmony_ci req->ring_index++; 224562306a36Sopenharmony_ci if (req->ring_index == req->length) { 224662306a36Sopenharmony_ci req->ring_index = 0; 224762306a36Sopenharmony_ci req->ring_ptr = req->ring; 224862306a36Sopenharmony_ci } else 224962306a36Sopenharmony_ci req->ring_ptr++; 225062306a36Sopenharmony_ci 225162306a36Sopenharmony_ci sp->qpair->cmd_cnt++; 225262306a36Sopenharmony_ci /* Set chip new ring index. */ 225362306a36Sopenharmony_ci wrt_reg_dword(req->req_q_in, req->ring_index); 225462306a36Sopenharmony_ci 225562306a36Sopenharmony_ci /* Manage unprocessed RIO/ZIO commands in response queue. */ 225662306a36Sopenharmony_ci if (vha->flags.process_response_queue && 225762306a36Sopenharmony_ci rsp->ring_ptr->signature != RESPONSE_PROCESSED) 225862306a36Sopenharmony_ci qla24xx_process_response_queue(vha, rsp); 225962306a36Sopenharmony_ci 226062306a36Sopenharmony_ci spin_unlock_irqrestore(&qpair->qp_lock, flags); 226162306a36Sopenharmony_ci 226262306a36Sopenharmony_ci return QLA_SUCCESS; 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_ciqueuing_error: 226562306a36Sopenharmony_ci if (status & QDSS_GOT_Q_SPACE) { 226662306a36Sopenharmony_ci req->outstanding_cmds[handle] = NULL; 226762306a36Sopenharmony_ci req->cnt += req_cnt; 226862306a36Sopenharmony_ci } 226962306a36Sopenharmony_ci /* Cleanup will be performed by the caller (queuecommand) */ 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci qla_put_fw_resources(sp->qpair, &sp->iores); 227262306a36Sopenharmony_ci spin_unlock_irqrestore(&qpair->qp_lock, flags); 227362306a36Sopenharmony_ci 227462306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 227562306a36Sopenharmony_ci} 227662306a36Sopenharmony_ci 227762306a36Sopenharmony_ci/* Generic Control-SRB manipulation functions. */ 227862306a36Sopenharmony_ci 227962306a36Sopenharmony_ci/* hardware_lock assumed to be held. */ 228062306a36Sopenharmony_ci 228162306a36Sopenharmony_civoid * 228262306a36Sopenharmony_ci__qla2x00_alloc_iocbs(struct qla_qpair *qpair, srb_t *sp) 228362306a36Sopenharmony_ci{ 228462306a36Sopenharmony_ci scsi_qla_host_t *vha = qpair->vha; 228562306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 228662306a36Sopenharmony_ci struct req_que *req = qpair->req; 228762306a36Sopenharmony_ci device_reg_t *reg = ISP_QUE_REG(ha, req->id); 228862306a36Sopenharmony_ci uint32_t handle; 228962306a36Sopenharmony_ci request_t *pkt; 229062306a36Sopenharmony_ci uint16_t cnt, req_cnt; 229162306a36Sopenharmony_ci 229262306a36Sopenharmony_ci pkt = NULL; 229362306a36Sopenharmony_ci req_cnt = 1; 229462306a36Sopenharmony_ci handle = 0; 229562306a36Sopenharmony_ci 229662306a36Sopenharmony_ci if (sp && (sp->type != SRB_SCSI_CMD)) { 229762306a36Sopenharmony_ci /* Adjust entry-counts as needed. */ 229862306a36Sopenharmony_ci req_cnt = sp->iocbs; 229962306a36Sopenharmony_ci } 230062306a36Sopenharmony_ci 230162306a36Sopenharmony_ci /* Check for room on request queue. */ 230262306a36Sopenharmony_ci if (req->cnt < req_cnt + 2) { 230362306a36Sopenharmony_ci if (qpair->use_shadow_reg) 230462306a36Sopenharmony_ci cnt = *req->out_ptr; 230562306a36Sopenharmony_ci else if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha) || 230662306a36Sopenharmony_ci IS_QLA28XX(ha)) 230762306a36Sopenharmony_ci cnt = rd_reg_dword(®->isp25mq.req_q_out); 230862306a36Sopenharmony_ci else if (IS_P3P_TYPE(ha)) 230962306a36Sopenharmony_ci cnt = rd_reg_dword(reg->isp82.req_q_out); 231062306a36Sopenharmony_ci else if (IS_FWI2_CAPABLE(ha)) 231162306a36Sopenharmony_ci cnt = rd_reg_dword(®->isp24.req_q_out); 231262306a36Sopenharmony_ci else if (IS_QLAFX00(ha)) 231362306a36Sopenharmony_ci cnt = rd_reg_dword(®->ispfx00.req_q_out); 231462306a36Sopenharmony_ci else 231562306a36Sopenharmony_ci cnt = qla2x00_debounce_register( 231662306a36Sopenharmony_ci ISP_REQ_Q_OUT(ha, ®->isp)); 231762306a36Sopenharmony_ci 231862306a36Sopenharmony_ci if (!qpair->use_shadow_reg && cnt == ISP_REG16_DISCONNECT) { 231962306a36Sopenharmony_ci qla_schedule_eeh_work(vha); 232062306a36Sopenharmony_ci return NULL; 232162306a36Sopenharmony_ci } 232262306a36Sopenharmony_ci 232362306a36Sopenharmony_ci if (req->ring_index < cnt) 232462306a36Sopenharmony_ci req->cnt = cnt - req->ring_index; 232562306a36Sopenharmony_ci else 232662306a36Sopenharmony_ci req->cnt = req->length - 232762306a36Sopenharmony_ci (req->ring_index - cnt); 232862306a36Sopenharmony_ci } 232962306a36Sopenharmony_ci if (req->cnt < req_cnt + 2) 233062306a36Sopenharmony_ci goto queuing_error; 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci if (sp) { 233362306a36Sopenharmony_ci handle = qla2xxx_get_next_handle(req); 233462306a36Sopenharmony_ci if (handle == 0) { 233562306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x700b, 233662306a36Sopenharmony_ci "No room on outstanding cmd array.\n"); 233762306a36Sopenharmony_ci goto queuing_error; 233862306a36Sopenharmony_ci } 233962306a36Sopenharmony_ci 234062306a36Sopenharmony_ci /* Prep command array. */ 234162306a36Sopenharmony_ci req->current_outstanding_cmd = handle; 234262306a36Sopenharmony_ci req->outstanding_cmds[handle] = sp; 234362306a36Sopenharmony_ci sp->handle = handle; 234462306a36Sopenharmony_ci } 234562306a36Sopenharmony_ci 234662306a36Sopenharmony_ci /* Prep packet */ 234762306a36Sopenharmony_ci req->cnt -= req_cnt; 234862306a36Sopenharmony_ci pkt = req->ring_ptr; 234962306a36Sopenharmony_ci memset(pkt, 0, REQUEST_ENTRY_SIZE); 235062306a36Sopenharmony_ci if (IS_QLAFX00(ha)) { 235162306a36Sopenharmony_ci wrt_reg_byte((u8 __force __iomem *)&pkt->entry_count, req_cnt); 235262306a36Sopenharmony_ci wrt_reg_dword((__le32 __force __iomem *)&pkt->handle, handle); 235362306a36Sopenharmony_ci } else { 235462306a36Sopenharmony_ci pkt->entry_count = req_cnt; 235562306a36Sopenharmony_ci pkt->handle = handle; 235662306a36Sopenharmony_ci } 235762306a36Sopenharmony_ci 235862306a36Sopenharmony_ci return pkt; 235962306a36Sopenharmony_ci 236062306a36Sopenharmony_ciqueuing_error: 236162306a36Sopenharmony_ci qpair->tgt_counters.num_alloc_iocb_failed++; 236262306a36Sopenharmony_ci return pkt; 236362306a36Sopenharmony_ci} 236462306a36Sopenharmony_ci 236562306a36Sopenharmony_civoid * 236662306a36Sopenharmony_ciqla2x00_alloc_iocbs_ready(struct qla_qpair *qpair, srb_t *sp) 236762306a36Sopenharmony_ci{ 236862306a36Sopenharmony_ci scsi_qla_host_t *vha = qpair->vha; 236962306a36Sopenharmony_ci 237062306a36Sopenharmony_ci if (qla2x00_reset_active(vha)) 237162306a36Sopenharmony_ci return NULL; 237262306a36Sopenharmony_ci 237362306a36Sopenharmony_ci return __qla2x00_alloc_iocbs(qpair, sp); 237462306a36Sopenharmony_ci} 237562306a36Sopenharmony_ci 237662306a36Sopenharmony_civoid * 237762306a36Sopenharmony_ciqla2x00_alloc_iocbs(struct scsi_qla_host *vha, srb_t *sp) 237862306a36Sopenharmony_ci{ 237962306a36Sopenharmony_ci return __qla2x00_alloc_iocbs(vha->hw->base_qpair, sp); 238062306a36Sopenharmony_ci} 238162306a36Sopenharmony_ci 238262306a36Sopenharmony_cistatic void 238362306a36Sopenharmony_ciqla24xx_prli_iocb(srb_t *sp, struct logio_entry_24xx *logio) 238462306a36Sopenharmony_ci{ 238562306a36Sopenharmony_ci struct srb_iocb *lio = &sp->u.iocb_cmd; 238662306a36Sopenharmony_ci 238762306a36Sopenharmony_ci logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; 238862306a36Sopenharmony_ci logio->control_flags = cpu_to_le16(LCF_COMMAND_PRLI); 238962306a36Sopenharmony_ci if (lio->u.logio.flags & SRB_LOGIN_NVME_PRLI) { 239062306a36Sopenharmony_ci logio->control_flags |= cpu_to_le16(LCF_NVME_PRLI); 239162306a36Sopenharmony_ci if (sp->vha->flags.nvme_first_burst) 239262306a36Sopenharmony_ci logio->io_parameter[0] = 239362306a36Sopenharmony_ci cpu_to_le32(NVME_PRLI_SP_FIRST_BURST); 239462306a36Sopenharmony_ci if (sp->vha->flags.nvme2_enabled) { 239562306a36Sopenharmony_ci /* Set service parameter BIT_7 for NVME CONF support */ 239662306a36Sopenharmony_ci logio->io_parameter[0] |= 239762306a36Sopenharmony_ci cpu_to_le32(NVME_PRLI_SP_CONF); 239862306a36Sopenharmony_ci /* Set service parameter BIT_8 for SLER support */ 239962306a36Sopenharmony_ci logio->io_parameter[0] |= 240062306a36Sopenharmony_ci cpu_to_le32(NVME_PRLI_SP_SLER); 240162306a36Sopenharmony_ci /* Set service parameter BIT_9 for PI control support */ 240262306a36Sopenharmony_ci logio->io_parameter[0] |= 240362306a36Sopenharmony_ci cpu_to_le32(NVME_PRLI_SP_PI_CTRL); 240462306a36Sopenharmony_ci } 240562306a36Sopenharmony_ci } 240662306a36Sopenharmony_ci 240762306a36Sopenharmony_ci logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); 240862306a36Sopenharmony_ci logio->port_id[0] = sp->fcport->d_id.b.al_pa; 240962306a36Sopenharmony_ci logio->port_id[1] = sp->fcport->d_id.b.area; 241062306a36Sopenharmony_ci logio->port_id[2] = sp->fcport->d_id.b.domain; 241162306a36Sopenharmony_ci logio->vp_index = sp->vha->vp_idx; 241262306a36Sopenharmony_ci} 241362306a36Sopenharmony_ci 241462306a36Sopenharmony_cistatic void 241562306a36Sopenharmony_ciqla24xx_login_iocb(srb_t *sp, struct logio_entry_24xx *logio) 241662306a36Sopenharmony_ci{ 241762306a36Sopenharmony_ci struct srb_iocb *lio = &sp->u.iocb_cmd; 241862306a36Sopenharmony_ci 241962306a36Sopenharmony_ci logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; 242062306a36Sopenharmony_ci logio->control_flags = cpu_to_le16(LCF_COMMAND_PLOGI); 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_ci if (lio->u.logio.flags & SRB_LOGIN_PRLI_ONLY) { 242362306a36Sopenharmony_ci logio->control_flags = cpu_to_le16(LCF_COMMAND_PRLI); 242462306a36Sopenharmony_ci } else { 242562306a36Sopenharmony_ci logio->control_flags = cpu_to_le16(LCF_COMMAND_PLOGI); 242662306a36Sopenharmony_ci if (lio->u.logio.flags & SRB_LOGIN_COND_PLOGI) 242762306a36Sopenharmony_ci logio->control_flags |= cpu_to_le16(LCF_COND_PLOGI); 242862306a36Sopenharmony_ci if (lio->u.logio.flags & SRB_LOGIN_SKIP_PRLI) 242962306a36Sopenharmony_ci logio->control_flags |= cpu_to_le16(LCF_SKIP_PRLI); 243062306a36Sopenharmony_ci if (lio->u.logio.flags & SRB_LOGIN_FCSP) { 243162306a36Sopenharmony_ci logio->control_flags |= 243262306a36Sopenharmony_ci cpu_to_le16(LCF_COMMON_FEAT | LCF_SKIP_PRLI); 243362306a36Sopenharmony_ci logio->io_parameter[0] = 243462306a36Sopenharmony_ci cpu_to_le32(LIO_COMM_FEAT_FCSP | LIO_COMM_FEAT_CIO); 243562306a36Sopenharmony_ci } 243662306a36Sopenharmony_ci } 243762306a36Sopenharmony_ci logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); 243862306a36Sopenharmony_ci logio->port_id[0] = sp->fcport->d_id.b.al_pa; 243962306a36Sopenharmony_ci logio->port_id[1] = sp->fcport->d_id.b.area; 244062306a36Sopenharmony_ci logio->port_id[2] = sp->fcport->d_id.b.domain; 244162306a36Sopenharmony_ci logio->vp_index = sp->vha->vp_idx; 244262306a36Sopenharmony_ci} 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_cistatic void 244562306a36Sopenharmony_ciqla2x00_login_iocb(srb_t *sp, struct mbx_entry *mbx) 244662306a36Sopenharmony_ci{ 244762306a36Sopenharmony_ci struct qla_hw_data *ha = sp->vha->hw; 244862306a36Sopenharmony_ci struct srb_iocb *lio = &sp->u.iocb_cmd; 244962306a36Sopenharmony_ci uint16_t opts; 245062306a36Sopenharmony_ci 245162306a36Sopenharmony_ci mbx->entry_type = MBX_IOCB_TYPE; 245262306a36Sopenharmony_ci SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id); 245362306a36Sopenharmony_ci mbx->mb0 = cpu_to_le16(MBC_LOGIN_FABRIC_PORT); 245462306a36Sopenharmony_ci opts = lio->u.logio.flags & SRB_LOGIN_COND_PLOGI ? BIT_0 : 0; 245562306a36Sopenharmony_ci opts |= lio->u.logio.flags & SRB_LOGIN_SKIP_PRLI ? BIT_1 : 0; 245662306a36Sopenharmony_ci if (HAS_EXTENDED_IDS(ha)) { 245762306a36Sopenharmony_ci mbx->mb1 = cpu_to_le16(sp->fcport->loop_id); 245862306a36Sopenharmony_ci mbx->mb10 = cpu_to_le16(opts); 245962306a36Sopenharmony_ci } else { 246062306a36Sopenharmony_ci mbx->mb1 = cpu_to_le16((sp->fcport->loop_id << 8) | opts); 246162306a36Sopenharmony_ci } 246262306a36Sopenharmony_ci mbx->mb2 = cpu_to_le16(sp->fcport->d_id.b.domain); 246362306a36Sopenharmony_ci mbx->mb3 = cpu_to_le16(sp->fcport->d_id.b.area << 8 | 246462306a36Sopenharmony_ci sp->fcport->d_id.b.al_pa); 246562306a36Sopenharmony_ci mbx->mb9 = cpu_to_le16(sp->vha->vp_idx); 246662306a36Sopenharmony_ci} 246762306a36Sopenharmony_ci 246862306a36Sopenharmony_cistatic void 246962306a36Sopenharmony_ciqla24xx_logout_iocb(srb_t *sp, struct logio_entry_24xx *logio) 247062306a36Sopenharmony_ci{ 247162306a36Sopenharmony_ci u16 control_flags = LCF_COMMAND_LOGO; 247262306a36Sopenharmony_ci logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; 247362306a36Sopenharmony_ci 247462306a36Sopenharmony_ci if (sp->fcport->explicit_logout) { 247562306a36Sopenharmony_ci control_flags |= LCF_EXPL_LOGO|LCF_FREE_NPORT; 247662306a36Sopenharmony_ci } else { 247762306a36Sopenharmony_ci control_flags |= LCF_IMPL_LOGO; 247862306a36Sopenharmony_ci 247962306a36Sopenharmony_ci if (!sp->fcport->keep_nport_handle) 248062306a36Sopenharmony_ci control_flags |= LCF_FREE_NPORT; 248162306a36Sopenharmony_ci } 248262306a36Sopenharmony_ci 248362306a36Sopenharmony_ci logio->control_flags = cpu_to_le16(control_flags); 248462306a36Sopenharmony_ci logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); 248562306a36Sopenharmony_ci logio->port_id[0] = sp->fcport->d_id.b.al_pa; 248662306a36Sopenharmony_ci logio->port_id[1] = sp->fcport->d_id.b.area; 248762306a36Sopenharmony_ci logio->port_id[2] = sp->fcport->d_id.b.domain; 248862306a36Sopenharmony_ci logio->vp_index = sp->vha->vp_idx; 248962306a36Sopenharmony_ci} 249062306a36Sopenharmony_ci 249162306a36Sopenharmony_cistatic void 249262306a36Sopenharmony_ciqla2x00_logout_iocb(srb_t *sp, struct mbx_entry *mbx) 249362306a36Sopenharmony_ci{ 249462306a36Sopenharmony_ci struct qla_hw_data *ha = sp->vha->hw; 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_ci mbx->entry_type = MBX_IOCB_TYPE; 249762306a36Sopenharmony_ci SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id); 249862306a36Sopenharmony_ci mbx->mb0 = cpu_to_le16(MBC_LOGOUT_FABRIC_PORT); 249962306a36Sopenharmony_ci mbx->mb1 = HAS_EXTENDED_IDS(ha) ? 250062306a36Sopenharmony_ci cpu_to_le16(sp->fcport->loop_id) : 250162306a36Sopenharmony_ci cpu_to_le16(sp->fcport->loop_id << 8); 250262306a36Sopenharmony_ci mbx->mb2 = cpu_to_le16(sp->fcport->d_id.b.domain); 250362306a36Sopenharmony_ci mbx->mb3 = cpu_to_le16(sp->fcport->d_id.b.area << 8 | 250462306a36Sopenharmony_ci sp->fcport->d_id.b.al_pa); 250562306a36Sopenharmony_ci mbx->mb9 = cpu_to_le16(sp->vha->vp_idx); 250662306a36Sopenharmony_ci /* Implicit: mbx->mbx10 = 0. */ 250762306a36Sopenharmony_ci} 250862306a36Sopenharmony_ci 250962306a36Sopenharmony_cistatic void 251062306a36Sopenharmony_ciqla24xx_adisc_iocb(srb_t *sp, struct logio_entry_24xx *logio) 251162306a36Sopenharmony_ci{ 251262306a36Sopenharmony_ci logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; 251362306a36Sopenharmony_ci logio->control_flags = cpu_to_le16(LCF_COMMAND_ADISC); 251462306a36Sopenharmony_ci logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); 251562306a36Sopenharmony_ci logio->vp_index = sp->vha->vp_idx; 251662306a36Sopenharmony_ci} 251762306a36Sopenharmony_ci 251862306a36Sopenharmony_cistatic void 251962306a36Sopenharmony_ciqla2x00_adisc_iocb(srb_t *sp, struct mbx_entry *mbx) 252062306a36Sopenharmony_ci{ 252162306a36Sopenharmony_ci struct qla_hw_data *ha = sp->vha->hw; 252262306a36Sopenharmony_ci 252362306a36Sopenharmony_ci mbx->entry_type = MBX_IOCB_TYPE; 252462306a36Sopenharmony_ci SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id); 252562306a36Sopenharmony_ci mbx->mb0 = cpu_to_le16(MBC_GET_PORT_DATABASE); 252662306a36Sopenharmony_ci if (HAS_EXTENDED_IDS(ha)) { 252762306a36Sopenharmony_ci mbx->mb1 = cpu_to_le16(sp->fcport->loop_id); 252862306a36Sopenharmony_ci mbx->mb10 = cpu_to_le16(BIT_0); 252962306a36Sopenharmony_ci } else { 253062306a36Sopenharmony_ci mbx->mb1 = cpu_to_le16((sp->fcport->loop_id << 8) | BIT_0); 253162306a36Sopenharmony_ci } 253262306a36Sopenharmony_ci mbx->mb2 = cpu_to_le16(MSW(ha->async_pd_dma)); 253362306a36Sopenharmony_ci mbx->mb3 = cpu_to_le16(LSW(ha->async_pd_dma)); 253462306a36Sopenharmony_ci mbx->mb6 = cpu_to_le16(MSW(MSD(ha->async_pd_dma))); 253562306a36Sopenharmony_ci mbx->mb7 = cpu_to_le16(LSW(MSD(ha->async_pd_dma))); 253662306a36Sopenharmony_ci mbx->mb9 = cpu_to_le16(sp->vha->vp_idx); 253762306a36Sopenharmony_ci} 253862306a36Sopenharmony_ci 253962306a36Sopenharmony_cistatic void 254062306a36Sopenharmony_ciqla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk) 254162306a36Sopenharmony_ci{ 254262306a36Sopenharmony_ci uint32_t flags; 254362306a36Sopenharmony_ci uint64_t lun; 254462306a36Sopenharmony_ci struct fc_port *fcport = sp->fcport; 254562306a36Sopenharmony_ci scsi_qla_host_t *vha = fcport->vha; 254662306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 254762306a36Sopenharmony_ci struct srb_iocb *iocb = &sp->u.iocb_cmd; 254862306a36Sopenharmony_ci struct req_que *req = sp->qpair->req; 254962306a36Sopenharmony_ci 255062306a36Sopenharmony_ci flags = iocb->u.tmf.flags; 255162306a36Sopenharmony_ci lun = iocb->u.tmf.lun; 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_ci tsk->entry_type = TSK_MGMT_IOCB_TYPE; 255462306a36Sopenharmony_ci tsk->entry_count = 1; 255562306a36Sopenharmony_ci tsk->handle = make_handle(req->id, tsk->handle); 255662306a36Sopenharmony_ci tsk->nport_handle = cpu_to_le16(fcport->loop_id); 255762306a36Sopenharmony_ci tsk->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); 255862306a36Sopenharmony_ci tsk->control_flags = cpu_to_le32(flags); 255962306a36Sopenharmony_ci tsk->port_id[0] = fcport->d_id.b.al_pa; 256062306a36Sopenharmony_ci tsk->port_id[1] = fcport->d_id.b.area; 256162306a36Sopenharmony_ci tsk->port_id[2] = fcport->d_id.b.domain; 256262306a36Sopenharmony_ci tsk->vp_index = fcport->vha->vp_idx; 256362306a36Sopenharmony_ci 256462306a36Sopenharmony_ci if (flags & (TCF_LUN_RESET | TCF_ABORT_TASK_SET| 256562306a36Sopenharmony_ci TCF_CLEAR_TASK_SET|TCF_CLEAR_ACA)) { 256662306a36Sopenharmony_ci int_to_scsilun(lun, &tsk->lun); 256762306a36Sopenharmony_ci host_to_fcp_swap((uint8_t *)&tsk->lun, 256862306a36Sopenharmony_ci sizeof(tsk->lun)); 256962306a36Sopenharmony_ci } 257062306a36Sopenharmony_ci} 257162306a36Sopenharmony_ci 257262306a36Sopenharmony_cistatic void 257362306a36Sopenharmony_ciqla2x00_async_done(struct srb *sp, int res) 257462306a36Sopenharmony_ci{ 257562306a36Sopenharmony_ci if (del_timer(&sp->u.iocb_cmd.timer)) { 257662306a36Sopenharmony_ci /* 257762306a36Sopenharmony_ci * Successfully cancelled the timeout handler 257862306a36Sopenharmony_ci * ref: TMR 257962306a36Sopenharmony_ci */ 258062306a36Sopenharmony_ci if (kref_put(&sp->cmd_kref, qla2x00_sp_release)) 258162306a36Sopenharmony_ci return; 258262306a36Sopenharmony_ci } 258362306a36Sopenharmony_ci sp->async_done(sp, res); 258462306a36Sopenharmony_ci} 258562306a36Sopenharmony_ci 258662306a36Sopenharmony_civoid 258762306a36Sopenharmony_ciqla2x00_sp_release(struct kref *kref) 258862306a36Sopenharmony_ci{ 258962306a36Sopenharmony_ci struct srb *sp = container_of(kref, struct srb, cmd_kref); 259062306a36Sopenharmony_ci 259162306a36Sopenharmony_ci sp->free(sp); 259262306a36Sopenharmony_ci} 259362306a36Sopenharmony_ci 259462306a36Sopenharmony_civoid 259562306a36Sopenharmony_ciqla2x00_init_async_sp(srb_t *sp, unsigned long tmo, 259662306a36Sopenharmony_ci void (*done)(struct srb *sp, int res)) 259762306a36Sopenharmony_ci{ 259862306a36Sopenharmony_ci timer_setup(&sp->u.iocb_cmd.timer, qla2x00_sp_timeout, 0); 259962306a36Sopenharmony_ci sp->done = qla2x00_async_done; 260062306a36Sopenharmony_ci sp->async_done = done; 260162306a36Sopenharmony_ci sp->free = qla2x00_sp_free; 260262306a36Sopenharmony_ci sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout; 260362306a36Sopenharmony_ci sp->u.iocb_cmd.timer.expires = jiffies + tmo * HZ; 260462306a36Sopenharmony_ci if (IS_QLAFX00(sp->vha->hw) && sp->type == SRB_FXIOCB_DCMD) 260562306a36Sopenharmony_ci init_completion(&sp->u.iocb_cmd.u.fxiocb.fxiocb_comp); 260662306a36Sopenharmony_ci sp->start_timer = 1; 260762306a36Sopenharmony_ci} 260862306a36Sopenharmony_ci 260962306a36Sopenharmony_cistatic void qla2x00_els_dcmd_sp_free(srb_t *sp) 261062306a36Sopenharmony_ci{ 261162306a36Sopenharmony_ci struct srb_iocb *elsio = &sp->u.iocb_cmd; 261262306a36Sopenharmony_ci 261362306a36Sopenharmony_ci kfree(sp->fcport); 261462306a36Sopenharmony_ci 261562306a36Sopenharmony_ci if (elsio->u.els_logo.els_logo_pyld) 261662306a36Sopenharmony_ci dma_free_coherent(&sp->vha->hw->pdev->dev, DMA_POOL_SIZE, 261762306a36Sopenharmony_ci elsio->u.els_logo.els_logo_pyld, 261862306a36Sopenharmony_ci elsio->u.els_logo.els_logo_pyld_dma); 261962306a36Sopenharmony_ci 262062306a36Sopenharmony_ci del_timer(&elsio->timer); 262162306a36Sopenharmony_ci qla2x00_rel_sp(sp); 262262306a36Sopenharmony_ci} 262362306a36Sopenharmony_ci 262462306a36Sopenharmony_cistatic void 262562306a36Sopenharmony_ciqla2x00_els_dcmd_iocb_timeout(void *data) 262662306a36Sopenharmony_ci{ 262762306a36Sopenharmony_ci srb_t *sp = data; 262862306a36Sopenharmony_ci fc_port_t *fcport = sp->fcport; 262962306a36Sopenharmony_ci struct scsi_qla_host *vha = sp->vha; 263062306a36Sopenharmony_ci struct srb_iocb *lio = &sp->u.iocb_cmd; 263162306a36Sopenharmony_ci unsigned long flags = 0; 263262306a36Sopenharmony_ci int res, h; 263362306a36Sopenharmony_ci 263462306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3069, 263562306a36Sopenharmony_ci "%s Timeout, hdl=%x, portid=%02x%02x%02x\n", 263662306a36Sopenharmony_ci sp->name, sp->handle, fcport->d_id.b.domain, fcport->d_id.b.area, 263762306a36Sopenharmony_ci fcport->d_id.b.al_pa); 263862306a36Sopenharmony_ci 263962306a36Sopenharmony_ci /* Abort the exchange */ 264062306a36Sopenharmony_ci res = qla24xx_async_abort_cmd(sp, false); 264162306a36Sopenharmony_ci if (res) { 264262306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3070, 264362306a36Sopenharmony_ci "mbx abort_command failed.\n"); 264462306a36Sopenharmony_ci spin_lock_irqsave(sp->qpair->qp_lock_ptr, flags); 264562306a36Sopenharmony_ci for (h = 1; h < sp->qpair->req->num_outstanding_cmds; h++) { 264662306a36Sopenharmony_ci if (sp->qpair->req->outstanding_cmds[h] == sp) { 264762306a36Sopenharmony_ci sp->qpair->req->outstanding_cmds[h] = NULL; 264862306a36Sopenharmony_ci break; 264962306a36Sopenharmony_ci } 265062306a36Sopenharmony_ci } 265162306a36Sopenharmony_ci spin_unlock_irqrestore(sp->qpair->qp_lock_ptr, flags); 265262306a36Sopenharmony_ci complete(&lio->u.els_logo.comp); 265362306a36Sopenharmony_ci } else { 265462306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3071, 265562306a36Sopenharmony_ci "mbx abort_command success.\n"); 265662306a36Sopenharmony_ci } 265762306a36Sopenharmony_ci} 265862306a36Sopenharmony_ci 265962306a36Sopenharmony_cistatic void qla2x00_els_dcmd_sp_done(srb_t *sp, int res) 266062306a36Sopenharmony_ci{ 266162306a36Sopenharmony_ci fc_port_t *fcport = sp->fcport; 266262306a36Sopenharmony_ci struct srb_iocb *lio = &sp->u.iocb_cmd; 266362306a36Sopenharmony_ci struct scsi_qla_host *vha = sp->vha; 266462306a36Sopenharmony_ci 266562306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3072, 266662306a36Sopenharmony_ci "%s hdl=%x, portid=%02x%02x%02x done\n", 266762306a36Sopenharmony_ci sp->name, sp->handle, fcport->d_id.b.domain, 266862306a36Sopenharmony_ci fcport->d_id.b.area, fcport->d_id.b.al_pa); 266962306a36Sopenharmony_ci 267062306a36Sopenharmony_ci complete(&lio->u.els_logo.comp); 267162306a36Sopenharmony_ci} 267262306a36Sopenharmony_ci 267362306a36Sopenharmony_ciint 267462306a36Sopenharmony_ciqla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode, 267562306a36Sopenharmony_ci port_id_t remote_did) 267662306a36Sopenharmony_ci{ 267762306a36Sopenharmony_ci srb_t *sp; 267862306a36Sopenharmony_ci fc_port_t *fcport = NULL; 267962306a36Sopenharmony_ci struct srb_iocb *elsio = NULL; 268062306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 268162306a36Sopenharmony_ci struct els_logo_payload logo_pyld; 268262306a36Sopenharmony_ci int rval = QLA_SUCCESS; 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_ci fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); 268562306a36Sopenharmony_ci if (!fcport) { 268662306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x70e5, "fcport allocation failed\n"); 268762306a36Sopenharmony_ci return -ENOMEM; 268862306a36Sopenharmony_ci } 268962306a36Sopenharmony_ci 269062306a36Sopenharmony_ci /* Alloc SRB structure 269162306a36Sopenharmony_ci * ref: INIT 269262306a36Sopenharmony_ci */ 269362306a36Sopenharmony_ci sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); 269462306a36Sopenharmony_ci if (!sp) { 269562306a36Sopenharmony_ci kfree(fcport); 269662306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x70e6, 269762306a36Sopenharmony_ci "SRB allocation failed\n"); 269862306a36Sopenharmony_ci return -ENOMEM; 269962306a36Sopenharmony_ci } 270062306a36Sopenharmony_ci 270162306a36Sopenharmony_ci elsio = &sp->u.iocb_cmd; 270262306a36Sopenharmony_ci fcport->loop_id = 0xFFFF; 270362306a36Sopenharmony_ci fcport->d_id.b.domain = remote_did.b.domain; 270462306a36Sopenharmony_ci fcport->d_id.b.area = remote_did.b.area; 270562306a36Sopenharmony_ci fcport->d_id.b.al_pa = remote_did.b.al_pa; 270662306a36Sopenharmony_ci 270762306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3073, "portid=%02x%02x%02x done\n", 270862306a36Sopenharmony_ci fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa); 270962306a36Sopenharmony_ci 271062306a36Sopenharmony_ci sp->type = SRB_ELS_DCMD; 271162306a36Sopenharmony_ci sp->name = "ELS_DCMD"; 271262306a36Sopenharmony_ci sp->fcport = fcport; 271362306a36Sopenharmony_ci qla2x00_init_async_sp(sp, ELS_DCMD_TIMEOUT, 271462306a36Sopenharmony_ci qla2x00_els_dcmd_sp_done); 271562306a36Sopenharmony_ci sp->free = qla2x00_els_dcmd_sp_free; 271662306a36Sopenharmony_ci sp->u.iocb_cmd.timeout = qla2x00_els_dcmd_iocb_timeout; 271762306a36Sopenharmony_ci init_completion(&sp->u.iocb_cmd.u.els_logo.comp); 271862306a36Sopenharmony_ci 271962306a36Sopenharmony_ci elsio->u.els_logo.els_logo_pyld = dma_alloc_coherent(&ha->pdev->dev, 272062306a36Sopenharmony_ci DMA_POOL_SIZE, &elsio->u.els_logo.els_logo_pyld_dma, 272162306a36Sopenharmony_ci GFP_KERNEL); 272262306a36Sopenharmony_ci 272362306a36Sopenharmony_ci if (!elsio->u.els_logo.els_logo_pyld) { 272462306a36Sopenharmony_ci /* ref: INIT */ 272562306a36Sopenharmony_ci kref_put(&sp->cmd_kref, qla2x00_sp_release); 272662306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 272762306a36Sopenharmony_ci } 272862306a36Sopenharmony_ci 272962306a36Sopenharmony_ci memset(&logo_pyld, 0, sizeof(struct els_logo_payload)); 273062306a36Sopenharmony_ci 273162306a36Sopenharmony_ci elsio->u.els_logo.els_cmd = els_opcode; 273262306a36Sopenharmony_ci logo_pyld.opcode = els_opcode; 273362306a36Sopenharmony_ci logo_pyld.s_id[0] = vha->d_id.b.al_pa; 273462306a36Sopenharmony_ci logo_pyld.s_id[1] = vha->d_id.b.area; 273562306a36Sopenharmony_ci logo_pyld.s_id[2] = vha->d_id.b.domain; 273662306a36Sopenharmony_ci host_to_fcp_swap(logo_pyld.s_id, sizeof(uint32_t)); 273762306a36Sopenharmony_ci memcpy(&logo_pyld.wwpn, vha->port_name, WWN_SIZE); 273862306a36Sopenharmony_ci 273962306a36Sopenharmony_ci memcpy(elsio->u.els_logo.els_logo_pyld, &logo_pyld, 274062306a36Sopenharmony_ci sizeof(struct els_logo_payload)); 274162306a36Sopenharmony_ci ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x3075, "LOGO buffer:"); 274262306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x010a, 274362306a36Sopenharmony_ci elsio->u.els_logo.els_logo_pyld, 274462306a36Sopenharmony_ci sizeof(*elsio->u.els_logo.els_logo_pyld)); 274562306a36Sopenharmony_ci 274662306a36Sopenharmony_ci rval = qla2x00_start_sp(sp); 274762306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 274862306a36Sopenharmony_ci /* ref: INIT */ 274962306a36Sopenharmony_ci kref_put(&sp->cmd_kref, qla2x00_sp_release); 275062306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 275162306a36Sopenharmony_ci } 275262306a36Sopenharmony_ci 275362306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3074, 275462306a36Sopenharmony_ci "%s LOGO sent, hdl=%x, loopid=%x, portid=%02x%02x%02x.\n", 275562306a36Sopenharmony_ci sp->name, sp->handle, fcport->loop_id, fcport->d_id.b.domain, 275662306a36Sopenharmony_ci fcport->d_id.b.area, fcport->d_id.b.al_pa); 275762306a36Sopenharmony_ci 275862306a36Sopenharmony_ci wait_for_completion(&elsio->u.els_logo.comp); 275962306a36Sopenharmony_ci 276062306a36Sopenharmony_ci /* ref: INIT */ 276162306a36Sopenharmony_ci kref_put(&sp->cmd_kref, qla2x00_sp_release); 276262306a36Sopenharmony_ci return rval; 276362306a36Sopenharmony_ci} 276462306a36Sopenharmony_ci 276562306a36Sopenharmony_cistatic void 276662306a36Sopenharmony_ciqla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) 276762306a36Sopenharmony_ci{ 276862306a36Sopenharmony_ci scsi_qla_host_t *vha = sp->vha; 276962306a36Sopenharmony_ci struct srb_iocb *elsio = &sp->u.iocb_cmd; 277062306a36Sopenharmony_ci 277162306a36Sopenharmony_ci els_iocb->entry_type = ELS_IOCB_TYPE; 277262306a36Sopenharmony_ci els_iocb->entry_count = 1; 277362306a36Sopenharmony_ci els_iocb->sys_define = 0; 277462306a36Sopenharmony_ci els_iocb->entry_status = 0; 277562306a36Sopenharmony_ci els_iocb->handle = sp->handle; 277662306a36Sopenharmony_ci els_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id); 277762306a36Sopenharmony_ci els_iocb->tx_dsd_count = cpu_to_le16(1); 277862306a36Sopenharmony_ci els_iocb->vp_index = vha->vp_idx; 277962306a36Sopenharmony_ci els_iocb->sof_type = EST_SOFI3; 278062306a36Sopenharmony_ci els_iocb->rx_dsd_count = 0; 278162306a36Sopenharmony_ci els_iocb->opcode = elsio->u.els_logo.els_cmd; 278262306a36Sopenharmony_ci 278362306a36Sopenharmony_ci els_iocb->d_id[0] = sp->fcport->d_id.b.al_pa; 278462306a36Sopenharmony_ci els_iocb->d_id[1] = sp->fcport->d_id.b.area; 278562306a36Sopenharmony_ci els_iocb->d_id[2] = sp->fcport->d_id.b.domain; 278662306a36Sopenharmony_ci /* For SID the byte order is different than DID */ 278762306a36Sopenharmony_ci els_iocb->s_id[1] = vha->d_id.b.al_pa; 278862306a36Sopenharmony_ci els_iocb->s_id[2] = vha->d_id.b.area; 278962306a36Sopenharmony_ci els_iocb->s_id[0] = vha->d_id.b.domain; 279062306a36Sopenharmony_ci 279162306a36Sopenharmony_ci if (elsio->u.els_logo.els_cmd == ELS_DCMD_PLOGI) { 279262306a36Sopenharmony_ci if (vha->hw->flags.edif_enabled) 279362306a36Sopenharmony_ci els_iocb->control_flags = cpu_to_le16(ECF_SEC_LOGIN); 279462306a36Sopenharmony_ci else 279562306a36Sopenharmony_ci els_iocb->control_flags = 0; 279662306a36Sopenharmony_ci els_iocb->tx_byte_count = els_iocb->tx_len = 279762306a36Sopenharmony_ci cpu_to_le32(sizeof(struct els_plogi_payload)); 279862306a36Sopenharmony_ci put_unaligned_le64(elsio->u.els_plogi.els_plogi_pyld_dma, 279962306a36Sopenharmony_ci &els_iocb->tx_address); 280062306a36Sopenharmony_ci els_iocb->rx_dsd_count = cpu_to_le16(1); 280162306a36Sopenharmony_ci els_iocb->rx_byte_count = els_iocb->rx_len = 280262306a36Sopenharmony_ci cpu_to_le32(sizeof(struct els_plogi_payload)); 280362306a36Sopenharmony_ci put_unaligned_le64(elsio->u.els_plogi.els_resp_pyld_dma, 280462306a36Sopenharmony_ci &els_iocb->rx_address); 280562306a36Sopenharmony_ci 280662306a36Sopenharmony_ci ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x3073, 280762306a36Sopenharmony_ci "PLOGI ELS IOCB:\n"); 280862306a36Sopenharmony_ci ql_dump_buffer(ql_log_info, vha, 0x0109, 280962306a36Sopenharmony_ci (uint8_t *)els_iocb, 281062306a36Sopenharmony_ci sizeof(*els_iocb)); 281162306a36Sopenharmony_ci } else { 281262306a36Sopenharmony_ci els_iocb->tx_byte_count = 281362306a36Sopenharmony_ci cpu_to_le32(sizeof(struct els_logo_payload)); 281462306a36Sopenharmony_ci put_unaligned_le64(elsio->u.els_logo.els_logo_pyld_dma, 281562306a36Sopenharmony_ci &els_iocb->tx_address); 281662306a36Sopenharmony_ci els_iocb->tx_len = cpu_to_le32(sizeof(struct els_logo_payload)); 281762306a36Sopenharmony_ci 281862306a36Sopenharmony_ci els_iocb->rx_byte_count = 0; 281962306a36Sopenharmony_ci els_iocb->rx_address = 0; 282062306a36Sopenharmony_ci els_iocb->rx_len = 0; 282162306a36Sopenharmony_ci ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x3076, 282262306a36Sopenharmony_ci "LOGO ELS IOCB:"); 282362306a36Sopenharmony_ci ql_dump_buffer(ql_log_info, vha, 0x010b, 282462306a36Sopenharmony_ci els_iocb, 282562306a36Sopenharmony_ci sizeof(*els_iocb)); 282662306a36Sopenharmony_ci } 282762306a36Sopenharmony_ci 282862306a36Sopenharmony_ci sp->vha->qla_stats.control_requests++; 282962306a36Sopenharmony_ci} 283062306a36Sopenharmony_ci 283162306a36Sopenharmony_civoid 283262306a36Sopenharmony_ciqla2x00_els_dcmd2_iocb_timeout(void *data) 283362306a36Sopenharmony_ci{ 283462306a36Sopenharmony_ci srb_t *sp = data; 283562306a36Sopenharmony_ci fc_port_t *fcport = sp->fcport; 283662306a36Sopenharmony_ci struct scsi_qla_host *vha = sp->vha; 283762306a36Sopenharmony_ci unsigned long flags = 0; 283862306a36Sopenharmony_ci int res, h; 283962306a36Sopenharmony_ci 284062306a36Sopenharmony_ci ql_dbg(ql_dbg_io + ql_dbg_disc, vha, 0x3069, 284162306a36Sopenharmony_ci "%s hdl=%x ELS Timeout, %8phC portid=%06x\n", 284262306a36Sopenharmony_ci sp->name, sp->handle, fcport->port_name, fcport->d_id.b24); 284362306a36Sopenharmony_ci 284462306a36Sopenharmony_ci /* Abort the exchange */ 284562306a36Sopenharmony_ci res = qla24xx_async_abort_cmd(sp, false); 284662306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3070, 284762306a36Sopenharmony_ci "mbx abort_command %s\n", 284862306a36Sopenharmony_ci (res == QLA_SUCCESS) ? "successful" : "failed"); 284962306a36Sopenharmony_ci if (res) { 285062306a36Sopenharmony_ci spin_lock_irqsave(sp->qpair->qp_lock_ptr, flags); 285162306a36Sopenharmony_ci for (h = 1; h < sp->qpair->req->num_outstanding_cmds; h++) { 285262306a36Sopenharmony_ci if (sp->qpair->req->outstanding_cmds[h] == sp) { 285362306a36Sopenharmony_ci sp->qpair->req->outstanding_cmds[h] = NULL; 285462306a36Sopenharmony_ci break; 285562306a36Sopenharmony_ci } 285662306a36Sopenharmony_ci } 285762306a36Sopenharmony_ci spin_unlock_irqrestore(sp->qpair->qp_lock_ptr, flags); 285862306a36Sopenharmony_ci sp->done(sp, QLA_FUNCTION_TIMEOUT); 285962306a36Sopenharmony_ci } 286062306a36Sopenharmony_ci} 286162306a36Sopenharmony_ci 286262306a36Sopenharmony_civoid qla2x00_els_dcmd2_free(scsi_qla_host_t *vha, struct els_plogi *els_plogi) 286362306a36Sopenharmony_ci{ 286462306a36Sopenharmony_ci if (els_plogi->els_plogi_pyld) 286562306a36Sopenharmony_ci dma_free_coherent(&vha->hw->pdev->dev, 286662306a36Sopenharmony_ci els_plogi->tx_size, 286762306a36Sopenharmony_ci els_plogi->els_plogi_pyld, 286862306a36Sopenharmony_ci els_plogi->els_plogi_pyld_dma); 286962306a36Sopenharmony_ci 287062306a36Sopenharmony_ci if (els_plogi->els_resp_pyld) 287162306a36Sopenharmony_ci dma_free_coherent(&vha->hw->pdev->dev, 287262306a36Sopenharmony_ci els_plogi->rx_size, 287362306a36Sopenharmony_ci els_plogi->els_resp_pyld, 287462306a36Sopenharmony_ci els_plogi->els_resp_pyld_dma); 287562306a36Sopenharmony_ci} 287662306a36Sopenharmony_ci 287762306a36Sopenharmony_cistatic void qla2x00_els_dcmd2_sp_done(srb_t *sp, int res) 287862306a36Sopenharmony_ci{ 287962306a36Sopenharmony_ci fc_port_t *fcport = sp->fcport; 288062306a36Sopenharmony_ci struct srb_iocb *lio = &sp->u.iocb_cmd; 288162306a36Sopenharmony_ci struct scsi_qla_host *vha = sp->vha; 288262306a36Sopenharmony_ci struct event_arg ea; 288362306a36Sopenharmony_ci struct qla_work_evt *e; 288462306a36Sopenharmony_ci struct fc_port *conflict_fcport; 288562306a36Sopenharmony_ci port_id_t cid; /* conflict Nport id */ 288662306a36Sopenharmony_ci const __le32 *fw_status = sp->u.iocb_cmd.u.els_plogi.fw_status; 288762306a36Sopenharmony_ci u16 lid; 288862306a36Sopenharmony_ci 288962306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x3072, 289062306a36Sopenharmony_ci "%s ELS done rc %d hdl=%x, portid=%06x %8phC\n", 289162306a36Sopenharmony_ci sp->name, res, sp->handle, fcport->d_id.b24, fcport->port_name); 289262306a36Sopenharmony_ci 289362306a36Sopenharmony_ci fcport->flags &= ~(FCF_ASYNC_SENT|FCF_ASYNC_ACTIVE); 289462306a36Sopenharmony_ci /* For edif, set logout on delete to ensure any residual key from FW is flushed.*/ 289562306a36Sopenharmony_ci fcport->logout_on_delete = 1; 289662306a36Sopenharmony_ci fcport->chip_reset = vha->hw->base_qpair->chip_reset; 289762306a36Sopenharmony_ci 289862306a36Sopenharmony_ci if (sp->flags & SRB_WAKEUP_ON_COMP) 289962306a36Sopenharmony_ci complete(&lio->u.els_plogi.comp); 290062306a36Sopenharmony_ci else { 290162306a36Sopenharmony_ci switch (le32_to_cpu(fw_status[0])) { 290262306a36Sopenharmony_ci case CS_DATA_UNDERRUN: 290362306a36Sopenharmony_ci case CS_COMPLETE: 290462306a36Sopenharmony_ci memset(&ea, 0, sizeof(ea)); 290562306a36Sopenharmony_ci ea.fcport = fcport; 290662306a36Sopenharmony_ci ea.rc = res; 290762306a36Sopenharmony_ci qla_handle_els_plogi_done(vha, &ea); 290862306a36Sopenharmony_ci break; 290962306a36Sopenharmony_ci 291062306a36Sopenharmony_ci case CS_IOCB_ERROR: 291162306a36Sopenharmony_ci switch (le32_to_cpu(fw_status[1])) { 291262306a36Sopenharmony_ci case LSC_SCODE_PORTID_USED: 291362306a36Sopenharmony_ci lid = le32_to_cpu(fw_status[2]) & 0xffff; 291462306a36Sopenharmony_ci qlt_find_sess_invalidate_other(vha, 291562306a36Sopenharmony_ci wwn_to_u64(fcport->port_name), 291662306a36Sopenharmony_ci fcport->d_id, lid, &conflict_fcport); 291762306a36Sopenharmony_ci if (conflict_fcport) { 291862306a36Sopenharmony_ci /* 291962306a36Sopenharmony_ci * Another fcport shares the same 292062306a36Sopenharmony_ci * loop_id & nport id; conflict 292162306a36Sopenharmony_ci * fcport needs to finish cleanup 292262306a36Sopenharmony_ci * before this fcport can proceed 292362306a36Sopenharmony_ci * to login. 292462306a36Sopenharmony_ci */ 292562306a36Sopenharmony_ci conflict_fcport->conflict = fcport; 292662306a36Sopenharmony_ci fcport->login_pause = 1; 292762306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20ed, 292862306a36Sopenharmony_ci "%s %d %8phC pid %06x inuse with lid %#x.\n", 292962306a36Sopenharmony_ci __func__, __LINE__, 293062306a36Sopenharmony_ci fcport->port_name, 293162306a36Sopenharmony_ci fcport->d_id.b24, lid); 293262306a36Sopenharmony_ci } else { 293362306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20ed, 293462306a36Sopenharmony_ci "%s %d %8phC pid %06x inuse with lid %#x sched del\n", 293562306a36Sopenharmony_ci __func__, __LINE__, 293662306a36Sopenharmony_ci fcport->port_name, 293762306a36Sopenharmony_ci fcport->d_id.b24, lid); 293862306a36Sopenharmony_ci qla2x00_clear_loop_id(fcport); 293962306a36Sopenharmony_ci set_bit(lid, vha->hw->loop_id_map); 294062306a36Sopenharmony_ci fcport->loop_id = lid; 294162306a36Sopenharmony_ci fcport->keep_nport_handle = 0; 294262306a36Sopenharmony_ci qlt_schedule_sess_for_deletion(fcport); 294362306a36Sopenharmony_ci } 294462306a36Sopenharmony_ci break; 294562306a36Sopenharmony_ci 294662306a36Sopenharmony_ci case LSC_SCODE_NPORT_USED: 294762306a36Sopenharmony_ci cid.b.domain = (le32_to_cpu(fw_status[2]) >> 16) 294862306a36Sopenharmony_ci & 0xff; 294962306a36Sopenharmony_ci cid.b.area = (le32_to_cpu(fw_status[2]) >> 8) 295062306a36Sopenharmony_ci & 0xff; 295162306a36Sopenharmony_ci cid.b.al_pa = le32_to_cpu(fw_status[2]) & 0xff; 295262306a36Sopenharmony_ci cid.b.rsvd_1 = 0; 295362306a36Sopenharmony_ci 295462306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20ec, 295562306a36Sopenharmony_ci "%s %d %8phC lid %#x in use with pid %06x post gnl\n", 295662306a36Sopenharmony_ci __func__, __LINE__, fcport->port_name, 295762306a36Sopenharmony_ci fcport->loop_id, cid.b24); 295862306a36Sopenharmony_ci set_bit(fcport->loop_id, 295962306a36Sopenharmony_ci vha->hw->loop_id_map); 296062306a36Sopenharmony_ci fcport->loop_id = FC_NO_LOOP_ID; 296162306a36Sopenharmony_ci qla24xx_post_gnl_work(vha, fcport); 296262306a36Sopenharmony_ci break; 296362306a36Sopenharmony_ci 296462306a36Sopenharmony_ci case LSC_SCODE_NOXCB: 296562306a36Sopenharmony_ci vha->hw->exch_starvation++; 296662306a36Sopenharmony_ci if (vha->hw->exch_starvation > 5) { 296762306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0xd046, 296862306a36Sopenharmony_ci "Exchange starvation. Resetting RISC\n"); 296962306a36Sopenharmony_ci vha->hw->exch_starvation = 0; 297062306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, 297162306a36Sopenharmony_ci &vha->dpc_flags); 297262306a36Sopenharmony_ci qla2xxx_wake_dpc(vha); 297362306a36Sopenharmony_ci break; 297462306a36Sopenharmony_ci } 297562306a36Sopenharmony_ci fallthrough; 297662306a36Sopenharmony_ci default: 297762306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20eb, 297862306a36Sopenharmony_ci "%s %8phC cmd error fw_status 0x%x 0x%x 0x%x\n", 297962306a36Sopenharmony_ci __func__, sp->fcport->port_name, 298062306a36Sopenharmony_ci fw_status[0], fw_status[1], fw_status[2]); 298162306a36Sopenharmony_ci 298262306a36Sopenharmony_ci fcport->flags &= ~FCF_ASYNC_SENT; 298362306a36Sopenharmony_ci qlt_schedule_sess_for_deletion(fcport); 298462306a36Sopenharmony_ci break; 298562306a36Sopenharmony_ci } 298662306a36Sopenharmony_ci break; 298762306a36Sopenharmony_ci 298862306a36Sopenharmony_ci default: 298962306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20eb, 299062306a36Sopenharmony_ci "%s %8phC cmd error 2 fw_status 0x%x 0x%x 0x%x\n", 299162306a36Sopenharmony_ci __func__, sp->fcport->port_name, 299262306a36Sopenharmony_ci fw_status[0], fw_status[1], fw_status[2]); 299362306a36Sopenharmony_ci 299462306a36Sopenharmony_ci sp->fcport->flags &= ~FCF_ASYNC_SENT; 299562306a36Sopenharmony_ci qlt_schedule_sess_for_deletion(fcport); 299662306a36Sopenharmony_ci break; 299762306a36Sopenharmony_ci } 299862306a36Sopenharmony_ci 299962306a36Sopenharmony_ci e = qla2x00_alloc_work(vha, QLA_EVT_UNMAP); 300062306a36Sopenharmony_ci if (!e) { 300162306a36Sopenharmony_ci struct srb_iocb *elsio = &sp->u.iocb_cmd; 300262306a36Sopenharmony_ci 300362306a36Sopenharmony_ci qla2x00_els_dcmd2_free(vha, &elsio->u.els_plogi); 300462306a36Sopenharmony_ci /* ref: INIT */ 300562306a36Sopenharmony_ci kref_put(&sp->cmd_kref, qla2x00_sp_release); 300662306a36Sopenharmony_ci return; 300762306a36Sopenharmony_ci } 300862306a36Sopenharmony_ci e->u.iosb.sp = sp; 300962306a36Sopenharmony_ci qla2x00_post_work(vha, e); 301062306a36Sopenharmony_ci } 301162306a36Sopenharmony_ci} 301262306a36Sopenharmony_ci 301362306a36Sopenharmony_ciint 301462306a36Sopenharmony_ciqla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode, 301562306a36Sopenharmony_ci fc_port_t *fcport, bool wait) 301662306a36Sopenharmony_ci{ 301762306a36Sopenharmony_ci srb_t *sp; 301862306a36Sopenharmony_ci struct srb_iocb *elsio = NULL; 301962306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 302062306a36Sopenharmony_ci int rval = QLA_SUCCESS; 302162306a36Sopenharmony_ci void *ptr, *resp_ptr; 302262306a36Sopenharmony_ci 302362306a36Sopenharmony_ci /* Alloc SRB structure 302462306a36Sopenharmony_ci * ref: INIT 302562306a36Sopenharmony_ci */ 302662306a36Sopenharmony_ci sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); 302762306a36Sopenharmony_ci if (!sp) { 302862306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x70e6, 302962306a36Sopenharmony_ci "SRB allocation failed\n"); 303062306a36Sopenharmony_ci fcport->flags &= ~FCF_ASYNC_ACTIVE; 303162306a36Sopenharmony_ci return -ENOMEM; 303262306a36Sopenharmony_ci } 303362306a36Sopenharmony_ci 303462306a36Sopenharmony_ci fcport->flags |= FCF_ASYNC_SENT; 303562306a36Sopenharmony_ci qla2x00_set_fcport_disc_state(fcport, DSC_LOGIN_PEND); 303662306a36Sopenharmony_ci elsio = &sp->u.iocb_cmd; 303762306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3073, 303862306a36Sopenharmony_ci "%s Enter: PLOGI portid=%06x\n", __func__, fcport->d_id.b24); 303962306a36Sopenharmony_ci 304062306a36Sopenharmony_ci if (wait) 304162306a36Sopenharmony_ci sp->flags = SRB_WAKEUP_ON_COMP; 304262306a36Sopenharmony_ci 304362306a36Sopenharmony_ci sp->type = SRB_ELS_DCMD; 304462306a36Sopenharmony_ci sp->name = "ELS_DCMD"; 304562306a36Sopenharmony_ci sp->fcport = fcport; 304662306a36Sopenharmony_ci qla2x00_init_async_sp(sp, ELS_DCMD_TIMEOUT + 2, 304762306a36Sopenharmony_ci qla2x00_els_dcmd2_sp_done); 304862306a36Sopenharmony_ci sp->u.iocb_cmd.timeout = qla2x00_els_dcmd2_iocb_timeout; 304962306a36Sopenharmony_ci 305062306a36Sopenharmony_ci elsio->u.els_plogi.tx_size = elsio->u.els_plogi.rx_size = DMA_POOL_SIZE; 305162306a36Sopenharmony_ci 305262306a36Sopenharmony_ci ptr = elsio->u.els_plogi.els_plogi_pyld = 305362306a36Sopenharmony_ci dma_alloc_coherent(&ha->pdev->dev, elsio->u.els_plogi.tx_size, 305462306a36Sopenharmony_ci &elsio->u.els_plogi.els_plogi_pyld_dma, GFP_KERNEL); 305562306a36Sopenharmony_ci 305662306a36Sopenharmony_ci if (!elsio->u.els_plogi.els_plogi_pyld) { 305762306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 305862306a36Sopenharmony_ci goto out; 305962306a36Sopenharmony_ci } 306062306a36Sopenharmony_ci 306162306a36Sopenharmony_ci resp_ptr = elsio->u.els_plogi.els_resp_pyld = 306262306a36Sopenharmony_ci dma_alloc_coherent(&ha->pdev->dev, elsio->u.els_plogi.rx_size, 306362306a36Sopenharmony_ci &elsio->u.els_plogi.els_resp_pyld_dma, GFP_KERNEL); 306462306a36Sopenharmony_ci 306562306a36Sopenharmony_ci if (!elsio->u.els_plogi.els_resp_pyld) { 306662306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 306762306a36Sopenharmony_ci goto out; 306862306a36Sopenharmony_ci } 306962306a36Sopenharmony_ci 307062306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3073, "PLOGI %p %p\n", ptr, resp_ptr); 307162306a36Sopenharmony_ci 307262306a36Sopenharmony_ci memset(ptr, 0, sizeof(struct els_plogi_payload)); 307362306a36Sopenharmony_ci memset(resp_ptr, 0, sizeof(struct els_plogi_payload)); 307462306a36Sopenharmony_ci memcpy(elsio->u.els_plogi.els_plogi_pyld->data, 307562306a36Sopenharmony_ci (void *)&ha->plogi_els_payld + offsetof(struct fc_els_flogi, fl_csp), 307662306a36Sopenharmony_ci sizeof(ha->plogi_els_payld) - offsetof(struct fc_els_flogi, fl_csp)); 307762306a36Sopenharmony_ci 307862306a36Sopenharmony_ci elsio->u.els_plogi.els_cmd = els_opcode; 307962306a36Sopenharmony_ci elsio->u.els_plogi.els_plogi_pyld->opcode = els_opcode; 308062306a36Sopenharmony_ci 308162306a36Sopenharmony_ci if (els_opcode == ELS_DCMD_PLOGI && DBELL_ACTIVE(vha)) { 308262306a36Sopenharmony_ci struct fc_els_flogi *p = ptr; 308362306a36Sopenharmony_ci 308462306a36Sopenharmony_ci p->fl_csp.sp_features |= cpu_to_be16(FC_SP_FT_SEC); 308562306a36Sopenharmony_ci } 308662306a36Sopenharmony_ci 308762306a36Sopenharmony_ci ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x3073, "PLOGI buffer:\n"); 308862306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x0109, 308962306a36Sopenharmony_ci (uint8_t *)elsio->u.els_plogi.els_plogi_pyld, 309062306a36Sopenharmony_ci sizeof(*elsio->u.els_plogi.els_plogi_pyld)); 309162306a36Sopenharmony_ci 309262306a36Sopenharmony_ci init_completion(&elsio->u.els_plogi.comp); 309362306a36Sopenharmony_ci rval = qla2x00_start_sp(sp); 309462306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 309562306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 309662306a36Sopenharmony_ci } else { 309762306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x3074, 309862306a36Sopenharmony_ci "%s PLOGI sent, hdl=%x, loopid=%x, to port_id %06x from port_id %06x\n", 309962306a36Sopenharmony_ci sp->name, sp->handle, fcport->loop_id, 310062306a36Sopenharmony_ci fcport->d_id.b24, vha->d_id.b24); 310162306a36Sopenharmony_ci } 310262306a36Sopenharmony_ci 310362306a36Sopenharmony_ci if (wait) { 310462306a36Sopenharmony_ci wait_for_completion(&elsio->u.els_plogi.comp); 310562306a36Sopenharmony_ci 310662306a36Sopenharmony_ci if (elsio->u.els_plogi.comp_status != CS_COMPLETE) 310762306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 310862306a36Sopenharmony_ci } else { 310962306a36Sopenharmony_ci goto done; 311062306a36Sopenharmony_ci } 311162306a36Sopenharmony_ci 311262306a36Sopenharmony_ciout: 311362306a36Sopenharmony_ci fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); 311462306a36Sopenharmony_ci qla2x00_els_dcmd2_free(vha, &elsio->u.els_plogi); 311562306a36Sopenharmony_ci /* ref: INIT */ 311662306a36Sopenharmony_ci kref_put(&sp->cmd_kref, qla2x00_sp_release); 311762306a36Sopenharmony_cidone: 311862306a36Sopenharmony_ci return rval; 311962306a36Sopenharmony_ci} 312062306a36Sopenharmony_ci 312162306a36Sopenharmony_ci/* it is assume qpair lock is held */ 312262306a36Sopenharmony_civoid qla_els_pt_iocb(struct scsi_qla_host *vha, 312362306a36Sopenharmony_ci struct els_entry_24xx *els_iocb, 312462306a36Sopenharmony_ci struct qla_els_pt_arg *a) 312562306a36Sopenharmony_ci{ 312662306a36Sopenharmony_ci els_iocb->entry_type = ELS_IOCB_TYPE; 312762306a36Sopenharmony_ci els_iocb->entry_count = 1; 312862306a36Sopenharmony_ci els_iocb->sys_define = 0; 312962306a36Sopenharmony_ci els_iocb->entry_status = 0; 313062306a36Sopenharmony_ci els_iocb->handle = QLA_SKIP_HANDLE; 313162306a36Sopenharmony_ci els_iocb->nport_handle = a->nport_handle; 313262306a36Sopenharmony_ci els_iocb->rx_xchg_address = a->rx_xchg_address; 313362306a36Sopenharmony_ci els_iocb->tx_dsd_count = cpu_to_le16(1); 313462306a36Sopenharmony_ci els_iocb->vp_index = a->vp_idx; 313562306a36Sopenharmony_ci els_iocb->sof_type = EST_SOFI3; 313662306a36Sopenharmony_ci els_iocb->rx_dsd_count = cpu_to_le16(0); 313762306a36Sopenharmony_ci els_iocb->opcode = a->els_opcode; 313862306a36Sopenharmony_ci 313962306a36Sopenharmony_ci els_iocb->d_id[0] = a->did.b.al_pa; 314062306a36Sopenharmony_ci els_iocb->d_id[1] = a->did.b.area; 314162306a36Sopenharmony_ci els_iocb->d_id[2] = a->did.b.domain; 314262306a36Sopenharmony_ci /* For SID the byte order is different than DID */ 314362306a36Sopenharmony_ci els_iocb->s_id[1] = vha->d_id.b.al_pa; 314462306a36Sopenharmony_ci els_iocb->s_id[2] = vha->d_id.b.area; 314562306a36Sopenharmony_ci els_iocb->s_id[0] = vha->d_id.b.domain; 314662306a36Sopenharmony_ci 314762306a36Sopenharmony_ci els_iocb->control_flags = cpu_to_le16(a->control_flags); 314862306a36Sopenharmony_ci 314962306a36Sopenharmony_ci els_iocb->tx_byte_count = cpu_to_le32(a->tx_byte_count); 315062306a36Sopenharmony_ci els_iocb->tx_len = cpu_to_le32(a->tx_len); 315162306a36Sopenharmony_ci put_unaligned_le64(a->tx_addr, &els_iocb->tx_address); 315262306a36Sopenharmony_ci 315362306a36Sopenharmony_ci els_iocb->rx_byte_count = cpu_to_le32(a->rx_byte_count); 315462306a36Sopenharmony_ci els_iocb->rx_len = cpu_to_le32(a->rx_len); 315562306a36Sopenharmony_ci put_unaligned_le64(a->rx_addr, &els_iocb->rx_address); 315662306a36Sopenharmony_ci} 315762306a36Sopenharmony_ci 315862306a36Sopenharmony_cistatic void 315962306a36Sopenharmony_ciqla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) 316062306a36Sopenharmony_ci{ 316162306a36Sopenharmony_ci struct bsg_job *bsg_job = sp->u.bsg_job; 316262306a36Sopenharmony_ci struct fc_bsg_request *bsg_request = bsg_job->request; 316362306a36Sopenharmony_ci 316462306a36Sopenharmony_ci els_iocb->entry_type = ELS_IOCB_TYPE; 316562306a36Sopenharmony_ci els_iocb->entry_count = 1; 316662306a36Sopenharmony_ci els_iocb->sys_define = 0; 316762306a36Sopenharmony_ci els_iocb->entry_status = 0; 316862306a36Sopenharmony_ci els_iocb->handle = sp->handle; 316962306a36Sopenharmony_ci els_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id); 317062306a36Sopenharmony_ci els_iocb->tx_dsd_count = cpu_to_le16(bsg_job->request_payload.sg_cnt); 317162306a36Sopenharmony_ci els_iocb->vp_index = sp->vha->vp_idx; 317262306a36Sopenharmony_ci els_iocb->sof_type = EST_SOFI3; 317362306a36Sopenharmony_ci els_iocb->rx_dsd_count = cpu_to_le16(bsg_job->reply_payload.sg_cnt); 317462306a36Sopenharmony_ci 317562306a36Sopenharmony_ci els_iocb->opcode = 317662306a36Sopenharmony_ci sp->type == SRB_ELS_CMD_RPT ? 317762306a36Sopenharmony_ci bsg_request->rqst_data.r_els.els_code : 317862306a36Sopenharmony_ci bsg_request->rqst_data.h_els.command_code; 317962306a36Sopenharmony_ci els_iocb->d_id[0] = sp->fcport->d_id.b.al_pa; 318062306a36Sopenharmony_ci els_iocb->d_id[1] = sp->fcport->d_id.b.area; 318162306a36Sopenharmony_ci els_iocb->d_id[2] = sp->fcport->d_id.b.domain; 318262306a36Sopenharmony_ci els_iocb->control_flags = 0; 318362306a36Sopenharmony_ci els_iocb->rx_byte_count = 318462306a36Sopenharmony_ci cpu_to_le32(bsg_job->reply_payload.payload_len); 318562306a36Sopenharmony_ci els_iocb->tx_byte_count = 318662306a36Sopenharmony_ci cpu_to_le32(bsg_job->request_payload.payload_len); 318762306a36Sopenharmony_ci 318862306a36Sopenharmony_ci put_unaligned_le64(sg_dma_address(bsg_job->request_payload.sg_list), 318962306a36Sopenharmony_ci &els_iocb->tx_address); 319062306a36Sopenharmony_ci els_iocb->tx_len = cpu_to_le32(sg_dma_len 319162306a36Sopenharmony_ci (bsg_job->request_payload.sg_list)); 319262306a36Sopenharmony_ci 319362306a36Sopenharmony_ci put_unaligned_le64(sg_dma_address(bsg_job->reply_payload.sg_list), 319462306a36Sopenharmony_ci &els_iocb->rx_address); 319562306a36Sopenharmony_ci els_iocb->rx_len = cpu_to_le32(sg_dma_len 319662306a36Sopenharmony_ci (bsg_job->reply_payload.sg_list)); 319762306a36Sopenharmony_ci 319862306a36Sopenharmony_ci sp->vha->qla_stats.control_requests++; 319962306a36Sopenharmony_ci} 320062306a36Sopenharmony_ci 320162306a36Sopenharmony_cistatic void 320262306a36Sopenharmony_ciqla2x00_ct_iocb(srb_t *sp, ms_iocb_entry_t *ct_iocb) 320362306a36Sopenharmony_ci{ 320462306a36Sopenharmony_ci uint16_t avail_dsds; 320562306a36Sopenharmony_ci struct dsd64 *cur_dsd; 320662306a36Sopenharmony_ci struct scatterlist *sg; 320762306a36Sopenharmony_ci int index; 320862306a36Sopenharmony_ci uint16_t tot_dsds; 320962306a36Sopenharmony_ci scsi_qla_host_t *vha = sp->vha; 321062306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 321162306a36Sopenharmony_ci struct bsg_job *bsg_job = sp->u.bsg_job; 321262306a36Sopenharmony_ci int entry_count = 1; 321362306a36Sopenharmony_ci 321462306a36Sopenharmony_ci memset(ct_iocb, 0, sizeof(ms_iocb_entry_t)); 321562306a36Sopenharmony_ci ct_iocb->entry_type = CT_IOCB_TYPE; 321662306a36Sopenharmony_ci ct_iocb->entry_status = 0; 321762306a36Sopenharmony_ci ct_iocb->handle1 = sp->handle; 321862306a36Sopenharmony_ci SET_TARGET_ID(ha, ct_iocb->loop_id, sp->fcport->loop_id); 321962306a36Sopenharmony_ci ct_iocb->status = cpu_to_le16(0); 322062306a36Sopenharmony_ci ct_iocb->control_flags = cpu_to_le16(0); 322162306a36Sopenharmony_ci ct_iocb->timeout = 0; 322262306a36Sopenharmony_ci ct_iocb->cmd_dsd_count = 322362306a36Sopenharmony_ci cpu_to_le16(bsg_job->request_payload.sg_cnt); 322462306a36Sopenharmony_ci ct_iocb->total_dsd_count = 322562306a36Sopenharmony_ci cpu_to_le16(bsg_job->request_payload.sg_cnt + 1); 322662306a36Sopenharmony_ci ct_iocb->req_bytecount = 322762306a36Sopenharmony_ci cpu_to_le32(bsg_job->request_payload.payload_len); 322862306a36Sopenharmony_ci ct_iocb->rsp_bytecount = 322962306a36Sopenharmony_ci cpu_to_le32(bsg_job->reply_payload.payload_len); 323062306a36Sopenharmony_ci 323162306a36Sopenharmony_ci put_unaligned_le64(sg_dma_address(bsg_job->request_payload.sg_list), 323262306a36Sopenharmony_ci &ct_iocb->req_dsd.address); 323362306a36Sopenharmony_ci ct_iocb->req_dsd.length = ct_iocb->req_bytecount; 323462306a36Sopenharmony_ci 323562306a36Sopenharmony_ci put_unaligned_le64(sg_dma_address(bsg_job->reply_payload.sg_list), 323662306a36Sopenharmony_ci &ct_iocb->rsp_dsd.address); 323762306a36Sopenharmony_ci ct_iocb->rsp_dsd.length = ct_iocb->rsp_bytecount; 323862306a36Sopenharmony_ci 323962306a36Sopenharmony_ci avail_dsds = 1; 324062306a36Sopenharmony_ci cur_dsd = &ct_iocb->rsp_dsd; 324162306a36Sopenharmony_ci index = 0; 324262306a36Sopenharmony_ci tot_dsds = bsg_job->reply_payload.sg_cnt; 324362306a36Sopenharmony_ci 324462306a36Sopenharmony_ci for_each_sg(bsg_job->reply_payload.sg_list, sg, tot_dsds, index) { 324562306a36Sopenharmony_ci cont_a64_entry_t *cont_pkt; 324662306a36Sopenharmony_ci 324762306a36Sopenharmony_ci /* Allocate additional continuation packets? */ 324862306a36Sopenharmony_ci if (avail_dsds == 0) { 324962306a36Sopenharmony_ci /* 325062306a36Sopenharmony_ci * Five DSDs are available in the Cont. 325162306a36Sopenharmony_ci * Type 1 IOCB. 325262306a36Sopenharmony_ci */ 325362306a36Sopenharmony_ci cont_pkt = qla2x00_prep_cont_type1_iocb(vha, 325462306a36Sopenharmony_ci vha->hw->req_q_map[0]); 325562306a36Sopenharmony_ci cur_dsd = cont_pkt->dsd; 325662306a36Sopenharmony_ci avail_dsds = 5; 325762306a36Sopenharmony_ci entry_count++; 325862306a36Sopenharmony_ci } 325962306a36Sopenharmony_ci 326062306a36Sopenharmony_ci append_dsd64(&cur_dsd, sg); 326162306a36Sopenharmony_ci avail_dsds--; 326262306a36Sopenharmony_ci } 326362306a36Sopenharmony_ci ct_iocb->entry_count = entry_count; 326462306a36Sopenharmony_ci 326562306a36Sopenharmony_ci sp->vha->qla_stats.control_requests++; 326662306a36Sopenharmony_ci} 326762306a36Sopenharmony_ci 326862306a36Sopenharmony_cistatic void 326962306a36Sopenharmony_ciqla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb) 327062306a36Sopenharmony_ci{ 327162306a36Sopenharmony_ci uint16_t avail_dsds; 327262306a36Sopenharmony_ci struct dsd64 *cur_dsd; 327362306a36Sopenharmony_ci struct scatterlist *sg; 327462306a36Sopenharmony_ci int index; 327562306a36Sopenharmony_ci uint16_t cmd_dsds, rsp_dsds; 327662306a36Sopenharmony_ci scsi_qla_host_t *vha = sp->vha; 327762306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 327862306a36Sopenharmony_ci struct bsg_job *bsg_job = sp->u.bsg_job; 327962306a36Sopenharmony_ci int entry_count = 1; 328062306a36Sopenharmony_ci cont_a64_entry_t *cont_pkt = NULL; 328162306a36Sopenharmony_ci 328262306a36Sopenharmony_ci ct_iocb->entry_type = CT_IOCB_TYPE; 328362306a36Sopenharmony_ci ct_iocb->entry_status = 0; 328462306a36Sopenharmony_ci ct_iocb->sys_define = 0; 328562306a36Sopenharmony_ci ct_iocb->handle = sp->handle; 328662306a36Sopenharmony_ci 328762306a36Sopenharmony_ci ct_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id); 328862306a36Sopenharmony_ci ct_iocb->vp_index = sp->vha->vp_idx; 328962306a36Sopenharmony_ci ct_iocb->comp_status = cpu_to_le16(0); 329062306a36Sopenharmony_ci 329162306a36Sopenharmony_ci cmd_dsds = bsg_job->request_payload.sg_cnt; 329262306a36Sopenharmony_ci rsp_dsds = bsg_job->reply_payload.sg_cnt; 329362306a36Sopenharmony_ci 329462306a36Sopenharmony_ci ct_iocb->cmd_dsd_count = cpu_to_le16(cmd_dsds); 329562306a36Sopenharmony_ci ct_iocb->timeout = 0; 329662306a36Sopenharmony_ci ct_iocb->rsp_dsd_count = cpu_to_le16(rsp_dsds); 329762306a36Sopenharmony_ci ct_iocb->cmd_byte_count = 329862306a36Sopenharmony_ci cpu_to_le32(bsg_job->request_payload.payload_len); 329962306a36Sopenharmony_ci 330062306a36Sopenharmony_ci avail_dsds = 2; 330162306a36Sopenharmony_ci cur_dsd = ct_iocb->dsd; 330262306a36Sopenharmony_ci index = 0; 330362306a36Sopenharmony_ci 330462306a36Sopenharmony_ci for_each_sg(bsg_job->request_payload.sg_list, sg, cmd_dsds, index) { 330562306a36Sopenharmony_ci /* Allocate additional continuation packets? */ 330662306a36Sopenharmony_ci if (avail_dsds == 0) { 330762306a36Sopenharmony_ci /* 330862306a36Sopenharmony_ci * Five DSDs are available in the Cont. 330962306a36Sopenharmony_ci * Type 1 IOCB. 331062306a36Sopenharmony_ci */ 331162306a36Sopenharmony_ci cont_pkt = qla2x00_prep_cont_type1_iocb( 331262306a36Sopenharmony_ci vha, ha->req_q_map[0]); 331362306a36Sopenharmony_ci cur_dsd = cont_pkt->dsd; 331462306a36Sopenharmony_ci avail_dsds = 5; 331562306a36Sopenharmony_ci entry_count++; 331662306a36Sopenharmony_ci } 331762306a36Sopenharmony_ci 331862306a36Sopenharmony_ci append_dsd64(&cur_dsd, sg); 331962306a36Sopenharmony_ci avail_dsds--; 332062306a36Sopenharmony_ci } 332162306a36Sopenharmony_ci 332262306a36Sopenharmony_ci index = 0; 332362306a36Sopenharmony_ci 332462306a36Sopenharmony_ci for_each_sg(bsg_job->reply_payload.sg_list, sg, rsp_dsds, index) { 332562306a36Sopenharmony_ci /* Allocate additional continuation packets? */ 332662306a36Sopenharmony_ci if (avail_dsds == 0) { 332762306a36Sopenharmony_ci /* 332862306a36Sopenharmony_ci * Five DSDs are available in the Cont. 332962306a36Sopenharmony_ci * Type 1 IOCB. 333062306a36Sopenharmony_ci */ 333162306a36Sopenharmony_ci cont_pkt = qla2x00_prep_cont_type1_iocb(vha, 333262306a36Sopenharmony_ci ha->req_q_map[0]); 333362306a36Sopenharmony_ci cur_dsd = cont_pkt->dsd; 333462306a36Sopenharmony_ci avail_dsds = 5; 333562306a36Sopenharmony_ci entry_count++; 333662306a36Sopenharmony_ci } 333762306a36Sopenharmony_ci 333862306a36Sopenharmony_ci append_dsd64(&cur_dsd, sg); 333962306a36Sopenharmony_ci avail_dsds--; 334062306a36Sopenharmony_ci } 334162306a36Sopenharmony_ci ct_iocb->entry_count = entry_count; 334262306a36Sopenharmony_ci} 334362306a36Sopenharmony_ci 334462306a36Sopenharmony_ci/* 334562306a36Sopenharmony_ci * qla82xx_start_scsi() - Send a SCSI command to the ISP 334662306a36Sopenharmony_ci * @sp: command to send to the ISP 334762306a36Sopenharmony_ci * 334862306a36Sopenharmony_ci * Returns non-zero if a failure occurred, else zero. 334962306a36Sopenharmony_ci */ 335062306a36Sopenharmony_ciint 335162306a36Sopenharmony_ciqla82xx_start_scsi(srb_t *sp) 335262306a36Sopenharmony_ci{ 335362306a36Sopenharmony_ci int nseg; 335462306a36Sopenharmony_ci unsigned long flags; 335562306a36Sopenharmony_ci struct scsi_cmnd *cmd; 335662306a36Sopenharmony_ci uint32_t *clr_ptr; 335762306a36Sopenharmony_ci uint32_t handle; 335862306a36Sopenharmony_ci uint16_t cnt; 335962306a36Sopenharmony_ci uint16_t req_cnt; 336062306a36Sopenharmony_ci uint16_t tot_dsds; 336162306a36Sopenharmony_ci struct device_reg_82xx __iomem *reg; 336262306a36Sopenharmony_ci uint32_t dbval; 336362306a36Sopenharmony_ci __be32 *fcp_dl; 336462306a36Sopenharmony_ci uint8_t additional_cdb_len; 336562306a36Sopenharmony_ci struct ct6_dsd *ctx; 336662306a36Sopenharmony_ci struct scsi_qla_host *vha = sp->vha; 336762306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 336862306a36Sopenharmony_ci struct req_que *req = NULL; 336962306a36Sopenharmony_ci struct rsp_que *rsp = NULL; 337062306a36Sopenharmony_ci struct qla_qpair *qpair = sp->qpair; 337162306a36Sopenharmony_ci 337262306a36Sopenharmony_ci /* Setup device pointers. */ 337362306a36Sopenharmony_ci reg = &ha->iobase->isp82; 337462306a36Sopenharmony_ci cmd = GET_CMD_SP(sp); 337562306a36Sopenharmony_ci req = vha->req; 337662306a36Sopenharmony_ci rsp = ha->rsp_q_map[0]; 337762306a36Sopenharmony_ci 337862306a36Sopenharmony_ci /* So we know we haven't pci_map'ed anything yet */ 337962306a36Sopenharmony_ci tot_dsds = 0; 338062306a36Sopenharmony_ci 338162306a36Sopenharmony_ci dbval = 0x04 | (ha->portnum << 5); 338262306a36Sopenharmony_ci 338362306a36Sopenharmony_ci /* Send marker if required */ 338462306a36Sopenharmony_ci if (vha->marker_needed != 0) { 338562306a36Sopenharmony_ci if (qla2x00_marker(vha, ha->base_qpair, 338662306a36Sopenharmony_ci 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) { 338762306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x300c, 338862306a36Sopenharmony_ci "qla2x00_marker failed for cmd=%p.\n", cmd); 338962306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 339062306a36Sopenharmony_ci } 339162306a36Sopenharmony_ci vha->marker_needed = 0; 339262306a36Sopenharmony_ci } 339362306a36Sopenharmony_ci 339462306a36Sopenharmony_ci /* Acquire ring specific lock */ 339562306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 339662306a36Sopenharmony_ci 339762306a36Sopenharmony_ci handle = qla2xxx_get_next_handle(req); 339862306a36Sopenharmony_ci if (handle == 0) 339962306a36Sopenharmony_ci goto queuing_error; 340062306a36Sopenharmony_ci 340162306a36Sopenharmony_ci /* Map the sg table so we have an accurate count of sg entries needed */ 340262306a36Sopenharmony_ci if (scsi_sg_count(cmd)) { 340362306a36Sopenharmony_ci nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd), 340462306a36Sopenharmony_ci scsi_sg_count(cmd), cmd->sc_data_direction); 340562306a36Sopenharmony_ci if (unlikely(!nseg)) 340662306a36Sopenharmony_ci goto queuing_error; 340762306a36Sopenharmony_ci } else 340862306a36Sopenharmony_ci nseg = 0; 340962306a36Sopenharmony_ci 341062306a36Sopenharmony_ci tot_dsds = nseg; 341162306a36Sopenharmony_ci 341262306a36Sopenharmony_ci if (tot_dsds > ql2xshiftctondsd) { 341362306a36Sopenharmony_ci struct cmd_type_6 *cmd_pkt; 341462306a36Sopenharmony_ci uint16_t more_dsd_lists = 0; 341562306a36Sopenharmony_ci struct dsd_dma *dsd_ptr; 341662306a36Sopenharmony_ci uint16_t i; 341762306a36Sopenharmony_ci 341862306a36Sopenharmony_ci more_dsd_lists = qla24xx_calc_dsd_lists(tot_dsds); 341962306a36Sopenharmony_ci if ((more_dsd_lists + qpair->dsd_inuse) >= NUM_DSD_CHAIN) { 342062306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x300d, 342162306a36Sopenharmony_ci "Num of DSD list %d is than %d for cmd=%p.\n", 342262306a36Sopenharmony_ci more_dsd_lists + qpair->dsd_inuse, NUM_DSD_CHAIN, 342362306a36Sopenharmony_ci cmd); 342462306a36Sopenharmony_ci goto queuing_error; 342562306a36Sopenharmony_ci } 342662306a36Sopenharmony_ci 342762306a36Sopenharmony_ci if (more_dsd_lists <= qpair->dsd_avail) 342862306a36Sopenharmony_ci goto sufficient_dsds; 342962306a36Sopenharmony_ci else 343062306a36Sopenharmony_ci more_dsd_lists -= qpair->dsd_avail; 343162306a36Sopenharmony_ci 343262306a36Sopenharmony_ci for (i = 0; i < more_dsd_lists; i++) { 343362306a36Sopenharmony_ci dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC); 343462306a36Sopenharmony_ci if (!dsd_ptr) { 343562306a36Sopenharmony_ci ql_log(ql_log_fatal, vha, 0x300e, 343662306a36Sopenharmony_ci "Failed to allocate memory for dsd_dma " 343762306a36Sopenharmony_ci "for cmd=%p.\n", cmd); 343862306a36Sopenharmony_ci goto queuing_error; 343962306a36Sopenharmony_ci } 344062306a36Sopenharmony_ci 344162306a36Sopenharmony_ci dsd_ptr->dsd_addr = dma_pool_alloc(ha->dl_dma_pool, 344262306a36Sopenharmony_ci GFP_ATOMIC, &dsd_ptr->dsd_list_dma); 344362306a36Sopenharmony_ci if (!dsd_ptr->dsd_addr) { 344462306a36Sopenharmony_ci kfree(dsd_ptr); 344562306a36Sopenharmony_ci ql_log(ql_log_fatal, vha, 0x300f, 344662306a36Sopenharmony_ci "Failed to allocate memory for dsd_addr " 344762306a36Sopenharmony_ci "for cmd=%p.\n", cmd); 344862306a36Sopenharmony_ci goto queuing_error; 344962306a36Sopenharmony_ci } 345062306a36Sopenharmony_ci list_add_tail(&dsd_ptr->list, &qpair->dsd_list); 345162306a36Sopenharmony_ci qpair->dsd_avail++; 345262306a36Sopenharmony_ci } 345362306a36Sopenharmony_ci 345462306a36Sopenharmony_cisufficient_dsds: 345562306a36Sopenharmony_ci req_cnt = 1; 345662306a36Sopenharmony_ci 345762306a36Sopenharmony_ci if (req->cnt < (req_cnt + 2)) { 345862306a36Sopenharmony_ci cnt = (uint16_t)rd_reg_dword_relaxed( 345962306a36Sopenharmony_ci ®->req_q_out[0]); 346062306a36Sopenharmony_ci if (req->ring_index < cnt) 346162306a36Sopenharmony_ci req->cnt = cnt - req->ring_index; 346262306a36Sopenharmony_ci else 346362306a36Sopenharmony_ci req->cnt = req->length - 346462306a36Sopenharmony_ci (req->ring_index - cnt); 346562306a36Sopenharmony_ci if (req->cnt < (req_cnt + 2)) 346662306a36Sopenharmony_ci goto queuing_error; 346762306a36Sopenharmony_ci } 346862306a36Sopenharmony_ci 346962306a36Sopenharmony_ci ctx = &sp->u.scmd.ct6_ctx; 347062306a36Sopenharmony_ci 347162306a36Sopenharmony_ci memset(ctx, 0, sizeof(struct ct6_dsd)); 347262306a36Sopenharmony_ci ctx->fcp_cmnd = dma_pool_zalloc(ha->fcp_cmnd_dma_pool, 347362306a36Sopenharmony_ci GFP_ATOMIC, &ctx->fcp_cmnd_dma); 347462306a36Sopenharmony_ci if (!ctx->fcp_cmnd) { 347562306a36Sopenharmony_ci ql_log(ql_log_fatal, vha, 0x3011, 347662306a36Sopenharmony_ci "Failed to allocate fcp_cmnd for cmd=%p.\n", cmd); 347762306a36Sopenharmony_ci goto queuing_error; 347862306a36Sopenharmony_ci } 347962306a36Sopenharmony_ci 348062306a36Sopenharmony_ci /* Initialize the DSD list and dma handle */ 348162306a36Sopenharmony_ci INIT_LIST_HEAD(&ctx->dsd_list); 348262306a36Sopenharmony_ci ctx->dsd_use_cnt = 0; 348362306a36Sopenharmony_ci 348462306a36Sopenharmony_ci if (cmd->cmd_len > 16) { 348562306a36Sopenharmony_ci additional_cdb_len = cmd->cmd_len - 16; 348662306a36Sopenharmony_ci if ((cmd->cmd_len % 4) != 0) { 348762306a36Sopenharmony_ci /* SCSI command bigger than 16 bytes must be 348862306a36Sopenharmony_ci * multiple of 4 348962306a36Sopenharmony_ci */ 349062306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x3012, 349162306a36Sopenharmony_ci "scsi cmd len %d not multiple of 4 " 349262306a36Sopenharmony_ci "for cmd=%p.\n", cmd->cmd_len, cmd); 349362306a36Sopenharmony_ci goto queuing_error_fcp_cmnd; 349462306a36Sopenharmony_ci } 349562306a36Sopenharmony_ci ctx->fcp_cmnd_len = 12 + cmd->cmd_len + 4; 349662306a36Sopenharmony_ci } else { 349762306a36Sopenharmony_ci additional_cdb_len = 0; 349862306a36Sopenharmony_ci ctx->fcp_cmnd_len = 12 + 16 + 4; 349962306a36Sopenharmony_ci } 350062306a36Sopenharmony_ci 350162306a36Sopenharmony_ci cmd_pkt = (struct cmd_type_6 *)req->ring_ptr; 350262306a36Sopenharmony_ci cmd_pkt->handle = make_handle(req->id, handle); 350362306a36Sopenharmony_ci 350462306a36Sopenharmony_ci /* Zero out remaining portion of packet. */ 350562306a36Sopenharmony_ci /* tagged queuing modifier -- default is TSK_SIMPLE (0). */ 350662306a36Sopenharmony_ci clr_ptr = (uint32_t *)cmd_pkt + 2; 350762306a36Sopenharmony_ci memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); 350862306a36Sopenharmony_ci cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); 350962306a36Sopenharmony_ci 351062306a36Sopenharmony_ci /* Set NPORT-ID and LUN number*/ 351162306a36Sopenharmony_ci cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); 351262306a36Sopenharmony_ci cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; 351362306a36Sopenharmony_ci cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; 351462306a36Sopenharmony_ci cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; 351562306a36Sopenharmony_ci cmd_pkt->vp_index = sp->vha->vp_idx; 351662306a36Sopenharmony_ci 351762306a36Sopenharmony_ci /* Build IOCB segments */ 351862306a36Sopenharmony_ci if (qla24xx_build_scsi_type_6_iocbs(sp, cmd_pkt, tot_dsds)) 351962306a36Sopenharmony_ci goto queuing_error_fcp_cmnd; 352062306a36Sopenharmony_ci 352162306a36Sopenharmony_ci int_to_scsilun(cmd->device->lun, &cmd_pkt->lun); 352262306a36Sopenharmony_ci host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); 352362306a36Sopenharmony_ci 352462306a36Sopenharmony_ci /* build FCP_CMND IU */ 352562306a36Sopenharmony_ci int_to_scsilun(cmd->device->lun, &ctx->fcp_cmnd->lun); 352662306a36Sopenharmony_ci ctx->fcp_cmnd->additional_cdb_len = additional_cdb_len; 352762306a36Sopenharmony_ci 352862306a36Sopenharmony_ci if (cmd->sc_data_direction == DMA_TO_DEVICE) 352962306a36Sopenharmony_ci ctx->fcp_cmnd->additional_cdb_len |= 1; 353062306a36Sopenharmony_ci else if (cmd->sc_data_direction == DMA_FROM_DEVICE) 353162306a36Sopenharmony_ci ctx->fcp_cmnd->additional_cdb_len |= 2; 353262306a36Sopenharmony_ci 353362306a36Sopenharmony_ci /* Populate the FCP_PRIO. */ 353462306a36Sopenharmony_ci if (ha->flags.fcp_prio_enabled) 353562306a36Sopenharmony_ci ctx->fcp_cmnd->task_attribute |= 353662306a36Sopenharmony_ci sp->fcport->fcp_prio << 3; 353762306a36Sopenharmony_ci 353862306a36Sopenharmony_ci memcpy(ctx->fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len); 353962306a36Sopenharmony_ci 354062306a36Sopenharmony_ci fcp_dl = (__be32 *)(ctx->fcp_cmnd->cdb + 16 + 354162306a36Sopenharmony_ci additional_cdb_len); 354262306a36Sopenharmony_ci *fcp_dl = htonl((uint32_t)scsi_bufflen(cmd)); 354362306a36Sopenharmony_ci 354462306a36Sopenharmony_ci cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(ctx->fcp_cmnd_len); 354562306a36Sopenharmony_ci put_unaligned_le64(ctx->fcp_cmnd_dma, 354662306a36Sopenharmony_ci &cmd_pkt->fcp_cmnd_dseg_address); 354762306a36Sopenharmony_ci 354862306a36Sopenharmony_ci sp->flags |= SRB_FCP_CMND_DMA_VALID; 354962306a36Sopenharmony_ci cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); 355062306a36Sopenharmony_ci /* Set total data segment count. */ 355162306a36Sopenharmony_ci cmd_pkt->entry_count = (uint8_t)req_cnt; 355262306a36Sopenharmony_ci /* Specify response queue number where 355362306a36Sopenharmony_ci * completion should happen 355462306a36Sopenharmony_ci */ 355562306a36Sopenharmony_ci cmd_pkt->entry_status = (uint8_t) rsp->id; 355662306a36Sopenharmony_ci } else { 355762306a36Sopenharmony_ci struct cmd_type_7 *cmd_pkt; 355862306a36Sopenharmony_ci 355962306a36Sopenharmony_ci req_cnt = qla24xx_calc_iocbs(vha, tot_dsds); 356062306a36Sopenharmony_ci if (req->cnt < (req_cnt + 2)) { 356162306a36Sopenharmony_ci cnt = (uint16_t)rd_reg_dword_relaxed( 356262306a36Sopenharmony_ci ®->req_q_out[0]); 356362306a36Sopenharmony_ci if (req->ring_index < cnt) 356462306a36Sopenharmony_ci req->cnt = cnt - req->ring_index; 356562306a36Sopenharmony_ci else 356662306a36Sopenharmony_ci req->cnt = req->length - 356762306a36Sopenharmony_ci (req->ring_index - cnt); 356862306a36Sopenharmony_ci } 356962306a36Sopenharmony_ci if (req->cnt < (req_cnt + 2)) 357062306a36Sopenharmony_ci goto queuing_error; 357162306a36Sopenharmony_ci 357262306a36Sopenharmony_ci cmd_pkt = (struct cmd_type_7 *)req->ring_ptr; 357362306a36Sopenharmony_ci cmd_pkt->handle = make_handle(req->id, handle); 357462306a36Sopenharmony_ci 357562306a36Sopenharmony_ci /* Zero out remaining portion of packet. */ 357662306a36Sopenharmony_ci /* tagged queuing modifier -- default is TSK_SIMPLE (0).*/ 357762306a36Sopenharmony_ci clr_ptr = (uint32_t *)cmd_pkt + 2; 357862306a36Sopenharmony_ci memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); 357962306a36Sopenharmony_ci cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); 358062306a36Sopenharmony_ci 358162306a36Sopenharmony_ci /* Set NPORT-ID and LUN number*/ 358262306a36Sopenharmony_ci cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); 358362306a36Sopenharmony_ci cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; 358462306a36Sopenharmony_ci cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; 358562306a36Sopenharmony_ci cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; 358662306a36Sopenharmony_ci cmd_pkt->vp_index = sp->vha->vp_idx; 358762306a36Sopenharmony_ci 358862306a36Sopenharmony_ci int_to_scsilun(cmd->device->lun, &cmd_pkt->lun); 358962306a36Sopenharmony_ci host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, 359062306a36Sopenharmony_ci sizeof(cmd_pkt->lun)); 359162306a36Sopenharmony_ci 359262306a36Sopenharmony_ci /* Populate the FCP_PRIO. */ 359362306a36Sopenharmony_ci if (ha->flags.fcp_prio_enabled) 359462306a36Sopenharmony_ci cmd_pkt->task |= sp->fcport->fcp_prio << 3; 359562306a36Sopenharmony_ci 359662306a36Sopenharmony_ci /* Load SCSI command packet. */ 359762306a36Sopenharmony_ci memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len); 359862306a36Sopenharmony_ci host_to_fcp_swap(cmd_pkt->fcp_cdb, sizeof(cmd_pkt->fcp_cdb)); 359962306a36Sopenharmony_ci 360062306a36Sopenharmony_ci cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); 360162306a36Sopenharmony_ci 360262306a36Sopenharmony_ci /* Build IOCB segments */ 360362306a36Sopenharmony_ci qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds, req); 360462306a36Sopenharmony_ci 360562306a36Sopenharmony_ci /* Set total data segment count. */ 360662306a36Sopenharmony_ci cmd_pkt->entry_count = (uint8_t)req_cnt; 360762306a36Sopenharmony_ci /* Specify response queue number where 360862306a36Sopenharmony_ci * completion should happen. 360962306a36Sopenharmony_ci */ 361062306a36Sopenharmony_ci cmd_pkt->entry_status = (uint8_t) rsp->id; 361162306a36Sopenharmony_ci 361262306a36Sopenharmony_ci } 361362306a36Sopenharmony_ci /* Build command packet. */ 361462306a36Sopenharmony_ci req->current_outstanding_cmd = handle; 361562306a36Sopenharmony_ci req->outstanding_cmds[handle] = sp; 361662306a36Sopenharmony_ci sp->handle = handle; 361762306a36Sopenharmony_ci cmd->host_scribble = (unsigned char *)(unsigned long)handle; 361862306a36Sopenharmony_ci req->cnt -= req_cnt; 361962306a36Sopenharmony_ci wmb(); 362062306a36Sopenharmony_ci 362162306a36Sopenharmony_ci /* Adjust ring index. */ 362262306a36Sopenharmony_ci req->ring_index++; 362362306a36Sopenharmony_ci if (req->ring_index == req->length) { 362462306a36Sopenharmony_ci req->ring_index = 0; 362562306a36Sopenharmony_ci req->ring_ptr = req->ring; 362662306a36Sopenharmony_ci } else 362762306a36Sopenharmony_ci req->ring_ptr++; 362862306a36Sopenharmony_ci 362962306a36Sopenharmony_ci sp->flags |= SRB_DMA_VALID; 363062306a36Sopenharmony_ci 363162306a36Sopenharmony_ci /* Set chip new ring index. */ 363262306a36Sopenharmony_ci /* write, read and verify logic */ 363362306a36Sopenharmony_ci dbval = dbval | (req->id << 8) | (req->ring_index << 16); 363462306a36Sopenharmony_ci if (ql2xdbwr) 363562306a36Sopenharmony_ci qla82xx_wr_32(ha, (uintptr_t __force)ha->nxdb_wr_ptr, dbval); 363662306a36Sopenharmony_ci else { 363762306a36Sopenharmony_ci wrt_reg_dword(ha->nxdb_wr_ptr, dbval); 363862306a36Sopenharmony_ci wmb(); 363962306a36Sopenharmony_ci while (rd_reg_dword(ha->nxdb_rd_ptr) != dbval) { 364062306a36Sopenharmony_ci wrt_reg_dword(ha->nxdb_wr_ptr, dbval); 364162306a36Sopenharmony_ci wmb(); 364262306a36Sopenharmony_ci } 364362306a36Sopenharmony_ci } 364462306a36Sopenharmony_ci 364562306a36Sopenharmony_ci /* Manage unprocessed RIO/ZIO commands in response queue. */ 364662306a36Sopenharmony_ci if (vha->flags.process_response_queue && 364762306a36Sopenharmony_ci rsp->ring_ptr->signature != RESPONSE_PROCESSED) 364862306a36Sopenharmony_ci qla24xx_process_response_queue(vha, rsp); 364962306a36Sopenharmony_ci 365062306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 365162306a36Sopenharmony_ci return QLA_SUCCESS; 365262306a36Sopenharmony_ci 365362306a36Sopenharmony_ciqueuing_error_fcp_cmnd: 365462306a36Sopenharmony_ci dma_pool_free(ha->fcp_cmnd_dma_pool, ctx->fcp_cmnd, ctx->fcp_cmnd_dma); 365562306a36Sopenharmony_ciqueuing_error: 365662306a36Sopenharmony_ci if (tot_dsds) 365762306a36Sopenharmony_ci scsi_dma_unmap(cmd); 365862306a36Sopenharmony_ci 365962306a36Sopenharmony_ci if (sp->u.scmd.crc_ctx) { 366062306a36Sopenharmony_ci mempool_free(sp->u.scmd.crc_ctx, ha->ctx_mempool); 366162306a36Sopenharmony_ci sp->u.scmd.crc_ctx = NULL; 366262306a36Sopenharmony_ci } 366362306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 366462306a36Sopenharmony_ci 366562306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 366662306a36Sopenharmony_ci} 366762306a36Sopenharmony_ci 366862306a36Sopenharmony_cistatic void 366962306a36Sopenharmony_ciqla24xx_abort_iocb(srb_t *sp, struct abort_entry_24xx *abt_iocb) 367062306a36Sopenharmony_ci{ 367162306a36Sopenharmony_ci struct srb_iocb *aio = &sp->u.iocb_cmd; 367262306a36Sopenharmony_ci scsi_qla_host_t *vha = sp->vha; 367362306a36Sopenharmony_ci struct req_que *req = sp->qpair->req; 367462306a36Sopenharmony_ci srb_t *orig_sp = sp->cmd_sp; 367562306a36Sopenharmony_ci 367662306a36Sopenharmony_ci memset(abt_iocb, 0, sizeof(struct abort_entry_24xx)); 367762306a36Sopenharmony_ci abt_iocb->entry_type = ABORT_IOCB_TYPE; 367862306a36Sopenharmony_ci abt_iocb->entry_count = 1; 367962306a36Sopenharmony_ci abt_iocb->handle = make_handle(req->id, sp->handle); 368062306a36Sopenharmony_ci if (sp->fcport) { 368162306a36Sopenharmony_ci abt_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id); 368262306a36Sopenharmony_ci abt_iocb->port_id[0] = sp->fcport->d_id.b.al_pa; 368362306a36Sopenharmony_ci abt_iocb->port_id[1] = sp->fcport->d_id.b.area; 368462306a36Sopenharmony_ci abt_iocb->port_id[2] = sp->fcport->d_id.b.domain; 368562306a36Sopenharmony_ci } 368662306a36Sopenharmony_ci abt_iocb->handle_to_abort = 368762306a36Sopenharmony_ci make_handle(le16_to_cpu(aio->u.abt.req_que_no), 368862306a36Sopenharmony_ci aio->u.abt.cmd_hndl); 368962306a36Sopenharmony_ci abt_iocb->vp_index = vha->vp_idx; 369062306a36Sopenharmony_ci abt_iocb->req_que_no = aio->u.abt.req_que_no; 369162306a36Sopenharmony_ci 369262306a36Sopenharmony_ci /* need to pass original sp */ 369362306a36Sopenharmony_ci if (orig_sp) 369462306a36Sopenharmony_ci qla_nvme_abort_set_option(abt_iocb, orig_sp); 369562306a36Sopenharmony_ci 369662306a36Sopenharmony_ci /* Send the command to the firmware */ 369762306a36Sopenharmony_ci wmb(); 369862306a36Sopenharmony_ci} 369962306a36Sopenharmony_ci 370062306a36Sopenharmony_cistatic void 370162306a36Sopenharmony_ciqla2x00_mb_iocb(srb_t *sp, struct mbx_24xx_entry *mbx) 370262306a36Sopenharmony_ci{ 370362306a36Sopenharmony_ci int i, sz; 370462306a36Sopenharmony_ci 370562306a36Sopenharmony_ci mbx->entry_type = MBX_IOCB_TYPE; 370662306a36Sopenharmony_ci mbx->handle = sp->handle; 370762306a36Sopenharmony_ci sz = min(ARRAY_SIZE(mbx->mb), ARRAY_SIZE(sp->u.iocb_cmd.u.mbx.out_mb)); 370862306a36Sopenharmony_ci 370962306a36Sopenharmony_ci for (i = 0; i < sz; i++) 371062306a36Sopenharmony_ci mbx->mb[i] = sp->u.iocb_cmd.u.mbx.out_mb[i]; 371162306a36Sopenharmony_ci} 371262306a36Sopenharmony_ci 371362306a36Sopenharmony_cistatic void 371462306a36Sopenharmony_ciqla2x00_ctpthru_cmd_iocb(srb_t *sp, struct ct_entry_24xx *ct_pkt) 371562306a36Sopenharmony_ci{ 371662306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.iocb = ct_pkt; 371762306a36Sopenharmony_ci qla24xx_prep_ms_iocb(sp->vha, &sp->u.iocb_cmd.u.ctarg); 371862306a36Sopenharmony_ci ct_pkt->handle = sp->handle; 371962306a36Sopenharmony_ci} 372062306a36Sopenharmony_ci 372162306a36Sopenharmony_cistatic void qla2x00_send_notify_ack_iocb(srb_t *sp, 372262306a36Sopenharmony_ci struct nack_to_isp *nack) 372362306a36Sopenharmony_ci{ 372462306a36Sopenharmony_ci struct imm_ntfy_from_isp *ntfy = sp->u.iocb_cmd.u.nack.ntfy; 372562306a36Sopenharmony_ci 372662306a36Sopenharmony_ci nack->entry_type = NOTIFY_ACK_TYPE; 372762306a36Sopenharmony_ci nack->entry_count = 1; 372862306a36Sopenharmony_ci nack->ox_id = ntfy->ox_id; 372962306a36Sopenharmony_ci 373062306a36Sopenharmony_ci nack->u.isp24.handle = sp->handle; 373162306a36Sopenharmony_ci nack->u.isp24.nport_handle = ntfy->u.isp24.nport_handle; 373262306a36Sopenharmony_ci if (le16_to_cpu(ntfy->u.isp24.status) == IMM_NTFY_ELS) { 373362306a36Sopenharmony_ci nack->u.isp24.flags = ntfy->u.isp24.flags & 373462306a36Sopenharmony_ci cpu_to_le16(NOTIFY24XX_FLAGS_PUREX_IOCB); 373562306a36Sopenharmony_ci } 373662306a36Sopenharmony_ci nack->u.isp24.srr_rx_id = ntfy->u.isp24.srr_rx_id; 373762306a36Sopenharmony_ci nack->u.isp24.status = ntfy->u.isp24.status; 373862306a36Sopenharmony_ci nack->u.isp24.status_subcode = ntfy->u.isp24.status_subcode; 373962306a36Sopenharmony_ci nack->u.isp24.fw_handle = ntfy->u.isp24.fw_handle; 374062306a36Sopenharmony_ci nack->u.isp24.exchange_address = ntfy->u.isp24.exchange_address; 374162306a36Sopenharmony_ci nack->u.isp24.srr_rel_offs = ntfy->u.isp24.srr_rel_offs; 374262306a36Sopenharmony_ci nack->u.isp24.srr_ui = ntfy->u.isp24.srr_ui; 374362306a36Sopenharmony_ci nack->u.isp24.srr_flags = 0; 374462306a36Sopenharmony_ci nack->u.isp24.srr_reject_code = 0; 374562306a36Sopenharmony_ci nack->u.isp24.srr_reject_code_expl = 0; 374662306a36Sopenharmony_ci nack->u.isp24.vp_index = ntfy->u.isp24.vp_index; 374762306a36Sopenharmony_ci 374862306a36Sopenharmony_ci if (ntfy->u.isp24.status_subcode == ELS_PLOGI && 374962306a36Sopenharmony_ci (le16_to_cpu(ntfy->u.isp24.flags) & NOTIFY24XX_FLAGS_FCSP) && 375062306a36Sopenharmony_ci sp->vha->hw->flags.edif_enabled) { 375162306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, sp->vha, 0x3074, 375262306a36Sopenharmony_ci "%s PLOGI NACK sent with FC SECURITY bit, hdl=%x, loopid=%x, to pid %06x\n", 375362306a36Sopenharmony_ci sp->name, sp->handle, sp->fcport->loop_id, 375462306a36Sopenharmony_ci sp->fcport->d_id.b24); 375562306a36Sopenharmony_ci nack->u.isp24.flags |= cpu_to_le16(NOTIFY_ACK_FLAGS_FCSP); 375662306a36Sopenharmony_ci } 375762306a36Sopenharmony_ci} 375862306a36Sopenharmony_ci 375962306a36Sopenharmony_ci/* 376062306a36Sopenharmony_ci * Build NVME LS request 376162306a36Sopenharmony_ci */ 376262306a36Sopenharmony_cistatic void 376362306a36Sopenharmony_ciqla_nvme_ls(srb_t *sp, struct pt_ls4_request *cmd_pkt) 376462306a36Sopenharmony_ci{ 376562306a36Sopenharmony_ci struct srb_iocb *nvme; 376662306a36Sopenharmony_ci 376762306a36Sopenharmony_ci nvme = &sp->u.iocb_cmd; 376862306a36Sopenharmony_ci cmd_pkt->entry_type = PT_LS4_REQUEST; 376962306a36Sopenharmony_ci cmd_pkt->entry_count = 1; 377062306a36Sopenharmony_ci cmd_pkt->timeout = cpu_to_le16(nvme->u.nvme.timeout_sec); 377162306a36Sopenharmony_ci cmd_pkt->vp_index = sp->fcport->vha->vp_idx; 377262306a36Sopenharmony_ci 377362306a36Sopenharmony_ci if (sp->unsol_rsp) { 377462306a36Sopenharmony_ci cmd_pkt->control_flags = 377562306a36Sopenharmony_ci cpu_to_le16(CF_LS4_RESPONDER << CF_LS4_SHIFT); 377662306a36Sopenharmony_ci cmd_pkt->nport_handle = nvme->u.nvme.nport_handle; 377762306a36Sopenharmony_ci cmd_pkt->exchange_address = nvme->u.nvme.exchange_address; 377862306a36Sopenharmony_ci } else { 377962306a36Sopenharmony_ci cmd_pkt->control_flags = 378062306a36Sopenharmony_ci cpu_to_le16(CF_LS4_ORIGINATOR << CF_LS4_SHIFT); 378162306a36Sopenharmony_ci cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); 378262306a36Sopenharmony_ci cmd_pkt->rx_dseg_count = cpu_to_le16(1); 378362306a36Sopenharmony_ci cmd_pkt->rx_byte_count = nvme->u.nvme.rsp_len; 378462306a36Sopenharmony_ci cmd_pkt->dsd[1].length = nvme->u.nvme.rsp_len; 378562306a36Sopenharmony_ci put_unaligned_le64(nvme->u.nvme.rsp_dma, &cmd_pkt->dsd[1].address); 378662306a36Sopenharmony_ci } 378762306a36Sopenharmony_ci 378862306a36Sopenharmony_ci cmd_pkt->tx_dseg_count = cpu_to_le16(1); 378962306a36Sopenharmony_ci cmd_pkt->tx_byte_count = nvme->u.nvme.cmd_len; 379062306a36Sopenharmony_ci cmd_pkt->dsd[0].length = nvme->u.nvme.cmd_len; 379162306a36Sopenharmony_ci put_unaligned_le64(nvme->u.nvme.cmd_dma, &cmd_pkt->dsd[0].address); 379262306a36Sopenharmony_ci} 379362306a36Sopenharmony_ci 379462306a36Sopenharmony_cistatic void 379562306a36Sopenharmony_ciqla25xx_ctrlvp_iocb(srb_t *sp, struct vp_ctrl_entry_24xx *vce) 379662306a36Sopenharmony_ci{ 379762306a36Sopenharmony_ci int map, pos; 379862306a36Sopenharmony_ci 379962306a36Sopenharmony_ci vce->entry_type = VP_CTRL_IOCB_TYPE; 380062306a36Sopenharmony_ci vce->handle = sp->handle; 380162306a36Sopenharmony_ci vce->entry_count = 1; 380262306a36Sopenharmony_ci vce->command = cpu_to_le16(sp->u.iocb_cmd.u.ctrlvp.cmd); 380362306a36Sopenharmony_ci vce->vp_count = cpu_to_le16(1); 380462306a36Sopenharmony_ci 380562306a36Sopenharmony_ci /* 380662306a36Sopenharmony_ci * index map in firmware starts with 1; decrement index 380762306a36Sopenharmony_ci * this is ok as we never use index 0 380862306a36Sopenharmony_ci */ 380962306a36Sopenharmony_ci map = (sp->u.iocb_cmd.u.ctrlvp.vp_index - 1) / 8; 381062306a36Sopenharmony_ci pos = (sp->u.iocb_cmd.u.ctrlvp.vp_index - 1) & 7; 381162306a36Sopenharmony_ci vce->vp_idx_map[map] |= 1 << pos; 381262306a36Sopenharmony_ci} 381362306a36Sopenharmony_ci 381462306a36Sopenharmony_cistatic void 381562306a36Sopenharmony_ciqla24xx_prlo_iocb(srb_t *sp, struct logio_entry_24xx *logio) 381662306a36Sopenharmony_ci{ 381762306a36Sopenharmony_ci logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; 381862306a36Sopenharmony_ci logio->control_flags = 381962306a36Sopenharmony_ci cpu_to_le16(LCF_COMMAND_PRLO|LCF_IMPL_PRLO); 382062306a36Sopenharmony_ci 382162306a36Sopenharmony_ci logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); 382262306a36Sopenharmony_ci logio->port_id[0] = sp->fcport->d_id.b.al_pa; 382362306a36Sopenharmony_ci logio->port_id[1] = sp->fcport->d_id.b.area; 382462306a36Sopenharmony_ci logio->port_id[2] = sp->fcport->d_id.b.domain; 382562306a36Sopenharmony_ci logio->vp_index = sp->fcport->vha->vp_idx; 382662306a36Sopenharmony_ci} 382762306a36Sopenharmony_ci 382862306a36Sopenharmony_cistatic int qla_get_iocbs_resource(struct srb *sp) 382962306a36Sopenharmony_ci{ 383062306a36Sopenharmony_ci bool get_exch; 383162306a36Sopenharmony_ci bool push_it_through = false; 383262306a36Sopenharmony_ci 383362306a36Sopenharmony_ci if (!ql2xenforce_iocb_limit) { 383462306a36Sopenharmony_ci sp->iores.res_type = RESOURCE_NONE; 383562306a36Sopenharmony_ci return 0; 383662306a36Sopenharmony_ci } 383762306a36Sopenharmony_ci sp->iores.res_type = RESOURCE_NONE; 383862306a36Sopenharmony_ci 383962306a36Sopenharmony_ci switch (sp->type) { 384062306a36Sopenharmony_ci case SRB_TM_CMD: 384162306a36Sopenharmony_ci case SRB_PRLI_CMD: 384262306a36Sopenharmony_ci case SRB_ADISC_CMD: 384362306a36Sopenharmony_ci push_it_through = true; 384462306a36Sopenharmony_ci fallthrough; 384562306a36Sopenharmony_ci case SRB_LOGIN_CMD: 384662306a36Sopenharmony_ci case SRB_ELS_CMD_RPT: 384762306a36Sopenharmony_ci case SRB_ELS_CMD_HST: 384862306a36Sopenharmony_ci case SRB_ELS_CMD_HST_NOLOGIN: 384962306a36Sopenharmony_ci case SRB_CT_CMD: 385062306a36Sopenharmony_ci case SRB_NVME_LS: 385162306a36Sopenharmony_ci case SRB_ELS_DCMD: 385262306a36Sopenharmony_ci get_exch = true; 385362306a36Sopenharmony_ci break; 385462306a36Sopenharmony_ci 385562306a36Sopenharmony_ci case SRB_FXIOCB_DCMD: 385662306a36Sopenharmony_ci case SRB_FXIOCB_BCMD: 385762306a36Sopenharmony_ci sp->iores.res_type = RESOURCE_NONE; 385862306a36Sopenharmony_ci return 0; 385962306a36Sopenharmony_ci 386062306a36Sopenharmony_ci case SRB_SA_UPDATE: 386162306a36Sopenharmony_ci case SRB_SA_REPLACE: 386262306a36Sopenharmony_ci case SRB_MB_IOCB: 386362306a36Sopenharmony_ci case SRB_ABT_CMD: 386462306a36Sopenharmony_ci case SRB_NACK_PLOGI: 386562306a36Sopenharmony_ci case SRB_NACK_PRLI: 386662306a36Sopenharmony_ci case SRB_NACK_LOGO: 386762306a36Sopenharmony_ci case SRB_LOGOUT_CMD: 386862306a36Sopenharmony_ci case SRB_CTRL_VP: 386962306a36Sopenharmony_ci case SRB_MARKER: 387062306a36Sopenharmony_ci default: 387162306a36Sopenharmony_ci push_it_through = true; 387262306a36Sopenharmony_ci get_exch = false; 387362306a36Sopenharmony_ci } 387462306a36Sopenharmony_ci 387562306a36Sopenharmony_ci sp->iores.res_type |= RESOURCE_IOCB; 387662306a36Sopenharmony_ci sp->iores.iocb_cnt = 1; 387762306a36Sopenharmony_ci if (get_exch) { 387862306a36Sopenharmony_ci sp->iores.res_type |= RESOURCE_EXCH; 387962306a36Sopenharmony_ci sp->iores.exch_cnt = 1; 388062306a36Sopenharmony_ci } 388162306a36Sopenharmony_ci if (push_it_through) 388262306a36Sopenharmony_ci sp->iores.res_type |= RESOURCE_FORCE; 388362306a36Sopenharmony_ci 388462306a36Sopenharmony_ci return qla_get_fw_resources(sp->qpair, &sp->iores); 388562306a36Sopenharmony_ci} 388662306a36Sopenharmony_ci 388762306a36Sopenharmony_cistatic void 388862306a36Sopenharmony_ciqla_marker_iocb(srb_t *sp, struct mrk_entry_24xx *mrk) 388962306a36Sopenharmony_ci{ 389062306a36Sopenharmony_ci mrk->entry_type = MARKER_TYPE; 389162306a36Sopenharmony_ci mrk->modifier = sp->u.iocb_cmd.u.tmf.modifier; 389262306a36Sopenharmony_ci mrk->handle = make_handle(sp->qpair->req->id, sp->handle); 389362306a36Sopenharmony_ci if (sp->u.iocb_cmd.u.tmf.modifier != MK_SYNC_ALL) { 389462306a36Sopenharmony_ci mrk->nport_handle = cpu_to_le16(sp->u.iocb_cmd.u.tmf.loop_id); 389562306a36Sopenharmony_ci int_to_scsilun(sp->u.iocb_cmd.u.tmf.lun, (struct scsi_lun *)&mrk->lun); 389662306a36Sopenharmony_ci host_to_fcp_swap(mrk->lun, sizeof(mrk->lun)); 389762306a36Sopenharmony_ci mrk->vp_index = sp->u.iocb_cmd.u.tmf.vp_index; 389862306a36Sopenharmony_ci } 389962306a36Sopenharmony_ci} 390062306a36Sopenharmony_ci 390162306a36Sopenharmony_ciint 390262306a36Sopenharmony_ciqla2x00_start_sp(srb_t *sp) 390362306a36Sopenharmony_ci{ 390462306a36Sopenharmony_ci int rval = QLA_SUCCESS; 390562306a36Sopenharmony_ci scsi_qla_host_t *vha = sp->vha; 390662306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 390762306a36Sopenharmony_ci struct qla_qpair *qp = sp->qpair; 390862306a36Sopenharmony_ci void *pkt; 390962306a36Sopenharmony_ci unsigned long flags; 391062306a36Sopenharmony_ci 391162306a36Sopenharmony_ci if (vha->hw->flags.eeh_busy) 391262306a36Sopenharmony_ci return -EIO; 391362306a36Sopenharmony_ci 391462306a36Sopenharmony_ci spin_lock_irqsave(qp->qp_lock_ptr, flags); 391562306a36Sopenharmony_ci rval = qla_get_iocbs_resource(sp); 391662306a36Sopenharmony_ci if (rval) { 391762306a36Sopenharmony_ci spin_unlock_irqrestore(qp->qp_lock_ptr, flags); 391862306a36Sopenharmony_ci return -EAGAIN; 391962306a36Sopenharmony_ci } 392062306a36Sopenharmony_ci 392162306a36Sopenharmony_ci pkt = __qla2x00_alloc_iocbs(sp->qpair, sp); 392262306a36Sopenharmony_ci if (!pkt) { 392362306a36Sopenharmony_ci rval = -EAGAIN; 392462306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x700c, 392562306a36Sopenharmony_ci "qla2x00_alloc_iocbs failed.\n"); 392662306a36Sopenharmony_ci goto done; 392762306a36Sopenharmony_ci } 392862306a36Sopenharmony_ci 392962306a36Sopenharmony_ci switch (sp->type) { 393062306a36Sopenharmony_ci case SRB_LOGIN_CMD: 393162306a36Sopenharmony_ci IS_FWI2_CAPABLE(ha) ? 393262306a36Sopenharmony_ci qla24xx_login_iocb(sp, pkt) : 393362306a36Sopenharmony_ci qla2x00_login_iocb(sp, pkt); 393462306a36Sopenharmony_ci break; 393562306a36Sopenharmony_ci case SRB_PRLI_CMD: 393662306a36Sopenharmony_ci qla24xx_prli_iocb(sp, pkt); 393762306a36Sopenharmony_ci break; 393862306a36Sopenharmony_ci case SRB_LOGOUT_CMD: 393962306a36Sopenharmony_ci IS_FWI2_CAPABLE(ha) ? 394062306a36Sopenharmony_ci qla24xx_logout_iocb(sp, pkt) : 394162306a36Sopenharmony_ci qla2x00_logout_iocb(sp, pkt); 394262306a36Sopenharmony_ci break; 394362306a36Sopenharmony_ci case SRB_ELS_CMD_RPT: 394462306a36Sopenharmony_ci case SRB_ELS_CMD_HST: 394562306a36Sopenharmony_ci qla24xx_els_iocb(sp, pkt); 394662306a36Sopenharmony_ci break; 394762306a36Sopenharmony_ci case SRB_ELS_CMD_HST_NOLOGIN: 394862306a36Sopenharmony_ci qla_els_pt_iocb(sp->vha, pkt, &sp->u.bsg_cmd.u.els_arg); 394962306a36Sopenharmony_ci ((struct els_entry_24xx *)pkt)->handle = sp->handle; 395062306a36Sopenharmony_ci break; 395162306a36Sopenharmony_ci case SRB_CT_CMD: 395262306a36Sopenharmony_ci IS_FWI2_CAPABLE(ha) ? 395362306a36Sopenharmony_ci qla24xx_ct_iocb(sp, pkt) : 395462306a36Sopenharmony_ci qla2x00_ct_iocb(sp, pkt); 395562306a36Sopenharmony_ci break; 395662306a36Sopenharmony_ci case SRB_ADISC_CMD: 395762306a36Sopenharmony_ci IS_FWI2_CAPABLE(ha) ? 395862306a36Sopenharmony_ci qla24xx_adisc_iocb(sp, pkt) : 395962306a36Sopenharmony_ci qla2x00_adisc_iocb(sp, pkt); 396062306a36Sopenharmony_ci break; 396162306a36Sopenharmony_ci case SRB_TM_CMD: 396262306a36Sopenharmony_ci IS_QLAFX00(ha) ? 396362306a36Sopenharmony_ci qlafx00_tm_iocb(sp, pkt) : 396462306a36Sopenharmony_ci qla24xx_tm_iocb(sp, pkt); 396562306a36Sopenharmony_ci break; 396662306a36Sopenharmony_ci case SRB_FXIOCB_DCMD: 396762306a36Sopenharmony_ci case SRB_FXIOCB_BCMD: 396862306a36Sopenharmony_ci qlafx00_fxdisc_iocb(sp, pkt); 396962306a36Sopenharmony_ci break; 397062306a36Sopenharmony_ci case SRB_NVME_LS: 397162306a36Sopenharmony_ci qla_nvme_ls(sp, pkt); 397262306a36Sopenharmony_ci break; 397362306a36Sopenharmony_ci case SRB_ABT_CMD: 397462306a36Sopenharmony_ci IS_QLAFX00(ha) ? 397562306a36Sopenharmony_ci qlafx00_abort_iocb(sp, pkt) : 397662306a36Sopenharmony_ci qla24xx_abort_iocb(sp, pkt); 397762306a36Sopenharmony_ci break; 397862306a36Sopenharmony_ci case SRB_ELS_DCMD: 397962306a36Sopenharmony_ci qla24xx_els_logo_iocb(sp, pkt); 398062306a36Sopenharmony_ci break; 398162306a36Sopenharmony_ci case SRB_CT_PTHRU_CMD: 398262306a36Sopenharmony_ci qla2x00_ctpthru_cmd_iocb(sp, pkt); 398362306a36Sopenharmony_ci break; 398462306a36Sopenharmony_ci case SRB_MB_IOCB: 398562306a36Sopenharmony_ci qla2x00_mb_iocb(sp, pkt); 398662306a36Sopenharmony_ci break; 398762306a36Sopenharmony_ci case SRB_NACK_PLOGI: 398862306a36Sopenharmony_ci case SRB_NACK_PRLI: 398962306a36Sopenharmony_ci case SRB_NACK_LOGO: 399062306a36Sopenharmony_ci qla2x00_send_notify_ack_iocb(sp, pkt); 399162306a36Sopenharmony_ci break; 399262306a36Sopenharmony_ci case SRB_CTRL_VP: 399362306a36Sopenharmony_ci qla25xx_ctrlvp_iocb(sp, pkt); 399462306a36Sopenharmony_ci break; 399562306a36Sopenharmony_ci case SRB_PRLO_CMD: 399662306a36Sopenharmony_ci qla24xx_prlo_iocb(sp, pkt); 399762306a36Sopenharmony_ci break; 399862306a36Sopenharmony_ci case SRB_SA_UPDATE: 399962306a36Sopenharmony_ci qla24xx_sa_update_iocb(sp, pkt); 400062306a36Sopenharmony_ci break; 400162306a36Sopenharmony_ci case SRB_SA_REPLACE: 400262306a36Sopenharmony_ci qla24xx_sa_replace_iocb(sp, pkt); 400362306a36Sopenharmony_ci break; 400462306a36Sopenharmony_ci case SRB_MARKER: 400562306a36Sopenharmony_ci qla_marker_iocb(sp, pkt); 400662306a36Sopenharmony_ci break; 400762306a36Sopenharmony_ci default: 400862306a36Sopenharmony_ci break; 400962306a36Sopenharmony_ci } 401062306a36Sopenharmony_ci 401162306a36Sopenharmony_ci if (sp->start_timer) { 401262306a36Sopenharmony_ci /* ref: TMR timer ref 401362306a36Sopenharmony_ci * this code should be just before start_iocbs function 401462306a36Sopenharmony_ci * This will make sure that caller function don't to do 401562306a36Sopenharmony_ci * kref_put even on failure 401662306a36Sopenharmony_ci */ 401762306a36Sopenharmony_ci kref_get(&sp->cmd_kref); 401862306a36Sopenharmony_ci add_timer(&sp->u.iocb_cmd.timer); 401962306a36Sopenharmony_ci } 402062306a36Sopenharmony_ci 402162306a36Sopenharmony_ci wmb(); 402262306a36Sopenharmony_ci qla2x00_start_iocbs(vha, qp->req); 402362306a36Sopenharmony_cidone: 402462306a36Sopenharmony_ci if (rval) 402562306a36Sopenharmony_ci qla_put_fw_resources(sp->qpair, &sp->iores); 402662306a36Sopenharmony_ci spin_unlock_irqrestore(qp->qp_lock_ptr, flags); 402762306a36Sopenharmony_ci return rval; 402862306a36Sopenharmony_ci} 402962306a36Sopenharmony_ci 403062306a36Sopenharmony_cistatic void 403162306a36Sopenharmony_ciqla25xx_build_bidir_iocb(srb_t *sp, struct scsi_qla_host *vha, 403262306a36Sopenharmony_ci struct cmd_bidir *cmd_pkt, uint32_t tot_dsds) 403362306a36Sopenharmony_ci{ 403462306a36Sopenharmony_ci uint16_t avail_dsds; 403562306a36Sopenharmony_ci struct dsd64 *cur_dsd; 403662306a36Sopenharmony_ci uint32_t req_data_len = 0; 403762306a36Sopenharmony_ci uint32_t rsp_data_len = 0; 403862306a36Sopenharmony_ci struct scatterlist *sg; 403962306a36Sopenharmony_ci int index; 404062306a36Sopenharmony_ci int entry_count = 1; 404162306a36Sopenharmony_ci struct bsg_job *bsg_job = sp->u.bsg_job; 404262306a36Sopenharmony_ci 404362306a36Sopenharmony_ci /*Update entry type to indicate bidir command */ 404462306a36Sopenharmony_ci put_unaligned_le32(COMMAND_BIDIRECTIONAL, &cmd_pkt->entry_type); 404562306a36Sopenharmony_ci 404662306a36Sopenharmony_ci /* Set the transfer direction, in this set both flags 404762306a36Sopenharmony_ci * Also set the BD_WRAP_BACK flag, firmware will take care 404862306a36Sopenharmony_ci * assigning DID=SID for outgoing pkts. 404962306a36Sopenharmony_ci */ 405062306a36Sopenharmony_ci cmd_pkt->wr_dseg_count = cpu_to_le16(bsg_job->request_payload.sg_cnt); 405162306a36Sopenharmony_ci cmd_pkt->rd_dseg_count = cpu_to_le16(bsg_job->reply_payload.sg_cnt); 405262306a36Sopenharmony_ci cmd_pkt->control_flags = cpu_to_le16(BD_WRITE_DATA | BD_READ_DATA | 405362306a36Sopenharmony_ci BD_WRAP_BACK); 405462306a36Sopenharmony_ci 405562306a36Sopenharmony_ci req_data_len = rsp_data_len = bsg_job->request_payload.payload_len; 405662306a36Sopenharmony_ci cmd_pkt->wr_byte_count = cpu_to_le32(req_data_len); 405762306a36Sopenharmony_ci cmd_pkt->rd_byte_count = cpu_to_le32(rsp_data_len); 405862306a36Sopenharmony_ci cmd_pkt->timeout = cpu_to_le16(qla2x00_get_async_timeout(vha) + 2); 405962306a36Sopenharmony_ci 406062306a36Sopenharmony_ci vha->bidi_stats.transfer_bytes += req_data_len; 406162306a36Sopenharmony_ci vha->bidi_stats.io_count++; 406262306a36Sopenharmony_ci 406362306a36Sopenharmony_ci vha->qla_stats.output_bytes += req_data_len; 406462306a36Sopenharmony_ci vha->qla_stats.output_requests++; 406562306a36Sopenharmony_ci 406662306a36Sopenharmony_ci /* Only one dsd is available for bidirectional IOCB, remaining dsds 406762306a36Sopenharmony_ci * are bundled in continuation iocb 406862306a36Sopenharmony_ci */ 406962306a36Sopenharmony_ci avail_dsds = 1; 407062306a36Sopenharmony_ci cur_dsd = &cmd_pkt->fcp_dsd; 407162306a36Sopenharmony_ci 407262306a36Sopenharmony_ci index = 0; 407362306a36Sopenharmony_ci 407462306a36Sopenharmony_ci for_each_sg(bsg_job->request_payload.sg_list, sg, 407562306a36Sopenharmony_ci bsg_job->request_payload.sg_cnt, index) { 407662306a36Sopenharmony_ci cont_a64_entry_t *cont_pkt; 407762306a36Sopenharmony_ci 407862306a36Sopenharmony_ci /* Allocate additional continuation packets */ 407962306a36Sopenharmony_ci if (avail_dsds == 0) { 408062306a36Sopenharmony_ci /* Continuation type 1 IOCB can accomodate 408162306a36Sopenharmony_ci * 5 DSDS 408262306a36Sopenharmony_ci */ 408362306a36Sopenharmony_ci cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->req); 408462306a36Sopenharmony_ci cur_dsd = cont_pkt->dsd; 408562306a36Sopenharmony_ci avail_dsds = 5; 408662306a36Sopenharmony_ci entry_count++; 408762306a36Sopenharmony_ci } 408862306a36Sopenharmony_ci append_dsd64(&cur_dsd, sg); 408962306a36Sopenharmony_ci avail_dsds--; 409062306a36Sopenharmony_ci } 409162306a36Sopenharmony_ci /* For read request DSD will always goes to continuation IOCB 409262306a36Sopenharmony_ci * and follow the write DSD. If there is room on the current IOCB 409362306a36Sopenharmony_ci * then it is added to that IOCB else new continuation IOCB is 409462306a36Sopenharmony_ci * allocated. 409562306a36Sopenharmony_ci */ 409662306a36Sopenharmony_ci for_each_sg(bsg_job->reply_payload.sg_list, sg, 409762306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, index) { 409862306a36Sopenharmony_ci cont_a64_entry_t *cont_pkt; 409962306a36Sopenharmony_ci 410062306a36Sopenharmony_ci /* Allocate additional continuation packets */ 410162306a36Sopenharmony_ci if (avail_dsds == 0) { 410262306a36Sopenharmony_ci /* Continuation type 1 IOCB can accomodate 410362306a36Sopenharmony_ci * 5 DSDS 410462306a36Sopenharmony_ci */ 410562306a36Sopenharmony_ci cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->req); 410662306a36Sopenharmony_ci cur_dsd = cont_pkt->dsd; 410762306a36Sopenharmony_ci avail_dsds = 5; 410862306a36Sopenharmony_ci entry_count++; 410962306a36Sopenharmony_ci } 411062306a36Sopenharmony_ci append_dsd64(&cur_dsd, sg); 411162306a36Sopenharmony_ci avail_dsds--; 411262306a36Sopenharmony_ci } 411362306a36Sopenharmony_ci /* This value should be same as number of IOCB required for this cmd */ 411462306a36Sopenharmony_ci cmd_pkt->entry_count = entry_count; 411562306a36Sopenharmony_ci} 411662306a36Sopenharmony_ci 411762306a36Sopenharmony_ciint 411862306a36Sopenharmony_ciqla2x00_start_bidir(srb_t *sp, struct scsi_qla_host *vha, uint32_t tot_dsds) 411962306a36Sopenharmony_ci{ 412062306a36Sopenharmony_ci 412162306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 412262306a36Sopenharmony_ci unsigned long flags; 412362306a36Sopenharmony_ci uint32_t handle; 412462306a36Sopenharmony_ci uint16_t req_cnt; 412562306a36Sopenharmony_ci uint16_t cnt; 412662306a36Sopenharmony_ci uint32_t *clr_ptr; 412762306a36Sopenharmony_ci struct cmd_bidir *cmd_pkt = NULL; 412862306a36Sopenharmony_ci struct rsp_que *rsp; 412962306a36Sopenharmony_ci struct req_que *req; 413062306a36Sopenharmony_ci int rval = EXT_STATUS_OK; 413162306a36Sopenharmony_ci 413262306a36Sopenharmony_ci rval = QLA_SUCCESS; 413362306a36Sopenharmony_ci 413462306a36Sopenharmony_ci rsp = ha->rsp_q_map[0]; 413562306a36Sopenharmony_ci req = vha->req; 413662306a36Sopenharmony_ci 413762306a36Sopenharmony_ci /* Send marker if required */ 413862306a36Sopenharmony_ci if (vha->marker_needed != 0) { 413962306a36Sopenharmony_ci if (qla2x00_marker(vha, ha->base_qpair, 414062306a36Sopenharmony_ci 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) 414162306a36Sopenharmony_ci return EXT_STATUS_MAILBOX; 414262306a36Sopenharmony_ci vha->marker_needed = 0; 414362306a36Sopenharmony_ci } 414462306a36Sopenharmony_ci 414562306a36Sopenharmony_ci /* Acquire ring specific lock */ 414662306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 414762306a36Sopenharmony_ci 414862306a36Sopenharmony_ci handle = qla2xxx_get_next_handle(req); 414962306a36Sopenharmony_ci if (handle == 0) { 415062306a36Sopenharmony_ci rval = EXT_STATUS_BUSY; 415162306a36Sopenharmony_ci goto queuing_error; 415262306a36Sopenharmony_ci } 415362306a36Sopenharmony_ci 415462306a36Sopenharmony_ci /* Calculate number of IOCB required */ 415562306a36Sopenharmony_ci req_cnt = qla24xx_calc_iocbs(vha, tot_dsds); 415662306a36Sopenharmony_ci 415762306a36Sopenharmony_ci /* Check for room on request queue. */ 415862306a36Sopenharmony_ci if (req->cnt < req_cnt + 2) { 415962306a36Sopenharmony_ci if (IS_SHADOW_REG_CAPABLE(ha)) { 416062306a36Sopenharmony_ci cnt = *req->out_ptr; 416162306a36Sopenharmony_ci } else { 416262306a36Sopenharmony_ci cnt = rd_reg_dword_relaxed(req->req_q_out); 416362306a36Sopenharmony_ci if (qla2x00_check_reg16_for_disconnect(vha, cnt)) 416462306a36Sopenharmony_ci goto queuing_error; 416562306a36Sopenharmony_ci } 416662306a36Sopenharmony_ci 416762306a36Sopenharmony_ci if (req->ring_index < cnt) 416862306a36Sopenharmony_ci req->cnt = cnt - req->ring_index; 416962306a36Sopenharmony_ci else 417062306a36Sopenharmony_ci req->cnt = req->length - 417162306a36Sopenharmony_ci (req->ring_index - cnt); 417262306a36Sopenharmony_ci } 417362306a36Sopenharmony_ci if (req->cnt < req_cnt + 2) { 417462306a36Sopenharmony_ci rval = EXT_STATUS_BUSY; 417562306a36Sopenharmony_ci goto queuing_error; 417662306a36Sopenharmony_ci } 417762306a36Sopenharmony_ci 417862306a36Sopenharmony_ci cmd_pkt = (struct cmd_bidir *)req->ring_ptr; 417962306a36Sopenharmony_ci cmd_pkt->handle = make_handle(req->id, handle); 418062306a36Sopenharmony_ci 418162306a36Sopenharmony_ci /* Zero out remaining portion of packet. */ 418262306a36Sopenharmony_ci /* tagged queuing modifier -- default is TSK_SIMPLE (0).*/ 418362306a36Sopenharmony_ci clr_ptr = (uint32_t *)cmd_pkt + 2; 418462306a36Sopenharmony_ci memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); 418562306a36Sopenharmony_ci 418662306a36Sopenharmony_ci /* Set NPORT-ID (of vha)*/ 418762306a36Sopenharmony_ci cmd_pkt->nport_handle = cpu_to_le16(vha->self_login_loop_id); 418862306a36Sopenharmony_ci cmd_pkt->port_id[0] = vha->d_id.b.al_pa; 418962306a36Sopenharmony_ci cmd_pkt->port_id[1] = vha->d_id.b.area; 419062306a36Sopenharmony_ci cmd_pkt->port_id[2] = vha->d_id.b.domain; 419162306a36Sopenharmony_ci 419262306a36Sopenharmony_ci qla25xx_build_bidir_iocb(sp, vha, cmd_pkt, tot_dsds); 419362306a36Sopenharmony_ci cmd_pkt->entry_status = (uint8_t) rsp->id; 419462306a36Sopenharmony_ci /* Build command packet. */ 419562306a36Sopenharmony_ci req->current_outstanding_cmd = handle; 419662306a36Sopenharmony_ci req->outstanding_cmds[handle] = sp; 419762306a36Sopenharmony_ci sp->handle = handle; 419862306a36Sopenharmony_ci req->cnt -= req_cnt; 419962306a36Sopenharmony_ci 420062306a36Sopenharmony_ci /* Send the command to the firmware */ 420162306a36Sopenharmony_ci wmb(); 420262306a36Sopenharmony_ci qla2x00_start_iocbs(vha, req); 420362306a36Sopenharmony_ciqueuing_error: 420462306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 420562306a36Sopenharmony_ci 420662306a36Sopenharmony_ci return rval; 420762306a36Sopenharmony_ci} 420862306a36Sopenharmony_ci 420962306a36Sopenharmony_ci/** 421062306a36Sopenharmony_ci * qla_start_scsi_type6() - Send a SCSI command to the ISP 421162306a36Sopenharmony_ci * @sp: command to send to the ISP 421262306a36Sopenharmony_ci * 421362306a36Sopenharmony_ci * Returns non-zero if a failure occurred, else zero. 421462306a36Sopenharmony_ci */ 421562306a36Sopenharmony_cistatic int 421662306a36Sopenharmony_ciqla_start_scsi_type6(srb_t *sp) 421762306a36Sopenharmony_ci{ 421862306a36Sopenharmony_ci int nseg; 421962306a36Sopenharmony_ci unsigned long flags; 422062306a36Sopenharmony_ci uint32_t *clr_ptr; 422162306a36Sopenharmony_ci uint32_t handle; 422262306a36Sopenharmony_ci struct cmd_type_6 *cmd_pkt; 422362306a36Sopenharmony_ci uint16_t cnt; 422462306a36Sopenharmony_ci uint16_t req_cnt; 422562306a36Sopenharmony_ci uint16_t tot_dsds; 422662306a36Sopenharmony_ci struct req_que *req = NULL; 422762306a36Sopenharmony_ci struct rsp_que *rsp; 422862306a36Sopenharmony_ci struct scsi_cmnd *cmd = GET_CMD_SP(sp); 422962306a36Sopenharmony_ci struct scsi_qla_host *vha = sp->fcport->vha; 423062306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 423162306a36Sopenharmony_ci struct qla_qpair *qpair = sp->qpair; 423262306a36Sopenharmony_ci uint16_t more_dsd_lists = 0; 423362306a36Sopenharmony_ci struct dsd_dma *dsd_ptr; 423462306a36Sopenharmony_ci uint16_t i; 423562306a36Sopenharmony_ci __be32 *fcp_dl; 423662306a36Sopenharmony_ci uint8_t additional_cdb_len; 423762306a36Sopenharmony_ci struct ct6_dsd *ctx; 423862306a36Sopenharmony_ci 423962306a36Sopenharmony_ci /* Acquire qpair specific lock */ 424062306a36Sopenharmony_ci spin_lock_irqsave(&qpair->qp_lock, flags); 424162306a36Sopenharmony_ci 424262306a36Sopenharmony_ci /* Setup qpair pointers */ 424362306a36Sopenharmony_ci req = qpair->req; 424462306a36Sopenharmony_ci rsp = qpair->rsp; 424562306a36Sopenharmony_ci 424662306a36Sopenharmony_ci /* So we know we haven't pci_map'ed anything yet */ 424762306a36Sopenharmony_ci tot_dsds = 0; 424862306a36Sopenharmony_ci 424962306a36Sopenharmony_ci /* Send marker if required */ 425062306a36Sopenharmony_ci if (vha->marker_needed != 0) { 425162306a36Sopenharmony_ci if (__qla2x00_marker(vha, qpair, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) { 425262306a36Sopenharmony_ci spin_unlock_irqrestore(&qpair->qp_lock, flags); 425362306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 425462306a36Sopenharmony_ci } 425562306a36Sopenharmony_ci vha->marker_needed = 0; 425662306a36Sopenharmony_ci } 425762306a36Sopenharmony_ci 425862306a36Sopenharmony_ci handle = qla2xxx_get_next_handle(req); 425962306a36Sopenharmony_ci if (handle == 0) 426062306a36Sopenharmony_ci goto queuing_error; 426162306a36Sopenharmony_ci 426262306a36Sopenharmony_ci /* Map the sg table so we have an accurate count of sg entries needed */ 426362306a36Sopenharmony_ci if (scsi_sg_count(cmd)) { 426462306a36Sopenharmony_ci nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd), 426562306a36Sopenharmony_ci scsi_sg_count(cmd), cmd->sc_data_direction); 426662306a36Sopenharmony_ci if (unlikely(!nseg)) 426762306a36Sopenharmony_ci goto queuing_error; 426862306a36Sopenharmony_ci } else { 426962306a36Sopenharmony_ci nseg = 0; 427062306a36Sopenharmony_ci } 427162306a36Sopenharmony_ci 427262306a36Sopenharmony_ci tot_dsds = nseg; 427362306a36Sopenharmony_ci 427462306a36Sopenharmony_ci /* eventhough driver only need 1 T6 IOCB, FW still convert DSD to Continueation IOCB */ 427562306a36Sopenharmony_ci req_cnt = qla24xx_calc_iocbs(vha, tot_dsds); 427662306a36Sopenharmony_ci 427762306a36Sopenharmony_ci sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH; 427862306a36Sopenharmony_ci sp->iores.exch_cnt = 1; 427962306a36Sopenharmony_ci sp->iores.iocb_cnt = req_cnt; 428062306a36Sopenharmony_ci 428162306a36Sopenharmony_ci if (qla_get_fw_resources(sp->qpair, &sp->iores)) 428262306a36Sopenharmony_ci goto queuing_error; 428362306a36Sopenharmony_ci 428462306a36Sopenharmony_ci more_dsd_lists = qla24xx_calc_dsd_lists(tot_dsds); 428562306a36Sopenharmony_ci if ((more_dsd_lists + qpair->dsd_inuse) >= NUM_DSD_CHAIN) { 428662306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3028, 428762306a36Sopenharmony_ci "Num of DSD list %d is than %d for cmd=%p.\n", 428862306a36Sopenharmony_ci more_dsd_lists + qpair->dsd_inuse, NUM_DSD_CHAIN, cmd); 428962306a36Sopenharmony_ci goto queuing_error; 429062306a36Sopenharmony_ci } 429162306a36Sopenharmony_ci 429262306a36Sopenharmony_ci if (more_dsd_lists <= qpair->dsd_avail) 429362306a36Sopenharmony_ci goto sufficient_dsds; 429462306a36Sopenharmony_ci else 429562306a36Sopenharmony_ci more_dsd_lists -= qpair->dsd_avail; 429662306a36Sopenharmony_ci 429762306a36Sopenharmony_ci for (i = 0; i < more_dsd_lists; i++) { 429862306a36Sopenharmony_ci dsd_ptr = kzalloc(sizeof(*dsd_ptr), GFP_ATOMIC); 429962306a36Sopenharmony_ci if (!dsd_ptr) { 430062306a36Sopenharmony_ci ql_log(ql_log_fatal, vha, 0x3029, 430162306a36Sopenharmony_ci "Failed to allocate memory for dsd_dma for cmd=%p.\n", cmd); 430262306a36Sopenharmony_ci goto queuing_error; 430362306a36Sopenharmony_ci } 430462306a36Sopenharmony_ci INIT_LIST_HEAD(&dsd_ptr->list); 430562306a36Sopenharmony_ci 430662306a36Sopenharmony_ci dsd_ptr->dsd_addr = dma_pool_alloc(ha->dl_dma_pool, 430762306a36Sopenharmony_ci GFP_ATOMIC, &dsd_ptr->dsd_list_dma); 430862306a36Sopenharmony_ci if (!dsd_ptr->dsd_addr) { 430962306a36Sopenharmony_ci kfree(dsd_ptr); 431062306a36Sopenharmony_ci ql_log(ql_log_fatal, vha, 0x302a, 431162306a36Sopenharmony_ci "Failed to allocate memory for dsd_addr for cmd=%p.\n", cmd); 431262306a36Sopenharmony_ci goto queuing_error; 431362306a36Sopenharmony_ci } 431462306a36Sopenharmony_ci list_add_tail(&dsd_ptr->list, &qpair->dsd_list); 431562306a36Sopenharmony_ci qpair->dsd_avail++; 431662306a36Sopenharmony_ci } 431762306a36Sopenharmony_ci 431862306a36Sopenharmony_cisufficient_dsds: 431962306a36Sopenharmony_ci req_cnt = 1; 432062306a36Sopenharmony_ci 432162306a36Sopenharmony_ci if (req->cnt < (req_cnt + 2)) { 432262306a36Sopenharmony_ci if (IS_SHADOW_REG_CAPABLE(ha)) { 432362306a36Sopenharmony_ci cnt = *req->out_ptr; 432462306a36Sopenharmony_ci } else { 432562306a36Sopenharmony_ci cnt = (uint16_t)rd_reg_dword_relaxed(req->req_q_out); 432662306a36Sopenharmony_ci if (qla2x00_check_reg16_for_disconnect(vha, cnt)) 432762306a36Sopenharmony_ci goto queuing_error; 432862306a36Sopenharmony_ci } 432962306a36Sopenharmony_ci 433062306a36Sopenharmony_ci if (req->ring_index < cnt) 433162306a36Sopenharmony_ci req->cnt = cnt - req->ring_index; 433262306a36Sopenharmony_ci else 433362306a36Sopenharmony_ci req->cnt = req->length - (req->ring_index - cnt); 433462306a36Sopenharmony_ci if (req->cnt < (req_cnt + 2)) 433562306a36Sopenharmony_ci goto queuing_error; 433662306a36Sopenharmony_ci } 433762306a36Sopenharmony_ci 433862306a36Sopenharmony_ci ctx = &sp->u.scmd.ct6_ctx; 433962306a36Sopenharmony_ci 434062306a36Sopenharmony_ci memset(ctx, 0, sizeof(struct ct6_dsd)); 434162306a36Sopenharmony_ci ctx->fcp_cmnd = dma_pool_zalloc(ha->fcp_cmnd_dma_pool, 434262306a36Sopenharmony_ci GFP_ATOMIC, &ctx->fcp_cmnd_dma); 434362306a36Sopenharmony_ci if (!ctx->fcp_cmnd) { 434462306a36Sopenharmony_ci ql_log(ql_log_fatal, vha, 0x3031, 434562306a36Sopenharmony_ci "Failed to allocate fcp_cmnd for cmd=%p.\n", cmd); 434662306a36Sopenharmony_ci goto queuing_error; 434762306a36Sopenharmony_ci } 434862306a36Sopenharmony_ci 434962306a36Sopenharmony_ci /* Initialize the DSD list and dma handle */ 435062306a36Sopenharmony_ci INIT_LIST_HEAD(&ctx->dsd_list); 435162306a36Sopenharmony_ci ctx->dsd_use_cnt = 0; 435262306a36Sopenharmony_ci 435362306a36Sopenharmony_ci if (cmd->cmd_len > 16) { 435462306a36Sopenharmony_ci additional_cdb_len = cmd->cmd_len - 16; 435562306a36Sopenharmony_ci if (cmd->cmd_len % 4 || 435662306a36Sopenharmony_ci cmd->cmd_len > QLA_CDB_BUF_SIZE) { 435762306a36Sopenharmony_ci /* 435862306a36Sopenharmony_ci * SCSI command bigger than 16 bytes must be 435962306a36Sopenharmony_ci * multiple of 4 or too big. 436062306a36Sopenharmony_ci */ 436162306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x3033, 436262306a36Sopenharmony_ci "scsi cmd len %d not multiple of 4 for cmd=%p.\n", 436362306a36Sopenharmony_ci cmd->cmd_len, cmd); 436462306a36Sopenharmony_ci goto queuing_error_fcp_cmnd; 436562306a36Sopenharmony_ci } 436662306a36Sopenharmony_ci ctx->fcp_cmnd_len = 12 + cmd->cmd_len + 4; 436762306a36Sopenharmony_ci } else { 436862306a36Sopenharmony_ci additional_cdb_len = 0; 436962306a36Sopenharmony_ci ctx->fcp_cmnd_len = 12 + 16 + 4; 437062306a36Sopenharmony_ci } 437162306a36Sopenharmony_ci 437262306a36Sopenharmony_ci /* Build command packet. */ 437362306a36Sopenharmony_ci req->current_outstanding_cmd = handle; 437462306a36Sopenharmony_ci req->outstanding_cmds[handle] = sp; 437562306a36Sopenharmony_ci sp->handle = handle; 437662306a36Sopenharmony_ci cmd->host_scribble = (unsigned char *)(unsigned long)handle; 437762306a36Sopenharmony_ci req->cnt -= req_cnt; 437862306a36Sopenharmony_ci 437962306a36Sopenharmony_ci cmd_pkt = (struct cmd_type_6 *)req->ring_ptr; 438062306a36Sopenharmony_ci cmd_pkt->handle = make_handle(req->id, handle); 438162306a36Sopenharmony_ci 438262306a36Sopenharmony_ci /* tagged queuing modifier -- default is TSK_SIMPLE (0). */ 438362306a36Sopenharmony_ci clr_ptr = (uint32_t *)cmd_pkt + 2; 438462306a36Sopenharmony_ci memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); 438562306a36Sopenharmony_ci cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); 438662306a36Sopenharmony_ci 438762306a36Sopenharmony_ci /* Set NPORT-ID and LUN number */ 438862306a36Sopenharmony_ci cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); 438962306a36Sopenharmony_ci cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; 439062306a36Sopenharmony_ci cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; 439162306a36Sopenharmony_ci cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; 439262306a36Sopenharmony_ci cmd_pkt->vp_index = sp->vha->vp_idx; 439362306a36Sopenharmony_ci 439462306a36Sopenharmony_ci /* Build IOCB segments */ 439562306a36Sopenharmony_ci qla24xx_build_scsi_type_6_iocbs(sp, cmd_pkt, tot_dsds); 439662306a36Sopenharmony_ci 439762306a36Sopenharmony_ci int_to_scsilun(cmd->device->lun, &cmd_pkt->lun); 439862306a36Sopenharmony_ci host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); 439962306a36Sopenharmony_ci 440062306a36Sopenharmony_ci /* build FCP_CMND IU */ 440162306a36Sopenharmony_ci int_to_scsilun(cmd->device->lun, &ctx->fcp_cmnd->lun); 440262306a36Sopenharmony_ci ctx->fcp_cmnd->additional_cdb_len = additional_cdb_len; 440362306a36Sopenharmony_ci 440462306a36Sopenharmony_ci if (cmd->sc_data_direction == DMA_TO_DEVICE) 440562306a36Sopenharmony_ci ctx->fcp_cmnd->additional_cdb_len |= 1; 440662306a36Sopenharmony_ci else if (cmd->sc_data_direction == DMA_FROM_DEVICE) 440762306a36Sopenharmony_ci ctx->fcp_cmnd->additional_cdb_len |= 2; 440862306a36Sopenharmony_ci 440962306a36Sopenharmony_ci /* Populate the FCP_PRIO. */ 441062306a36Sopenharmony_ci if (ha->flags.fcp_prio_enabled) 441162306a36Sopenharmony_ci ctx->fcp_cmnd->task_attribute |= 441262306a36Sopenharmony_ci sp->fcport->fcp_prio << 3; 441362306a36Sopenharmony_ci 441462306a36Sopenharmony_ci memcpy(ctx->fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len); 441562306a36Sopenharmony_ci 441662306a36Sopenharmony_ci fcp_dl = (__be32 *)(ctx->fcp_cmnd->cdb + 16 + 441762306a36Sopenharmony_ci additional_cdb_len); 441862306a36Sopenharmony_ci *fcp_dl = htonl((uint32_t)scsi_bufflen(cmd)); 441962306a36Sopenharmony_ci 442062306a36Sopenharmony_ci cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(ctx->fcp_cmnd_len); 442162306a36Sopenharmony_ci put_unaligned_le64(ctx->fcp_cmnd_dma, 442262306a36Sopenharmony_ci &cmd_pkt->fcp_cmnd_dseg_address); 442362306a36Sopenharmony_ci 442462306a36Sopenharmony_ci sp->flags |= SRB_FCP_CMND_DMA_VALID; 442562306a36Sopenharmony_ci cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); 442662306a36Sopenharmony_ci /* Set total data segment count. */ 442762306a36Sopenharmony_ci cmd_pkt->entry_count = (uint8_t)req_cnt; 442862306a36Sopenharmony_ci 442962306a36Sopenharmony_ci wmb(); 443062306a36Sopenharmony_ci /* Adjust ring index. */ 443162306a36Sopenharmony_ci req->ring_index++; 443262306a36Sopenharmony_ci if (req->ring_index == req->length) { 443362306a36Sopenharmony_ci req->ring_index = 0; 443462306a36Sopenharmony_ci req->ring_ptr = req->ring; 443562306a36Sopenharmony_ci } else { 443662306a36Sopenharmony_ci req->ring_ptr++; 443762306a36Sopenharmony_ci } 443862306a36Sopenharmony_ci 443962306a36Sopenharmony_ci sp->qpair->cmd_cnt++; 444062306a36Sopenharmony_ci sp->flags |= SRB_DMA_VALID; 444162306a36Sopenharmony_ci 444262306a36Sopenharmony_ci /* Set chip new ring index. */ 444362306a36Sopenharmony_ci wrt_reg_dword(req->req_q_in, req->ring_index); 444462306a36Sopenharmony_ci 444562306a36Sopenharmony_ci /* Manage unprocessed RIO/ZIO commands in response queue. */ 444662306a36Sopenharmony_ci if (vha->flags.process_response_queue && 444762306a36Sopenharmony_ci rsp->ring_ptr->signature != RESPONSE_PROCESSED) 444862306a36Sopenharmony_ci qla24xx_process_response_queue(vha, rsp); 444962306a36Sopenharmony_ci 445062306a36Sopenharmony_ci spin_unlock_irqrestore(&qpair->qp_lock, flags); 445162306a36Sopenharmony_ci 445262306a36Sopenharmony_ci return QLA_SUCCESS; 445362306a36Sopenharmony_ci 445462306a36Sopenharmony_ciqueuing_error_fcp_cmnd: 445562306a36Sopenharmony_ci dma_pool_free(ha->fcp_cmnd_dma_pool, ctx->fcp_cmnd, ctx->fcp_cmnd_dma); 445662306a36Sopenharmony_ci 445762306a36Sopenharmony_ciqueuing_error: 445862306a36Sopenharmony_ci if (tot_dsds) 445962306a36Sopenharmony_ci scsi_dma_unmap(cmd); 446062306a36Sopenharmony_ci 446162306a36Sopenharmony_ci qla_put_fw_resources(sp->qpair, &sp->iores); 446262306a36Sopenharmony_ci 446362306a36Sopenharmony_ci if (sp->u.scmd.crc_ctx) { 446462306a36Sopenharmony_ci mempool_free(sp->u.scmd.crc_ctx, ha->ctx_mempool); 446562306a36Sopenharmony_ci sp->u.scmd.crc_ctx = NULL; 446662306a36Sopenharmony_ci } 446762306a36Sopenharmony_ci 446862306a36Sopenharmony_ci spin_unlock_irqrestore(&qpair->qp_lock, flags); 446962306a36Sopenharmony_ci 447062306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 447162306a36Sopenharmony_ci} 4472