static int pm80xx_chip_sata_req()

in pm8001/pm80xx_hwi.c [4532:4766]


static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
	struct pm8001_ccb_info *ccb)
{
	struct sas_task *task = ccb->task;
	struct domain_device *dev = task->dev;
	struct pm8001_device *pm8001_ha_dev = dev->lldd_dev;
	struct ata_queued_cmd *qc = task->uldd_task;
	u32 tag = ccb->ccb_tag;
	int ret;
	u32 q_index, cpu_id;
	struct sata_start_req sata_cmd;
	u32 hdr_tag, ncg_tag = 0;
	u64 phys_addr, start_addr, end_addr;
	u32 end_addr_high, end_addr_low;
	u32 ATAP = 0x0;
	u32 dir;
	struct inbound_queue_table *circularQ;
	unsigned long flags;
	u32 opc = OPC_INB_SATA_HOST_OPSTART;
	memset(&sata_cmd, 0, sizeof(sata_cmd));
	cpu_id = smp_processor_id();
	q_index = (u32) (cpu_id) % (pm8001_ha->max_q_num);
	circularQ = &pm8001_ha->inbnd_q_tbl[q_index];

	if (task->data_dir == DMA_NONE) {
		ATAP = 0x04; /* no data*/
		pm8001_dbg(pm8001_ha, IO, "no data\n");
	} else if (likely(!task->ata_task.device_control_reg_update)) {
		if (task->ata_task.dma_xfer) {
			ATAP = 0x06; /* DMA */
			pm8001_dbg(pm8001_ha, IO, "DMA\n");
		} else {
			ATAP = 0x05; /* PIO*/
			pm8001_dbg(pm8001_ha, IO, "PIO\n");
		}
		if (task->ata_task.use_ncq &&
		    dev->sata_dev.class != ATA_DEV_ATAPI) {
			ATAP = 0x07; /* FPDMA */
			pm8001_dbg(pm8001_ha, IO, "FPDMA\n");
		}
	}
	if (task->ata_task.use_ncq && pm8001_get_ncq_tag(task, &hdr_tag)) {
		task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3);
		ncg_tag = hdr_tag;
	}
	dir = data_dir_flags[task->data_dir] << 8;
	sata_cmd.tag = cpu_to_le32(tag);
	sata_cmd.device_id = cpu_to_le32(pm8001_ha_dev->device_id);
	sata_cmd.data_len = cpu_to_le32(task->total_xfer_len);

	sata_cmd.sata_fis = task->ata_task.fis;
	if (likely(!task->ata_task.device_control_reg_update))
		sata_cmd.sata_fis.flags |= 0x80;/* C=1: update ATA cmd reg */
	sata_cmd.sata_fis.flags &= 0xF0;/* PM_PORT field shall be 0 */

	/* Check if encryption is set */
	if (pm8001_ha->chip->encrypt &&
		!(pm8001_ha->encrypt_info.status) && check_enc_sat_cmd(task)) {
		pm8001_dbg(pm8001_ha, IO,
			   "Encryption enabled.Sending Encrypt SATA cmd 0x%x\n",
			   sata_cmd.sata_fis.command);
		opc = OPC_INB_SATA_DIF_ENC_IO;

		/* set encryption bit */
		sata_cmd.ncqtag_atap_dir_m_dad =
			cpu_to_le32(((ncg_tag & 0xff)<<16)|
				((ATAP & 0x3f) << 10) | 0x20 | dir);
							/* dad (bit 0-1) is 0 */
		/* fill in PRD (scatter/gather) table, if any */
		if (task->num_scatter > 1) {
			pm8001_chip_make_sg(task->scatter,
						ccb->n_elem, ccb->buf_prd);
			phys_addr = ccb->ccb_dma_handle;
			sata_cmd.enc_addr_low = lower_32_bits(phys_addr);
			sata_cmd.enc_addr_high = upper_32_bits(phys_addr);
			sata_cmd.enc_esgl = cpu_to_le32(1 << 31);
		} else if (task->num_scatter == 1) {
			u64 dma_addr = sg_dma_address(task->scatter);
			sata_cmd.enc_addr_low = lower_32_bits(dma_addr);
			sata_cmd.enc_addr_high = upper_32_bits(dma_addr);
			sata_cmd.enc_len = cpu_to_le32(task->total_xfer_len);
			sata_cmd.enc_esgl = 0;
			/* Check 4G Boundary */
			start_addr = cpu_to_le64(dma_addr);
			end_addr = (start_addr + sata_cmd.enc_len) - 1;
			end_addr_low = cpu_to_le32(lower_32_bits(end_addr));
			end_addr_high = cpu_to_le32(upper_32_bits(end_addr));
			if (end_addr_high != sata_cmd.enc_addr_high) {
				pm8001_dbg(pm8001_ha, FAIL,
					   "The sg list address start_addr=0x%016llx data_len=0x%x end_addr_high=0x%08x end_addr_low=0x%08x has crossed 4G boundary\n",
					   start_addr, sata_cmd.enc_len,
					   end_addr_high, end_addr_low);
				pm8001_chip_make_sg(task->scatter, 1,
					ccb->buf_prd);
				phys_addr = ccb->ccb_dma_handle;
				sata_cmd.enc_addr_low =
					lower_32_bits(phys_addr);
				sata_cmd.enc_addr_high =
					upper_32_bits(phys_addr);
				sata_cmd.enc_esgl =
					cpu_to_le32(1 << 31);
			}
		} else if (task->num_scatter == 0) {
			sata_cmd.enc_addr_low = 0;
			sata_cmd.enc_addr_high = 0;
			sata_cmd.enc_len = cpu_to_le32(task->total_xfer_len);
			sata_cmd.enc_esgl = 0;
		}
		/* XTS mode. All other fields are 0 */
		sata_cmd.key_index_mode = 0x6 << 4;
		/* set tweak values. Should be the start lba */
		sata_cmd.twk_val0 =
			cpu_to_le32((sata_cmd.sata_fis.lbal_exp << 24) |
					(sata_cmd.sata_fis.lbah << 16) |
					(sata_cmd.sata_fis.lbam << 8) |
					(sata_cmd.sata_fis.lbal));
		sata_cmd.twk_val1 =
			cpu_to_le32((sata_cmd.sata_fis.lbah_exp << 8) |
					 (sata_cmd.sata_fis.lbam_exp));
	} else {
		pm8001_dbg(pm8001_ha, IO,
			   "Sending Normal SATA command 0x%x inb %x\n",
			   sata_cmd.sata_fis.command, q_index);
		/* dad (bit 0-1) is 0 */
		sata_cmd.ncqtag_atap_dir_m_dad =
			cpu_to_le32(((ncg_tag & 0xff)<<16) |
					((ATAP & 0x3f) << 10) | dir);

		/* fill in PRD (scatter/gather) table, if any */
		if (task->num_scatter > 1) {
			pm8001_chip_make_sg(task->scatter,
					ccb->n_elem, ccb->buf_prd);
			phys_addr = ccb->ccb_dma_handle;
			sata_cmd.addr_low = lower_32_bits(phys_addr);
			sata_cmd.addr_high = upper_32_bits(phys_addr);
			sata_cmd.esgl = cpu_to_le32(1 << 31);
		} else if (task->num_scatter == 1) {
			u64 dma_addr = sg_dma_address(task->scatter);
			sata_cmd.addr_low = lower_32_bits(dma_addr);
			sata_cmd.addr_high = upper_32_bits(dma_addr);
			sata_cmd.len = cpu_to_le32(task->total_xfer_len);
			sata_cmd.esgl = 0;
			/* Check 4G Boundary */
			start_addr = cpu_to_le64(dma_addr);
			end_addr = (start_addr + sata_cmd.len) - 1;
			end_addr_low = cpu_to_le32(lower_32_bits(end_addr));
			end_addr_high = cpu_to_le32(upper_32_bits(end_addr));
			if (end_addr_high != sata_cmd.addr_high) {
				pm8001_dbg(pm8001_ha, FAIL,
					   "The sg list address start_addr=0x%016llx data_len=0x%xend_addr_high=0x%08x end_addr_low=0x%08x has crossed 4G boundary\n",
					   start_addr, sata_cmd.len,
					   end_addr_high, end_addr_low);
				pm8001_chip_make_sg(task->scatter, 1,
					ccb->buf_prd);
				phys_addr = ccb->ccb_dma_handle;
				sata_cmd.addr_low =
					lower_32_bits(phys_addr);
				sata_cmd.addr_high =
					upper_32_bits(phys_addr);
				sata_cmd.esgl = cpu_to_le32(1 << 31);
			}
		} else if (task->num_scatter == 0) {
			sata_cmd.addr_low = 0;
			sata_cmd.addr_high = 0;
			sata_cmd.len = cpu_to_le32(task->total_xfer_len);
			sata_cmd.esgl = 0;
		}
		/* scsi cdb */
		sata_cmd.atapi_scsi_cdb[0] =
			cpu_to_le32(((task->ata_task.atapi_packet[0]) |
			(task->ata_task.atapi_packet[1] << 8) |
			(task->ata_task.atapi_packet[2] << 16) |
			(task->ata_task.atapi_packet[3] << 24)));
		sata_cmd.atapi_scsi_cdb[1] =
			cpu_to_le32(((task->ata_task.atapi_packet[4]) |
			(task->ata_task.atapi_packet[5] << 8) |
			(task->ata_task.atapi_packet[6] << 16) |
			(task->ata_task.atapi_packet[7] << 24)));
		sata_cmd.atapi_scsi_cdb[2] =
			cpu_to_le32(((task->ata_task.atapi_packet[8]) |
			(task->ata_task.atapi_packet[9] << 8) |
			(task->ata_task.atapi_packet[10] << 16) |
			(task->ata_task.atapi_packet[11] << 24)));
		sata_cmd.atapi_scsi_cdb[3] =
			cpu_to_le32(((task->ata_task.atapi_packet[12]) |
			(task->ata_task.atapi_packet[13] << 8) |
			(task->ata_task.atapi_packet[14] << 16) |
			(task->ata_task.atapi_packet[15] << 24)));
	}

	/* Check for read log for failed drive and return */
	if (sata_cmd.sata_fis.command == 0x2f) {
		if (pm8001_ha_dev && ((pm8001_ha_dev->id & NCQ_READ_LOG_FLAG) ||
			(pm8001_ha_dev->id & NCQ_ABORT_ALL_FLAG) ||
			(pm8001_ha_dev->id & NCQ_2ND_RLE_FLAG))) {
			struct task_status_struct *ts;

			pm8001_ha_dev->id &= 0xDFFFFFFF;
			ts = &task->task_status;

			spin_lock_irqsave(&task->task_state_lock, flags);
			ts->resp = SAS_TASK_COMPLETE;
			ts->stat = SAS_SAM_STAT_GOOD;
			task->task_state_flags &= ~SAS_TASK_STATE_PENDING;
			task->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
			task->task_state_flags |= SAS_TASK_STATE_DONE;
			if (unlikely((task->task_state_flags &
					SAS_TASK_STATE_ABORTED))) {
				spin_unlock_irqrestore(&task->task_state_lock,
							flags);
				pm8001_dbg(pm8001_ha, FAIL,
					   "task 0x%p resp 0x%x  stat 0x%x but aborted by upper layer\n",
					   task, ts->resp,
					   ts->stat);
				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
				return 0;
			} else {
				spin_unlock_irqrestore(&task->task_state_lock,
							flags);
				pm8001_ccb_task_free_done(pm8001_ha, task,
								ccb, tag);
				atomic_dec(&pm8001_ha_dev->running_req);
				return 0;
			}
		}
	}
	trace_pm80xx_request_issue(pm8001_ha->id,
				ccb->device ? ccb->device->attached_phy : PM8001_MAX_PHYS,
				ccb->ccb_tag, opc,
				qc ? qc->tf.command : 0, // ata opcode
				ccb->device ? atomic_read(&ccb->device->running_req) : 0);
	ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc,
			&sata_cmd, sizeof(sata_cmd), q_index);
	return ret;
}